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?
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;
});
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');
}
}
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 use
ing the global service locator from outside the closure in all other solutions).
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