Пример разработки блога на Zend Framework 2. Часть 1. ZendSkeletonApplication

Пример разработки блога на Zend Framework 2. Часть 1. ZendSkeletonApplication

В последние несколько лет моя работа связана с использованием CMS Drupal, но на досуге я изучал и just for fun запускал проекты на питоновских фреймворках Django, Flask и Twisted. Сейчас я решил освоить основы двух-трех популярных PHP-фреймфорков и первыми я решил изучить Zend Framework 2 и Yii.

В процессе ознакомления с Zend Framework 2 я изучил туториал с официального сайта (http://framework.zend.com/manual/2.2/en/user-guide/overview.html), просмотрел документацию фреймворка (http://framework.zend.com/manual/2.2/en/index.html), прочитал книгу Michael Romer “Web development with Zend Framework 2” и собрал собственное тестовое приложение.

  • в нем не рассказывается о работе с пользователями, сессиями и правами доступа,
  • лишь вскользь рассматривается такая основополагающая часть фреймворка как ServiceManager,
  • в качестве интерфейса с базой данных безальтернативно используется паттерн Table Gateway (и соответствующая его реализация в фреймворке),
  • используется встроенный в фреймворк шаблонизатор, который после питоновского Jinja 2 кажется совершенно неудобным и примитивным,
  • и т.д.
  • в качестве шаблонизатора будет использоваться Twig,
  • для работы с БД — Doctrine ORM,
  • для авторизации/аутентификации и распределения прав доступа я буду использовать существующие модули ZfcUser и BjyAuthorize,
  • также я рассмотрю вопросы разработки собственных валидаторов форм, View плагинов и другие.
  • в первой (текущей) части я рассмотрю структуру ZendSkeletonApplication, разберу разработку собственного модуля (формы, работа с БД при помощи Doctrine ORM, разработка View-плагина), будет посвящена работе с пользователями и шаблонизатором Twig.

Окружение

Я предполагаю, что у вас уже есть настроенный веб-сервер (мой доступен по адресу zblog.kece.ru) и в MySQL создана пустая база данных под этот проект. Ввиду того, что для работы с БД я планирую использовать Doctrine, база данных может быть любой, поддерживаемой этой ORM.

Я предполагаю, что у вас под рукой есть исходный код ZendSkeletonApllication или моего туториала. Взять их можно тут: github.com/zendframework/ZendSkeletonApplication и тут: github.com/romka/zend-blog-example. Кроме того, я предполагаю, что вы понимаете паттерн MVC, имеете опыт работы с каким-либо шаблонизатором и валидатором форм.

Zend Framework использует замечательный менеджер зависимостей Composer, который также должен быть установлен в вашей системе. Подробнее о Композере можно прочитать вот в этой статье: habrahabr.ru/post/145946. Если говорить в двух словах, то Composer — это утилита командной строки, которая позволяет быстро и удобно скачать и установить внешние библиотеки, от которых зависит ваш PHP-проект. На входе утилита принимает JSON-файл в интуитивно понятном формате содержащий список имен и версий зависимостей, на выходе она скачивает и устанавливает нужные библиотеки и их зависимости освобождая вас от рутинной работы.

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

ZendSkeletonApplication

Используя Zend Framework вы можете с нуля спроектировать и создать структуру вашего приложения, но для изучения работы системы лучше воспользоваться заготовкой ZendSkeletonApplication. В случае если у вас настроен Composer достаточно выполнить команду:

(при должной настройке, команду php composer.phar можно заменить просто на composer, но далее в статье я буду приводить первый вариант как более универсальный)

После ее выполнения вы получите приложение со следующей структурой (я оставил только самые интересные директории и файлы):

Теперь вы можете открыть созданный проект. Моя версия доступна по адресу zblog.kece.ru.

Давайте детально разберем созданные директории и файлы.

Структура проекта

composer.json

Начнем с файла composer.json в корне проекта. Он имеет следующий вид:

В этом файле задаются параметры приложения, которые будут использоваться Композером. Самой интересной частью этого конфига является секция require, которая содержит список внешних библиотек, от которых зависит приложение. Сейчас в списке зависимостей есть только Zend Framework 2, но в будущем, мы добавим сюда еще несколько зависимостей: Доктрину, Твиг и другие. После добавления новой зависимости достаточно будет в консоли исполнить команду:

и Композер скачает необходимые библиотеки. Все внешние зависимости складываются в директорию vendor, сейчас мы в ней можем увидеть директории zendframework и composer.

Document root

Document_root нашего приложения находится не в корне проекта, а в директории public, именно здесь находится файл index.php — точка входа в наш проект и именно на работу с этой директорией должен быть настроен веб-сервер.

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

Для подключения внешних библиотек исполняется файл init_autoloader.php из корня проекта, который в свою очередь вызывает vendor/autoload.php и вслед за ним автоматически сгенерированный Композером файл vendor/composer/autoaload_real.php. В этом файле определены автолоад-методы для загруженных Композером внешних библиотек. Таким образом, когда мы в коде наших модулей будем подключать неймспейсы вида Zend\View\Model\ViewModel PHP будет знать в каких файлах искать указанные неймспейсы.

загружает конфигурационные файлы приложения и запускает его. В процессе инициализации приложения (вызов метода Zend\Mvc\Application::init()) создается ServiceManager — ключевой объект, использующийся во многих частях приложения. По умолчанию СервисМенеджер создает еще один ключевой объект — EventManager. В дальнейшем, когда мы будем создавать свои модули в их настройках мы будем сообщать СервисМенеджеру какие еще объекты необходимо создать для работы нашего модуля.

О СервисМенеджере мы еще поговорим позже, а сейчас давайте подробнее рассмотрим директорию config. В ней находится файл application.config.php, возвращающий массив с конфигурацией приложения, который может рассказать много интересного.

Массив modules содержит список включенных модулей. Сейчас у нас включен только один модуль Application, но в будущем их будет больше.

  • module_paths подсказывает где искать подключаемые модули, по умолчанию в директориях vendor — внешние зависимости, и module — здесь будут находиться модули разработанные нами для нашего проекта.
  • Config_glob_paths содержит маски путей к конфигурационным файлам модулей. Регулярное выражение 'config/autoload/.php' означает, что будут загружены все файлы вида module_name..php, global.php, local.php из директории config/autoload.

Если в config/autoload есть два файла настроек для одного и того же модуля: глобальный и локальный (module_name.global.php и module_name.local.php), то первым делом будет загружен глобальный файл, а за ним локальный, то есть локальные настройки имеют приоритет перед глобальными.

Файлы local.php и *.local.php по умолчанию включены в файл .gitignore (если вы используете другую систему контроля версий, то их нужно добавить в исключения вручную) и они должны использоваться только для настроек, соответствующих только текущему окружению. То есть, если у вас проект в том или ином виде запускается на нескольких разных площадках: production, тестовой и девелоперских площадках, то в глобальных настройках приложения нужно хранить данные, актуальные для всех перечисленных площадок, а в локальных — уникальные для каждой площадки, например, данные для доступа к БД.

Кроме глобальных для всего приложения конфигурационных файлов каждый из модулей может иметь свой файл настроек. Такие конфигурационные файлы модулей загружаются в том порядке, в котором определен список активных модулей в файле application.config.php. Таким образом, если вы хотите в своем модуле переопределить настройки другого модуля, то ваш модуль должен быть ниже в этом списке.

Последней важной и пока еще не рассмотренной директорией является директория modules. В этой директории будут находиться модули, разработанные нами для нашего приложения. Вместе с ZendSkeletonApplication поставляется один модуль Application, но прежде чем изучать его структуру, давайте разберемся с тем, что такое ServiceManager и зачем он нужен.

ServiceManager

В официальной документации (http://framework.zend.com/manual/2.2/en/modules/zend.service-manager.intro.html) сказано, что ServiceManager — это компонент, реализующий паттерн Service Locator, предназначенный для извлечения других объектов. Другими словами, это некоторая точка входа, которая позволяет из любого места приложения получить доступ к любым объектам, зарегистрированным в СервисМенеджере.

Регистрируются объекты в СервисМенеджере либо в кофигурационном файле module.config.php в секции service_manager, либо в Module.php в методе getServiceConfig(), выглядит это примерно так (пример скопирован из документации):

Имея приведенную выше конфигурацию СервисМенеджера в любом нашем контроллере теперь мы можем вызвать код вида:

и объект $user_form будет содержать соответствующую форму.

Теперь настало время вернуться к модулю Application, входящему в ZendSkeletonApplication.

Модуль Application

Дерево каталогов этого модуля выглядит так:

  1. onBootstrap();
  2. getConfig();
  3. getAutoloaderConfig().

Метод getAutoloaderConfig() сообщает ядру фреймворка где искать исходные коды модуля:

В текущем случае это директория modules/Application/src/Application.

В методе getConfig() возвращается путь к файлу настроек модуля:

  • элемент массива router — это массив содержащий список маршрутов, обслуживаемых модулем и список контроллеров, для каждого из маршрутов,
  • view_manager содержит пути к шаблонам, которые будут использоваться приложением и ряд дополнительных настроек шаблонизатора,
  • service_manager — список объектов, которые должны быть инициализированы СервисМенеджером,
  • ряд других настроек.

В настройках модуля Application определяется два маршрута:

  • За маршрут / (корень сайта, тип Literal) отвечает контроллер Application\Controller\Index.
  • за маршруты вида /application/[:controller[/:action]] (тип Segment) — контроллер и экшен переданные в качестве аргументов, то есть внутри модуля достаточно определить новые контроллеры и экшены и они тут же будут доступны по описанному адресу. Благодаря этому, маршрут / здесь идентичен маршруту /application/index/index.

Модуль Application содержит один единственный контроллер IndexController() с одним единственным экшеном indexAction(), который возвращает страничку с приветственным сообщением. Для отображения этой странички используются шаблоны, находящиеся в директории view модуля.

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

📎📎📎📎📎📎📎📎📎📎