ZF2: Как получить Zend\Navigation внутри собственного маршрута?
У меня есть собственный маршрутизатор, и я должен получить доступ к 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
ирк шанелл и 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
, только после установки новой фабрики (как выше) возвращает массив с navigation
и другие услуги.
Вопрос в том, как я могу поделиться этим массивом (или ServiceManager) с моим настраиваемым маршрутизатором: Alias
?
Я должен сказать, что все, что я хочу сделать, было возможно в ZF1, и это было довольно легко.
РЕДАКТИРОВАТЬ
Я нашел решение. Ответ ниже
2 ответа
Я нашел решение, но это НЕ элегантное решение, я думаю. Однако все работает отлично. Если кто-то знает недостатки этого решения, пожалуйста, прокомментируйте этот ответ или добавьте другой, лучше. Мне пришлось изменить идею @ 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
а затем наш собственный маршрут. После этого мы можем передать класс Navigation в пользовательский маршрут, используя 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
класс в статической переменной. Это ужасно, но хорошо работает. Может быть, есть способ создать его экземпляр только один раз и в конфигурации маршрута получить его экземпляр, но в данный момент это лучший ответ на мой вопрос. Достаточно просто и работает правильно.
Это потому, что сам объект действительно не имеет объявленных свойств.Но если вы сделаете это:
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);
}
}