diff --git a/CHANGELOG.md b/CHANGELOG.md index 31063e9c8d..affa9a803d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ * **Build 21x** (2015-03-xx) - Form fields can now use a simpler interface for using the Input preset converter (see Backend > Forms docs). + - The event `cms.page.init` no longer passes the URL as the third parameter, `$controller->getRouter()->getUrl()` should be used instead. * **Build 217** (2015-03-06) - Improvements made to the user menu in the back-end: clicking your avatar will display a popover with settings links from the `mysettings` context. diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 1dab0b07ab..d9f71d8c52 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -130,16 +130,6 @@ public function __construct($theme = null) self::$instance = $this; } - /** - * Returns an existing instance of the controller. - * If the controller doesn't exists, returns null. - * @return mixed Returns the controller object or null; - */ - public static function getController() - { - return self::$instance; - } - /** * Finds and serves the requested page. * If the page cannot be found, returns the page with the URL /404. @@ -210,6 +200,54 @@ public function run($url = '/') } } + /* + * Run the page + */ + $result = $this->runPage($page, $this->router->getParameters()); + + /* + * Extensibility + */ + if ( + ($event = $this->fireEvent('page.display', [$url, $page, $result], true)) || + ($event = Event::fire('cms.page.display', [$this, $url, $page, $result], true)) + ) { + return $event; + } + + if (!is_string($result)) { + return $result; + } + + return Response::make($result, $this->statusCode); + } + + /** + * Renders a page in its entirety, including component initialization. + * AJAX will be disabled for this process. + * @param string $pageFile Specifies the CMS page file name to run. + * @param array $params Routing parameters. + * @param \Cms\Classes\Theme $theme Theme object + */ + public static function render($pageFile, $params = [], $theme = null) + { + if (!$theme && (!$theme = Theme::getActiveTheme())) { + throw new CmsException(Lang::get('cms::lang.theme.active.not_found')); + } + + $controller = new static($theme); + $page = Page::load($theme, $pageFile); + return $controller->runPage($page, $params, false); + } + + /** + * Runs a page directly from its object and supplied parameters. + * @param \Cms\Classes\Page $page Specifies the CMS page to run. + * @param array $params Routing parameters. + * @return string + */ + public function runPage($page, $params = [], $useAjax = true) + { $this->page = $page; /* @@ -232,7 +270,7 @@ public function run($url = '/') 'page' => $this->page, 'layout' => $this->layout, 'theme' => $this->theme, - 'param' => $this->router->getParameters(), + 'param' => $params, 'controller' => $this, 'environment' => App::environment(), 'session' => App::make('session'), @@ -270,8 +308,8 @@ public function run($url = '/') * Extensibility */ if ( - ($event = $this->fireEvent('page.init', [$url, $page], true)) || - ($event = Event::fire('cms.page.init', [$this, $url, $page], true)) + ($event = $this->fireEvent('page.init', [$page], true)) || + ($event = Event::fire('cms.page.init', [$this, $page], true)) ) { return $event; } @@ -279,7 +317,7 @@ public function run($url = '/') /* * Execute AJAX event */ - if ($ajaxResponse = $this->execAjaxHandlers()) { + if ($useAjax && $ajaxResponse = $this->execAjaxHandlers()) { return $ajaxResponse; } @@ -287,6 +325,7 @@ public function run($url = '/') * Execute postback handler */ if ( + $useAjax && ($handler = post('_handler')) && ($handlerResponse = $this->runAjaxHandler($handler)) && $handlerResponse !== true @@ -330,23 +369,89 @@ public function run($url = '/') $result = $template->render($this->vars); CmsException::unmask(); + return $result; + } + + /** + * Invokes the current page cycle without rendering the page, + * used by AJAX handler that may rely on the logic inside the action. + */ + public function pageCycle() + { + return $this->execPageCycle(); + } + + /** + * Executes the page life cycle. + * Creates an object from the PHP sections of the page and + * it's layout, then executes their life cycle functions. + */ + protected function execPageCycle() + { /* * Extensibility */ if ( - ($event = $this->fireEvent('page.display', [$url, $page, $result], true)) || - ($event = Event::fire('cms.page.display', [$this, $url, $page, $result], true)) + ($event = $this->fireEvent('page.start', [], true)) || + ($event = Event::fire('cms.page.start', [$this], true)) ) { return $event; } - if (!is_string($result)) { - return $result; + /* + * Run layout functions + */ + if ($this->layoutObj) { + CmsException::mask($this->layout, 300); + $response = (($result = $this->layoutObj->onStart()) || + ($result = $this->layout->runComponents()) || + ($result = $this->layoutObj->onBeforePageStart())) ? $result: null; + CmsException::unmask(); + + if ($response) { + return $response; + } } - return Response::make($result, $this->statusCode); + /* + * Run page functions + */ + CmsException::mask($this->page, 300); + $response = (($result = $this->pageObj->onStart()) || + ($result = $this->page->runComponents()) || + ($result = $this->pageObj->onEnd())) ? $result : null; + CmsException::unmask(); + + if ($response) { + return $response; + } + + /* + * Run remaining layout functions + */ + if ($this->layoutObj) { + CmsException::mask($this->layout, 300); + $response = ($result = $this->layoutObj->onEnd()) ? $result : null; + CmsException::unmask(); + } + + /* + * Extensibility + */ + if ( + ($event = $this->fireEvent('page.end', [], true)) || + ($event = Event::fire('cms.page.end', [$this], true)) + ) { + return $event; + } + + return $response; } + // + // Initialization + // + /** * Initializes the Twig environment and loader. * Registers the \Cms\Twig\Extension object with Twig. @@ -427,39 +532,9 @@ protected function initComponents() Event::fire('cms.page.initComponents', [$this, $this->page, $this->layout]); } - /** - * Adds a component to the page object - * @param mixed $name Component class name or short name - * @param string $alias Alias to give the component - * @param array $properties Component properties - * @param bool $addToLayout Add to layout, instead of page - * @return ComponentBase Component object - */ - public function addComponent($name, $alias, $properties, $addToLayout = false) - { - $manager = ComponentManager::instance(); - - if ($addToLayout) { - if (!$componentObj = $manager->makeComponent($name, $this->layoutObj, $properties)) { - throw new CmsException(Lang::get('cms::lang.component.not_found', ['name'=>$name])); - } - - $componentObj->alias = $alias; - $this->vars[$alias] = $this->layout->components[$alias] = $componentObj; - } - else { - if (!$componentObj = $manager->makeComponent($name, $this->pageObj, $properties)) { - throw new CmsException(Lang::get('cms::lang.component.not_found', ['name'=>$name])); - } - - $componentObj->alias = $alias; - $this->vars[$alias] = $this->page->components[$alias] = $componentObj; - } - - $this->setComponentPropertiesFromParams($componentObj); - $componentObj->init(); - return $componentObj; - } + // + // AJAX + // /** * Executes the page, layout, component and plugin AJAX handlers. @@ -593,81 +668,9 @@ protected function runAjaxHandler($handler) return false; } - /** - * Invokes the current page cycle without rendering the page, - * used by AJAX handler that may rely on the logic inside the action. - */ - public function pageCycle() - { - return $this->execPageCycle(); - } - - /** - * Executes the page life cycle. - * Creates an object from the PHP sections of the page and - * it's layout, then executes their life cycle functions. - */ - protected function execPageCycle() - { - /* - * Extensibility - */ - if ( - ($event = $this->fireEvent('page.start', [], true)) || - ($event = Event::fire('cms.page.start', [$this], true)) - ) { - return $event; - } - - /* - * Run layout functions - */ - if ($this->layoutObj) { - CmsException::mask($this->layout, 300); - $response = (($result = $this->layoutObj->onStart()) || - ($result = $this->layout->runComponents()) || - ($result = $this->layoutObj->onBeforePageStart())) ? $result: null; - CmsException::unmask(); - - if ($response) { - return $response; - } - } - - /* - * Run page functions - */ - CmsException::mask($this->page, 300); - $response = (($result = $this->pageObj->onStart()) || - ($result = $this->page->runComponents()) || - ($result = $this->pageObj->onEnd())) ? $result : null; - CmsException::unmask(); - - if ($response) { - return $response; - } - - /* - * Run remaining layout functions - */ - if ($this->layoutObj) { - CmsException::mask($this->layout, 300); - $response = ($result = $this->layoutObj->onEnd()) ? $result : null; - CmsException::unmask(); - } - - /* - * Extensibility - */ - if ( - ($event = $this->fireEvent('page.end', [], true)) || - ($event = Event::fire('cms.page.end', [$this], true)) - ) { - return $event; - } - - return $response; - } + // + // Rendering + // /** * Renders a requested page. @@ -913,6 +916,10 @@ public function renderComponent($name, $parameters = []) return $this->renderPartial($name.'::default', [], false); } + // + // Setters + // + /** * Sets the status code for the current web response. * @param int $code Status code @@ -923,6 +930,20 @@ public function setStatusCode($code) return $this; } + // + // Getters + // + + /** + * Returns an existing instance of the controller. + * If the controller doesn't exists, returns null. + * @return mixed Returns the controller object or null. + */ + public static function getController() + { + return self::$instance; + } + /** * Returns the current CMS theme. * @return \Cms\Classes\Theme @@ -988,6 +1009,10 @@ public function getLayoutObject() return $this->layoutObj; } + // + // Page helpers + // + /** * Looks up the URL for a supplied page and returns it relative to the website root. * @@ -1070,6 +1095,44 @@ public function param($name, $default = null) return $this->router->getParameter($name, $default); } + // + // Component helpers + // + + /** + * Adds a component to the page object + * @param mixed $name Component class name or short name + * @param string $alias Alias to give the component + * @param array $properties Component properties + * @param bool $addToLayout Add to layout, instead of page + * @return ComponentBase Component object + */ + public function addComponent($name, $alias, $properties, $addToLayout = false) + { + $manager = ComponentManager::instance(); + + if ($addToLayout) { + if (!$componentObj = $manager->makeComponent($name, $this->layoutObj, $properties)) { + throw new CmsException(Lang::get('cms::lang.component.not_found', ['name'=>$name])); + } + + $componentObj->alias = $alias; + $this->vars[$alias] = $this->layout->components[$alias] = $componentObj; + } + else { + if (!$componentObj = $manager->makeComponent($name, $this->pageObj, $properties)) { + throw new CmsException(Lang::get('cms::lang.component.not_found', ['name'=>$name])); + } + + $componentObj->alias = $alias; + $this->vars[$alias] = $this->page->components[$alias] = $componentObj; + } + + $this->setComponentPropertiesFromParams($componentObj); + $componentObj->init(); + return $componentObj; + } + /** * Searches the layout and page components by an alias * @return ComponentBase The component object, if found diff --git a/modules/cms/classes/Router.php b/modules/cms/classes/Router.php index 779947e193..44f684b467 100644 --- a/modules/cms/classes/Router.php +++ b/modules/cms/classes/Router.php @@ -41,6 +41,11 @@ class Router */ protected $theme; + /** + * @var string The last URL to be looked up using findByUrl(). + */ + protected $url; + /** * @var array A list of parameters names and values extracted from the URL pattern and URL string. */ @@ -49,12 +54,12 @@ class Router /** * @var array Contains the URL map - the list of page file names and corresponding URL patterns. */ - private static $urlMap = []; + protected static $urlMap = []; /** * October\Rain\Router\Router Router object with routes preloaded. */ - private static $routerObj; + protected static $routerObj; /** * Creates the router instance. @@ -72,6 +77,7 @@ public function __construct(Theme $theme) */ public function findByUrl($url) { + $this->url = $url; $url = RouterHelper::normalizeUrl($url); $apiResult = Event::fire('cms.router.beforeRoute', [$url], true); @@ -268,6 +274,15 @@ public function getParameters() return $this->parameters; } + /** + * Returns the last URL to be looked up. + * @return string + */ + public function getUrl() + { + return $this->url; + } + /** * Returns a routing parameter. * @return array