Symfony 2.0 краткий обзор

:

Symfony 2 претерпел серьезные изменения в сравнении с 1.x веткой. Фреймворк стал более гибким и быстрым. Теперь, по заявлениям разработчиков — это один из самых быстрых фреймворков написанных на PHP, на цифры можно посмотреть тут. Однако не стоит воспринимать эти заявления близко к сердцу, что действительно важно — он стал быстрее и гибче.

На данный момент Symfony 2 еще находится в разработке и не готов к использованию в production. Но попробовать в целях изучения, его уже можно. Ознакомление я хочу начать с обзора приложения базирующегося на фреймворке. Исходники Symfony 2 на github. Там же на github есть готовое приложение sandbox построенное на Symfony 2.0, но в нем версия Symfony несколько отличается от последней. Поэтому после получения исходников sandbox, первым делом я заменил версию Symfony в src/vendor/symfony на последнюю.
git clone git://github.com/symfony/symfony-sandbox.git sandbox
cd sandbox/src/vendor
rm -rf symfony
git clone git://github.com/symfony/symfony symfony

Итак, первым, что бросается в глаза — структура директорий приложения совершенно другая. А именно есть три директории: hello, src, web.

  • hello/: директория названная в честь приложения и содержащая конфигурационные файлы.
  • src/: весь PHP код хранится здесь.
  • web/: корневая директория веб сервера.

Корневая директория веб сервера содержит все доступные из веб файлы, такие как изображения, таблицы стилей, javascript. Также здесь находятся фронт контроллеры index.php — для production окружения и index_dev.php — для development окружения. В общем, все как и раньше, за одним исключением, здесь появился полезный скрипт check.php позволяющий проверить окружение на соответствие системным требованиям Symfony 2.0.
результате check.php

Фронт контроллер подключает класс ядра приложения, создает экземпляр класса, определяя окружение и запускает приложение вызывая метод run.

В директории приложения hello/ содержится класс ядра приложения, который расширяет абстрактный класс Symfony\Foundation\Kernel и производит основные определения. В частности здесь определяется корневая директория приложения, регистрируются «бандлы» (то из чего теперь состоит Symfony и приложения построенные на нем), регистрируются пути по которым следует искать «бандлы», создается Dependency Injection Container и регистрируются правила маршрутизации (routing). Методы создающие IOC контейнер и определяющий правила маршрутизации в реализации по умолчанию загружают конфигурационные файлы из директории приложения hello/. Здесь же в классе ядра подключаются два важных файла src/autoload.php и src/vendor/symfony/src/Symfony/Foundation/bootstrap.php необходимые для правильной работы ядра, в частности в autoload.php создается экземпляр класса Symfony\Foundation\UnversalClassLoader и настраиваются пути для авто-загрузки файлов с классами. Пути задаются двумя методами registerNamespaces — позволяющим задать пути для поиска классов по их пространствам имен (namespace) и registerPrefixes — позволяющим задать пути поиска файлов по префиксам классов, например Swift_, Zend_ т.е. для классов написанных в стиле PHP версии ниже 5.3

В этой же директории находится файл hello/console — аналог файла symfony в Symfony 1.x, т.е. инструмент позволяющий выполнять различные команды из консоли.
Здесь же находятся директории:

  • hello/cache: для кеша
  • hello/logs: для логов
  • hello/config: для конфигурационных файлов

В директории исходных кодов src/ находятся уже упомянутый выше файл src/autoload.php и директории:
  • src/Application: содержит «бандлы» нашего веб приложения, в данном случае HelloBundle
  • src/Bundle: содержит сторонние, либо расшариваемые между несколькими приложениями «бандлы», в нашем случае здесь ничего нет
  • src/vendor: содержит исходный код сторонних библиотек, в нашем случае содержит doctrine, swiftmailer, symfony, zend

В HelloBundle содержатся:
  • класс «бандла» Bundle расширяющий класс Symfony\Foundation\Bundle\Bundle, который в свою очередь реализует интерфейс Symfony\Foundation\Bundle\BundleInterface
  • HelloBundle/Controller/HelloController.php: контроллер приложения
  • HelloBundle/Resources: ресурсы «бандла» в том числе шаблоны

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

Рассмотрев структуру директорий приложения можно попробовать выяснить где же скрывается обещанная гибкость и что конкретно можно поменять. Ну, если честно, сама структура директорий — это первое, что мы можем менять по своему усмотрению. В Symfony 1.x была директория apps/ содержащая различные приложения использующие общий код. В нашем случае этой директории нет, но разные приложения можно создавать и делать это можно удобным для нас способом. Например можно создать директории приложения на одном уровне с src/ и web/, т.е. как сделано в нашем случае с приложением hello. Мы можем добавить еще одно приложение, например bye. Либо мы можем просто добавить класс нового приложения ByeKernel в директорию hello/ прописав в нем корневую директорию приложения. Кстати, никто не запрещает создать директорию apps/ в которой размещать приложения. В общем, в плане структуры директорий, все очень гибко.

Следующее интересное место — «бандлы» (bundles). «Бандл» — это «first-class citizens» в Symfony, это структурированный набор файлов реализующих определенную функциональность и который легко может быть использован другими разработчиками в других приложениях. Это не совсем тоже самое, что и плагины в Symfony 1.x, как я сказал выше. Ближайшая аналогия, которую я для себя нашел — это «application» в Django. В Symfony 2 все состоит из «бандлов», сам фреймворк — это набор «бандлов», приложение, которое вы разрабатываете также является «бандлом», либо набором «бандлов». Это позволяет гибко настраивать приложения и подключать функциональность упакованную в «бандлы», также это дает возможность распространять код упаковывая его в «бандл».

Например в приложении sandbox, которое я взял с github, если заглянуть в класс ядра, то можно увидеть какие «бандлы» используются и это будут:

  • Symfony\Foundation\Bundle\KernelBundle
  • Symfony\Framework\WebBundle\Bundle
  • Symfony\Framework\ZendBundle\Bundle
  • Symfony\Framework\SwiftmailerBundle\Bundle
  • Symfony\Framework\DoctrineBundle\Bundle
  • Application\HelloBundle\Bundle

Исходя из того, что все что делает приложение — это печатает Hello и имя переданное в параметрах, можно смело отключить DoctrineBundle, SwiftmailerBundle.

Каждый «бандл» можно кастомизировать используя конфигурационные файлы. Конфиги приложения находятся в директории hello/config/. В частности там есть:

  • hello/config/config.yml: общие настройки
  • hello/config/config_dev.yml: настройки для dev окружения
  • hello/config/config_prod.yml: настройки для prod окружения
  • hello/config/routing.yml: правила маршрутизации

Интересно, что файлы config_dev.yml и config_prod.yml подключают файл config.yml иcпользуя инструкцию imports это очень удобно. Если открыть файл config.yml, то в нем есть настройки для подключаемых «бандлов».
#hello/config/config.yml
kernel.config: ~
web.web: ~
web.templating: ~

Каждое вхождение, вроде kernel.config определяет настройки для «бандла». Некоторые «бандлы» могут иметь несколько вхождений, как например WebBundle, который имеет два вхождения web.web и web.templating
Для каждого окружения можно перекрывать настройки «бандлов», например как это сделано в config_dev.yml:
# hello/config/config_dev.yml
imports:
  - { resource: config.yml }
web.debug:
  exception: %kernel.debug%
  toolbar: %kernel.debug%

zend.logger:
  priority: info
  path: %kernel.root_dir%/logs/%kernel.environment%.log

Итак, подводя итог обзора приложения, можно выделить следующие интересные моменты. Фреймворк базируется на идее микро-ядра с подключаемыми «бандлами». Связывается это все используя Dependency Injection Container. В результате можно добавлять/удалять функциональность в приложении за счет подключения/отключения «бандлов», которые также можно кастомизировать используя конфигурационные Yaml или XML файлы. Можно отключать либо заменять части самого фреймворка путем отключения или замены «бандлов».
Теперь можно кратко ознакомиться с содержимым самого фреймворка, что я сделаю в следующей части.