Magento 2 Routing
http://example.com/index.php/front_name/controller/action
In that url, you will see the front_name
which will be use to find the module. The router define this name for each module by define in routes.xml which we will see more detail bellow.
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 call in Http class to routing 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 find out the controller action for this request, that action will be called and executed.
Create custom route on frontend/admin
In this part, we will use a simple module Mageplaza_HelloWorld. Please follow the previous article to know how to create Module in Magento 2.
We will find how to create a frontend route, admin route and how to use route to rewrite controller.
Frontend route
Routes.xml
To register a frontend route, we must create a routes.xml file:
File: app/code/Mageplaza/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="Mageplaza_HelloWorld"/>
</route>
</router>
</config>
Please look into the code, you will see it’s very simple to register a route. You must 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 same as the frontend route but you must declare it in adminhtml folder with router id is admin
.
File: app/code/Mageplaza/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="mageplaza_helloworld" frontName="mageplaza_helloworld">
<!--The module which this route match to-->
<module name="Mageplaza_HelloWorld"/>
</route>
</router>
</config>
The url of the admin page is the same structure with frontend page, but the admin_area
name will be added before route_frontName
to recognize this is a admin router. For example, the url of admin cms page:
http://example.com/index.php/admin/mageplaza_helloworld/controller/action
The controller action for 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 router. As above path, you can see each route will have an id attribute to identify. So what happen if we define 2 route with the same id attribute?
The answer is that the controller action will be find in both of that modules. Magento system provide the attribute before/after to config the module sort order which define what module controller will be find 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/Mageplaza/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="Mageplaza_HelloWorld"/>
</route>
<route id="customer">
<module name="Mageplaza_HelloWorld" before="Magento_Customer" />
</route>
</router>
</config>
And the controller file: app/code/Mageplaza/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 are successful rewrite a controller.
You can also use this to have a second module with the same router as another module. For example, with 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
If you got this error message: Exception printing is disabled by default for security reasons, this topic may help.
0 comments:
Post a Comment
Thanks