Недавно я начал проект, основанный на платформе 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);
}
}
Усеченный тег Entity
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);
}
}
POST-запрос к API Route
{
"name": "This is a Test",
"description": "A pool build for tests",
"public": true,
"tags": [{"tag":"testTag"},{"tag":"testTag2"}]
}
У вас должно быть 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();
}
}
В вашем теге Entity:
class Tag
{
/**
* @ORM\ManyToMany(targetEntity="Pool", mappedBy="tags")
*/
private $pools
}
POST-запрос к API Route
{
"name": "This is a Test",
"description": "A pool build for tests",
"public": true,
"tags": ["/api/tags/1","/api/tags/2"]
}
Ваша ошибка: Maximum function nesting level of '256' reached
на самом деле ошибка, которая возникает при использовании XDebug. Это намек на то, что вы создали бесконечную рекурсию, которая здесь имеет место.
Ты звонишь addTag()
в Pool
, который вызывает addPool()
в Tag
звонит addTag()
в Pool
и т. д.
Чтобы решить такую проблему, вы можете использовать формы Symfony (и, следовательно, встроенные), как описано здесь.