How to create Magento 2 Routing
Magento 2 request flow
The request URL in Magento 2 is:
http://example.com/index.php/{front_name}/{controller}/{action} |
In that URL, you will see the front_name which will be used to find the module. The router defines this name for each module by defining in routes.xml which we will see in more detail below.
When you make a request in Magento 2, it will follow this flow to find the controller/action: index.php → HTTP app → FrontController → Routing → Controller processing → etc
The FrontController will be called in Http class to route the request which will find the controller/action match.
File: vendor/magento/framework/App/FrontController.php
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; }
|
|
As you can see in this dispatch() method, the router list will be loop to find the match one with this request. If it finds out the controller action for this request, that action will be called and executed.
Create custom route on frontend/admin
Prior to implementing the below method, you may refer to the tutorial on how to create Modules in Magento 2.
We will find how to create a frontend route, admin route and how to use route to rewrite controller.
Frontend route
To register a frontend route, we need to create a routes.xml file:
File: app/code/Mageworld/HelloWorld/etc/frontend/routes.xml
<?xml version="1.0" ?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <!--Use router 'standard' for frontend route--> <router id="standard"> <!--Define a custom route with id and frontName--> <route frontName="helloworld" id="helloworld"> <!--The module which this route match to--> <module name="Mageworld_HelloWorld"/> </route> </router> </config>
|
Please look into the code, you will see it’s very simple to register a route. You need to use the standard router for the frontend. This route will have a child which define the module for it and 2 attributes:
-
The id attribute is a unique string which will identify this route. You will use this string to declare the layout handle for the action of this module
-
The frontName attribute is also a unique string which will be shown on the url request. For example, if you declare a route like this:
<route frontName="helloworld" id="helloworld">
|
The url to this module should be:
http://example.com/index.php/helloworld/controller/action
|
And the layout handle for this action is: helloworld_controller_action.xml So with this example path, you must create the action class in this folder: {namespace}/{module}/Controller/{Controller}/{Action}.php
Admin route
This route will be the same as the frontend route but you must declare it in the adminhtml folder with router id as admin.
File: app/code/Mageworld/HelloWorld/etc/adminhtml/routes.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <!--Use router 'admin' for admin route --> <router id="admin"> <!--Define a custom route with id and frontName --> <route id="mageworld_helloworld" frontName="mageworld_helloworld"> <!--The module which this route match to--> <module name="Mageworld_HelloWorld"/> </route> </router> </config>
|
The url of the admin page is the same structure as the frontend page, but the admin_area name will be added before route_frontName to recognize this is an admin router. For example, the url of admin cms page:
http://example.com/index.php/admin/mageworld_helloworld/controller/action |
The controller action for the admin page will be added inside of the folder Controller/Adminhtml. For example for above url:
{namespace}/{module}/Controller/Adminhtml/{Controller}/{Action}.php |
Use route to rewrite controller
In this path, we will see how to rewrite a controller with a router. As above, you can see each route will have an id attribute to identify. So what happens if we define 2 routes with the same id attribute?
The answer is that the controller action will be found in both of those modules. Magento system provides the attribute before/after to config the module sort order which defines what module controller will be found first. This’s the logic for the controller rewrite.
For example, if we want to rewrite the controller customer/account/login, we will define more route in the route.xml like this:
File: app/code/Mageworld/HelloWorld/etc/frontend/routes.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <!--Use router 'standard' for frontend route--> <router id="standard"> <!--Define a custom route with id and frontName--> <route frontName="helloworld" id="helloworld"> <!--The module which this route match to--> <module name="Mageworld_HelloWorld"/> </route> <route id="customer"> <module name="Mageworld_HelloWorld" before="Magento_Customer" /> </route> </router> </config>
|
And the controller file: app/code/Mageworld/HelloWorld/Controller/Account/Login.php
So the frontController will find the Login action in our module first, if it’s found, it will run and the Login action of Magento_Customer will not be run. We successfully rewrote a controller.
You can also use this to have a second module with the same router as another module. For example, with the above declare, you can use route ‘customer’ for your controller action. If you have controller ‘Blog’ and action ‘Index.php’ you can use this url:
http://example.com/customer/blog/index
|