我有一个问题/请求有关标准Symfony 4.2环境中JSON的避免化的想法。
想想以下两个实体 POST 和作者。每个 post 完全具有 1作者(单向多个协会)。
发布实体
/**
* @ORMEntity()
*/
class Post
{
/**
* @var int
*
* @ORMId
* @ORMColumn(type="integer", options={"unsigned": true})
* @ORMGeneratedValue
*/
private $id;
/**
* @var string
*
* @ORMColumn(type="text", length=50)
*/
private $text;
/**
* @var Author
*
* @ORMManyToOne(targetEntity="Author", fetch="EAGER")
*/
private $author;
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @return string
*/
public function getText(): string
{
return $this->text;
}
/**
* @param string $text
*/
public function setText(string $text): void
{
$this->text = $text;
}
/**
* @return Author
*/
public function getAuthor(): Author
{
return $this->author;
}
/**
* @param Author $author
*/
public function setAuthor(Author $author): void
{
$this->author = $author;
}
}
作者实体
/**
* @ORMEntity()
*/
class Author
{
/**
* @var int
*
* @ORMId
* @ORMColumn(type="integer", options={"unsigned": true})
* @ORMGeneratedValue
*/
private $id;
/**
* @var string
*
* @ORMColumn(type="text", length=50)
*/
private $name;
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
}
现在,让我们创建一个简单的控制器,它允许 get 和 post preast:
class SimpleController extends AbstractController
{
/**
* @Route("/fapi/post/{id}", methods={"GET", "HEAD"})
* @param int $id
*
* @return Response
*/
public function getEntityAction($id)
{
$em = $this->getDoctrine()->getManager();
$post = $em->getRepository(Post::class)->find($id);
$encoders = array(new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$serializedPost = $serializer->serialize($post, 'json');
return new Response($serializedPost);
}
/**
* @Route("/fapi/post", methods={"POST"})
*
* @param Request $request
*
* @return Response
*/
public function postEntityAction(Request $request)
{
$data = $request->getContent();
$encoders = array(new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$post = $serializer->deserialize($data, Post::class, 'json');
$em = $this->getDoctrine()->getManager();
$em->persist($post);
$em->flush();
return new Response(''); // return newly created Post
}
}
让我们假设数据库中已经存在(ID:1)。我们使用 get/fapi/post/1 获取它。这是结果:
{"id":1,"text":"Hello World!","author":{"id":1,"name":"Huber"}}
这是完全很好的,Symfony的对象态度可以照顾邮政对象的归一化,并将作者对象也包括在结果中。
现在,让我们尝试使用 post/fapi/post 的已经存在的作者创建一个新帖子:
{"id":null,"text":"Hello Universe!","author":{"id":1,"name":"Huber"}}
现在我们收到Symfony的错误:
notnormalizableValueException:class " app entity post "必须是" int " int "( null fiving)," app entity post "的类型)
我感谢这个错误并理解为什么会发生这种错误,但是没有任何内置的符号序列化方式来确保在此中没有考虑自动生成的值(由ORM,由ORM,由uuID(例如uuid))。"标准案例"。
我知道的解决方案:
- 根本不用请求发送 id (但根据我对静止的对象的理解,应交换对象的完整表示)
- 使用getSetMethodnormalizer而不是objectnormalizer(因为没有可行的 id 的setter,但有其他几个缺陷)。
- 排除 id 从否定化上下文(例如,'nighored_attributes')
- 创建自定义标准器以照顾这种情况
现在,让我们尝试从objectnormalizer更改为getSetMethodnormalizer克服我们的错误并重试发帖。
现在我们得到另一个错误:
fatalThrowableError:参数1传递给app entity post :: setauthor()必须是app entity fusit,rande,给定
的实例
根据getsetMethodnormalizer的文档,在设置符号化值时不会进一步归一化。
,我再次感谢这个错误并了解发生了什么。
API平台使用自定义的非规范化系统来照顾这些问题
我理解并欣赏Symfony和Doctrine是两个不同的软件包,,但是是如此频繁地组合(实际上通常在一起玩得很出色):
是否有符号序列化的内置或已知方式,基本上使我在上述"标准案例"中可以实现该链条无错误的运行,并且没有自定义实施量表或其他人?
database => doctrine orm => symfony get object => json =>发布相同的json => symfony => symfony => doctrine orm => database
P.S。:另一个小示例:
get/fapi/post/1仅提供
{"id":1,"text":"Hello World!","author":{"id":1,"name":"Huber"}}
因为许多to的关联是急切的,如果设置了默认的懒惰,则变为:
{"id":1,"text":"Hello World!","author":{"id":1,"name":"Huber","__initializer__":null,"__cloner__":null,"__isInitialized__":true}}
因为objectnormalizer序列化学说代理对象。
p.p.s:我知道JMSSerializerBundle并经常使用它,但我完全喜欢并支持Symfony拥有其"自己的"序列化合物组件。
添加nullable=true
为我解决了错误。添加后,且添加了DB映射的变化。所以我想这是完全安全的。
/**
* @ORMId()
* @ORMGeneratedValue()
* @ORMColumn(type="integer", nullable=true)
*/
private $id;