Zend Framework 2 - Приложения / Модули / Сервис-менеджеры - Oh My

Я только начал изучать Zend Framework 2 как давний разработчик Zend Framework 1. У меня возникли небольшие проблемы, когда я оборачиваюсь вокруг новой терминологии.

Назад в ZF1, если бы я хотел создать регистратор, который был бы глобальным для приложения, я бы добавил конфигурацию в файл application.ini, и загрузчик инициализировал бы его как ресурс (надеюсь, я правильно это говорю). Итак, с любого из моих контроллеров модулей я мог получить доступ к логгеру через ресурсы начальной загрузки.

Введите ZF2, Модули немного другой зверь, они самодостаточны, но я немного смущен тем, как они взаимодействуют с приложением. Мне кажется, что именно здесь ServiceManager вступает в игру. Моя цель состоит в том, чтобы иметь мой Модуль (не контроллер, а сам модуль), чтобы проверить, определено ли в Приложении логгер и, если он есть, использовать этот логгер во всем модуле. Если приложение не определяет регистратор, я хочу, чтобы модуль определил регистратор для регистрации всего модуля.

Этот вопрос также относится и к базам данных, скажем, я хочу, чтобы приложение определяло логику соединения с базой данных, в то время как я хочу, чтобы модуль определял логику требуемых таблиц. Как именно я это настраиваю и как / где я могу узнать, есть ли уже ресурс базы данных, определенный в Приложении.

Примечание: я прошел Quickstart Роба Аллена (достаточно информации и единственный ресурс, который я обнаружил, что при этом не хватает неизвестности), а также ZF2 (readthedocs), и уже погуглил тонны. Что я обнаружил, так это то, что информация, как правило, очень неясна, когда речь идет о том, "куда" уходят определенные кусочки головоломки.

2 ответа

Решение

То, что вы знаете из Zend Framework 1.x, является "Ресурсом приложения".

Понятие "ресурс приложения" заменено в Zend Framework 2 на так называемые "сервисы" (введение здесь)

Другое изменение - сами модули. В ZF1 модуль был в основном подразделом вашего приложения, который обрабатывал некоторые запросы. Это больше не верно в ZF2: если ваш модуль определяет сервис или контроллер, то теперь он доступен для всех приложений. Есть хорошее введение в некоторые различия между ZF1 и ZF2 от Гэри Хокина.

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

Для вашего конкретного случая с регистратором, я полагаю, что ваш модуль всегда определяет регистратор и использует его. Что можно сделать для определения логгера условно:

class MyModule
{
    public function onBootstrap($e)
    {
        // $e->getTarget() is the \Zend\Mvc\Application
        $sm = $e->getTarget()->getServiceManager();

        if (!$sm->has('some-logger-name')) {
            $sm->setFactory('some-logger-name', function ($sl) {
                return new MyLogger($sl->get('some-db'));
            });
        }
    }
}

После этого вы сможете использовать "some-logger-name" во всех своих приложениях.

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

class MyModule
{
    public function getConfig()
    {
        return array(
            'service_manager' => array(
                'factories' => array(
                    'some-logger-name' => 'My\Logger\Factory\ClassName'
                ),
            ),
        );
    }
}

То же самое достигается с getServiceConfig, который менее гибок и не может быть кэширован, но имеет более высокий приоритет над getConfig (позволяет переопределять) и позволяет также определять фабрики обслуживания как замыкания:

class MyModule
{
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'some-logger-name' => function ($sl) {
                    return new MyLogger($sl->get('some-db'));
                },
            ),
        );
    }
}

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

Концепция с модулями и конфигурациями заключается в том, что "последний модуль выигрывает", поэтому вы можете определить услугу 'some-logger-name' либо в вашем модуле, либо в любом модуле, загруженном до него.

Те же понятия применимы и к вашему соединению с БД.

Как видите, переход к услугам уже дал вам определенную степень свободы.

Имейте в виду, что это не то, что "Приложение" определяет что-то для вас: модули определяют ваши сервисы / конфиги / события и т. Д.... Тогда работающее приложение представляет собой совокупность всех этих вещей.

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

Прикрепить log слушатель событий в вашем Module.php:

public function onBootstrap(MvcEvent $e)
{
    //setup some $logger

    $sharedManager = $e->getApplication()->getEventManager()->getSharedManager();

    $sharedManager->attach('*', 'log', function($e) use ($logger) {
        /** @var $e MvcEvent */
        $target   = get_class($e->getTarget());
        $message  = $e->getParam('message', 'No message provided');
        $priority = $e->getParam('priority', Logger::INFO);
        $message  = sprintf('%s: %s', $target, $message);
        $logger->log($priority, $message);
    });
}

Затем запустите его из любого места в вашем приложении, например, из контроллера:

$this->getEventManager()->trigger('log', $this, array(
    'priority' => \Zend\Log\Logger::INFO, 
    'message' => 'just some info to be logged'
));
Другие вопросы по тегам