Doctrine ORM / Symfony - может ли обновлять дочерние объекты из родительского объекта? - PullRequest
0 голосов
/ 12 октября 2018

У меня есть две сущности: викторина и вопрос с повторением OneToMany (в 1 викторине может быть много вопросов).

Я пытаюсь обновить объект викторины (id = 19) с помощью действия put в RestApi, добавляя вмассив вопросов 2 идентификатора объектов вопросов.Эти идентификаторы действительны до тех пор, пока они не станут сиротами, их quiz_id равен нулю.

Идентификатор викторины 19 Перед обновлением:

{
    "id": 19
    "alias": "Test Quiz",
    "questions": [],
    "hasFifty": false,
    "hasTip": false,
    "hasNext": false
}

Действие Json Data on Put (Обновить объект викторины 19):

 {
    "alias": "quiz-bill",
    "questions": [42,43],
    "hasFifty": true,
    "hasTip": true,
    "hasNext": true
}

В ответе на запрос о размещении отображается объект проверки обновления:

 {
        "id": 19,
        "alias": "quiz-bill",
        "questions": [
            {
                "id": 42,
                "content": "test test test",
                "helpText": "dummy dummy dummy"                 
            },
            {
                "id": 43,
                "content": "test test",
                "helpText": "dummy"

            }
        ],
        "hasFifty": true,
        "hasTip": true,
        "hasNext": true
    }

Но этот объект является поддельным, когда я выбираю эти вопросы из базы данных, они по-прежнему имеют значение quiz_id null.Я прыгал, чтобы обновить родительское поле (quiz_id) этих дочерних объектов из родительского (Викторина) обновления, но это кажется невозможным.

Есть ли кто-нибудь, кто сделал что-то подобное с доктриной и Symfony framework?Или можете помочь мне в этом?

Викторина Entity:

/**
 * Quiz.
 *
 * @ORM\Table(name="quiz")
 * @ORM\Entity(repositoryClass="ApiBundle\Repository\QuizRepository")
 * @JMS\ExclusionPolicy("all")
 */
class Quiz
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @JMS\Groups({"task", "quiz"})
     * @JMS\Expose
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="alias", type="string", length=255)
     * @JMS\Groups({"quiz"})
     * @JMS\Expose
     */
    private $alias;

    /**
     * @var ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="Question", mappedBy="quiz")
     * @JMS\Groups({"quiz"})
     * @JMS\Expose
     */
    private $questions;

    /**
     * @var bool
     *
     * @ORM\Column(name="hasFifty", type="boolean", nullable=true)
     * @JMS\Groups({"quiz"})
     * @JMS\Expose
     */
    private $hasFifty;

    /**
     * @var bool
     *
     * @ORM\Column(name="hasTip", type="boolean", nullable=true)
     * @JMS\Groups({"quiz"})
     * @JMS\Expose
     */
    private $hasTip;

    /**
     * @var bool
     *
     * @ORM\Column(name="hasNext", type="boolean", nullable=true)
     * @JMS\Groups({"quiz"})
     * @JMS\Expose
     */
    private $hasNext;
/**
     * Get id.
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set alias.
     *
     * @param string $alias
     *
     * @return Quiz
     */
    public function setAlias($alias)
    {
        $this->alias = $alias;

        return $this;
    }

    /**
     * Get alias.
     *
     * @return string
     */
    public function getAlias()
    {
        return $this->alias;
    }

    /**
     * Set hasFifty.
     *
     * @param bool $hasFifty
     *
     * @return Quiz
     */
    public function setHasFifty($hasFifty)
    {
        $this->hasFifty = $hasFifty;

        return $this;
    }

    /**
     * Get hasFifty.
     *
     * @return bool
     */
    public function getHasFifty()
    {
        return $this->hasFifty;
    }

    /**
     * Set hasTip.
     *
     * @param bool $hasTip
     *
     * @return Quiz
     */
    public function setHasTip($hasTip)
    {
        $this->hasTip = $hasTip;

        return $this;
    }

    /**
     * Get hasTip.
     *
     * @return bool
     */
    public function getHasTip()
    {
        return $this->hasTip;
    }

    /**
     * Add question.
     *
     * @param \ApiBundle\Entity\Question $question
     *
     * @return Quiz
     */
    public function addQuestion(\ApiBundle\Entity\Question $question)
    {
        $this->questions[] = $question;

        return $this;
    }

    /**
     * Remove question.
     *
     * @param \ApiBundle\Entity\Question $question
     */
    public function removeQuestion(\ApiBundle\Entity\Question $question)
    {
        $this->questions->removeElement($question);
    }

    /**
     * Get questions.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getQuestions()
    {
        return $this->questions;
    }

    /**
     * Set hasNext.
     *
     * @param bool $hasNext
     *
     * @return Quiz
     */
    public function setHasNext($hasNext)
    {
        $this->hasNext = $hasNext;

        return $this;
    }

    /**
     * Get hasNext.
     *
     * @return bool
     */
    public function getHasNext()
    {
        return $this->hasNext;
    }
}

Вопрос Entity:

/**
 * Question.
 *
 * @ORM\Table(name="question")
 * @ORM\Entity(repositoryClass="ApiBundle\Repository\QuestionRepository")
 * @JMS\ExclusionPolicy("all")
 */
class Question
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @JMS\Groups({"quiz" ,"question"})
     * @JMS\Expose
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="content", type="text")
     * @JMS\Groups({"quiz" ,"question"})
     * @JMS\Expose
     */
    private $content;

    /**
     * @var string
     *
     * @ORM\Column(name="help", type="text", nullable=true)
     * @JMS\Groups({"quiz" ,"question"})
     * @JMS\Expose
     */
    private $helpText;

    /**
     * @var \ApiBundle\Entity\Quiz
     *
     * @ORM\ManyToOne(targetEntity="Quiz", inversedBy="questions")
     * @ORM\JoinColumn(name="quiz_id", referencedColumnName="id")
     */
    protected $quiz;

    /**
     * @var \DateTime
     *
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(name="createdAt", type="datetime")
     * @JMS\Groups({"quiz" ,"question"})
     * @JMS\Expose
     */
    private $createdAt;

    /**
     * @var \DateTime
     *
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(name="updatedAt", type="datetime", nullable=true)
     * @JMS\Groups({"quiz" ,"question"})
     * @JMS\Expose
     */
    private $updatedAt;

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

    /**
     * Get id.
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set content.
     *
     * @param string $content
     *
     * @return Question
     */
    public function setContent($content)
    {
        $this->content = $content;

        return $this;
    }

    /**
     * Get content.
     *
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * Set createdAt.
     *
     * @param \DateTime $createdAt
     *
     * @return Question
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Get createdAt.
     *
     * @return \DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set updatedAt.
     *
     * @param \DateTime $updatedAt
     *
     * @return Question
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt.
     *
     * @return \DateTime
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

    /**
     * Set helpText.
     *
     * @param string $helpText
     *
     * @return Question
     */
    public function setHelpText($helpText)
    {
        $this->helpText = $helpText;

        return $this;
    }

    /**
     * Get helpText.
     *
     * @return string
     */
    public function getHelpText()
    {
        return $this->helpText;
    }

    /**
     * Set quiz.
     *
     * @param \ApiBundle\Entity\Quiz $quiz
     *
     * @return Question
     */
    public function setQuiz(\ApiBundle\Entity\Quiz $quiz = null)
    {
        $this->quiz = $quiz;

        return $this;
    }

    /**
     * Get quiz.
     *
     * @return \ApiBundle\Entity\Quiz
     */
    public function getQuiz()
    {
        return $this->quiz;
    }


}

QuizController Put действие:

/**
     * Update an existing Quiz.
     *
     * @param Request $request
     * @param int     $id
     *
     * @return mixed
     *
     * @Operation(
     *     tags={"Quiz"},
     *     summary="Update an existing Quiz.",
     *     @SWG\Response(
     *         response="204",
     *         description="Returned when an existing Quiz has been successful updated"
     *     ),
     *     @SWG\Response(
     *         response="400",
     *         description="Return when errors"
     *     ),
     *     @SWG\Response(
     *         response="401",
     *         description="Returned when access is not authorized"
     *     ),
     *     @SWG\Response(
     *         response="404",
     *         description="Return when not found"
     *     )
     * )
     *
     *
     * @Rest\View(serializerGroups={"quiz"})
     */
    public function putAction(Request $request, $id)
    {
        $quiz = $this->getDoctrine()->getRepository('ApiBundle:Quiz')->find($id);
        if (null === $quiz || empty($quiz)) {
            return new View(null, Response::HTTP_NOT_FOUND);
        }

        $form = $this->createForm(QuizType::class, $quiz, [
             'method' => 'PUT',
             'csrf_protection' => false,
         ]);
        $form->submit($request->request->all(), false);
        if (!$form->isValid()) {
            return $form;
        }

        $em = $this->getDoctrine()->getManager();
        $em->persist($quiz);
        $em->flush();

        return $quiz;
    }

Форма QuizType:

<?php

namespace ApiBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class QuizType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
        ->add('alias')
        ->add('hasFifty')
        ->add('hasTip')
        ->add('hasNext')
        ->add('videoUrl')
        ->add('questions')
        ->add('task');
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'ApiBundle\Entity\Quiz',
            'csrf_protection' => false,
            'allow_extra_fields' => true,
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'apibundle_quiz';
    }
}

Ответы [ 2 ]

0 голосов
/ 12 октября 2018

Поскольку вы добавляете уже сохраненные вопросы в свой тест, вам не нужно каскадно сохранять, но вам все равно нужно настроить свой тест на добавленный вопрос:

// inside Quiz entity
public function addQuestion(\ApiBundle\Entity\Question $question)
{
    $question->setQuiz($this);
    $this->questions[] = $question;

    return $this;
}

Это потому (цитирование Doctrine ORM Documentation )

Doctrine будет проверять только изменения на стороне-владельце ассоциации.

Изменения, внесенные только в обратную сторону ассоциации, игнорируются.Обязательно обновите обе стороны двунаправленной ассоциации (или, по крайней мере, сторону-владельца, с точки зрения Doctrine)

В вашем случае обратной стороной ассоциации является Quiz сущность и владеющаясторона - это Question объект.

0 голосов
/ 12 октября 2018

В действии контроллера вы сохраняете только сущность Викторины, но вам также необходимо сохранять связанные сущности Вопроса.В отношении «многие к одному» соединение сохраняется в таблице объекта, который может иметь только один связанный объект.

foreach($quiz->getQuestions() as $question) {
    // I don't know if you need this line
    $question->setQuiz($quiz);
    $em->persist($question);
}
$em->persist($quiz);
...