Step 1. Routing
Details: How is the CMS frontend router (Magento\Cms\Controller\Router
) implemented?
Step 2. Magento\Cms\Controller\Page\View::execute()
/**
* View CMS page action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
$pageId = $this->getRequest()->getParam('page_id', $this->getRequest()->getParam('id', false));
$resultPage = $this->_objectManager->get('Magento\Cms\Helper\Page')->prepareResultPage($this, $pageId);
if (!$resultPage) {
$resultForward = $this->resultForwardFactory->create();
return $resultForward->forward('noroute');
}
return $resultPage;
}
Please note that the page is instantiated using the Magento\Framework\ObjectManagerInterface::get()
method, so the page is a singleton , and this object will be used later by the Magento\Cms\Block\Page
block.
Step 3. Magento\Cms\Helper\Page::prepareResultPage(). Loading the page from the database.
if ($pageId !== null && $pageId !== $this->_page->getId()) {
$delimiterPosition = strrpos($pageId, '|');
if ($delimiterPosition) {
$pageId = substr($pageId, 0, $delimiterPosition);
}
$this->_page->setStoreId($this->_storeManager->getStore()->getId());
if (!$this->_page->load($pageId)) {
return false;
}
}
if (!$this->_page->getId()) {
return false;
}
$inRange = $this->_localeDate->isScopeDateInInterval(
null,
$this->_page->getCustomThemeFrom(),
$this->_page->getCustomThemeTo()
);
if ($this->_page->getCustomTheme()) {
if ($inRange) {
$this->_design->setDesignTheme($this->_page->getCustomTheme());
}
}
Step 4. Creating the resulting instance of Magento\Framework\View\Result\Page
Step 4.1. Magento\Framework\View\Result\PageFactory::create()
/**
* Create new page regarding its type
*
* TODO: As argument has to be controller action interface, temporary solution until controller output models
* TODO: are not implemented
*
* @param bool $isView
* @param array $arguments
* @return \Magento\Framework\View\Result\Page
*/
public function create($isView = false, array $arguments = [])
{
/** @var \Magento\Framework\View\Result\Page $page */
$page = $this->objectManager->create($this->instanceName, $arguments);
// TODO Temporary solution for compatibility with View object. Will be deleted in MAGETWO-28359
if (!$isView) {
$page->addDefaultHandle();
}
return $page;
}
Step 5. Magento\Cms\Helper\Page::setLayoutType()
/**
* Set layout type
*
* @param bool $inRange
* @param \Magento\Framework\View\Result\Page $resultPage
* @return \Magento\Framework\View\Result\Page
*/
protected function setLayoutType($inRange, $resultPage)
{
if ($this->_page->getPageLayout()) {
if ($this->_page->getCustomPageLayout()
&& $this->_page->getCustomPageLayout() != 'empty'
&& $inRange
) {
$handle = $this->_page->getCustomPageLayout();
} else {
$handle = $this->_page->getPageLayout();
}
$resultPage->getConfig()->setPageLayout($handle);
}
return $resultPage;
}
Step 6. Layout handles setup
$resultPage->addHandle('cms_page_view');
$resultPage->addPageLayoutHandles(['id' => $this->_page->getIdentifier()]);
$this->_eventManager->dispatch(
'cms_page_render',
['page' => $this->_page, 'controller_action' => $action]
);
if ($this->_page->getCustomLayoutUpdateXml() && $inRange) {
$layoutUpdate = $this->_page->getCustomLayoutUpdateXml();
} else {
$layoutUpdate = $this->_page->getLayoutUpdateXml();
}
if (!empty($layoutUpdate)) {
$resultPage->getLayout()->getUpdate()->addUpdate($layoutUpdate);
}
Step 7. The layout building.
This code looks like just the page_content_heading
block setup (this block is not used for the «About us » page), but really any call for the Magento\Framework\View\Layout::getBlock()
method builds the layout (if it is not yet built):
Step 8. Magento\Cms\Block\Page::__construct()
/**
* Construct
*
* @param \Magento\Framework\View\Element\Context $context
* @param \Magento\Cms\Model\Page $page
* @param \Magento\Cms\Model\Template\FilterProvider $filterProvider
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Cms\Model\PageFactory $pageFactory
* @param \Magento\Framework\View\Page\Config $pageConfig
* @param array $data
*/
public function __construct(
\Magento\Framework\View\Element\Context $context,
\Magento\Cms\Model\Page $page,
\Magento\Cms\Model\Template\FilterProvider $filterProvider,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Cms\Model\PageFactory $pageFactory,
\Magento\Framework\View\Page\Config $pageConfig,
array $data = []
) {
parent::__construct($context, $data);
// used singleton (instead factory) because there exist dependencies on \Magento\Cms\Helper\Page
$this->_page = $page;
$this->_filterProvider = $filterProvider;
$this->_storeManager = $storeManager;
$this->_pageFactory = $pageFactory;
$this->pageConfig = $pageConfig;
}
The $page
is the singleton was created on the Step 2 .
Step 9. Magento\Cms\Block\Page::_prepareLayout()
Step 10. Magento\Cms\Block\Page::_addBreadcrumbs()
/**
* Prepare breadcrumbs
*
* @param \Magento\Cms\Model\Page $page
* @throws \Magento\Framework\Exception\LocalizedException
* @return void
*/
protected function _addBreadcrumbs(\Magento\Cms\Model\Page $page)
{
if ($this->_scopeConfig->getValue('web/default/show_cms_breadcrumbs', ScopeInterface::SCOPE_STORE)
&& ($breadcrumbsBlock = $this->getLayout()->getBlock('breadcrumbs'))
&& $page->getIdentifier() !== $this->_scopeConfig->getValue(
'web/default/cms_home_page',
ScopeInterface::SCOPE_STORE
)
&& $page->getIdentifier() !== $this->_scopeConfig->getValue(
'web/default/cms_no_route',
ScopeInterface::SCOPE_STORE
)
) {
$breadcrumbsBlock->addCrumb(
'home',
[
'label' => __('Home'),
'title' => __('Go to Home Page'),
'link' => $this->_storeManager->getStore()->getBaseUrl()
]
);
$breadcrumbsBlock->addCrumb('cms_page', ['label' => $page->getTitle(), 'title' => $page->getTitle()]);
}
}
Step 11. Magento\Cms\Controller\Page\View::execute() finish
Step 12. Magento\Framework\App\Action\Action::dispatch() finish
$result = $this->execute();
\Magento\Framework\Profiler::start('postdispatch');
if (!$this->_actionFlag->get('', self::FLAG_NO_POST_DISPATCH)) {
$this->_eventManager->dispatch(
'controller_action_postdispatch_' . $request->getFullActionName(),
$eventParameters
);
$this->_eventManager->dispatch(
'controller_action_postdispatch_' . $request->getRouteName(),
$eventParameters
);
$this->_eventManager->dispatch('controller_action_postdispatch', $eventParameters);
}
\Magento\Framework\Profiler::stop('postdispatch');
\Magento\Framework\Profiler::stop('action_body');
}
\Magento\Framework\Profiler::stop($profilerKey);
return $result ?: $this->_response;
Step 13. Magento\Framework\App\FrontController::dispatch() finish
Step 14. Returning to Magento\Framework\App\Http::launch(). Starting the page rendering
$result = $frontController->dispatch($this->_request);
// TODO: Temporary solution until all controllers return ResultInterface (MAGETWO-28359)
if ($result instanceof ResultInterface) {
$this->registry->register('use_page_cache_plugin', true, true);
$result->renderResult($this->_response);
Step 15. Magento\Framework\View\Result\Layout::renderResult()
Step 17. Magento_Cms/view/frontend/layout/cms_page_view.xml
Step 18. Magento\Cms\Block\Page::_toHtml()
The block was constructed on the Step 8.