Pull to refresh

Обработка POST запросов AngularJs в Symfony2

PHP *Symfony *Angular *
Translation
Tutorial
Original author: Sander aka Othillo
Примечание
Давненько уже читал пост на хабре, о сабже в контексте php, и все руки не доходили на Symfony2 привести это в какой-то красивый вид, а тут в недавнем дайджесте наткнулся на простое решение, которое здесь и представлено.


Использование Symfony2 и AngularJs в связке является хорошей идеей, но есть одна проблема — решение из коробки обладает проблемой в коммуникации. В этом посте будет рассказано о том, как автоматически декодировать JSON-запросы и использовать полученные данные при помощи Request Symfony используя библиотеку symfony-json-request-transformer (на самом деле всего-то один класс).

Идея

$http-сервис AngularJs автоматически отправляет данные с заголовком Content-Type: application/json в POST запросе, а Symfony в свою очередь ожидает application/x-www-form-urlencoded.

Для примера, отправим из нашего angular-приложения простой JSON-объект:
{
     "name": "John"
}

Теперь в контроллере получим эти данные:
public function postAction(Request $request)
{
    $data = json_decode($request->getContent(), true);
    echo $data['name']; // John
}

Довольно просто, верно? Но, к сожалению, мы не можем использовать ParameterBag интерфейс в объекте Request в данном случае.
Если name опционален и имеет значение по-умолчанию, хотелось бы получать данные вот так:
$name = $request->request->get('name', 'Ivan');

К счастью, используя метод replace мы можем заменить данные в ParameterBag на наш декодированный JSON.
public function postAction(Request $request)
{
    $data = json_decode($request->getContent(), true);
    $request->request->replace($data);

    echo $request->request->get('name', 'Ivan'); // John
}

Отлично, работает так, как нам хотелось. Но, ведь это только один контроллер…

Реализация

imageНо копирование кода в каждый контроллер нарушает DRY принцип, делая код мокрым (игра слов аббревиатур DRY и WET). Что если я скажу, что можно обрабатывать каждый JSON-запрос, совершенно не заботясь об этом? Используя обработчик событий, помеченный как kernel.event_listener, он:
  1. Проверит запрос на наличие заголовка Content-Type: application/json
  2. Если это так — декодирует его
  3. Заполнит объект Request::$request
  4. Вернет код ошибки HTTP 400 Bad Request, если что-то пошло не так


Можете увидеть полный код на Github.

Зарегистрировать обработчик события очень просто, просто определив новый сервис:
<service id="kernel.event_listener.json_request_transformer" class="Qandidate\Common\Symfony\HttpKernel\EventListener\JsonRequestTransformerListener">
    <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="100" />
</service>

Выход через сувенирную лавку

Чтобы показать приведенный код в действии, было создано демо-приложение, его код также на Github. На этом все, спасибо за внимание.
Tags:
Hubs:
Total votes 21: ↑17 and ↓4 +13
Views 17K
Comments 14
Comments Comments 14