在这篇文章中,我们将讨论Magento 2 路由中的一个重要部分。路由将定义模块的名称,我们可以在 url 中使用该名称来查找模块并执行控制器操作

目录

  • Magento 2 请求流程
  • 在前端/管理上创建自定义路由
    • 前端路线
      • routes.xml
    • 管理路线
    • 使用route重写controller

Magento 2 请求流程

在Magento 2中,请求 url 将如下所示:

http://example.com/index.php/front_name/controller/action

在该 url 中,您将看到front_name用于查找模块的 。路由器通过在routes.xml中定义为每个模块定义这个名称,我们将在下面看到更多细节。

当您在 Magento 2 中发出请求时,它将按照以下流程查找controller/action: index.php → HTTP app → FrontController → Routing → Controller processing → etc

FrontController在 Http 类中调用来路由将找到controller/action匹配项的请求。

文件: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;
}

正如您在此方法中看到的dispatch(),路由器列表将循环查找与此请求匹配的路由器。如果它找到此请求的控制器操作,则将调用并执行该操作。

在前端/管理上创建自定义路由

我们将了解如何创建前端路由、管理路由以及如何使用路由重写控制器。

前端路线

路由.xml

要注册前端路由,我们必须创建一个routes.xml文件:

文件:app/code/Example/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="Example_HelloWorld"/>
        </route>
    </router>
</config>

请看一下代码,你会发现注册路由非常简单。您必须使用标准路由器作为前端。该路由将有一个为其定义模块的子路由和 2 个属性:

  • id 属性是一个唯一的字符串,用于标识该路由。您将使用此字符串来声明此模块操作的布局句柄
  • frontName 属性也是一个唯一的字符串,将显示在 url 请求上。例如,如果您声明这样的路线:

 <route frontName="helloworld" id="helloworld">

该模块的 url 应该是:

http://example.com/index.php/helloworld/controller/action

此操作的布局句柄为:helloworld_controller_action.xml 因此,对于此示例路径,您必须在此文件夹中创建操作类:{namespace}/{module}/Controller/{Controller}/{Action}.php

管理路线

该路由与前端路由相同,但您必须在 adminhtml 文件夹中声明它,路由器 id 为admin

文件:app/code/Example/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="example_helloworld" frontName="example_helloworld">
            <!--The module which this route match to-->
            <module name="Example_HelloWorld"/>
        </route>
    </router>
</config>

管理页面的 url 与前端页面的结构相同,但admin_area前面会添加名称route_frontName以识别这是管理路由器。例如,管理 cms 页面的 url :

http://example.com/index.php/admin/example_helloworld/controller/action

管理页面的控制器操作将添加到文件夹内Controller/Adminhtml。例如上面的网址:

{namespace}/{module}/Controller/Adminhtml/{Controller}/{Action}.php

使用route重写controller

在此路径中,我们将看到如何使用路由器重写控制器。如上路径,可以看到每条路由都会有一个id属性来标识。那么如果我们定义 2 个具有相同 id 属性的路由会发生什么呢?

答案是控制器操作将在这两个模块中找到。Magento 系统提供before/after 属性来配置模块排序顺序,定义首先找到哪个模块控制器。这是控制器重写的逻辑。

例如,如果我们想重写控制器customer/account/login,我们将在route.xml中定义更多路由,如下所示:

文件:app/code/Example/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="Example_HelloWorld"/>
        </route>
       <route id="customer">
           <module name="Example_HelloWorld" before="Magento_Customer" />
       </route>
   </router>
</config>

和控制器文件:app/code/Example/HelloWorld/Controller/Account/Login.php

所以 frontController 会首先在我们的模块中查找Login 操作,如果找到,它将运行,而 Login 操作Magento_Customer将不会运行。我们成功重写了控制器。

您还可以使用它来拥有与另一个模块具有相同路由器的第二个模块。例如,通过上述声明,您可以将路由“customer”用于控制器操作。如果您有控制器“Blog”和操作“Index.php”,您可以使用以下网址:

http://example.com/customer/blog/index