Я создаю API с помощью Symfony 4 и FOSRestBundle. У меня довольно простые отношения:
Сущность: User.php
/**
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @JMS\Groups({"onlyId"})
*/
private $id;
/**
* @ORM\Column(unique=true, type="string", length=255)
*/
private $email;
//...
/**
* @ORM\OneToMany(targetEntity="App\Entity\UserProduct", mappedBy="user", orphanRemoval=true)
*/
private $userProducts;
Сущность: UserProduct.php
/**
* @ORM\Entity(repositoryClass="App\Repository\UserProductRepository")
*/
class UserProduct
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @JMS\Groups({"onlyId"})
*/
private $id;
//...
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="userProducts")
* @JMS\Groups({"onlyId"})
*/
private $user;
Конфигурация: fos_rest.yaml
fos_rest:
body_converter:
enabled: true
view:
view_response_listener: 'force'
formats:
json: true
routing_loader:
default_format: json
# param_fetcher_listener: true
# allowed_methods_listener: true
# routing_loader: true
# view:
# view_response_listener: true
# exception:
# codes:
# App\Exception\MyException: 403
# messages:
# App\Exception\MyException: Forbidden area.
format_listener:
rules:
- { path: ^/api, prefer_extension: true, fallback_format: json, priorities: [ json, html ] }
- { path: ^/login_check, stop: true }
- { path: ^/register, stop: true }
Сначала я не мог POST UserProduct отправлять JSON в конечную точку, когда я отправлял идентификатор пользователя вместе с данными JSON, поскольку он выдавал, что он ожидает экземпляр entity
, а не integer
или что-то еще, что я отправлял . Я понял это с помощью этого руководства -> https://medium.com/@maartendeboer/using-the-symfony-serializer-with-doctrine-relations-69ecb17e6ebd
он использует сериализатор Symfony. Я получил circular reference
ошибку при возврате View
из FOSRestBundle. На этом этапе я знал, что circular reference
ошибки отлично обрабатываются с помощью инструмента JMS Serializer, и использовал его внутри своего postUserProductAction
контроллера:
Чтобы отправить продукт и обработать circular reference
, я использую этот контроллер (десериализация отправленного JSON с помощью специального письменного метода десериализации из руководства, его ввод в базу данных и затем возвращение ответа ( not View) с помощью сериализатора JMS и его групп):
class UserProductController extends FOSRestController
{
/**
* @Rest\Route("/api/product", name="userProduct")
*
*
* @Method("POST")
*
* @param Request $request
* @param SerializerInterface $serializer
* @return Response
* @throws \InvalidArgumentException
*/
public function postUserProductAction(Request $request, SerializerInterface $serializer): View
{
$userProduct = $serializer->deserialize($request->getContent(), UserProduct::class, 'json');
dump($userProduct);
$em = $this->getDoctrine()->getManager();
$em->persist($userProduct);
$em->flush();
$userProduct = $this->JMSSerializeWithGroups($userProduct,array('onlyId'));
return new View($userProduct, Response::HTTP_OK);
}
}
/**
* @param $entity
* @param array $groupArray
* @return mixed|string
*/
public function JMSSerializeWithGroups($entity, Array $groupArray)
{
$JMSserializer = SerializerBuilder::create()->build();
$entity = $JMSserializer->serialize( $entity, 'json', SerializationContext::create()->setGroups($groupArray));
return $entity;
}
Ответ, который я получаю, ясен и ясен:
{
"id": 100,
"user": {
"id": 9
}
}
Но вроде бы много лишних шагов. Кроме того, если я выберу этот подход, мне нужно будет добавить сериализацию JMS самостоятельно к каждому из моих контроллеров (GET, PUT и т. Д.).
Итак, мой вопрос: почему FOSRestBundle не использует JMS по умолчанию для рендеринга View
, как сказано в документации (если он установлен и зарегистрирован)? Должен ли я добавить его где-нибудь дополнительно, чтобы FOSRestBundle распознал его? И, может быть, если бы это было так, мне вообще не нужно было бы использовать Symfony Serializer? Я думаю, что могу потеряться во всех обновлениях Symfony 4.
Спасибо!