Skip to content
intermediate Phase 15 · Routing & Areas

Magento 2 Router Classes

Deep dive into Magento router classes - Standard, UrlRewrite, Router interface, custom routers, and priority matching.

45m
0 problems
Topic Progress 0%

The RouterInterface Contract

Every router in Magento 2 must implement the Magento\Framework\App\RouterInterface. This interface defines a single method that is the contract for request matching.

<?php
namespace Magento\Framework\App\Router;

interface RouterInterface
{
    /**
     * Match a request to a router action
     *
     * @param \Magento\Framework\App\RequestInterface $request
     * @return \Magento\Framework\App\Action\ActionInterface|null
     */
    public function match(\Magento\Framework\App\RequestInterface $request);
}

The match() method receives the current request object and must return:

  • An ActionInterface instance if the router can handle the request
  • null if it cannot, allowing the next router to try

Router classes are injected into the FrontController as an array. The order in the array determines execution priority. Magento processes routers sequentially and stops at the first match.

You can inspect the current router list using the ObjectManager or via DI compilation output. The routers are registered in Magento/Framework/App/FrontController.php through constructor injection.

StandardRouter Deep Dive

The StandardRouter is the primary router that handles module/controller/action routing based on routes.xml configurations.

// Simplified StandardRouter matching logic
public function match(\Magento\Framework\App\RequestInterface $request)
{
    $pathInfo = trim($request->getPathInfo(), '/');
    $parts = explode('/', $pathInfo);
    
    if (empty($parts[0])) {
        return null;
    }
    
    // Try to find matching route by front name
    $frontName = $parts[0];
    $routeConfig = $this->routeConfig->getRouteByFrontName($frontName);
    
    if ($routeConfig === null) {
        return null;
    }
    
    // Set route information on request
    $request->setRouteName($routeConfig->getRouteId());
    $request->setModuleName($routeConfig->getModuleName());
    
    // Parse controller and action from remaining URL segments
    $controllerName = $parts[1] ?? 'index';
    $actionName = $parts[2] ?? 'index';
    
    $request->setControllerName($controllerName);
    $request->setActionName($actionName);
    
    return $this->actionFactory->create(
        \Magento\Framework\App\Action\Forward::class
    );
}

The StandardRouter relies on Magento\Framework\App\Route\ConfigInterface to load all route definitions from compiled configuration. Routes are loaded from etc/{area}/routes.xml across all enabled modules.

Controller classes must follow the naming convention:

App/Code/Vendor/Module/Controller/{ControllerName}/{ActionName}.php

The controller class must extend Magento\Framework\App\Action\Action (or Magento\Framework\App\Action\AbstractAction) and implement an execute() method that returns a ResultInterface.

UrlRewriteRouter and SEO URLs

The UrlRewriteRouter handles SEO-friendly URL rewrites. It queries the url_rewrite database table to find matching URL rules.

// UrlRewriteRouter match logic (simplified)
public function match(\Magento\Framework\App\RequestInterface $request)
{
    $requestPath = $request->getPathInfo();
    
    // Look up URL rewrite rule
    $rewrite = $this->urlFinder->findOneByData([
        'request_path' => $requestPath,
        'store_id' => $request->getStoreId(),
    ]);
    
    if ($rewrite === null) {
        return null;
    }
    
    // Set target route information
    $request->setRouteName($rewrite->getRouteName());
    $request->setModuleName($rewrite->getModuleName());
    $request->setControllerName($rewrite->getControllerName());
    $request->setActionName($rewrite->getActionName());
    
    // Store rewrite metadata
    $request->setAlias(
        \Magento\Framework\Url\Router\RewriteRequestAlias::CATALOG_REWRITE,
        $rewrite->getTargetPath()
    );
    
    return $this->actionFactory->create(
        \Magento\Framework\App\Action\Forward::class
    );
}

URL rewrites are generated automatically for products, categories, and CMS pages. You can create custom rewrites through the admin panel or programmatically:

$rewrite = $this->rewriteFactory->create();
$rewrite->setStoreId(1)
    ->setRequestPath('custom-url')
    ->setTargetPath('catalog/product/view/id/5')
    ->setEntityType('product')
    ->setEntityId(5);
$this->rewriteResource->save($rewrite);

Custom Routers and Priority

Creating a custom router involves implementing RouterInterface and registering it via dependency injection.

Complete custom router example:

<?php
namespace Vendor\Module\Controller\Router;

use Magento\Framework\App\ActionFactory;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\RouterInterface;

class LanguageRouter implements RouterInterface
{
    private $actionFactory;
    private $storeManager;
    
    public function __construct(
        ActionFactory $actionFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager
    ) {
        $this->actionFactory = $actionFactory;
        $this->storeManager = $storeManager;
    }
    
    public function match(RequestInterface $request)
    {
        $pathInfo = $request->getPathInfo();
        
        // Match pattern: /en/product/... or /fr/product/...
        if (preg_match('#^/(en|fr)/(.+)$#', $pathInfo, $matches)) {
            $langCode = $matches[1];
            $request->setPathInfo('/' . $matches[2]);
            
            // Set store based on language
            $store = $this->storeManager->getStore($langCode);
            $request->setStoreId($store->getId());
            
            return $this->actionFactory->create(
                \Magento\Framework\App\Action\Forward::class
            );
        }
        
        return null;
    }
}

Register with priority via di.xml:

<config>
    <type name="Magento\Framework\App\FrontController">
        <arguments>
            <argument name="routers" xsi:type="array">
                <item name="language" xsi:type="object" sortOrder="10">
                    Vendor\Module\Controller\Router\LanguageRouter
                </item>
            </argument>
        </arguments>
    </type>
</config>

The sortOrder attribute controls router priority. Lower values execute first. The StandardRouter typically has sortOrder 30, so custom routers with lower sortOrder run before it. This lets you intercept requests before standard routing occurs.

Debugging Router Issues

When routing doesn't work as expected, there are several debugging approaches.

Enable route logging in development:

// Add to app/bootstrap.php for debugging
error_reporting(E_ALL);
ini_set('display_errors', 1);

Check compiled route configuration:

php bin/magento setup:di:compile
# Check generated/metadata/global.php for route definitions

Verify your routes.xml is being loaded:

php bin/magento module:status Vendor_Module
# Ensure module is enabled

Inspect the router chain at runtime:

// In a custom module or script
$objectManager = \Magento\Framework\App\Bootstrap::create(
    BP,
    $_SERVER
)->getobjectManager();

$frontController = $objectManager->get(
    \Magento\Framework\App\FrontControllerInterface::class
);

// Check registered routers via reflection
$reflection = new \ReflectionClass($frontController);
$routersProperty = $reflection->getProperty('routers');
$routersProperty->setAccessible(true);
$routers = $routersProperty->getValue($frontController);

echo "Registered routers:\n";
foreach ($routers as $name => $router) {
    echo "- $name: " . get_class($router) . "\n";
}

Common routing issues:

  • Module not enabled (check app/etc/config.php)
  • Routes.xml has syntax errors
  • Controller class doesn't exist or doesn't extend Action
  • Controller class namespace doesn't follow convention
  • Duplicate front names causing route conflicts
  • Store ID not set for multi-store setups

Quiz

1. What must a custom router implement?

Question 1 options

2. How do you control router execution order?

Question 2 options

3. What happens when UrlRewriteRouter finds a match?

Question 3 options

Flashcards

Question

What method must RouterInterface implement?

Answer

match(RequestInterface $request) returning ActionInterface or null

Question

Which router handles module/controller/action routing?

Answer

StandardRouter

Question

What database table stores URL rewrites?

Answer

url_rewrite

Question

How do you register a custom router?

Answer

Via di.xml, adding to Magento\Framework\App\FrontController routers argument

Revision Notes

Key Takeaways

  • 1. RouterInterface requires a match() method returning ActionInterface or null
  • 2. StandardRouter resolves controllers from routes.xml configurations
  • 3. UrlRewriteRouter queries the url_rewrite database table for SEO URLs
  • 4. Custom routers are registered via di.xml with optional sortOrder
  • 5. Lower sortOrder values execute first in the router chain
  • 6. Router chain stops at the first match (chain of responsibility pattern)

Interview Tips

  • Explain how you would create a language-prefix router for multi-language stores
  • Discuss the difference between forwarding and redirecting in router context
  • Describe how to debug routing issues in Magento 2
  • Explain why Magento uses a chain of routers instead of a single router
  • Know the standard router priority order

Cheat Sheet

Router Classes Cheat Sheet

Interface: Magento\Framework\App\RouterInterface
Method: match(RequestInterface $request) : ActionInterface|null

Built-in Routers:

  • StandardRouter (sortOrder ~30) - module/controller/action
  • UrlRewriteRouter - database URL rewrites
  • BaseUrlRouter - store switching
  • DefaultRouter - CMS pages, noroute

Custom Router Registration:

<type name="Magento\Framework\App\FrontController">
  <arguments>
    <argument name="routers" xsi:type="array">
      <item name="custom" xsi:type="object" sortOrder="10">
        Vendor\Module\Controller\Router\CustomRouter
      </item>
    </argument>
  </arguments>
</type>