Итак, продолжаю осмотр фреймворка Symfony 2.0. В первой части я описал содержимое приложения symfony-sandbox созданного на базе Symfony 2.0. В этой части я загляну в содержимое самого фреймворка.
Перейдя в директорию
В первой части я писал, что сам фреймворк — это набор «бандлов» в этом легко убедиться заглянув в директорию
WebBundle пожалуй самый большой «бандл» из доступных на данный момент. Здесь и Controller от которого наследуется контроллер приложения, и класс User и сессии и templating и util и skeleton для приложения и для «бандла». В общем интересно в него заглянуть, но не в этот раз.
Содержимое
Ну и содержимое
Итак, если кратко, то работает это примерно так: при обращении к фронт контроллеру
После этого вызывается метод
Каждый «бандл» должен иметь класс реализующий интерфейс
Для примера как можно использовать метод
где класс
Во всем этом обзоре, я практически не затронул работу из консоли. Внешне все осталось почти так же, за тем исключением, что теперь консольный контроллер создается на уровне приложения, а не на уровне всего проекта, как это было в Symfony 1.x. Но внутри произошли серьезные перемены, появились дополнительные возможности, подробнее с которыми можно познакомиться изучая
Вот в общем и завершился краткий обзор Symfony 2.0. Фреймворк конечно еще сырой, в некоторых ситуациях возникают неожиданные ошибки, некоторых вещей еще нет. Но разработчики фреймворка призывают попробовать и высказать свои пожелания, мнения ну и баг-репорты конечно тоже. Так что велкам!
Ну а я попробую сделать краткие обзоры о Symfony/Components.
Перейдя в директорию
src/vendor/symfony/src/Symfony
приложения, увидим три директории:- Components
- Foundation
- Framework
В первой части я писал, что сам фреймворк — это набор «бандлов» в этом легко убедиться заглянув в директорию
Framework
, в которой находятся:Framework/DoctrineBundle
: это Doctrine ORMFramework/ProfilerBundle
: это друг разработчика — toolbarFramework/SwiftmailerBundle
: Swift mailerFramework/WebBundle
: web, templating, userFramework/ZendBundle
: Zend library, сейчас используется Zend_Log
WebBundle пожалуй самый большой «бандл» из доступных на данный момент. Здесь и Controller от которого наследуется контроллер приложения, и класс User и сессии и templating и util и skeleton для приложения и для «бандла». В общем интересно в него заглянуть, но не в этот раз.
Содержимое
Foundation
похоже на базовую библиотеку кода, т.е. здесь содержится код, позволяющий всему этому чуду работать как надо. В частности базовый класс ядра, «бандл» ядра, EventDispatcher, универсальный автозагрузчик классов, абстрактный класс Bundle реализующий интерфейс BundleInterface, от которого неследуются все «бандлы».Ну и содержимое
Components
— это те самые компоненты, но написанные в стиле PHP 5.3. На данный момент доступны:- Components/Console
- DependencyInjectionContainer
- EventDispatcher
- OutputEscaper
- RequestHandler
- Routing
- Templating
- Yaml
Итак, если кратко, то работает это примерно так: при обращении к фронт контроллеру
web/index.php
создается экземпляр класса ядра приложения в нашем случае HelloKernel
, который расширяет класс Symfony\Foundation\Kernel
. При создании объекта в конструктор класса передаются два параметра название окружения и флаг включения отладки true или false. В конструторе класса вызываются методы регистрации «бандлов», регистрации путей поиска «бандлов», регистрации корневой директории приложения и определяется имя самого приложения. После чего во фронт контроллере вызывается метод run()
в котором и происходит основная работа. И опять же если кратко, то основная работа выглядит так: выполняется метод boot()
в котором инициализируется DI контейнер (Dependency Injection Container), при инициализации вызываются методы построения контейнера всех подключенных «бандлов». После этого вызывается метод загрузки настроек приложения. Затем весь этот построенный и сформированный контейнер записывается в кеш в виде класса, чтобы не строить его при каждом запросе, подключается файл из кеша и создается экземпляр этого сформированного класса контейнера.После этого вызывается метод
boot()
всех подключенных «бандлов». Затем из контейнера вытаскивается объект запроса, по дефолту это объект класса Symfony\Components\RequestHandler\Request
. А затем из контейнера вытаскивается объект обработчика запроса, по дефолту это объект класса Symfony\Components\RequestHandler\RequestHandler
, у которого вызывается метод handle()
и в качестве параметра ему передается уже полученный объект запроса. Метод handle()
должен вернуть объект ответа Symfony\Components\RequestHandler\Response
у которого в свою очередь вызывается метод send()
, который отвечает за отправку ответа (заголовков и тела). Вот если коротко и грубо, то этим и ограничивается работа ядра. Все остальное лежит на плечах «бандлов».Каждый «бандл» должен иметь класс реализующий интерфейс
Symfony\Foundation\BundleInterface
в котором определено всего два метода buildContainer(ContainerInterface $container)
регистрирующий в контейнере параметры и сервисы и boot(ContainerInterface $container)
который отвечает за загрузку «бандла», загрузка осуществляется уже после того как все параметры и сервисы всех «бандлов» определены в DI контейнере. Большинство «бандлов», а именно все «бандлы» из Symfony/Framework
расширяют класс Symfony\Foundation\Bundle
и перекрывают лишь метод builderContainer
для определения в контейнере своих настроек и сервисов.Для примера как можно использовать метод
boot()
класса Bundle
. По дефолту в «бандле» WebBundle используется шаблонный движок на базе Symfony\Components\Templating
. Но сервис templating.engine
в WebBundle определен таким образом, что не позволяет передать в конструктор свои классы Renderer'а, в то время как Symfony\Components\Templating\Engine
в конструкторе вторым параметром принимает массив кастомных Renderer'ов. Но благодаря использованию Dependency Injection Container это легкое недоразумение легко исправляется. Для этого в нашем приложении в файле src/Application/HelloBundle/Bundle.php
в классе Bundle
определим метод:public function boot(ContainerInterface $container) { $container->getTemplatingService()->setRenderer('name', new Renderer()); }
где класс
Renderer
— наш кастомный рендерер, а 'name'
имя этого рендерера. Теперь при отображении шаблонов можно использовать свой собственный рендерер.Во всем этом обзоре, я практически не затронул работу из консоли. Внешне все осталось почти так же, за тем исключением, что теперь консольный контроллер создается на уровне приложения, а не на уровне всего проекта, как это было в Symfony 1.x. Но внутри произошли серьезные перемены, появились дополнительные возможности, подробнее с которыми можно познакомиться изучая
Components/Console
. Появилась и еще одна интересная возможность — Symfony shell. Достаточно запустить hello/console -s
и запустится интерактивный консольный сеанс, проще говоря Symfony shell позволяющий выполнять теже самые команды.Вот в общем и завершился краткий обзор Symfony 2.0. Фреймворк конечно еще сырой, в некоторых ситуациях возникают неожиданные ошибки, некоторых вещей еще нет. Но разработчики фреймворка призывают попробовать и высказать свои пожелания, мнения ну и баг-репорты конечно тоже. Так что велкам!
Ну а я попробую сделать краткие обзоры о Symfony/Components.