最近我开始了一个基于API平台的项目。我和其他Symfony项目一样设计了我的实体。创建/更新没有关系的普通实体非常好但我有一个“特殊”实体,有两个多对多关系,为简单起见,我将这篇文章限制在两个关系中的一个上。如果我尝试创建一个新实体,包括通过API调用多对多关系的新元素,则调用它以产生500错误。
我有点困惑也许你可以帮助我。
Shortend Stacktrace:
[Tue Mar 13 12:19:35 2018] PHP Fatal error: Maximum function nesting level of '256' reached, aborting! in <ProjectPath>/vendor/symfony/debug/ErrorHandler.php on line 605
[Tue Mar 13 12:19:35 2018] PHP Stack trace:
[Tue Mar 13 12:19:35 2018] PHP 1. {main}() <ProjectPath>/public/index.php:0
[Tue Mar 13 12:19:35 2018] PHP 2. Symfony\Component\HttpKernel\Kernel->handle() <ProjectPath>/public/index.php:37
[Tue Mar 13 12:19:35 2018] PHP 3. Symfony\Component\HttpKernel\HttpKernel->handle() <ProjectPath>/vendor/symfony/http-kernel/Kernel.php:202
[Tue Mar 13 12:19:35 2018] PHP 4. Symfony\Component\HttpKernel\HttpKernel->handleRaw() <ProjectPath>/vendor/symfony/http-kernel/HttpKernel.php:68
[Tue Mar 13 12:19:35 2018] PHP 5. Symfony\Component\EventDispatcher\EventDispatcher->dispatch() <ProjectPath>/vendor/symfony/http-kernel/HttpKernel.php:127
[Tue Mar 13 12:19:35 2018] PHP 6. Symfony\Component\EventDispatcher\EventDispatcher->doDispatch() <ProjectPath>/vendor/symfony/event-dispatcher/EventDispatcher.php:44
[Tue Mar 13 12:19:35 2018] PHP 7. ApiPlatform\Core\EventListener\DeserializeListener->onKernelRequest() <ProjectPath>/vendor/symfony/event-dispatcher/EventDispatcher.php:212
[Tue Mar 13 12:19:35 2018] PHP 8. Symfony\Component\Serializer\Serializer->deserialize() <ProjectPath>/vendor/api-platform/core/src/EventListener/DeserializeListener.php:71
[Tue Mar 13 12:19:35 2018] PHP 9. Symfony\Component\Serializer\Serializer->denormalize() <ProjectPath>/vendor/symfony/serializer/Serializer.php:133
[Tue Mar 13 12:19:35 2018] PHP 10. ApiPlatform\Core\JsonLd\Serializer\ItemNormalizer->denormalize() <ProjectPath>/vendor/symfony/serializer/Serializer.php:182
[Tue Mar 13 12:19:35 2018] PHP 11. ApiPlatform\Core\Serializer\AbstractItemNormalizer->denormalize() <ProjectPath>/vendor/api-platform/core/src/JsonLd/Serializer/ItemNormalizer.php:108
[Tue Mar 13 12:19:35 2018] PHP 12. Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer->denormalize() <ProjectPath>/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php:121
[Tue Mar 13 12:19:35 2018] PHP 13. ApiPlatform\Core\Serializer\AbstractItemNormalizer->setAttributeValue() <ProjectPath>/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php:205
[Tue Mar 13 12:19:35 2018] PHP 14. ApiPlatform\Core\Serializer\AbstractItemNormalizer->setValue() <ProjectPath>/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php:191
[Tue Mar 13 12:19:35 2018] PHP 15. Symfony\Component\PropertyAccess\PropertyAccessor->setValue() <ProjectPath>/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php:344
[Tue Mar 13 12:19:35 2018] PHP 16. Symfony\Component\PropertyAccess\PropertyAccessor->writeProperty() <ProjectPath>/vendor/symfony/property-access/PropertyAccessor.php:217
[Tue Mar 13 12:19:35 2018] PHP 17. Symfony\Component\PropertyAccess\PropertyAccessor->writeCollection() <ProjectPath>/vendor/symfony/property-access/PropertyAccessor.php:627
[Tue Mar 13 12:19:35 2018] PHP 18. App\Entity\Pool->addTag() <ProjectPath>/vendor/symfony/property-access/PropertyAccessor.php:679
[Tue Mar 13 12:19:35 2018] PHP 19. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
[Tue Mar 13 12:19:35 2018] PHP 20. App\Entity\Pool->addTag() <ProjectPath>/src/Entity/Tag.php:85
[Tue Mar 13 12:19:35 2018] PHP 21. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
[Tue Mar 13 12:19:35 2018] PHP 22. App\Entity\Pool->addTag() <ProjectPath>/src/Entity/Tag.php:85
[Tue Mar 13 12:19:35 2018] PHP 23. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
[Tue Mar 13 12:19:35 2018] PHP 24. App\Entity\Pool->addTag() <ProjectPath>/src/Entity/Tag.php:85
[Tue Mar 13 12:19:35 2018] PHP 25. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
[Tue Mar 13 12:19:35 2018] PHP 26. App\Entity\Pool->addTag() <ProjectPath>/src/Entity/Tag.php:85
[Tue Mar 13 12:19:35 2018] PHP 27. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
[Tue Mar 13 12:19:35 2018] PHP 28. App\Entity\Pool->addTag() <ProjectPath>/src/Entity/Tag.php:85
[Tue Mar 13 12:19:35 2018] PHP 29. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
[Tue Mar 13 12:19:35 2018] PHP 30. App\Entity\Pool->addTag() <ProjectPath>/src/Entity/Tag.php:85
[Tue Mar 13 12:19:35 2018] PHP 31. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
[Tue Mar 13 12:19:35 2018] PHP 32. App\Entity\Pool->addTag() <ProjectPath>/src/Entity/Tag.php:85
[Tue Mar 13 12:19:35 2018] PHP 33. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
[Tue Mar 13 12:19:35 2018] PHP 34. App\Entity\Pool->addTag() <ProjectPath>/src/Entity/Tag.php:85
[Tue Mar 13 12:19:35 2018] PHP 35. App\Entity\Tag->addPool() <ProjectPath>/src/Entity/Pool.php:284
截断的实体池
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class Pool - This Entity describes a pool of tasks.
* @package App\Entity
* @ApiResource(attributes={
* "normalization_context"={"groups"={"read"}},
* "denormalization_context"={"groups"={"write"}}
* })
* @ORM\Entity
*/
class Pool
{
/**
* @var ArrayCollection|Tag[] $tags
* @param ArrayCollection|Tag[] $tags all tags that are that are related with this pool
* @ApiProperty(
* attributes={
* "swagger_context"={
* "$ref"="#/definitions/Tag",
* }
* }
* )
* @ORM\ManyToMany(targetEntity="Tag", inversedBy="pools", cascade={"persist"})
* @Groups({"read", "write"})
*/
private $tags;
public function __construct() {
$this->tasks = new ArrayCollection();
$this->tags = new ArrayCollection();
}
/**
* @return ArrayCollection
*/
public function getTags()
{
return $this->tags;
}
/**
* @param ArrayCollection $tags
*/
public function setTags(ArrayCollection $tags)
{
$this->tags = $tags;
}
/**
* @param Tag $tag
*/
public function addTag(Tag $tag):void
{
$tag->addPool($this);
$this->tags->add($tag);
}
/**
* @param Tag $tag
*/
public function removeTag(Tag $tag):void
{
$tag->removePool($this);
$this->tags->removeElement($tag);
}
}
截断标记实体
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiSubresource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class Tag
* @package App\Entity
* @ApiResource(attributes={
* "normalization_context"={"groups"={"tag_read"}},
* "denormalization_context"={"groups"={"write"}}
* })
* @ORM\Entity
*/
class Tag
{
/**
* @var ArrayCollection[Pool]
* @param ArrayCollection[Pool] $tasks all pool that are related with this tag
* @Groups({"tag_read", "write"})
* @ApiProperty(
* attributes={
* "swagger_context"={
* "$ref"="#/definitions/Pool",
* }
* }
* )
* @ORM\ManyToMany(targetEntity="Pool", mappedBy="tags",cascade={"persist"})
*/
private $pools;
/**
* @var string
* @param string $identifier the hashtag
* @ORM\Column(type="string")
* @Assert\NotBlank
* @Groups({"read", "write"})
*/
private $tag;
public function __construct() {
$this->pools = new ArrayCollection();
}
/**
* @return mixed
*/
public function getTag()
{
return $this->tag;
}
/**
* @param mixed $tag
*/
public function setTag($tag)
{
$this->tag = $tag;
}
public function addPool(Pool $pool):void
{
$pool->addTag($this);
$this->pools->add($pool);
}
public function removePool(Pool $pool):void
{
$pool->removeTag($this);
$this->pools->removeElement($pool);
}
}
对API路由的POST请求
{
"name": "This is a Test",
"description": "A pool build for tests",
"public": true,
"tags": [{"tag":"testTag"},{"tag":"testTag2"}]
}
答案 0 :(得分:3)
要实现多对多,您应该有3个表:Pool,Tag和PoolTag
在您的泳池实体中:
class Pool
{
/**
* @ORM\ManyToMany(targetEntity="Tag", inversedBy="pools")
* @ORM\JoinTable(
* name="pool_tag",
* joinColumns={
* @ORM\JoinColumn(name="pool_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="tag_id", referencedColumnName="id")
* }
* )
*/
private $tags;
public function __construct() {
$this->tags = new ArrayCollection();
}
}
在您的标签实体中:
class Tag
{
/**
* @ORM\ManyToMany(targetEntity="Pool", mappedBy="tags")
*/
private $pools
}
向API路由发布POST请求
{
"name": "This is a Test",
"description": "A pool build for tests",
"public": true,
"tags": ["/api/tags/1","/api/tags/2"]
}
答案 1 :(得分:1)
您的错误:Maximum function nesting level of '256' reached
实际上是您在使用XDebug时发生的错误。这是一个暗示,你已经创建了一个无休止的递归,这就是这里的情况。
您在addTag()
呼叫Pool
,addPool()
呼叫Tag
,呼叫addTag()
中的Pool
等等。< / p>
答案 2 :(得分:0)
您遇到的问题与API平台本身无关,这是一个语义错误,导致无限递归(就像之前的评论中所说的那样)。
解决方案可以是在add和remove方法中放置一个条件以避免此错误:
public function addTag(Tag $tag):void
{
if (!$this->tags->contains($tag)) {
$tag->addPool($this);
$this->tags->add($tag);
}
}
public function removeTag(Tag $tag):void
{
if ($this->tags->contains($tag)) {
$tag->removePool($this);
$this->tags->removeElement($tag);
}
}
public function addPool(Pool $pool):void
{
if (!$this->pools->contains($pool)) {
$pool->addTag($this);
$this->pools->add($pool);
}
}
public function removePool(Pool $pool):void
{
if ($this->pools->contains($pool)) {
$pool->removeTag($this);
$this->pools->removeElement($pool);
}
}
答案 3 :(得分:-2)
要解决此类问题,您可能需要使用Symfony表单(以及嵌入式)表单,如此处所述。