Как должна выглядеть форма json с другими встроенными формами

Я использую почтальон для проверки json-api. У меня есть связанные объекты:

Публикация:

<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\PublicationRepository")
 */
class Publication
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @Assert\NotBlank
     * @ORM\Column(type = "string", length=100)
     */
    private $title;

    /**
     * @Assert\NotBlank
     * @ORM\Column(type = "string", length=500)
     */
    private $body;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\Comment", mappedBy = "publication", orphanRemoval=true)
     */
    private $comments;

    public function __construct()
    {
        $this->comments = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(string $title): self
    {
        $this->title = $title;

        return $this;
    }

    public function getBody(): ?string
    {
        return $this->body;
    }

    public function setBody(string $body): self
    {
        $this->body = $body;
        return $this;
    }

    /**
     * @return Collection|Comment[]
     */
    public function getComments(): Collection
    {
        return $this->comments;
    }

    public function addComment(Comment $comment): self
    {
        if (!$this->comments->contains($comment)) {
            $this->comments[] = $comment;
            $comment->setPublication($this);
        }

        return $this;
    }

    public function removeComment(Comment $comment): self
    {
        if ($this->comments->contains($comment)) {
            $this->comments->removeElement($comment);
            // set the owning side to null (unless already changed)
            if ($comment->getPublication() === $this) {
                $comment->setPublication(null);
            }
        }
        return $this;
    }
}

Комментарий:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\CommentRepository")
 *
 */
class Comment
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @Assert\NotBlank
     * @ORM\Column(type = "string", length=255)
     */
    private $body;

    /**
     * @Assert\Positive
     * @ORM\Column(type = "integer")
     */
    private $likeCount;

    /**
     * @return mixed
     */
    public function getLikeCount()
    {
        return $this->likeCount;
    }

    /**
     * @param mixed $likeCount
     */
    public function setLikeCount($likeCount): void
    {
        $this->likeCount = $likeCount;
    }

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Publication", inversedBy = "comments")
     * @ORM\JoinColumn(nullable=false)
     */
    private $publication;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getBody(): ?string
    {
        return $this->body;
    }

    public function setBody(string $body): self
    {
        $this->body = $body;

        return $this;
    }

    public function getPublication(): ?Publication
    {
        return $this->publication;
    }

    public function setPublication(?Publication $publication): self
    {
        $this->publication = $publication;

        return $this;
    }
}

И классы формы:

Тип публикации:

<?php

namespace App\Form;

use App\Entity\Publication;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class PublicationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title')
            ->add('body')
            ->add('comments', CollectionType::class, [
                'entry_type' => CommentType::class,
                'entry_options' => ['label' => false],
            ]);
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Publication::class,
            'csrf_protection'=> false
        ]);
    }
}

Тип комментария:

<?php

namespace App\Form;


use App\Entity\Comment;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CommentType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('body')
            ->add('publication')
            ->add('likeCount');
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Comment::class,
            'csrf_protection'=> false
        ]);
    }
}

В соответствии с этим: https://symfony.com/doc/current/form/form_collections.html форма публикации может получать встроенную форму комментария:

Я пробовал что-то подобное в запросе POST почтальона:

{
    "title":"post with comments",
    "body":"some text",
    "comments":[
        {"body":"comment1","likeCount":"5"},
        {"body":"comment2","likeCount":"8"}
        ]
}

Но я получаю это:

{ "code": 400, "message": "Validation Failed", "errors": { "errors": [ "This form should not contain extra fields." ], "children": { "title": {}, "body": {}, "comments": {} } } }

Вопрос в том:

Как должен выглядеть запрос json?

Редактировать:

Я не думаю, что проблема в корневых ключах, потому что перед установкой отношения ManyToOne я отправлял форму следующим образом:

{
    "title":"post with comments",
    "body":"some text"  
}

дополнительная информация:

Это код контроллера:

$form = $this->formFactory->create(PublicationType::class, new Publication());
        $form->submit($request->request->all());
        if (false === $form->isValid()) {
            return $this->viewhandler->createResponse($this->view($form),$request,'json');
        }
        $this->entityManager->persist($form->getData());
        $this->entityManager->flush();
        return new JsonResponse(
            [
                'status' => 'ok',
            ]
        );

хотите показать функцию контроллера? однако мой инстинкт подсказывал бы, что у формы есть «имя», например «публикация», и, таким образом, можно ожидать, что данные будут находиться под ключом публикации или даже под публикацией_form. у вас могут быть лучшие результаты, если вместо этого вы создадите безымянную форму. посмотрите направо над раздел "заключительные мысли" на symfony.com/doc/current/forms.html#creating-form-classes

Jakumi 27.06.2019 09:43

просто повторю, если это не было очевидно: не работает не встроенная форма, а базовая форма (публикация). компонент формы жалуется на «лишние» ключи, и все упомянутые ключи взяты из базовой формы (ключи корневого уровня)

Jakumi 27.06.2019 09:46

Я отредактировал вопрос. Любая другая информация?

Armando Rodríguez Acosta 27.06.2019 15:52

возможно, это не имеет значения, но наличие публикации в качестве поля в форме комментария кажется странным, также, возможно, вам понадобятся allow_add и allow_delete?

Jakumi 27.06.2019 19:06

Я добавил allow_add и allow_delete в метод configureOptions в PublicationType и получил ту же ошибку.

Armando Rodríguez Acosta 27.06.2019 19:33

Плохо, я неправильно добавил allow_add.

Armando Rodríguez Acosta 27.06.2019 20:05

значит ли это, что ваша проблема решена?

Jakumi 27.06.2019 20:41

да, мне пришлось сделать немного больше, потому что у меня были проблемы с устойчивостью каскада, но теперь это решено. Как вы сказали, «Эта форма не должна содержать лишних полей». ошибка была решена добавлением "allow_add"=true в: >add('comments', CollectionType::class, array( 'entry_type' => CommentType::class, 'allow_add' => true, 'by_reference' => false, ' entry_options' => ['label' => false], ));

Armando Rodríguez Acosta 27.06.2019 21:00

Приятно. рад, что мое настойчивое нытье направило вас в правильном направлении.

Jakumi 27.06.2019 21:21

Спасибо, Джакуми был действительно полезен. Я думаю, вы должны опубликовать свое предложение о alow_add и allow_delete в качестве ответа для записей.

Armando Rodríguez Acosta 27.06.2019 22:10
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
2
10
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вопреки моему первому предположению, сообщение об ошибке действительно содержит поля это было ожидаемо:

{ 
    "code": 400, 
    "message": "Validation Failed", 
    "errors": { 
        "errors": [  
            "This form should not contain extra fields." 
        ], 
        "children": { 
            "title": {}, 
            "body": {}, 
            "comments": {} 
        } 
    } 
}

Однако это сообщение не особенно полезно, когда указаны именно эти поля, а проблема заключается в коллекции (подформа/подполя).

Однако CollectionType для comments не позволяет добавлять или удалять дочерние элементы (comments), если это не настроено. Добавление allow_add (и, возможно, allow_delete) устраняет проблему.

Другие вопросы по теме