MVC система в Zend Framework 2

в 13:34, , рубрики: mvc, zend, Zend Framework, zend framework 2, Веб-разработка, переводы, метки: , ,

Здравствуйте дорогие читатели.
Совсем недавно вышел в свет Zend Framework 2. Однако его изучение у многих усложняет отсутствие русской документации и единого сообщества. Так же во второй ветке этого фреймворка появилось множество нововведений и плюшек, про который обычный PHP программист раньше даже не слышал. Но их можно изучить особо не потея. А вот понять, как работает ZF2 без понимания логики работы его MVC системы достаточно затруднительно. Поэтому решил сделать перевод с официального сайта именно этого раздела.И так приступим.

MVC в Zend Framework 2

ZendMvc представляет собой совершено новую реализацию MVC системы для Zend Framework 2. Основное внимание было уделено производительности и гибкости.

Слой MVC построен на основе следующих компонентов:

  1. ZendServiceManager — Zend Framework предоставляет набор различных сервисов, определенных в ZendMvcService. ServiceManager создает и настраивает экземпляр вашего приложения и рабочего процесса.
  2. ZendEventManager – MVC является событиями. Данный компонент используется повсеместно. Для начальной загрузки приложения, возврата ответов (response) и запросов (request), настройки и получения маршрутов (routes), а так же для обработки (render) скриптов вида (views).
  3. ZendHttp – особый объект запросов (request) и ответов (response). Используется с ZendStdlibDispatchableInterface. Все контроллеры представляют собой объекты «dispatch».

В MVC слое используются следующие вспомогательные компоненты:

  1. ZendMvcRouter – содержит классы, обеспечивающие маршрутизацию запросов. Другими словами, перенаправляет запросы к нужным контроллерам.
  2. ZendHttpPhpEnvironment – предоставляет набор декораторов объектов HTTP запросов и ответов, обеспечивающих инъекцию запросов в текущую среду (включая GET и POST параметры, HTTP заголовки).
  3. ZendMvcController – набор абстрактных классов контроллеров с базовой функциональностью, такой как создание событий, диспетчеризацией действий и т.д.
  4. ZendMvcService – набор ServiceManager фабрик и определений по умолчанию для различных процессов приложения.
  5. ZendMvcView – предоставляет стандартные возможности визуализации скриптов вида, регистрации помощников и многое другое. Так же предоставляет различные слушатели, которые «связывают» рабочий процесс MVC, обеспечивая такие функции, как автоматическое разрешение имен шаблонов, автоматическое создание модели вида и инъекций, т.д.


Начальной точкой работы MVC является объект ZendMvcApplication (далее Приложение). Основными обязанностями которого являются начальная загрузка ресурсов, направление (роутинг) запросов, получение и отправка контроллеров, соответствующих роутингу.

Базовая структура приложения

application_root/
    config/
        application.config.php
        autoload/
            global.php
            local.php
            // etc.
    data/
    module/
    vendor/
    public/
        .htaccess
        index.php
    init_autoloader.php

За перенаправление всех пользовательских запросов на сайт отвечает файл public/index.php. Затем получает массив настроек приложения, расположенный в config/application.config.php. После запускает Приложение (Application) вызовом функции run(), которое обрабатывает запросы и в итоге отсылает полученный результат обратно пользователю.

Директория настроек «config» содержит необходимые настройки, используемые в ZendModuleManager для загрузки модулей и объединения конфигураций (настройки подключения к БД, меню, ACL и др.). Более подробно про сказанное немного позже.

Поддиректория «vendor» содержит любые третье- степенные (вспомогательные, third-party) модули библиотеки, необходимые для обеспечения работоспособности Вашего приложения. На пример, там может быть размещен непосредственно сам Zend Framework 2, пользовательские библиотеки, или другие вспомогательные библиотеки различных проектов. Библиотеки и модули, расположенные в данной поддиректории «vendor» не должны изменяться каким либо способом, не должны отличаться от оригинала, над ними нельзя совершать какие либо действия из приложения или сторонних программ.

Директория «module» содержит один или более модулей, обеспечивающих главный функционал Вашего приложения.

Базовая структура модуля

Содержимое модуля может быть абсолютно любым: PHP код, функциональные MVC структуры, коды библиотек, скрипты видов, публичные (public) ресурсы, такие как картинки, каскадные таблицы стилей CSS, JavaScript код и др. Единственное требование, и то оно не является обязательным — модуль должен выступать пространством имен (namespace) и содержать класс Module.php в пределах этого пространства имен. Этот класс необходим для нормальной работы ZendModuleManager и ряда других задач.

Рекомендуется придерживаться следующей структуры при создании модуля:

module_root<named-after-module-namespace>/
    Module.php
    autoload_classmap.php
    autoload_function.php
    autoload_register.php
    config/
        module.config.php
    public/
        images/
        css/
        js/
    src/
        <module_namespace>/
            <code files>
    test/
        phpunit.xml
        bootstrap.php
        <module_namespace>/
            <test code files>
    view/
        <dir-named-after-module-namespace>/
            <dir-named-after-a-controller>/
                <.phtml files>

В силу того, что модуль выступает пространством имен, корневой каталог модуля и есть это пространство имен. Пространство имен может включать вендорный префикс принадлежности. Для наглядности, модуль обеспечивающий базовую функциональность для пользователя «User», разработанный командой Zend может называться (желательно, но не обязательно) «ZendUser» — так же это является названием корневой папки модуля и пространства имен одновременно. Файл Module.php, расположенный сразу в корневой папке модуля будет уже находиться в пространстве имен данного модуля. Смотрим пример ниже:

namespace ZendUser;
 
class Module
{
}

Если определен метод init(), то он будет вызван слушателем ZendModuleManager’а, после загрузки класса, и передачи экземпляра менеджера по умолчанию. Такой подход позволяет создавать особых слушателей событий. НО! Будьте осторожны с методом init()! Он вызывается для каждого модуля на каждый запрос и должен использоваться исключительно для «легковесных» задач, таких как регистрация слушателей.

Тоже касается и метода onBootstrap(), который принимает экземпляр объекта MvcEvent и вызывается для каждого модуля при каждом запросе.

Три файла autoload_*.php необязательны, но желательны. Они обеспечивают следующее:

  • autoload_classmap.php
    Возвращает массив карты классов, содержащий пары имя класса/имя файла. Имена классов определяются с помощью магической константы __DIR__).
  • autoload_function.php
    Возвращает функцию обратного вызова, которая может быть передана в spl_autoload_register(). Как правило, функция обратного вызова использует карту, возвращаемую в autoload_classmap.php.
  • autoload_register.php
    Регистрирует функцию обратного вызова. Как правило она находится в autoload_function.php.

Эти три файлы обеспечивают загрузку по умолчанию классов, находящихся в модуле без использования ZendModuleManager. Например для использования модуля вне ZF2.

Директория «config» должна содержать различные специфические настройки модуля. Эти настройки могут быть в любом формате, который поддерживает ZendConfig. Желательно использовать для главного файла конфигурации имя «module.format». Например, для файла конфигурации в формате PHP имя главного конфигурационного файла должно быть таким: module.config.php. Как правило Вам придется создавать файлы настройки для маршрутизации и инъекций зависимости.

Директория «src» должна быть совместима с форматом PSR-0 и содержать основной код модуля. Как минимум, в ней должен быть подкаталог, названый так же, как и пространство имен модуля (корневая папка модуля). Однако может содержать код и с разными пространствами имен, если это необходимо.

Директория «test» должна содержать ваши unit-тесты. Как правило они пишутся с использованием PHPUnit и содержат файлы, связанные с его настройкой.

Директория «public» используется для общедоступных ресурсов. Это могут быть картинки, CSS, JavaScript и др. Полностью на усмотрение разработчика.

Директория «view» содержит скрипты видов, связанные с различными контроллерами.

Начальная загрузка приложений

Приложение имеет шесть основных зависимостей:

  1. Конфигурация – как правило массив или объект Traversable
  2. Экземпляр ServiceManager
  3. Экземпляр EventManager, который по умолчанию «рождается» из ServiceManager, заданием имени сервиса «EventManager»
  4. Экземпляр ModuleManager, который по умолчанию «рождается» из ServiceManager, заданием имени сервиса «ModuleManager»
  5. Экземпляр Request, который по умолчанию «рождается» из ServiceManager, заданием имени сервиса «Request»
  6. Экземпляр Response, который по умолчанию «рождается» из ServiceManager, заданием имени сервиса «Response»

Вышеперечисленное может быть реализовано при инициализации:

use ZendEventManagerEventManager;
use ZendHttpPhpEnvironment;
use ZendModuleManagerModuleManager;
use ZendMvcApplication;
use ZendServiceManagerServiceManager;
 
$config = include 'config/application.config.php';
 
$serviceManager = new ServiceManager();
$serviceManager->setService('EventManager', new EventManager());
$serviceManager->setService('ModuleManager', new ModuleManager()); 
$serviceManager->setService('Request', new PhpEnvironmentRequest());
$serviceManager->setService('Response', new PhpEnvironmentResponse());
 
$application = new Application($config, $serviceManager);

После выполнения всего, что было описано выше, у Вас есть выбор из двух действий.

Первое: Вы можете начать загрузку приложения (bootstrap). В реализации по умолчанию это выглядит так:

  • Присоединяется слушатель по умолчанию для маршрутизации: ZendMvcRouteListener
  • Присоединяется слушатель по умолчанию для диспетчеризации: ZendMvcDispatchListener
  • Присоединяется слушатель ViewManager: ZendMvcViewViewManager
  • Срабатывает событие начальной загрузки.

Если Вам нет необходимости выполнять эти действия, то можете сами задать альтернативы, расширяя класс Application и/или просто написав необходимый код.

Второе: Просто запустить приложение, вызвав метод run(). Этот метод сделает следующее:

  • сработает событие «route»
  • сработает событие «dispatch»
  • и в зависимости от выполнения предыдущих двух, возможно сработает событие «render»
  • после выполнения вышеперечисленного, сработает событие «finish» и вернется экземпляр ответа.

Если возникнут ошибки в процессе выполнения событий «route» или «dispatch», то сработает событие «dispatch.error».

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

use ZendLoaderAutoloaderFactory;
use ZendMvcServiceServiceManagerConfig;
use ZendServiceManagerServiceManager;
 
// setup autoloader
AutoloaderFactory::factory();
 
// get application stack configuration
$configuration = include 'config/application.config.php';
 
// setup service manager
$serviceManager = new ServiceManager(new ServiceManagerConfig());
$serviceManager->setService('ApplicationConfig', $configuration);
 
// load modules -- which will provide services, configuration, and more
$serviceManager->get('ModuleManager')->loadModules();
 
// bootstrap and run application
$application = $serviceManager->get('Application');
$application->bootstrap();
$response = $application->run();
$response->send();

Очень быстро Вы заметите, что у Вас в руках очень гибкая система с большим количеством различных настроек. Используя ServiceManager Вы получаете контроль над остальными доступными сервисами, их инициализацией и внедрением зависимостей. Используя EventManager получаете возможность перехватывать любые события, возникающие в приложении («bootstrap», «route», «dispatch», «dispatch.error», «render», «finish»), в любое время и в любом месте, что позволяет создавать свои процессы в приложении при необходимости.

Начальная загрузка модульного приложения

Описанный ранее подход работает. Но возникает вопрос, откуда взялись настройки приложения? Логично предположить, что настройки берутся непосредственно из самого модуля. И как тогда получить эти настройки в свое распоряжение?

Ответом на эти вопросы является ZendModuleManagerModuleManager. Сначала, этот компонент позволяет Вам указать, где находятся модули. Затем он находит каждый модуль и инициализирует его. Классы Module связываются различными слушателями в ModuleManager для обеспечения конфигурации, настроек, слушателей и многого другого. Если Вам кажется это сложным, то это ошибочное предположение.

Настройка Module Manager

Сначала займемся настройкой Module Manager. Просто сообщите Module Manager какие модули необходимо загружать, а при необходимости можно еще указать и настройки для слушателей модулей.

Теперь давайте вспомним про файл application.config.php, описанный ранее. Зададим настройки следующим образом:

<?php
// config/application.config.php
return array(
    'modules' => array(
        /* ... */
    ),
    'module_listener_options' => array(
        'module_paths' => array(
            './module',
            './vendor',
        ),
    ),
);

Что бы добавить модули, необходимо просто добавить элементы в массив модулей.

Каждый класс модуля Module должен определять метод getConfig(). Он должен возвращать массив или объект Traversable, такой как ZendConfigConfig.Рассмотрим на примере:

namespace ZendUser;
 
class Module
{
    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php'
    }
}

Так же существует еще целый ряд методов, которые можно определить для выполнения таких задач, как автозагрузка настроек, предоставление сервисов из ServiceManager, слушателей событий загрузки и др. Более подробно в документации по ModuleManager.

Выводы

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

Ссылки

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

Автор: struggleendlessly

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js