У меня есть настраиваемый маршрутизатор, и я должен получить доступ к Zend\Navigation
внутри этого настраиваемого маршрутизатора. Я искал поисковые запросы, искал и искал результаты: /
Все, что мне нужно, – найти узлы с параметром 'link', используя Zend \ Navigation в моей функции Alias :: match.
Вот мой module.config.php:
'navigation' => array( 'default' => array( 'account' => array( 'label' => 'Account', 'route' => 'node', 'pages' => array( 'home' => array( 'label' => 'Dashboard', 'route' => 'node', 'params' => array( 'id' => '1', 'link' => '/about/gallery' ), ), ), ), ), ), [...]
И вот мой класс Alias:
// file within ModuleName/src/ModuleName/Router/Alias.php namespace Application\Router; use Traversable; use Zend\Mvc\Router\Exception; use Zend\Stdlib\ArrayUtils; use Zend\Stdlib\RequestInterface as Request; use Zend\Mvc\Router\Http; use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorInterface; class Alias extends Http\Segment implements ServiceLocatorAwareInterface { public function setServiceLocator(ServiceLocatorInterface $serviceLocator) { $this->serviceLocator = $serviceLocator; return $this; } public function getServiceLocator() { return $this->serviceLocator; } public function match(Request $request, $pathOffset = null) { [...] return parent::match($request, $pathOffset); } }
Редакция:
Теперь я знаю, что я должен добавить менеджера сервисов в свой настраиваемый маршрутизатор. Дайте мне знать, если вы знаете, как это сделать 🙂
Редакция:
Хорошо, это не настраиваемый маршрутизатор, а маршрут. Виноват. Я говорил на #zftalk
irc chanell, и класс AliasSegment
должен реализовывать ServiceLocatorAwareInterface
.Хорошо, я пробовал, но теперь есть еще одна проблема.
В функции setServiceLocator
я не могу получить service locator
. Он возвращает нулевой объект, однако $serviceLocator
– это класс Zend\Mvc\Router\RoutePluginManager
.
public function setServiceLocator(ServiceLocatorInterface $serviceLocator){ $sl = $serviceLocator->getServiceLocator(); var_dump($sl); // NULL }
Любые идеи о том, как получить от Zend навигацию?
РЕДАКТИРОВАНИЕ
В соответствии с тем, что сказал @mmmshuddup, я изменил свой собственный класс маршрутизатора. (Новая версия выше). Также в моем Module.php
, внутри функции onBootstrap
, я добавил эту строку:
$sm->setFactory('Navigation', 'Zend\Navigation\Service\DefaultNavigationFactory', true);
Навигация работает и его экземпляр перед route
поэтому он должен быть видимым в моем классе Alias, но это не так.
Я включил функцию match
в классе Alias
:
$servicesArray = $this->getServiceLocator()->getRegisteredServices();
и $servicesArray
почти пуст. Нет сервиса, нет фабрик. onBootstrap
же строка, вставленная в onBootstrap
, сразу после установки новой фабрики (как указано выше) возвращает массив с navigation
и другими службами.
Вопрос в следующем: как я могу поделиться этим массивом (или ServiceManager) с моим настраиваемым маршрутизатором: Alias
?
Я должен сказать, что все, что я хочу сделать, было возможно в ZF1, и это было довольно легко.
РЕДАКТИРОВАТЬ
Я нашел решение. Ответ ниже
Это связано с тем, что сам объект действительно не имеет объявленных свойств . Но если вы это сделаете:
echo get_class($sl);
Вы увидите, что это действительно экземпляр Zend\ServiceManager\ServiceManager
Вы должны иметь возможность получить свой экземпляр навигации, выполнив что-то вроде:
$nav = $sl->get('Navigation');
РЕДАКТИРОВАТЬ:
Я просто заметил, что у вас есть кое-что в неправильном месте вашего кода. Вы вызываете getServiceLocator()
на $serviceLocator
который уже является экземпляром этого. Также вы вызываете его в setServiceLocator()
. Вы должны изменить его на:
// EDIT - file within ModuleName/src/Router/Alias.php namespace Application\Router; use Traversable; use Zend\Mvc\Router\Exception; use Zend\Stdlib\ArrayUtils; use Zend\Stdlib\RequestInterface as Request; use Zend\Mvc\Router\Http; class Alias extends Http\Segment implements ServiceLocatorAwareInterface { public function setServiceLocator(ServiceLocatorInterface $serviceLocator) { $this->serviceLocator = $serviceLocator; return $this; } public function getServiceLocator() { return $this->serviceLocator; } public function match(Request $request, $pathOffset = null) { $nav = $this->getServiceLocator()->get('Navigation'); // ... return parent::match($request, $pathOffset); } }
Я нашел решение, но это НЕ элегантное решение, я думаю. Однако все работает отлично. Если кто-то знает недостатки этого решения, прокомментируйте этот ответ или добавьте еще один, лучше. Мне пришлось изменить идею @mmmshuddup ( вы можете прочитать разговор ).
Прежде всего, внедрение ServiceLocatorAwareInterface
в пользовательский класс маршрута больше не требуется.
В Module.php
внутри функции onBootstrap
:
$app = $e->getApplication(); $sm = $app->getServiceManager(); $sm->get('translator'); $eventManager = $e->getApplication()->getEventManager(); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); $sm->setFactory('Navigation', 'Zend\Navigation\Service\DefaultNavigationFactory', true); $nav = $sm->get('Navigation'); $alias = $sm->get('Application\Router\Alias'); $alias->setNavigation($nav);
Сначала мы создаем Navigation
фабрику в ServiceManager
а затем в нашем обычном маршруте. После этого мы можем передать класс навигации в настраиваемый маршрут с setNavigation
функции setNavigation
. Чтобы завершить экземпляр нашего пользовательского маршрута, нам нужно получить getServiceConfig
в том же файле:
return array( 'factories' => array( 'Application\Router\Alias' => function($sm) { $alias = new \Application\Router\Alias('/node[/:id]'); return $alias; }, 'db_adapter' => function($sm) { $config = $sm->get('Configuration'); $dbAdapter = new \Zend\Db\Adapter\Adapter($config['db']); return $dbAdapter; }, ) );
И вот сложная часть. Этот экземпляр является временным. Во время маршрутизации этот класс будет создан еще один раз, и поэтому, я думаю, он не очень изящный. Мы должны вставить параметр в конструктор, но в этот момент значение этого параметра не имеет значения.
Пользовательский класс маршрута:
// file within ModuleName/src/ModuleName/Router/Alias.php namespace Application\Router; use Traversable; use Zend\Mvc\Router\Exception; use Zend\Stdlib\ArrayUtils; use Zend\Stdlib\RequestInterface as Request; use Zend\Mvc\Router\Http; class Alias extends Http\Segment { private static $_navigation = null; public function match(Request $request, $pathOffset = null) { //some logic here //get Navigation $nav = self::$_navigation; return parent::match($request, $pathOffset); } public function setNavigation($navigation){ self::$_navigation = $navigation; } }
Поскольку первый экземпляр является временным, мы должны собирать наш класс Navigation
в статической переменной. Это ужасно, но хорошо работает. Возможно, есть способ создать экземпляр только один раз и в конфигурации маршрута получить экземпляр, но на данный момент это лучший ответ на мой вопрос. Просто достаточно и работает правильно.