虽然我熟悉使用前端控制器进行注册,但如果不首先对控制器类的 PHP 包含进行硬编码,我似乎无法从路由器类中使用此前端控制器。 如果一切配置正确,我认为这没有必要。 我想利用这个路由器类来查看请求的 URL 是否与我的扩展匹配,如果是,则调用适当的控制器/操作。我当前的设置如下:

在我的扩展的 etc/config.xml 文件中,我注册了路由器和控制器:

<frontend>
    <routers>
        <doall_manual>
            <use>standard</use>
            <args>
                <module>DoALL_Manual</module>
                <frontName>doall_manual</frontName>
            </args>
        </doall_manual>
    </routers>
</frontend>
<default>
    <web>
        <routers>
            <doall_manual>
                <area>frontend</area>
                <class>DoALL_Manual_Controller_Router</class>
            </doall_manual>
        </routers>
    </web>
</default>

这是我的路由器类:

注意 require_once 在这里声明。我确信这行代码是 不必要 如果我的分机设置正确的话。例如,Mage_Cms_Controller_Router 就没有这样做。

class DoALL_Manual_Controller_Router extends Mage_Core_Controller_Varien_Router_Standard
{

    public function match(Zend_Controller_Request_Http $request)
    {
        // checking before even try to find out that current module
        // should use this router
        if (!$this->_beforeModuleMatch()) {
            return false;
        }

        $path = explode('/', trim($request->getPathInfo(), '/'));

        if ($path[0] != 'parts-manual') {
            return false;
        }

        $request
            ->setModuleName('doall_manual')
            ->setControllerName('manual');

        switch (count($path)) {
            case 1:
                $request->setActionName('index');
                break;

            case 2:
                $request->setActionName('manual');
                break;

            case 3:
                $request->setActionName('page');
                break;

            default:
                $request->setActionName('noroute');
                break;
        }

        // TODO: This line shouldn't be needed, but I'm unsure as to why it is not detecting the controller's location on it's own.
        require_once 'DoALL'.DS.'Manual'.DS.'controllers'.DS.'ManualController.php';

        $controllerInstance = Mage::getControllerInstance('DoALL_Manual_ManualController', $request, $this->getFront()->getResponse());

        // dispatch action
        $request->setDispatched(true);
        $controllerInstance->dispatch($request->getActionName());

        return true;
    }

}

我的前端控制器:

class DoALL_Manual_ManualController extends Mage_Core_Controller_Front_Action
{
    /**
     * Display all manuals
     */
    public function indexAction()
    {
        echo __METHOD__;
    }

    /**
     * Display a manual's index
     */
    public function manualAction()
    {
        echo __METHOD__;
    }

    /**
     * Display the parts from a manual's page.
     */
    public function pageAction()
    {
        echo __METHOD__;
    }

}

显然我还没有完成这个控制器的开发。然而,这篇文章的重点并不集中在该控制器操作的内容上。它只是从我的路由器访问这些操作, 无需先专门对其进行 require 声明。

前端控制器本身工作得很好。这些 URL 路径实际上会按预期回显方法名称:

/doall_manual/manual/
/doall_manual/manual/manual/
/doall_manual/manual/page/

此外,我当前的配置正在运行。正如我所期望的,这些 URL 路径也按预期执行:

/parts-manual/
/parts-manual/ANYTHING_HERE/
/parts-manual/ANYTHING_HERE/ANYTHING_HERE_ALSO/

最后,/parts-manual/ANYTHING_HERE/ANYTHING_HERE_ALSO/longer_url/ 结果是 Magento 的 404 页面。

一些观察结果:

我的路由器正在扩展 Mage_Core_Controller_Varien_Router_Standard 而 Mage_Cms 路由器正在扩展 Mage_Core_Controller_Varien_Router_Abstract. 。我尝试以与 Magento 相同的方式注册我的路由器:

class DoALL_Manual_Controller_Router extends Mage_Core_Controller_Varien_Router_Abstract

将此添加到我的 etc/config.xml 文件,并注释掉我对路由器的原始注册 default/web/routers:

<global>
    <events>
        <controller_front_init_routers>
            <observers>
                <doall_manual>
                    <class>DoALL_Manual_Controller_Router</class>
                    <method>initControllerRouters</method>
                </doall_manual>
            </observers>
        </controller_front_init_routers>
    </events>
<global>

然后将此方法添加到我的路由器中:

/**
 * Initialize Controller Router
 *
 * @param Varien_Event_Observer $observer
 */
public function initControllerRouters($observer)
{
    /* @var $front Mage_Core_Controller_Varien_Front */
    $front = $observer->getEvent()->getFront();

    $front->addRouter('doall_manual', $this);
}

这种方法虽然有效,但仍然没有解决我最初的问题 为什么我必须在我的控制器类上执行硬编码的 require 语句.

有帮助吗?

解决方案

出色地...在花了近一个小时写出这个问题后,我在写完它后就逐字逐句地解决了它。因此,为了至少不浪费这个时间,我决定发布它,以便它可以为社区做出一些贡献。

在这里,这是完全没有必要的:

$controllerInstance = Mage::getControllerInstance('DoALL_Manual_ManualController', $request, $this->getFront()->getResponse());

$request->setDispatched(true);
$controllerInstance->dispatch($request->getActionName());

我添加了这些线条,同时从中汲取灵感 Inchoo 2012 年的帖子.

最终配置如下:

等/配置.xml

<frontend>
    <routers>
        <doall_manual>
            <use>standard</use>
            <args>
                <module>DoALL_Manual</module>
                <frontName>doall_manual</frontName>
            </args>
        </doall_manual>
    </routers>
</frontend>
<default>
    <web>
        <routers>
            <doall_manual>
                <area>frontend</area>
                <class>DoALL_Manual_Controller_Router</class>
            </doall_manual>
        </routers>
    </web>
</default>

路由器:

class DoALL_Manual_Controller_Router extends Mage_Core_Controller_Varien_Router_Standard
{

    public function match(Zend_Controller_Request_Http $request)
    {
        // checking before even try to find out that current module
        // should use this router
        if (!$this->_beforeModuleMatch()) {
            return false;
        }

        $path = explode('/', trim($request->getPathInfo(), '/'));

        if ($path[0] != 'parts-manual') {
            return false;
        }

        $request
            ->setModuleName('doall_manual')
            ->setControllerName('manual');

        switch (count($path)) {
            case 1:
                $request->setActionName('index');
                break;

            case 2:
                $request->setActionName('manual');
                break;

            case 3:
                $request->setActionName('page');
                break;

            default:
                $request->setActionName('noroute');
                break;
        }

        return true;
    }

}

控制器:

(无需更改)

花了这么多时间,我才能消除那一行代码(require 语句)......

或许..也许,有一天这篇文章会帮其他人省去几个小时的挫败感:)

许可以下: CC-BY-SA归因
scroll top