Недавно я начал проект на платформе API. Я разработал свои сущности так же, как и в любом другом проекте Symfony. Создание / обновление обычных сущностей без отношений работает очень хорошо, но у меня есть «особая» сущность с двумя отношениями «многие-ко-многим», для простоты я ограничил этот пост одним из двух отношений. Если я попытаюсь создать новую сущность, включая новый элемент для отношения «многие ко многим» через API, вызовите ее, чтобы получить ошибку 500.
Я немного запутался, может ты мне поможешь.
Сокращение трассировки стека:
[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);
}
}
POST-запрос к API-маршруту
{
"name": "This is a Test",
"description": "A pool build for tests",
"public": true,
"tags": [{"tag":"testTag"},{"tag":"testTag2"}]
}
Я не вызываю эту функцию активно, платформа api строит операции CRUD на основе сущностей. Поэтому я понятия не имею, почему он называется рекурсивно. @kry
Взгляните на github.com/api-platform/api-platform/issues/187
@MathieuDormeval, я изменил свои сущности в соответствии с проблемой. Это решает описанную проблему, но теперь я получаю новую ошибку: "hydra: description": "Вложенные документы для атрибута \" теги \ "не разрешены. Вместо этого используйте IRI.",
Взгляните на github.com/api-platform/api-platform/issues/371
Это так расстраивает, я думаю, что сделал все из упомянутых проблем, но я всегда сталкиваюсь с ошибкой 500. Вот полные сущности, что я делаю не так? gist.github.com/ljbergmann/574d6a0f5129760b450132cee6771008






Ваша ошибка: Maximum function nesting level of '256' reached на самом деле является ошибкой, возникающей при использовании XDebug. Намек на то, что вы создали бесконечную рекурсию, как здесь.
Вы вызываете addTag() в Pool, который вызывает addPool() в Tag, вызывает addTag() в Pool и т. д.
Чтобы решить такую проблему, вы можете использовать формы Symfony (и, следовательно, встроенные), как описано здесь.
Symfony doc - Как встроить коллекцию форм
Привет, спасибо за повтор. Не думаю, что это подходящее решение. Я создаю api с api-platform.com, и я думаю, что ошибка связана с этим.
Я также работаю с API. Я отправляю полезные данные JSON, которые затем передаю в форму в контроллере. Однако я использую FOSRest.
Я знаю, что это жизнеспособный метод (я использовал его для других проектов), но не в контексте API, основанного на api-platform.com. Однако спасибо за ваш вклад.
У вас должно быть 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
}
POST-запрос к API-маршруту
{
"name": "This is a Test",
"description": "A pool build for tests",
"public": true,
"tags": ["/api/tags/1","/api/tags/2"]
}
Проблема, с которой вы столкнулись, не связана с самой платформой API, это семантическая ошибка, которая вызывает бесконечную рекурсию (как кто-то сказал в предыдущем комментарии). Решением может быть установка условия в методах добавления и удаления, чтобы избежать этой ошибки:
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);
}
}
Неустранимая ошибка PHP: достигнут максимальный уровень вложенности функций «256», прерывание! Разве вы не вызываете что-то рекурсивно с помощью этих отношений "многие-ко-многим"?