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);
    }
}
Другие вопросы по тегам