ZF2 - вставка страниц в навигацию перед вызовом контроллера

Я создаю динамическое приложение, в которое контент добавляется через CMS. Внутри CMS я устанавливаю запись в БД, в которой указывается, какой модуль использовать для каждой страницы контента.

NodeId, ParentNodeId, Name_de, Name_en, ModuleName, Foreignkey_ContentLinks,

в этой таблице записи выглядят следующим образом: 6, 1, Veranstaltung-21-02-2013, Event-21-02-2013, Events, 682

Все дерево должно попасть в мою навигацию (а также в мою маршрутизацию). Я не хочу добавлять его в какой-то контроллер, потому что мое приложение состоит из целой кучи модулей, и я хочу получить доступ к этой информации во всех моих модулях.

Я уже пытался внедрить его в global.php, но безрезультатно, потому что на этом этапе я не могу использовать свой адаптер базы данных или любые другие важные классы.

Любые идеи или ссылки на лучшие практики?


person Ben Greene    schedule 18.05.2013    source источник


Ответы (2)


Навигационные контейнеры состоят из фабричных классов. Самый простой подход — написать свою собственную фабрику и заставить метод getPages() получать страницы из базы данных, а не из конфигурации. Если вы расширяетесь от AbstractNavigationFactory, вам нужно написать всего пару методов.

<?php
namespace Application\Navigation\Service;

use Zend\Navigation\Service\AbstractNavigationFactory;
use Zend\ServiceManager\ServiceLocatorInterface;

class CmsNavigationFactory extends AbstractNavigationFactory
{
    /**
     * @param ServiceLocatorInterface $serviceLocator
     * @return array
     * @throws \Zend\Navigation\Exception\InvalidArgumentException
     */
    protected function getPages(ServiceLocatorInterface $serviceLocator)
    {
        if (null === $this->pages) {

            $application = $serviceLocator->get('Application');
            $routeMatch  = $application->getMvcEvent()->getRouteMatch();
            $router      = $application->getMvcEvent()->getRouter();

            // get your pages from wherever...
            $pages       = $this->getPagesFromDB();

            $this->pages = $this->injectComponents($pages, $routeMatch, $router);
        }
        return $this->pages;
    }

    public function getName()
    { 
         // this isn't used if fetching from db, it's just here to keep the abstract factory happy
         return 'cms';
    }
}

Добавьте фабрику в диспетчер служб, как и для других контейнеров.

'service_manager' => array(
    'factories' => array(
        'CmsNavigation' => 'Application\Navigation\Service\CmsNavigationFactory',
    ),
),

И используйте его с помощниками представления навигации таким же образом.

<?php echo $this->navigation()->menu('CmsNavigation'); ?>
person Crisp    schedule 18.05.2013
comment
Спасибо приятель! я полагаю, я действую аналогичным образом, чтобы ввести маршрут из базы данных? - person Ben Greene; 18.05.2013
comment
спасибо Крисп! Где правильно написать метод getPagesFromDB()? - person Michelangelo; 12.12.2014

Отвечая на ваш комментарий к ответу @Crisp и для будущих пользователей Google, я объясню, как сделать что-то подобное для маршрутизации.

Как правило, вы хотите создать собственный маршрутизатор, который может сопоставлять URL-адреса со страницами в вашей базе данных, аналогично стандартному маршрутизатору Segment. Для этого вам придется реализовать интерфейс Zend\Mvc\Router\RouteInterface. Например:

namespace Application\Router;

use Zend\Mvc\Router\RouteInterface;
use Application\Model\CMSTable;

class CmsRoute implements RouteInterface, ServiceLocatorAwareInterface
{
    protected $table;

    // Service locator injection code

    public function getCmsTable()
    {
        // Retrieve the table from the service manager
    }

    public function match(Request $request)
    {
        // Match the request on some route field, etc.
    }

    public function assemble(array $params = array(), array $options = array())
    {
        // Assemble a URL based on the given parameters (e.g. page ID).
    }

    public static function factory($options = array())
    {
        // Construct a new route, based on the options.
    }
}

Затем вы можете зарегистрировать этот маршрут как вызываемый для RoutePluginManager в конфигурации вашего модуля:

'route_manager' => array(
  'invokables' => array(
    'Cms' => 'Application\Router\CmsRoute'
  ),
),

Затем вы можете создать новый маршрут (как и любой другой маршрут) с типом Cms. Диспетчер плагинов маршрута создаст экземпляр вашего маршрута, и, поскольку CmsRoute реализует ServiceLocatorAwareInterface, менеджер плагинов внедрит себя в маршрут. В свою очередь, в менеджере плагинов установлен основной сервис-менеджер, так что оттуда можно получить таблицу базы данных!

Конечно, вы можете сопоставить идентификатор страницы, но если у вас иерархическая структура, лучше отразить это в ваших URL-адресах. Поэтому я бы рекомендовал добавить поле route в схему базы данных и сопоставить его, начиная с корня дерева и спускаясь вниз.

person Eric Spreen    schedule 25.03.2014