How to create Magento 2 Routing

30 Nov 2020
In web applications, such as Magento, routing is the act of providing data from a URL request to the appropriate class for processing

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

 

Related Posts

How to create CRUD Models in Magento 2

How to create CRUD Models in Magento 2

26 Nov 2020
Models are an important part of the MVC model. In Magento 2, Models is responsible for working with the database, and is divided into three parts: Model, Resource Model and Collection. They are used to work with CRUD operations (create, read, update, delete) without writing any more SQL code.