Почему / как это работает: Symfony 2.8 + FOSRestBundle автоматически десериализует объект запроса - PullRequest
0 голосов
/ 15 января 2019

Я работаю над переносом существующего Symfony 2.8, которое я не создал. Предыдущие разработчики не доступны для вопросов.

Большую часть кода легко понять, но в какой-то момент я просто не могу понять, почему это работает:

Параметр контроллера / действия автоматически десериализуется из данных JSON в пользовательский объект. В этом нет ничего особенного, я не понимаю, как / где Symfony сказали, что делать. С моей точки зрения, важные данные конфигурации отсутствуют, но они все равно работают.

Это было бы хорошо, но не понимая, почему это работает в этом случае, я не могу понять, почему он больше не работает при переносе проекта в Symfony 3.4 ...

Извините за (очень) длинный вопрос, но я пробовал разные способы решить проблему и ответить на вопросы, но все они привели к различным проблемам ...

Использование следующих комплектов

sensio/framework-extra-bundle       v3.0.29
friendsofsymfony/rest-bundle        2.4.0
jms/serializer                      1.13.0 
jms/serializer-bundle               1.5.0 

Config:

// app/config/config.yml
sensio_framework_extra:
    request: { converters: true }

fos_rest:
    ...
    body_converter:
        enabled: true

#jms_serializer:  (not configured)
#    ...

Код:

// src/AppBundle/Util/SortInfo.php
class SortInfo {
    public $sortOrder;
    public $sortBy;
}


// src/AppBundle/Resources/serializer/Util.SortInfo.yml
AppBundle\Util\SortInfo:
    exclusion_policy: ALL
    properties:
        sortOrder:
            type: string
            expose: true
        sortBy:
            type: string
            expose: true

// src/AppBundle/Controller/SortingController.php
class SortingController extends Controller {
    ...

    /**
     * @FOSRest\View()
     */
    public function sortAction(SortInfo $sortInfo) {
        $this->logger->info("sortAction");
        $this->logger->info("   ".gettype($sortInfo)."  --  ".get_class($sortInfo));
        $this->logger->info("   ".$sortInfo->sortOrder."  --  ".$sortInfo->sortBy);

        ...
    }     
}

Вот и все. После копания в течение нескольких часов я не смог найти какой-либо явной конфигурации, которая сообщала бы методу sortAction для автоматического преобразования данных JSON из запроса. Но это работает.

Запрос со следующим содержанием JSON приводит к следующему выводу журнала:

// JSON content
{"sortOrder":"ASC", "sortBy":"name"}

// Log output
sortAction
    object  --  AppBundle\Util\SortInfo
    ASC  --  name

Почему это работает?

Как уже было сказано, это нормально, но проблема в том, что тот же код не работает с Symfony 3.4 и более новыми версиями FOSRest, ExtrasBundle и JMSSerializer:

sensio/framework-extra-bundle       v5.2.4
friendsofsymfony/rest-bundle        2.5.0
jms/serializer                      2.1.0
jms/serializer-bundle               3.0.0 

Запрос с теми же данными JSON приводит к следующему выводу журнала в `Symfony 3.4 ':

// Log output
sortAction
    object  --  AppBundle\Util\SortInfo
      --  

Таким образом, хотя SortInfo создан (не ноль), свойства sortBy и sortOrder являются пустыми / нулевыми.

Как это может быть? Я не понимаю, почему данные десериализованы в первую очередь, но как можно создать объект SortInfo без установки свойств, еще более загадочно.

В Symfony 2.8 для процесса необходим файл Util.SortInfo.yml. Удаление этих файлов приводит к исключению:

Symfony \ Component \ HttpKernel \ Exception \ BadRequestHttpException: "Вы должен определить тип для AppBundle \ Util \ SortInfo :: $ SortBy. "

at /.../vendor/friendsofsymfony/rest-bundle/Request/RequestBodyParamConverter.php

Здесь я не понимаю, почему SortInfo::$sortBy проблема, а не SortInfo сама по себе. Кроме того, удаление файла в Symfony 3.4 ничего не меняет.

Но по крайней мере это сообщение об ошибке подтверждает, что FOS RequestBodyParamConverter участвует в процессе.

В соответствии с Symfony docs необходимо вручную указать параметр, который должен быть преобразован (хотя он прекрасно работает без этой конфигурации в Symfony 2.8):

/**
 * @FOSRest\View()
 * @ParamConverter("sortInfo", converter="fos_rest.request_body")
 */
public function sortAction(SortInfo $sortInfo) {
    ...
}

Однако добавление этой конфигурации приводит к другой ошибке в Symfony 3.4:

Uncaught PHP Exception RuntimeException: «Конвертер 'fos_rest.request_body' не поддерживает преобразование параметра '$ SortInfo'

Итог:

  • Это все очень загадочно.
  • Почему он работает без проблем в Symfony 2.8, хотя в отношении документации отсутствует необходимая конфигурация (явно укажите ParamConverter)
  • Почему это не работает в Symfony 3.4?
...