У меня есть настраиваемый маршрутизатор, и я должен получить доступ к 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 в статической переменной. Это ужасно, но хорошо работает. Возможно, есть способ создать экземпляр только один раз и в конфигурации маршрута получить экземпляр, но на данный момент это лучший ответ на мой вопрос. Просто достаточно и работает правильно.