Magento 2 路由开发
在这篇文章中,我们将讨论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