Search code examples
zend-framework2urlhelperviewhelper

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


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?


Solution

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