magento 2 routing

Magento 2 Routing: A Full Guide to Understanding and Implementing Routes

by Lily Tran

Routing in Magento is one of the most important parts. The entire application flow (Magento 2) depends on handling the URL request, and the router class is responsible for matching and processing the request. So what is Magento 2 routing and how does it work? In this article, we will go into detail and analyze it.

Magento 2 Routing: Handling Flow for a Normal Magento 2 Request

First, we will analyze the complete Magento 2 routing flow. As you all know, Magento 2 creates an HTTP application in the request flow that the class (initialization method) will start. The flow begins to work with the creation of the front controller :

$frontController=$this->_objectManager->get('Magento\Framework\App\
FrontControllerInterface ).

The front controller is responsible for looping through all available routers and the router is responsible for matching current requirements. Now in order to understand the overall flow, it is important to know how the application matches the routers.

The list of routers is created in RouterList (called in Front Controller to loop on routers) class, is in Magento\Framework\App, and this class is responsible for ordering and iterating on the list of routers. The router class is in charge of matching if the router is responsible for the current request. The following is the Magento 2 flow:

index.php(runs bootstrap and create HTTP application) -> HTTP app -> FrontController -> Routing -> Controller processing -> etc

Now we will analyze each part of the routing flow to understand Magento 2 routing.

How to Create a Magento 2 Route on Frontend/Admin

#1. Create Magento 2 Frontend Routes

etc->frontend->routes.xml

To register a Magento 2 frontend route, we must create a routes.xml file. For example:

file: app/code/Bss/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>

Explanation:

  • <router id="standard">: “standard” is one of the names in Table 1: Specification of the router names in Magento
  • route frontName="helloworld" id="helloworld">:
    • The id attribute is the only string that will identify this route. You will use this string to declare the layout handle for this module’s actions. helleworld_controller_action.xml for example.
    • The frontName attribute is also the only string that will show up on the URL request. For example: <store-url>/<store-code>/helloworld/controller/action
  • <module name="Bss_module"> specifies the modules’ name
  • Create action class in the folder: {namespace}/{module}/Controller/{Controller}/{Action}.php

Table 1: Names used in <id = "Name"> router in routes.xml file

Name( %routerId% ) Sort Order Description
robots 10 Match the request to the robots.txt file
URL rewrite 20 Match the request to the URL specified in the database
standard 30 Router standards
cms 60 Matching requirements for CMS pages
default 100 Router default

#2. Create Adminhtml Area Routers

This route will be the same as the frontend router, but must be declared in the adminhtml directory (etc ->adminhtml->router.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>

Explanation:

  • <router id="admin">: where “admin” is one of the names in Table 2: Specification of the router names in Magento
  • The admin page URL is similarly structured to the frontend page, but the admin_area name will be appended before route_frontName to identify this as the admin router. E.g. <store-url>/<store-code>/admin/helloworld/controller/action
  • The controller action for the admin page will be in the Controller/Adminhtml directory for example: {namespace}/{module}/Controller/Adminhtml/{Controller}/{Action}.php

Table 2:

Name(%routerId%) Sort Order Description
admin 10 Match the request to the admin Magento area
default 100 Default router for the admin zone

Create A Magento 2 Custom Router: Step-by-Step Guide and Examples

Standard router

  • Format URL: <store-url>/<store-code>/<front-name>/<controller-name>/<action-name>
  • <store-url> specifies the base URL for the Magento version
  • <store-code> specifies the store context
  • <frontend-name> specifies the frontName of the FrontController to be used (frontName in routes.xml)
  • <controller-name> specifies the name of the controller
  • <action-name> specifies the action class to execute in the controller class

=> The router standard parses this URL format and matches the controller with the exact action.

Step 1: Add Contents to The di.xml Module

  • The Front Controller will go through all routers in routerList (created from the configuration in routers.xml) so we need to add a custom router in lib/internal/Magento/Framework/App/RouterList.php by adding configuration in configuration for 1 router in the di.xml module. We will create a new module and a new router in routersList and finally, create a router class.
  • We can create a custom router by adding a configuration to di.xml in etc/frontend (if we only use custom route in frontend). Finally, we create Router.php in the Controller directory with the appropriate router logic. We’ll find the URL and check if there is a specific word in the URL and then depending on that word, we set up the module front name, controller path name, action name and then request a forward for the base controller.
  • To add your custom router to the router list for FrontController, add contents to the di.xml module.
<type name="Magento\Framework\App\RouterList">
    <arguments>
        <argument name="routerList" xsi:type="array">
            <item name="%name%" xsi:type="array">
                <item name="class" xsi:type="string">%classpath%</item>
                <item name="disable" xsi:type="boolean">false</item>
                <item name="sortOrder" xsi:type="string">%sortorder%</item>
            </item>
        </argument>
    </arguments>
</type>

Specifically:

  • % name%: The unique name of your router in Magento
  • % classpath%: the path of the router class>

for example: Bss\Agencies\Controller\Router\Custom

  • % sortorder%: The sort order of the custom route in the router list

Step 2: Create CustomRouter class

namespace Vendor\Module\Controller;

<?php
namespace Bss\Agencies\Controller\Router;
 
use Magento\Framework\App\Action\Forward;
use Magento\Framework\App\ActionFactory;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\RouterInterface;
 
/**
* Class CustomRouter
*
* @package Bss\Agencies\Controller
*/
class CustomRouter implements RouterInterface
{
   /**
    * @var ActionFactory
    */
   protected $actionFactory;
 
   /**
    * CustomRouter constructor.
    * @param ActionFactory $actionFactory
    */
   public function __construct(
       ActionFactory $actionFactory
   ) {
       $this->actionFactory = $actionFactory;
   }
 
   /**
    * Match Router
    *
    * @param RequestInterface $request
    * @return ActionInterface
    */
   public function match(RequestInterface $request)
   {
       $identifier = trim($request->getPathInfo(), '/');
       $paramsArr = explode('/', $identifier);
       if (count($paramsArr) == 1 && $paramsArr[0] == 'magento-development-company') {
           $request->setModuleName('agencies') //module name
           ->setControllerName('agencies') //controller name
           ->setActionName('index')//action name;
             } else {
           $request->setModuleName('agencies'); //module name
           $request->setControllerName('agencies') //controller name;
           $request->setParam("company", $paramsArr[1]) // truyền  tham số ;
           $request->setActionName("company")//action name;;
       }
       return $this->actionFactory->create(Forward::class);
   }

=> When we want to create a custom router: frontName/agencies/company to frontName/magento-development-company/company/ or frontName/agencies/index to frontName/magento-development-company

Step 3: Before and after in routes.xml

Add a “before” or after parameter in the module entry to record or extend the existing routes modules

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="customer">
            <module name="Bss_Routing" before="Magento_Customer" />
        </route>
    </router>
</config>

This configuration requires searching for actions in the Bss_Routing module before searching in the Magento_Customer module. For example, if there exists app/code/Bss/Routing/Controller/Account/Login we will use this file for processing the login route instead of the original class.

Result Object

1. JSON

You will use JSON results when you want to return a JSON object. You will do this if you implement a custom API endpoint or a simple AJAX endpoint.

Example: class returns data which is an array with information on name, age

<?php
namespace Bss\Hello\Controller\Router;
 
use Magento\Framework\App\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Result\Page;
/**
* Class Json
*
* @package Bss\Hello\Controller\Router
*/
class Json extends Action\Action
{
   protected $_resultJsonFactory;
 
   /**
    * RouterJson constructor.
    * @param Context $context
    * @param JsonFactory $resultJsonFactory
    */
   public function __construct(
       Context $context,
       JsonFactory $resultJsonFactory
   ) {
       $this->_resultJsonFactory = $resultJsonFactory;
       parent::__construct($context);
   }
 
   /**
    * Return information
    *
    * @return ResponseInterface|ResultInterface|Page
    */
   public function execute()
   {
       $result = $this->_resultJsonFactory->create();
       $params = [
           'Name' => "BSS",
           "Age" => "7 years old",
       ];
       return $result->setData($params);
   }
}

Results:

Result object

2. Raw

If you want to use raw results to return a plain string with no Magento layout and view rendering. By default raw results will return a text/html header. If you want something else (text/xml, text plain) then you will use setHeader

<?php
namespace Bss\Hello\Controller\Router;
 
use Magento\Framework\App\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Result\Page;
 
/**
* Class Raw
*
* @package Bss\Hello\Controller\Router
*/
class Raw extends Action\Action
{
   protected $rawResultFactory;
 
   /**
    * Raw constructor.
    *
    * @param Context $context
    * @param  RawFactory $rawResultFactory
    */
   public function __construct(
       Context $context,
       \Magento\Framework\Controller\Result\RawFactory $rawResultFactory
   ) {
       $this->rawResultFactory = $rawResultFactory;
       parent::__construct($context);
   }
 
   /**
    * Return result raw
    *
    * @return ResponseInterface|\Magento\Framework\Controller\Result\Json|ResultInterface
    */
   public function execute()
   {
       $result = $this->rawResultFactory->create();
       $result->setHeader('Content-Type', 'text/xml');
       $result->setContents('<root><science></science></root>');
       return $result;
   }
}

Results:

Result object Raw

3. Redirect:

When you want to send user/request to a new URL through redirecting the HTTP location header ( URL will change)

Example of how to redirect and send the array data to the home page at the same time

<?php
namespace Bss\Hello\Controller\Router;
 
use Magento\Framework\App\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Controller\ResultInterface;
 
/**
* Class BssRedirect
*
* @package Bss\Helloworld\Controller\Router
*/
class BssRedirect extends Action\Action
{
   protected $_pageFactory;
 
   /**
    * BssRedirect constructor.
    * @param Context $context
    */
   public function __construct(
       Context $context
   ) {
       $this->resultFactory = $context->getResultFactory();
 
       return parent::__construct($context);
   }
 
   /**
    * Redirect home page
    *
    * @return ResponseInterface|Redirect|ResultInterface
    */
   public function execute()
   {
       $data = [
'name' => "Bss",
            'age' => '7'
];
       $resultRedirect = $this->resultRedirectFactory->create();
       $resultRedirect->setPath('cms/index/index', $data);
       return $resultRedirect;
   }
}

When you access the URL hello/router/bssredirect it automatically redirects to the URL cms/index/index/name/Bss/age/7/ where name/bss/age/7 is the parameter and the data parameter passed to the home page

Result:

Result object redirect

4. Forward

Internally call the execution method of another action class and do not trigger a new request from the browser, but the URL remains unchanged.

-> Forward the current page to the home page

<?php
namespace Bss\Hellow\Controller\Router;
 
use Magento\Framework\App\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\Forward;
use Magento\Framework\Controller\Result\ForwardFactory;
use Magento\Framework\Controller\ResultInterface;
 
/**
* Class BssForward
*
* @package Bss\Internship\Controller\Internship
*/
class BssForward extends Action\Action
{
 
   /**
    * @var ForwardFactory
    */
   protected $_resultForwardFactory;
 
   /**
    * Page4 constructor.
    * @param Context $context
    * @param ForwardFactory $_resultForwardFactory
    */
   public function __construct(
       Context $context,
       ForwardFactory $_resultForwardFactory
   ) {
       $this->_resultForwardFactory = $_resultForwardFactory;
       parent::__construct($context);
   }
 
   /**
    *  Forward home page
    *
    * @return ResponseInterface|Forward|ResultInterface
    */
   public function execute()
   {
       $resultForward = $this->_resultForwardFactory->create();
       $resultForward->setController('index')
           ->setModule('cms')
           ->forward('index');
       return $resultForward;
   }
}

Results:

Magento routing Result object forward

5. Layout

You can use a generic response layout to render any type of layout

Example:

<?php
 
namespace Bss\Hello\Controller\Router;
 
use Magento\Framework\App\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Result\LayoutFactory;
 
/**
* Class RouterLayout
*
* @package Bss\Helloworld\Controller\Router
*/
class RouterLayout extends Action\Action
{
   /**
    * @var
    */
   protected $resultLayoutFactory;
 
   /**
    * RouterLayout constructor.
    * @param Context $context
    * @param LayoutFactory $rawFactory
    */
   public function __construct(Context $context, LayoutFactory $rawFactory)
   {
       $this->resultLayoutFactory = $rawFactory;
       parent::__construct($context);
   }
 
   /**
    * @return ResponseInterface|ResultInterface
    */
   public function execute()
   {
      //  ..
       $result = $this->resultLayoutFactory->create();
       return $result;
   }
}

Results:

Magento 2 Routing Result object layout

6. Page

Page triggers layout.xml to render into HTML

<?php
namespace Bss\Helloworld\Controller\Router;
 
use Magento\Framework\App\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Result\Page;
use Magento\Framework\View\Result\PageFactory;
 
/**
* Class RouterPage
*
* @package Bss\Helloworld\Controller\Router
*/
class RouterPage extends Action\Action
{
   protected $_resultPageFactory;
 
   /**
    * RouterPage constructor.
    * @param Context $context
    * @param PageFactory $pageFactory
    */
   public function __construct(Context $context, PageFactory $pageFactory)
   {
       $this->_resultPageFactory = $pageFactory;
       parent::__construct($context);
   }
 
   /**
    * Papare template
    *
    * @return ResponseInterface|ResultInterface|Page
    */
   public function execute()
   {
       return $this->_resultPageFactory->create();
   }
}

Results:

magento route - result object page

Conclusion

In conclusion, understanding Magento 2 routing is essential for developers to manage URL structures and request handling efficiently. By mastering the basics of routers, routes, and controllers, you can ensure smooth navigation and enhance the performance of your Magento 2 store.

Still struggling with the Magento issues, contact us today! At BSS Commerce, we specialize in providing top-notch Magento 2 extensions and services designed to optimize your store’s performance and user experience.

Next Reading Suggestions

© 2019 BSS Commerce owned by THANH CONG INTER ., JSC. All Rights Reserved.
Business registration certificate no. 0106064469 issued by Hanoi Department of Planning and Investment on 19 December 2019.
Legal Representative: Mr. Nguyen Quang Trung.