На сайте Symfony Components про компонент RequestHandler сказано примерно следующее:
Так ли это и что из себя представляет RequestHandler в Symfony 2 я попробую рассмотреть в этом топике.
Если взглянуть на процесс обработки запроса в приложении на базе Symfony 2, а именно рассмотреть метод
Для начала заглянем в
Из этого описания становится ясно, что объект запроса создается просто
Заглянув в Symfony/Components/RequestHandler мы увидим следующий набор файлов:
Ну в общем все почти очевидно. Многое ясно даже не заглядывая внутрь классов. Но все же коротко обо всем. Классы исключений, которые используются при возникновении соответствующих ситуаций, все что в них делается, так это прописывается сообщение и код ответа.
Фактически все, что делает обработчик запроса это используя переданный ему в параметрах диспетчер событий (EventDispatcher) генерирует различные события, тем самым как бы оповещая приложения о различных этапах разбора запроса и формирования ответа. И в зависимости от реакции слушателей (listeners) на эти события завершает работу либо генерирует следующее событие.
Список событий, которые создает обработчик запросов:
То есть события отражают основные этапы разбора запроса и формирования ответа.
Лучше, наверное это все попробовать на примере. Что в общем я сейчас и сделаю. Итак, разденем Symfony до гола, убрав все кроме ядра и навесим свой обработчик на событие
Пример будет на базе sandbox с обновленной версией Symfony, как создавалось окружение можно увидеть вот здесь.
Итак, начнем с конфигов. В файле
Теперь, надо описать в DI контейнере необходимые параметры и сервисы, для этого сначала создадим свое расширение для DI контейнера, создаем директорию
теперь зарегистрируем наше расширение:
Наше расширение будет искать файл
так что надо создать этот файл, с примерно таким содержимым:
В этом файле мы определили сервис, который навешивается на прослушиваение события
Теперь создадим парсер запроса:
Теперь последний штрих, в конфиге
Это всё! Теперь обратившись по любому адресу мы получим ответ:

Совершенно бесполезное приложение получилось. Но на этом примере легко показать как оно работает, подцепляться можно и к другим событиям. Все очень гибко и удобно.
Гибкое микро-ядро для быстрых фреймворков.
Так ли это и что из себя представляет RequestHandler в Symfony 2 я попробую рассмотреть в этом топике.
Если взглянуть на процесс обработки запроса в приложении на базе Symfony 2, а именно рассмотреть метод
run() класса Symfony\Foundation\Kernel, то увидим что после формирования и сохранения в кеше либо загрузки из кеша DI контейнера, происходит получение из контейнера объекта обработчика запроса и вызов его метода handle() в параметрах, которому передается объект запроса, кстати также полученный из DI контейнера. Данный метод должен вернуть объект ответа у которого вызывается метод send() для отправки ответа. В общем первый удар при обработке запроса принимает на себя RequestHandler, он же возвращает объект ответа, поэтому я решил начать обзор компонентов входящих в состав Symfony 2 именно с него.Для начала заглянем в
Symfony/Foundation/Resources/services.xml так как именно здесь происходит описание сервиса RequestHandlerService в DI контейнере.<parameter key="request_handler.class">Symfony\Components\RequestHandler\RequestHandler</parameter> <parameter key="request.class">Symfony\components\RequestHandler\Response</parameter> ... <service id="request_handler" class="%request_handler.class%"> <argument type="service" id="event_dispatcher" /> </service> <service id="request" class="%request.class%" />
Из этого описания становится ясно, что объект запроса создается просто
new Request(), а объект обработчика запроса, как new RequestHandler($dispatcher), где $dispatcher объект класса EventDispatcher, представляющий собой диспетчер событий.Заглянув в Symfony/Components/RequestHandler мы увидим следующий набор файлов:
Exception/: директория с классами исключений
ForbiddenHttpException.php: исключение кидаемое при 403 ForbiddenHttpException.php: базовый класс для исключенийNotFoundHttpException.php: исключение кидаемое при 404 Not FoundUnauthorizedHttpException.php: исключение кидаемое при 401 Unauthorized
Request.php: класс запросаRequestInterface.php: интерфейс, который должен реализовать объект запросаResponse.php: класс ответаResponseInterface.php: интерфейс, который должен реализовать объект ответаRequestHandler.php: обработчик запроса
Ну в общем все почти очевидно. Многое ясно даже не заглядывая внутрь классов. Но все же коротко обо всем. Классы исключений, которые используются при возникновении соответствующих ситуаций, все что в них делается, так это прописывается сообщение и код ответа.
Request — класс запроса, который разбирает переменные окружения, параметры и все что связано с запросом. Response — класс ответа, который содержит в себе тело ответва, формирует заголовки и все связанное с ответом. RequestHandler — это обработчик запроса. Пожалуй рассмотрим его подробнее.Фактически все, что делает обработчик запроса это используя переданный ему в параметрах диспетчер событий (EventDispatcher) генерирует различные события, тем самым как бы оповещая приложения о различных этапах разбора запроса и формирования ответа. И в зависимости от реакции слушателей (listeners) на эти события завершает работу либо генерирует следующее событие.
Список событий, которые создает обработчик запросов:
core.requestcore.load_controllercore.controllercore.viewcore.responsecore.exception: в случае возникновения исключений
То есть события отражают основные этапы разбора запроса и формирования ответа.
RequestHandler проверяя реакцию приложения на события продолжает создавать события либо завершает работу. Соответственно приложение навешивая свои обработчики на те или иные события участвует в формировании ответа. При этом некоторые части приложения могут ничего не знать друг о друге.Лучше, наверное это все попробовать на примере. Что в общем я сейчас и сделаю. Итак, разденем Symfony до гола, убрав все кроме ядра и навесим свой обработчик на событие
core.request, заодно будет небольшая демонстрация гибкости фреймворка.Пример будет на базе sandbox с обновленной версией Symfony, как создавалось окружение можно увидеть вот здесь.
Итак, начнем с конфигов. В файле
hello/config/config.yml закоментируем все за исключением строки kernel.config: ~. Теперь поправим ядро приложения, файл hello/HelloKernel.php
# hello/HelloKernel.php
// убираем все бандлы, за исключения ядра и нашего приложения
public function registerBundles()
{
return array(
new Symfony\Foundation\Bundle\KernelBundle(),
new Application\HelloBundle\Bundle(),
);
}
Теперь, надо описать в DI контейнере необходимые параметры и сервисы, для этого сначала создадим свое расширение для DI контейнера, создаем директорию
src/Application/HelloBundle/DependencyInjection, а в ней файл HelloExtension.php со следующим содержимым:
namespace Application\HelloBundle\DependencyInjection;
use Symfony\Components\DependencyInjection\Loader\LoaderExtension,
Symfony\Components\DependencyInjection\Loader\XmlFileLoader,
Symfony\Components\DependencyInjection\BuilderConfiguration,
Symfony\Components\DependencyInjection\Reference,
Symfony\Components\DependencyInjection\Definition;
class HelloExtension extends LoaderExtension
{
public function helloLoad($config)
{
$configuration = new BuilderConfiguration();
$loader = new XmlFileLoader(__DIR__.'/../Resources/config');
$configuration->merge($loader->load('hello.xml'));
return $configuration;
}
public function getAlias()
{
return 'hello';
}
public function getNamespace()
{
return 'http://poulikov.ru/schema/dic/hello';
}
public function getXsdValidationBasePath()
{
return __DIR__.'/../Resources/config/';
}
}
теперь зарегистрируем наше расширение:
# src/Application/HelloBundle/Bundle.php
// используем наше расширение
use Application\HelloBundle\DependencyInjection\HelloExtension;
...
// зарегистрируем расширение в контейнере
public function buildContainer(ContainerInterface $container)
{
Loader::registerExtension(new HelloExtension());
}
Наше расширение будет искать файл
hello.xml по пути src/Application/HelloBundle/Resources/config/hello.xmlтак что надо создать этот файл, с примерно таким содержимым:
<container xmlns="http://www.symfony-project.org/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="request_parser.class">Application\HelloBundle\Request\Parser</parameter>
</parameters>
<services>
<service id="request_parser" class="%request_parser.class%">
<annotation name="kernel.listener" event="core.request" method="resolve" />
<argument type="service" id="service_container" />
</service>
</services>
</container>
В этом файле мы определили сервис, который навешивается на прослушиваение события
core.requestТеперь создадим парсер запроса:
# src/Application/HelloBundle/Request/Parser.php
namespace Application\HelloBundle\Request;
use Symfony\Components\DependencyInjection\ContainerInterface;
use Symfony\Components\EventDispatcher\Event;
use Symfony\Components\Routing\RouterInterface;
class Parser
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function register()
{
$this->container->getEventDispatcherService()->connect('core.request', array($this, 'resolve'));
}
public function resolve(Event $event)
{
$response = $this->container->getResponseService();
$response->setContent("<div>Hello, World! I'm Symfony 2.0 lite</div>");
$event->setReturnValue($response);
$event->setProcessed(true);
}
}
Теперь последний штрих, в конфиге
hello/config/config.yml добавим строчку hello.hello: ~Это всё! Теперь обратившись по любому адресу мы получим ответ:

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