Edit in GitHubLog an issue

Routing

In web applications, such as Adobe Commerce and Magento Open Source, routing is the act of providing data from a URL request to the appropriate class for processing. Adobe Commerce and Magento Open Source routing uses the following flow:

Request processing

FrontController class#

The FrontController class class searches through a list of routers, provided by the RouterList class, until it matches one that can process a request. When the FrontController finds a matching router, it dispatches the request to an action class returned by the router.

If the FrontController cannot find a router to process a request, it uses the default router.

Router class#

The Router class matches a request to an action class that processes the request.

The following tables show the core routers that come with Magento:

frontend area routers:

NameSort orderDescription
robots10Matches request to the robots.txt file
urlrewrite20Matches requests with URL defined in the database
standard30The standard router
cms60Matches requests for CMS pages
default100The default router

adminhtml area routers:

NameSort orderDescription
admin10Matches requests in the Admin area
default100The default router for the Admin area

Standard router#

A URL that uses the standard router has the following format:

Copied to your clipboard
<store-url>/<store-code>/<front-name>/<controller-name>/<action-name>

Where:

  • <store-url> - specifies the base URL for the application instance
  • <store-code> - specifies the store context
  • <front-name> - specifies the frontName of the FrontController to use (for example, [routesxml])
  • <controller-name> - specifies the name of the controller
  • <action-name> - specifies the action class to execute on the controller class

The standard router parses this URL format and matches it to the correct controller and action.

Default router#

The DefaultRouter class, is the last router that the application checks during the routing process. Requests that reach this point often contain invalid URLs that previous routers cannot handle.

The application uses the default NoRouteHandler to process these requests, but you can write your own no-route handler by implementing the NoRouteHandlerInterface.

Custom routers#

Create an implementation of RouterInterface to create a custom router, and define the match() function in this class to use your own route matching logic.

If you need route configuration data, use the Route Config class.

To add your custom router to the list of routers for the FrontController, add the following entry in your module's frontend/di.xml file:

Copied to your clipboard
1<type name="Magento\Framework\App\RouterList">
2 <arguments>
3 <argument name="routerList" xsi:type="array">
4 <item name="%name%" xsi:type="array">
5 <item name="class" xsi:type="string">%classpath%</item>
6 <item name="disable" xsi:type="boolean">false</item>
7 <item name="sortOrder" xsi:type="string">%sortorder%</item>
8 </item>
9 </argument>
10 </arguments>
11</type>

Where:

  • %name% - The unique name of your router in Magento.
  • %classpath% - The path to your router class. Example: Magento\Robots\Controller\Router
  • %sortorder% - The sort order of this entry in the router list.

routes.xml#

The routes.xml file maps which module to use for a URL with a specific frontName and area. The location of the routes.xml file in a module, either etc/frontend or etc/adminhtml, specifies where those routes are active.

The content of this file uses the following format:

Copied to your clipboard
1<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
2 <router id="%routerId%">
3 <route id="%routeId%" frontName="%frontName%">
4 <module name="%moduleName%"/>
5 </route>
6 </router>
7</config>

Where:

  • %routerId - specifies the name of the router in Magento. See the reference tables in the Router class section.
  • %routeId% - specifies the unique node id for this route in Magento, is also the first segment of its associated layout handle XML filename (routeId_controller_action.xml).
  • %frontName% - specifies the first segment after the base URL of a request.
  • %moduleName% - specifies the name of your module.

For more details, see routes.xsd.

Before and after parameters#

You can add a before or after parameter in the module entry to override or extend routes in existing modules.

Example: routes.xml:

Copied to your clipboard
1<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
2 <router id="standard">
3 <route id="customer">
4 <module name="ExampleCorp_RoutingExample" before="Magento_Customer" />
5 </route>
6 </router>
7</config>

This configuration tells the FrontController to look for actions in the ExampleCorp_RoutingExample module before searching in the Magento_Customer module. If app/code/ExampleCorp/RoutingExample/Controller/Account/Login.php exists, it will use that file for processing the login route instead of the original class.

Action class#

Action classes are implementations of the ActionInterface that a router returns on matched requests. The execute() function in these classes contain the logic for dispatching requests.

Each Action should implement one or more Magento\Framework\App\Action\HttpHTTP MethodActionInterface to declare which HTTP request methods it can process. The most common ones are:

  • \Magento\Framework\App\Action\HttpDeleteActionInterface
  • \Magento\Framework\App\Action\HttpGetActionInterface
  • \Magento\Framework\App\Action\HttpPostActionInterface
  • \Magento\Framework\App\Action\HttpPutActionInterface

The application has a form key validation in place for all POST non-AJAX requests - if your Action doesn't need that validation or you want to modify it you can implement CsrfAwareActionInterface.

If you need to forward a request to another action in your class, use the Forward::forward(string $action) method.

Example:

Copied to your clipboard
1<?php
2declare(strict_types=1);
3
4namespace ExampleCorp\RoutingExample\Controller\Index;
5
6use Magento\Framework\App\Action\HttpGetActionInterface;
7use Magento\Framework\Controller\Result\Forward;
8use Magento\Framework\Controller\Result\ForwardFactory;
9
10/**
11 * Class Index
12 */
13class Index implements HttpGetActionInterface
14{
15 /**
16 * @var ForwardFactory
17 */
18 private $forwardFactory;
19
20 /**
21 * @param ForwardFactory $forwardFactory
22 */
23 public function __construct(
24 ForwardFactory $forwardFactory
25 ) {
26 $this->forwardFactory = $forwardFactory;
27 }
28
29 /**
30 * @inheritdoc
31 */
32 public function execute()
33 {
34 /** @var Forward $forward */
35 $forward = $this->forwardFactory->create();
36 return $forward->forward('defaultNoRoute');
37 }
38}

Result object#

NameDescription
jsonSets Content-Type:application/json in the header and returns a json encoded representation of an array with data
rawReturns the data as it's been set. Does not set a Content-Type in the header
redirectCreates an external redirect, which the browser follows and requests a new url
forwardInternally calls the execute method of another action class and does not trigger a new request from the browser. The URL stays the same
layoutView result. You can use a generic layout response to render any kind of layout. The layout comprises a response body from its layout elements and sets it to the HTTP response
pageView result. Encapsulates page type, page configuration, and imposes certain layout handles. page triggers layout.xml to render into HTML

Example of routing usage#

Declaring a new route:

File: ExampleCorp/RoutingExample/etc/frontend/routes.xml

Copied to your clipboard
1<?xml version="1.0"?>
2
3<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
5 <router id="standard">
6 <route id="routing" frontName="routing">
7 <module name="ExampleCorp_RoutingExample" />
8 </route>
9 </router>
10</config>

Declaring the layout handler for our new route:

File: ExampleCorp/RoutingExample/view/frontend/layout/routing_index_index.xml

Copied to your clipboard
1<?xml version="1.0"?>
2
3<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
5 <body>
6 <referenceBlock name="page.main.title">
7 <action method="setPageTitle">
8 <argument translate="true" name="title" xsi:type="string">Routing Page</argument>
9 </action>
10 </referenceBlock>
11 </body>
12</page>

Defining a new custom router:

File: ExampleCorp/RoutingExample/etc/frontend/di.xml

Copied to your clipboard
1<type name="Magento\Framework\App\RouterList">
2 <arguments>
3 <argument name="routerList" xsi:type="array">
4 <item name="routingExample" xsi:type="array">
5 <item name="class" xsi:type="string">ExampleCorp\RoutingExample\Controller\Router</item>
6 <item name="disable" xsi:type="boolean">false</item>
7 <item name="sortOrder" xsi:type="string">40</item>
8 </item>
9 </argument>
10 </arguments>
11</type>

Creating the controller that will handle the routing route and will get the parameters passed by our router.

File: ExampleCorp/RoutingExample/Controller/Index/Index.php

Copied to your clipboard
1<?php
2declare(strict_types=1);
3
4namespace ExampleCorp\RoutingExample\Controller\Index;
5
6use Magento\Framework\App\Action\HttpGetActionInterface;
7use Magento\Framework\App\RequestInterface;
8use Magento\Framework\View\Result\Page;
9use Magento\Framework\View\Result\PageFactory;
10
11/**
12 * Class Index
13 */
14class Index implements HttpGetActionInterface
15{
16 /**
17 * @var PageFactory
18 */
19 private $pageFactory;
20
21 /**
22 * @var RequestInterface
23 */
24 private $request;
25
26 /**
27 * @param PageFactory $pageFactory
28 * @param RequestInterface $request
29 */
30 public function __construct(PageFactory $pageFactory, RequestInterface $request)
31 {
32 $this->pageFactory = $pageFactory;
33 $this->request = $request;
34 }
35
36 /**
37 * @inheritdoc
38 */
39 public function execute()
40 {
41 // Get the params that were passed from our Router
42 $firstParam = $this->request->getParam('first_param', null);
43 $secondParam = $this->request->getParam('second_param', null);
44
45 return $this->pageFactory->create();
46 }
47}

In the end, let's create the router class, that will match the custom route name learning with the existing routing route.

File: ExampleCorp/RoutingExample/Controller/Router.php

Copied to your clipboard
1<?php
2declare(strict_types=1);
3
4namespace ExampleCorp\RoutingExample\Controller;
5
6use Magento\Framework\App\Action\Forward;
7use Magento\Framework\App\ActionFactory;
8use Magento\Framework\App\ActionInterface;
9use Magento\Framework\App\RequestInterface;
10use Magento\Framework\App\ResponseInterface;
11use Magento\Framework\App\RouterInterface;
12
13/**
14 * Class Router
15 */
16class Router implements RouterInterface
17{
18 /**
19 * @var ActionFactory
20 */
21 private $actionFactory;
22
23 /**
24 * @var ResponseInterface
25 */
26 private $response;
27
28 /**
29 * Router constructor.
30 *
31 * @param ActionFactory $actionFactory
32 * @param ResponseInterface $response
33 */
34 public function __construct(
35 ActionFactory $actionFactory,
36 ResponseInterface $response
37 ) {
38 $this->actionFactory = $actionFactory;
39 $this->response = $response;
40 }
41
42 /**
43 * @param RequestInterface $request
44 * @return ActionInterface|null
45 */
46 public function match(RequestInterface $request): ?ActionInterface
47 {
48 $identifier = trim($request->getPathInfo(), '/');
49
50 if (strpos($identifier, 'learning') !== false) {
51 $request->setModuleName('routing');
52 $request->setControllerName('index');
53 $request->setActionName('index');
54 $request->setParams([
55 'first_param' => 'first_value',
56 'second_param' => 'second_value'
57 ]);
58
59 return $this->actionFactory->create(Forward::class, ['request' => $request]);
60 }
61
62 return null;
63 }
64}

As a result, by accessing the http://site.com/learning route, the http://site.com/routing/index/index route is loaded.

Routing Result

Declaring the new route as Page Type#

After creating a new route routing/index/index, it is a good practice to give more control on it for the admin. By creating a new Page Type, the admin can manage the content of this page using widgets.

Defining a new page type:

etc/frontend/page_types.xml

Copied to your clipboard
1<?xml version="1.0"?>
2<page_types xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_types.xsd">
3 <type id="routing_index_index" label="Routing Page"/>
4</page_types>

Result#

As result, the new page is available in the Specified Page dropdown widget when creating a page.

Routing Page Type

Was this helpful?
  • Privacy
  • Terms of Use
  • Do not sell my personal information
  • AdChoices
Copyright © 2022 Adobe. All rights reserved.