grav/system/src/Grav/Common/Grav.php

302 lines
8.6 KiB
PHP

<?php
namespace Grav\Common;
use Grav\Common\Page\Pages;
use Grav\Common\Service\ConfigServiceProvider;
use Grav\Common\Service\ErrorServiceProvider;
use Grav\Common\Service\StreamsServiceProvider;
use RocketTheme\Toolbox\DI\Container;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\Event\EventDispatcher;
use Grav\Common\Page\Medium;
/**
* Grav
*
* @author Andy Miller
* @link http://www.rockettheme.com
* @license http://opensource.org/licenses/MIT
*
* Influenced by Pico, Stacey, Kirby, PieCrust and other great platforms...
*/
class Grav extends Container
{
/**
* @var string
*/
protected $output;
/**
* @var static
*/
protected static $instance;
public static function instance(array $values = array())
{
if (!self::$instance) {
self::$instance = static::load($values);
GravTrait::setGrav(self::$instance);
} elseif ($values) {
$instance = self::$instance;
foreach ($values as $key => $value) {
$instance->offsetSet($key, $value);
}
}
return self::$instance;
}
protected static function load(array $values)
{
$container = new static($values);
$container['grav'] = $container;
$container['debugger'] = new Debugger();
$container['debugger']->startTimer('_init', 'Init');
$container->register(new ErrorServiceProvider);
$container['uri'] = function ($c) {
return new Uri($c);
};
$container['task'] = function ($c) {
return !empty($_POST['task']) ? $_POST['task'] : $c['uri']->param('task');
};
$container['events'] = function ($c) {
return new EventDispatcher;
};
$container['cache'] = function ($c) {
return new Cache($c);
};
$container['plugins'] = function ($c) {
return new Plugins($c);
};
$container['themes'] = function ($c) {
return new Themes($c);
};
$container['twig'] = function ($c) {
return new Twig($c);
};
$container['taxonomy'] = function ($c) {
return new Taxonomy($c);
};
$container['pages'] = function ($c) {
return new Page\Pages($c);
};
$container['assets'] = function ($c) {
return new Assets();
};
$container['page'] = function ($c) {
/** @var Pages $pages */
$pages = $c['pages'];
$page = $pages->dispatch($c['uri']->route());
if (!$page || !$page->routable()) {
// special case where a media file is requested
if (!$page) {
$path_parts = pathinfo($c['uri']->route());
$page = $c['pages']->dispatch($path_parts['dirname']);
if ($page) {
$media = $page->media()->all();
$media_file = urldecode($path_parts['basename']);
if (isset($media[$media_file])) {
$medium = $media[$media_file];
// loop through actions for the image and call them
foreach ($c['uri']->query(null,true) as $action => $params) {
if (in_array($action, Medium::$valid_actions)) {
call_user_func_array(array(&$medium, $action), explode(',', $params));
}
}
header('Content-type: '. $mime = $medium->get('mime'));
echo file_get_contents($medium->path());
die;
}
}
}
// If no page found, fire event
$event = $c->fireEvent('onPageNotFound');
if (isset($event->page)) {
$page = $event->page;
} else {
throw new \RuntimeException('Page Not Found', 404);
}
}
return $page;
};
$container['output'] = function ($c) {
return $c['twig']->processSite($c['uri']->extension());
};
$container['browser'] = function ($c) {
return new Browser();
};
$container->register(new StreamsServiceProvider);
$container->register(new ConfigServiceProvider);
$container['debugger']->stopTimer('_init');
return $container;
}
public function process()
{
// Use output buffering to prevent headers from being sent too early.
ob_start();
// Initialize configuration.
$this['debugger']->startTimer('_config', 'Configuration');
$this['config']->init();
$this['debugger']->stopTimer('_config');
$this['debugger']->startTimer('_debugger', 'Debugger');
$this['debugger']->init();
$this['debugger']->stopTimer('_debugger');
$this['debugger']->startTimer('plugins', 'Plugins');
$this['plugins']->init();
$this->fireEvent('onPluginsInitialized');
$this['debugger']->stopTimer('plugins');
$this['debugger']->startTimer('themes', 'Themes');
$this['themes']->init();
$this->fireEvent('onThemeInitialized');
$this['debugger']->stopTimer('themes');
$task = $this['task'];
if ($task) {
$this->fireEvent('onTask.' . $task);
}
$this['assets']->init();
$this['debugger']->addAssets();
$this->fireEvent('onAssetsInitialized');
$this['debugger']->startTimer('twig', 'Twig');
$this['twig']->init();
$this['debugger']->stopTimer('twig');
$this['debugger']->startTimer('pages', 'Pages');
$this['pages']->init();
$this->fireEvent('onPagesInitialized');
$this['debugger']->stopTimer('pages');
$this->fireEvent('onPageInitialized');
// Process whole page as required
$this['debugger']->startTimer('render', 'Render');
$this->output = $this['output'];
$this->fireEvent('onOutputGenerated');
$this['debugger']->stopTimer('render');
// Set the header type
$this->header();
echo $this->output;
$this['debugger']->render();
$this->fireEvent('onOutputRendered');
register_shutdown_function([$this, 'shutdown']);
}
/**
* Redirect browser to another location.
*
* @param string $route Internal route.
* @param int $code Redirection code (30x)
*/
public function redirect($route, $code = 303)
{
/** @var Uri $uri */
$uri = $this['uri'];
if (isset($this['session'])) {
$this['session']->close();
}
header("Location: " . rtrim($uri->rootUrl(), '/') .'/'. trim($route, '/'), true, $code);
exit();
}
/**
* Returns mime type for the file format.
*
* @param string $format
* @return string
*/
public function mime($format)
{
switch ($format) {
case 'json':
return 'application/json';
case 'html':
return 'text/html';
case 'atom':
return 'application/atom+xml';
case 'rss':
return 'application/rss+xml';
case 'xml':
return 'application/xml';
}
return 'text/html';
}
/**
* Set response header.
*/
public function header()
{
header('Content-type: ' . $this->mime($this['uri']->extension()));
}
/**
* Fires an event with optional parameters.
*
* @param string $eventName
* @param Event $event
* @return Event
*/
public function fireEvent($eventName, Event $event = null)
{
/** @var EventDispatcher $events */
$events = $this['events'];
return $events->dispatch($eventName, $event);
}
/**
* Set the final content length for the page and flush the buffer
*
*/
public function shutdown()
{
if($this['config']->get('system.debugger.shutdown.close_connection')) {
set_time_limit(0);
ignore_user_abort(true);
if (isset($this['session'])) {
$this['session']->close();
}
header('Content-length: ' . ob_get_length());
header("Connection: close\r\n");
ob_end_flush();
ob_flush();
flush();
}
$this->fireEvent('onShutdown');
}
}