dac*_*una 12 json symfony doctrine-orm deserialization
我正在尝试使用symfony序列化程序组件对具有关系的实体进行反序列化.这是我的实体:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Document
*
* @ORM\Table(name="document")
* @ORM\Entity(repositoryClass="AppBundle\Repository\DocumentRepository")
*/
class Document
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Genre", inversedBy="documents")
* @ORM\JoinColumn(name="id_genre", referencedColumnName="id")
*/
private $genre;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=100)
*/
private $name;
//getters and setters down here
...
}
Run Code Online (Sandbox Code Playgroud)
和类型实体:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Genre
*
* @ORM\Table(name="genre")
* @ORM\Entity(repositoryClass="AppBundle\Repository\GenreRepository")
*/
class Genre
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=50, nullable=true)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity="Document", mappedBy="genre")
*/
private $documents;
public function __construct()
{
$this->documents= new ArrayCollection();
}
//getters and setters down here
....
}
Run Code Online (Sandbox Code Playgroud)
在我的控制器动作中,我正在尝试这个:
$encoders = array(new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$document = $serializer->deserialize($request->getContent(), 'AppBundle\Entity\Document', 'json');
Run Code Online (Sandbox Code Playgroud)
我的json数据:
{"name": "My document", "genre": {"id": 1, "name": "My genre"}}
Run Code Online (Sandbox Code Playgroud)
但我得到了下一个错误:
给出的类型为"AppBundle\Entity\Genre","数组"的预期参数(500内部服务器错误)
是否可以使用内部关系的实体反序列化json请求?
谢谢你的推荐.
是的,不是.首先,您不应该在控制器中重新创建序列化程序的新实例,而是使用该serializer服务.
其次,不能用Symfony序列化器开箱即用.我们是在https://api-platform.com/中进行的,但那里有一些魔力.也就是说,已经制定了PR来支持它:https://github.com/symfony/symfony/pull/19277
小智 5
对于在 18 年从事此工作的任何人。我已经设法使用两种不同的方法来完成这项工作。
我正在使用的关联实体。
class Category
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", name="name", length=45, unique=true)
*/
private $name;
}
class Item
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", name="uuid", length=36, unique=true)
*/
private $uuid;
/**
* @ORM\Column(type="string", name="name", length=100)
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Category", fetch="EAGER")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=false)
*/
private $category;
}
Run Code Online (Sandbox Code Playgroud)
方法一:使用表单类
#ItemType.php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use App\Entity\Category;
use App\Entity\Item;
class ItemType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('category', EntityType::class, [
'class' => Category::class,
'choice_label' => 'name',
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Item::class,
));
}
}
#ItemController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
use App\Entity\Item;
use App\Form\ItemType;
class ItemController extends BaseEntityController
{
protected $entityClass = Item::class;
/**
* @Route("/items", methods="POST")
*/
public function createAction(Request $request)
{
$data = $request->getContent();
$item = new Item();
$form = $this->createForm(ItemType::class, $item);
$decoded = $this->get('serializer')->decode($data, 'json');
$form->submit($decoded);
$object = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($object);
$entityManager->flush();
return $this->generateDataResponse("response text", 201);
}
}
Run Code Online (Sandbox Code Playgroud)
方法 2:自定义规范器
需要启用 PropertyInfo 组件。
#/config/packages/framework.yaml
framework:
property_info:
enabled: true
Run Code Online (Sandbox Code Playgroud)
注册自定义规范器。
#/config/services.yaml
services:
entity_normalizer:
class: App\SupportClasses\EntityNormalizer
public: false
autowire: true
autoconfigure: true
tags: [serializer.normalizer]
Run Code Online (Sandbox Code Playgroud)
自定义规范器。
#EntityNormalizer.php
namespace App\SupportClasses;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
class EntityNormalizer extends ObjectNormalizer
{
protected $entityManager;
public function __construct(
EntityManagerInterface $entityManager,
?ClassMetadataFactoryInterface $classMetadataFactory = null,
?NameConverterInterface $nameConverter = null,
?PropertyAccessorInterface $propertyAccessor = null,
?PropertyTypeExtractorInterface $propertyTypeExtractor = null
) {
$this->entityManager = $entityManager;
parent::__construct($classMetadataFactory, $nameConverter, $propertyAccessor, $propertyTypeExtractor);
}
public function supportsDenormalization($data, $type, $format = null)
{
return (strpos($type, 'App\\Entity\\') === 0) &&
(is_numeric($data) || is_string($data) || (is_array($data) && isset($data['id'])));
}
public function denormalize($data, $class, $format = null, array $context = [])
{
return $this->entityManager->find($class, $data);
}
}
Run Code Online (Sandbox Code Playgroud)
我们的控制器的创建操作。
#ItemController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
use App\Entity\Item;
use App\Form\ItemType;
class ItemController extends BaseEntityController
{
protected $entityClass = Item::class;
/**
* @Route("/items", methods="POST")
*/
public function createAction(Request $request)
{
$data = $request->getContent();
$object = $this->get('serializer')->deserialize($data, $this->entityClass, 'json');
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($object);
$entityManager->flush();
return $this->generateDataResponse('response text', 201);
}
}
Run Code Online (Sandbox Code Playgroud)
这对我有用。我的灵感来自:https : //medium.com/@maartendeboer/using-the-symfony-serializer-with-doctrine-relations-69ecb17e6ebd
我修改了规范化器,以允许我将类别作为子 json 对象发送,当从 json 解码数据时,该对象将转换为子数组。希望这有助于某人。