Extending Zend\View\Helper\Url in Zend Framework 2

不打扰是莪最后的温柔 提交于 2019-12-22 10:57:36

问题


I wrote a simple url view helper, that extends Zend\View\Helper\Url and attached it to the 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');
        ...
    }

}

Now the application throws an exception:

Fatal error: Uncaught exception 'Zend\View\Exception\RuntimeException' with message 'No RouteStackInterface instance provided' in /var/www/foo/bar/vendor/zendframework/zendframework/library/Zend/View/Helper/Url.php on line 76

Zend\View\Exception\RuntimeException: No RouteStackInterface instance provided in /var/www/foo/bar/vendor/zendframework/zendframework/library/Zend/View/Helper/Url.php on line 76

I debugged both Url classes. Wenn MyNamespace\View\Helper\Url is used, the method Zend\View\Helper\Url#setRouter(...) is not called and the router is not set. Don't get why...

How to get it working?


回答1:


Not tested this so I don't know if it works, I am just guessing:

Replace:

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

with:

$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;
});



回答2:


You can also use initializers!

'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);
                }
            }
        }
    )
)

And You can extend \Zend\View\Helper\Url as You want it

namespace MyModule\View\Helper;

use Zend\View\Helper\Url as ZendUrl;

class MyUrl extends ZendUrl {

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

}



回答3:


Though this questions is quite old, figured it might be worth adding a configuration based override here as well using a factory registered with the HelperPluginManager:

Inside the module.config.php:

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

And the view helper plugin factory itself:

<?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;
    }
}

The trick here really is that in this factory, one only receives the HelperPluginManager service locator. To access other services, one needs to fetch the global service locator first (which is done by the useing the global service locator from outside the closure in all other solutions).




回答4:


Aydin's solution worked for me, I put the code, more or less untouched in the getViewHelperConfig of the module.php

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;
            }
        ),
    );
}


来源:https://stackoverflow.com/questions/15988083/extending-zend-view-helper-url-in-zend-framework-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!