In the article, we’re going to compare routing in Magento 1 and Magento 2. Actually, there’s an article containing routing description in Magento 1, so in case you’d like to have a closer look at routing in Magento 1, read our blog.
Route determination starts from searching for current route defined in the system. The process starts here:
/vendor/magento/framework/App/FrontController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public function dispatch(RequestInterface $request) { \Magento\Framework\Profiler::start('routers_match'); $routingCycleCounter = 0; $result = null; while (!$request->isDispatched() && $routingCycleCounter++ < 100) { /** @var \Magento\Framework\App\RouterInterface $router */ foreach ($this->_routerList as $router) { try { $actionInstance = $router->match($request); if ($actionInstance) { $request->setDispatched(true); $this->response->setNoCacheHeaders(); if ($actionInstance instanceof \Magento\Framework\App\Action\AbstractAction) { $result = $actionInstance->dispatch($request); } else { $result = $actionInstance->execute(); } break; } } catch (\Magento\Framework\Exception\NotFoundException $e) { $request->initForward(); $request->setActionName('noroute'); $request->setDispatched(false); break; } } } \Magento\Framework\Profiler::stop('routers_match'); if ($routingCycleCounter > 100) { throw new \LogicException('Front controller reached 100 router match iterations'); } return $result; } |
In the method dispatch() as well as in Magento 1 file app/code/core/Mage/Core/Controller/Varien/Front.php there are some matches:
- Checking is a request by dispatcher ($request->isDispatched());
- Searching for matches ($router->match($request)).
In comparison with Magento 1, there are only two routings determined in Magento 2:
- /vendor/magento/framework/App/Router/Base.php;
- /vendor/magento/framework/App/Router/DefaultRouter.php.
The same as in Magento 1, after 100 iterations if a router is not found, there will be a message displayed. Here we can find attributes of Magento 1:
1 2 3 |
if ($routingCycleCounter > 100) { throw new \LogicException('Front controller reached 100 router match iterations'); } |
The main steps of routing process are the same as in Magento 1:
- Determining module
- Determining controller
- Action for detection
- Data for current request detection
Router initialization in Magento 2 differs from Magento 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
protected function _getRoutes($scope = null) { $scope = $scope ?: $this->_configScope->getCurrentScope(); if (isset($this->_routes[$scope])) { return $this->_routes[$scope]; } $cacheId = $scope . '::' . $this->_cacheId; $cachedRoutes = unserialize($this->_cache->load($cacheId)); if (is_array($cachedRoutes)) { $this->_routes[$scope] = $cachedRoutes; return $cachedRoutes; } $routers = $this->_reader->read($scope); $routes = $routers[$this->_areaList->getDefaultRouter($scope)]['routes']; $this->_cache->save(serialize($routes), $cacheId); $this->_routes[$scope] = $routes; return $routes; } public function read($scope = null) { $scope = $scope ?: $this->_defaultScope; $fileList = $this->_fileResolver->get($this->_fileName, $scope); if (!count($fileList)) { return []; } $output = $this->_readFiles($fileList); return $output; } |
Initialization occurs when searching for an appropriate router:
1 2 3 4 5 6 7 8 |
… while (!$request->isDispatched() && $routingCycleCounter++ < 100) { /** @var \Magento\Framework\App\RouterInterface $router */ foreach ($this->_routerList as $router) { try { $actionInstance = $router->match($request); if ($actionInstance) { … |
Further routing process resembles Magento 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
protected function parseRequest(\Magento\Framework\App\RequestInterface $request) { $output = []; $path = trim($request->getPathInfo(), '/'); $params = explode('/', $path ? $path : $this->pathConfig->getDefaultPath()); foreach ($this->_requiredParams as $paramName) { $output[$paramName] = array_shift($params); } for ($i = 0, $l = sizeof($params); $i < $l; $i += 2) { $output['variables'][$params[$i]] = isset($params[$i + 1]) ? urldecode($params[$i + 1]) : ''; } return $output; } |
The first three elements are considered as main. They define a module, controller, and action for a current request.
Then module is determined from its moduleFrontName:
1 2 3 4 |
/** * Searching router args by module name from route using it as key */ $modules = $this→_routeConfig→getModulesByFrontName($moduleFrontName); |
Then a controller and action for a current request are determined:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
/** * Going through modules to find appropriate controller */ $currentModuleName = null; $actionPath = null; $action = null; $actionInstance = null; $actionPath = $this->matchActionPath($request, $params['actionPath']); $action = $request->getActionName() ?: ($params['actionName'] ?: $this->_defaultPath->getPart('action')); $this->_checkShouldBeSecure($request, '/' . $moduleFrontName . '/' . $actionPath . '/' . $action); foreach ($modules as $moduleName) { $currentModuleName = $moduleName; $actionClassName = $this->actionList->get($moduleName, $this->pathPrefix, $actionPath, $action); if (!$actionClassName || !is_subclass_of($actionClassName, $this->actionInterface)) { continue; } $actionInstance = $this->actionFactory->create($actionClassName); break; } if (null == $actionInstance) { $actionInstance = $this->getNotFoundAction($currentModuleName); if ($actionInstance === null) { return null; } $action = 'noroute'; } |
Besides, it is checked whether the connection is safe if there is a controller file, as well as previous realization, is stored:
1 |
$this->_checkShouldBeSecure($request, '/' . $moduleFrontName . '/' . $actionPath . '/' . $action); |
It implies that route is processed. Module, controller, and action are determined. Moreover, an action for a current request is being processed.
1 2 3 4 5 6 7 8 9 10 |
// set values only after all the checks are done $request->setModuleName($moduleFrontName); $request->setControllerName($actionPath); $request->setActionName($action); $request->setControllerModule($currentModuleName); $request->setRouteName($this->_routeConfig->getRouteByFrontName($moduleFrontName)); if (isset($params['variables'])) { $request->setParams($params['variables']); } return $actionInstance; |
Control element returns for performing action:
1 2 3 4 5 6 7 8 9 10 11 12 |
… if ($actionInstance) { $request->setDispatched(true); $this->response->setNoCacheHeaders(); if ($actionInstance instanceof \Magento\Framework\App\Action\AbstractAction) { $result = $actionInstance->dispatch($request); } else { $result = $actionInstance->execute(); } break; } ... |
Where for a current request output is determined.