Расширение Zend\View\Helper\Url в Zend Framework 2
Я написал простой помощник вида 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');
...
}
}
Теперь приложение выдает исключение:
Неустранимая ошибка: необработанное исключение "Zend\View\Exception\RuntimeException" с сообщением "Не предоставлен экземпляр RouteStackInterface" в /var/www/foo/bar/vendor/zendframework/zendframework/library/Zend/View/Helper/Url.php on линия 76
Zend\View\Exception\RuntimeException: экземпляр / RouteStackInterface не предоставлен в /var/www/foo/bar/vendor/zendframework/zendframework/library/Zend/View/Helper/Url.php в строке 76
Я отлаживал оба Url
классы. Венна MyNamespace\View\Helper\Url
используется метод Zend\View\Helper\Url#setRouter(...)
не вызывается и роутер не установлен. Не понимаю почему...
Как заставить это работать?
4 ответа
Не проверял это, поэтому я не знаю, работает ли это, я просто догадываюсь:
Заменить:
$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;
});
Вы также можете использовать инициализаторы!
'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');
}
}
Хотя этот вопрос довольно старый, он решил, что здесь стоит добавить переопределение на основе конфигурации, а также использовать фабрику, зарегистрированную в HelperPluginManager
:
Внутри module.config.php
:
'view_helpers' => array(
'factories'=> array(
'url' => 'Application\View\Helper\UrlFactory',
)
),
А сам плагин view helper factory:
<?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
использование глобального локатора услуг извне замыкания во всех других решениях).
Решение Айдына сработало для меня, я поместил код, более или менее нетронутый в getViewHelperConfig файла 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;
}
),
);
}