系统学习magento二次开发,推荐小册:《Magento中文全栈二次开发 》
本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。
我们可以说Magento中的路由是最重要的部分之一。完整的应用程序(Magento 2)流程取决于处理URL请求和负责匹配和处理该请求的路由器类。本文介绍了Magento 2中的路由器流,并分析了默认安装附带的一些路由器。还将展示如何创建一个自定义路由器。将提到路由器如何匹配操作(控制器类),有关控制器的详细信息将在单独的文章中介绍。
### 路由流
首先,我们需要分析完整的路由流程,以便稍后可以更详细地了解每个部分。正如我们已经知道的,Magento 2创建了HTTP应用程序,其中类(启动方法)请求流将在其中启动。我们的流程从创建前端控制器开始:
$frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface');
前端控制器负责遍历所有可用的路由器,并为当前请求匹配负责的路由器。稍后我们将详细介绍前端控制器。现在,要了解完整的流程,了解应用程序如何匹配路由器非常重要。路由器列表是在位于Magento\Framework\App的RouterList类中创建的(在Front Controller中调用用于在路由器上循环),该类负责路由器列表的排序和迭代。如果路由器负责当前请求,则路由器类负责匹配。让我们来看看Magento 2流程:
index.php(运行引导程序并创建HTTP应用程序)→HTTP应用程序→FrontController →路由→控制器处理→等
现在,我们将分析路由流的每个部分,以便更好地了解Magento 2中的路由。
### 前端控制器
与Magento 1相同,这是在HTTP应用程序启动(启动方法)时调用的入口路由点。它负责匹配负责当前请求的路由器。它位于lib/internal/Magento/Framework/App/FrontController.php下。你可以看到在HTTP启动方法中使用了FrontControllerInterface。让我们在代码中看一下:
class Http implements \Magento\Framework\AppInterface { public function launch() { ... //Here Application is calling front controller and it's dispatch method $frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface'); $result = $frontController->dispatch($this->_request); ... } }
现在,当我们知道如何以及何时调用前端控制器时,让我们看一下前端控制器类和调度方法本身:
lib/internal/Magento/Framework/App/FrontController.php
class FrontController implements FrontControllerInterface { 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); $actionInstance->getResponse()->setNoCacheHeaders(); $result = $actionInstance->dispatch($request); 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; } }
正如我们所看到的,调度方法将遍历所有路由器(启用,我们稍后将在路由器配置中介绍这一点),直到一个路由器匹配并调度请求($request→setDispatched(true);)或工艺路线周期计数器超过 100。路由器可以匹配,但是如果没有调度,它将重复环路槽路由器(向前操作)。此外,路由器可以重定向和调度,也可以匹配和处理。路由器列表类在请求流中解释。现在,我们可以继续查看路由器匹配(匹配方法)的工作原理以及路由器到底是什么。
### 路由器
简而言之,路由器是负责匹配和处理URL请求的PHP类。默认情况下,Magento框架和Magento核心中有一些路由器;Base、DefaultRouter、CMS 和 UrlRewrite。我们将涵盖所有这些内容,解释它们的目的以及它们的工作原理。路由器正在实现路由器接口。现在,让我们看一下默认路由器的流程:
基本路由器→ CMS 路由器→ url重写路由器→默认路由器
(这是路由器循环 – FrontController::d ispatch())
### 基础路由器
它位于lib/internal/Magento/Framework/App/Router/Base.php,它是循环中的第一个,如果你是Magento 1开发人员,你知道它是标准路由器。匹配方法将解析请求和匹配操作,在第二种方法中,它将设置模块前端名称、控制器路径名、操作名称、控制器模块和路由名称。在基本路由器上,标准Magento URL(前端名称/操作路径/操作/参数1/等参数/)匹配。
### 内容管理系统路由器
CMS路由器位于app/code/Magento/Cms/Controller/Router.php中,用于处理CMS页面,它将模块名称(模块前端名称)设置为“cms”,控制器名称(控制器路径名称)设置为“页面”,操作名称设置为“view” – app/code/Magento/Cms/Controller/Page/View.php控制器。设置基本控制器的格式后,它将设置页面 ID 并转发它,但不会调度它。转发意味着它将中断当前的路由器环路并再次启动环路(它最多可以这样做 100 次)。该路由器环路将匹配基本路由器,该路由器将在 Cms/控制器/页面中激活视图控制器并显示保存的页面 ID(根据 url 找到的页面 ID)。
### 网址重写路由器
在Magento 2中,UrlRewrite有自己的路由器,如果你熟悉Magento 1,那么你就会知道Url Rewrite是标准路由器的一部分。它位于:app/code/Magento/UrlRewrite/Controller/Router.php它使用Url Finder来获取与数据库中的URL匹配的url重写:
$rewrite = $this->urlFinder->findOneByData( [ UrlRewrite::ENTITY_TYPE => $oldRewrite->getEntityType(), UrlRewrite::ENTITY_ID => $oldRewrite->getEntityId(), UrlRewrite::STORE_ID => $this->storeManager->getStore()->getId(), UrlRewrite::IS_AUTOGENERATED => 1, ] );
它将像 CMS 路由器一样转发动作。
### 默认路由器
它位于lib/internal/Magento/Framework/App/Router/DefaultRouter中.php它是路由器循环中的最后一个。当所有其他路由器不匹配时,使用它。在Magento 2中,我们可以为“未找到”页面创建自定义句柄以显示自定义内容。以下是 DefaultRouter 中没有路由处理程序列表的循环:
foreach ($this->noRouteHandlerList->getHandlers() as $noRouteHandler) { if ($noRouteHandler->process($request)) { break; } }
### 自定义路由器(带示例)
前端控制器将遍历 routersList 中的所有路由器(从 routes.xml 中的配置创建),因此我们需要通过在 di.xml 模块中添加我们对新路由器的配置,在 lib/internal/Magento/Framework/App/RouterList 中添加自定义路由器.php。我们将创建一个新模块(我们称之为Inchoo/CustomRouter),然后我们将在routersList中添加新的路由器,最后,创建路由器类。
自定义路由器只是一个示例,您可以在其中了解如何匹配和转发要匹配的基本路由器的请求。首先,我们需要为位于app/code/Inchoo/CustomRouter中的模块创建文件夹结构,然后我们将在etc文件夹中创建模块.xml并在模块根目录中创建composer.json,其中包含模块信息。现在,我们可以通过在 etc/前端文件夹中向 di.xml 添加配置来创建自定义路由器,因为我们只想为前端提供自定义路由器。最后,我们将在控制器文件夹中创建路由器.php,其中包含用于匹配路由器的逻辑。我们将搜索 URL 并检查 URL 中是否有特定单词,然后,根据该单词,我们将设置模块前端名称、控制器路径名称、操作名称,然后转发基本控制器的请求。我们将搜索两个词:“examplerouter”和“exampletocms”。在“examplerouter”匹配中,我们将转发到基本路由器匹配格式(通过将模块前端名称设置为“inchootest”,控制器路径名称设置为“test”,操作名称设置为“test”),在“exampletocms”上,我们将转发到基本路由器以显示“关于我们”页面。
di.xml(位于 etc/前端)
<?xml version="1.0"?> <!-- /** * Copyright © 2015 Inchoo d.o.o. * created by Zoran Salamun(zoran.salamun@inchoo.net) * Module is created for Custom Router demonstration */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd"> <type name="Magento\Framework\App\RouterList"> <arguments> <argument name="routerList" xsi:type="array"> <item name="inchoocustomrouter" xsi:type="array"> <item name="class" xsi:type="string">Inchoo\CustomRouter\Controller\Router</item> <item name="disable" xsi:type="boolean">false</item> <item name="sortOrder" xsi:type="string">22</item> </item> </argument> </arguments> </type> </config> <?php namespace Inchoo\CustomRouter\Controller; /** * Inchoo Custom router Controller Router * * @author Zoran Salamun <zoran.salamun@inchoo.net> */ class Router implements \Magento\Framework\App\RouterInterface { /** * @var \Magento\Framework\App\ActionFactory */ protected $actionFactory; /** * Response * * @var \Magento\Framework\App\ResponseInterface */ protected $_response; /** * @param \Magento\Framework\App\ActionFactory $actionFactory * @param \Magento\Framework\App\ResponseInterface $response */ public function __construct( \Magento\Framework\App\ActionFactory $actionFactory, \Magento\Framework\App\ResponseInterface $response ) { $this->actionFactory = $actionFactory; $this->_response = $response; } /** * Validate and Match * * @param \Magento\Framework\App\RequestInterface $request * @return bool */ public function match(\Magento\Framework\App\RequestInterface $request) { /* * We will search “examplerouter” and “exampletocms” words and make forward depend on word * -examplerouter will forward to base router to match inchootest front name, test controller path and test controller class * -exampletocms will set front name to cms, controller path to page and action to view */ $identifier = trim($request->getPathInfo(), '/'); if(strpos($identifier, 'exampletocms') !== false) { /* * We must set module, controller path and action name + we will set page id 5 witch is about us page on * default magento 2 installation with sample data. */ $request->setModuleName('cms')->setControllerName('page')->setActionName('view')->setParam('page_id', 5); } else if(strpos($identifier, 'examplerouter') !== false) { /* * We must set module, controller path and action name for our controller class(Controller/Test/Test.php) */ $request->setModuleName('inchootest')->setControllerName('test')->setActionName('test'); } else { //There is no match return; } /* * We have match and now we will forward action */ return $this->actionFactory->create( 'Magento\Framework\App\Action\Forward', ['request' => $request] ); } }
routes.xml (located in etc/frontend)
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd"> <router id="standard"> <route id="inchootest" frontName="inchootest"> <module name="Inchoo_CustomRouter" /> </route> </router> </config>
Test.php (test controller action class)
<?php /** * Copyright © 2015 Inchoo d.o.o. * created by Zoran Salamun(zoran.salamun@inchoo.net) */ namespace Inchoo\CustomRouter\Controller\Test; class Test extends \Magento\Framework\App\Action\Action { /** * Listing all images in gallery * -@param gallery id */ public function execute() { die("Inchoo\\CustomRouter\\Controller\\Test\\Test controller execute()"); } }
您可以在以下位置查看示例模块:
https://github.com/zoransalamun/magento2-custom-router
安装:
首先将存储库添加到作曲家配置:
composer config repositories.inchoocustomrouter vcs git@github.com:zoransalamun/magento2-custom-router.git
需要带有作曲家的新包:
composer require inchoo/custom-router:dev-master
启用 Inchoo 自定义路由器模块
php bin/magento module:enable Inchoo_CustomRouter
刷新所有内容:
php bin/magento setup:upgrade