3

我写了一个简单的 url 视图助手,它扩展Zend\View\Helper\Url并附加到ViewHelperManager

MyNamespace\View\Helper\Url

namespace MyNamespace\View\Helper;

use Zend\View\Helper\Url as ZendUrl;

class Url extends ZendUrl {
    
    public function __invoke($name = null, array $params = array(), $options = array(), $reuseMatchedParams = false) {
        $link = parent::__invoke($name, $params, $options, $reuseMatchedParams);
        ...
        return $link;
    }
    
}

Application\Module

namespace Application;

use ...

class Module {
    
    public function onBootstrap(MvcEvent $mvcEvent) {
        $application = $mvcEvent->getApplication();
        $serviceManager = $application->getServiceManager();
        $viewHelperManager = $serviceManager->get('ViewHelperManager');
        $viewHelperManager->setInvokableClass('url', 'MyNamespace\View\Helper\Url');
        ...
    }
    
}

现在应用程序抛出异常:

致命错误:在 /var/www/foo/bar/vendor/zendframework/zendframework/library/Zend/View/Helper/Url.php 中未捕获异常 'Zend\View\Exception\RuntimeException' 并带有消息 'No RouteStackInterface instance provided'第 76 行

Zend\View\Exception\RuntimeException:第 76 行的 /var/www/foo/bar/vendor/zendframework/zendframework/library/Zend/View/Helper/Url.php 中没有提供 RouteStackInterface 实例

我调试了两个Url类。使用了wenn MyNamespace\View\Helper\Url,没有调用方法Zend\View\Helper\Url#setRouter(...),也没有设置路由器。不明白为什么...

如何让它工作?

4

4 回答 4

1

没有测试过,所以我不知道它是否有效,我只是猜测:

代替:

$viewHelperManager->setInvokableClass('url', 'MyNamespace\View\Helper\Url');

和:

$viewHelperManager->setFactory('url', function ($sm) use($serviceLocator) {
    $helper = new \MyNamespace\View\Helper\Url;
    $router = Console::isConsole() ? 'HttpRouter' : 'Router';
    $helper->setRouter($serviceLocator->get($router));

    $match = $serviceLocator->get('application')
    ->getMvcEvent()
    ->getRouteMatch();

    if ($match instanceof RouteMatch) {
        $helper->setRouteMatch($match);
    }

    return $helper;
});
于 2013-04-13T13:57:57.043 回答
1

您还可以使用初始化程序!

'view_helpers' => array(
    'invokables' => array(
        'MyUrl' => 'MyModule\View\Helper\MyUrl'
    ),
    'initializers' => array(
        function ($instance, $sm) {
            if ($instance instanceof \Zend\View\Helper\Url) {
                $serviceLocator = $sm->getServiceLocator();

                $router = \Zend\Console\Console::isConsole() ? 'HttpRouter' : 'Router';
                $instance->setRouter($serviceLocator->get($router));

                $match = $serviceLocator->get('application')
                    ->getMvcEvent()
                    ->getRouteMatch();

                if ($match instanceof RouteMatch) {
                    $instance->setRouteMatch($match);
                }
            }
        }
    )
)

您可以根据需要扩展 \Zend\View\Helper\Url

namespace MyModule\View\Helper;

use Zend\View\Helper\Url as ZendUrl;

class MyUrl extends ZendUrl {

    public function __invoke() {
        return parent::__invoke('MyRoute');
    }

}
于 2014-06-28T15:17:34.740 回答
1

尽管这个问题已经很老了,但认为在这里添加基于配置的覆盖以及使用注册的工厂可能值得HelperPluginManager

里面module.config.php

'view_helpers' => array(
    'factories'=> array(
        'url' => 'Application\View\Helper\UrlFactory',
    )
),

以及视图助手插件工厂本身:

<?php

namespace Application\View\Helper;

use Zend\Console\Console;
use Zend\Mvc\Router\RouteMatch;
use Zend\Mvc\Router\RouteStackInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\View\Helper\Url as BaseUrlHelper;
use Zend\View\HelperPluginManager;

class UrlFactory implements FactoryInterface
{
    /**
     * Create service
     *
     * @param ServiceLocatorInterface $helperPluginManager
     * @return mixed
     */
    public function createService(ServiceLocatorInterface $helperPluginManager)
    {
        /**
         * @var $helperPluginManager HelperPluginManager
         * @var $router RouteStackInterface
         */
        $serviceLocator = $helperPluginManager->getServiceLocator();
        $helper = new Url();

        $router = Console::isConsole() ? 'HttpRouter' : 'Router';
        $router = $serviceLocator->get($router);
        $helper->setRouter($router);

        $match = $serviceLocator->get('application')
            ->getMvcEvent()
            ->getRouteMatch()
        ;

        if ($match instanceof RouteMatch) {
            $helper->setRouteMatch($match);
        }

        return $helper;
    }
}

这里的诀窍是,在这个工厂里,一个人只接收HelperPluginManager服务定位器。要访问其他服务,首先需要获取全局服务定位器(use在所有其他解决方案中,这是通过从闭包外部获取全局服务定位器来完成的)。

于 2016-02-06T10:33:45.693 回答
0

Aydin 的解决方案对我有用,我将代码或多或少地放在 module.php 的 getViewHelperConfig 中

public function getViewHelperConfig()
{
    return array(
        'invokables' => array(
            .....
        ),
        'factories' => array(
            'modalurl'            => function ($helperPluginManager) {
                $serviceLocator = $helperPluginManager->getServiceLocator();
                $view_helper =  new \Application\View\Helper\ModalUrl();
                $router = \Zend\Console\Console::isConsole() ? 'HttpRouter' : 'Router';
                $view_helper->setRouter($serviceLocator->get($router));

                $match = $serviceLocator->get('application')
                    ->getMvcEvent()
                    ->getRouteMatch();

                if ($match instanceof RouteMatch) {
                    $view_helper->setRouteMatch($match);
                }

                return $view_helper;
            }
        ),
    );
}
于 2013-06-12T13:24:50.387 回答