Search code examples
symfonydoctrineone-to-onepersistent

OneToOne entities won't persist with Doctrine in Symfony2


I have a OneToOne relation in Symfony between user and student, where user is the owner, when I try to persist changes are not made in neither of sides, this is my last configuration:

<?php

/**
 * User
 *
 * @ORM\Table(name="user")
 * @ORM\Entity(repositoryClass="BackendBundle\Repository\UserRepository")
 */
class User  implements UserInterface, \Serializable
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
    * @ORM\OneToOne(targetEntity="Student", mappedBy="user")
    */
    private $student;

    public function __construct() {
    }


    /**
     * Set student
     *
     * @param \BackendBundle\Entity\Student $student
     *
     * @return User
     */
    public function setStudent(\BackendBundle\Entity\Student $student)
    {
        $this->student = $student;

        return $this;
    }

    /**
     * Get student
     *
     * @return \BackendBundle\Entity\Student
     */
    public function getStudent()
    {
        return $this->student;
    }

}

The student:

<?php

/**
 * Student
 *
 * @ORM\Table(name="Student")
 * @ORM\Entity(repositoryClass="BackendBundle\Repository\StudentRepository")
 */
class Student
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
    * @ORM\OneToOne(targetEntity="User", inversedBy="student")
    * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
    */
    private $user;

    public function __construct() {

    }
}

and in the controller:

    public function editAction(Request $request, User $user)
{
    $student = new Student();
    $user->setStudent($student);

    $em = $this->getDoctrine()->getManager();
    $em->persist($student);
    $user->setStudent($student);
    $em->persist($user);
    $em->flush();
    /.../
}

I can save both entities and changes without any exceptions, but I can't relate them, for example in view, when I do {{ user.student }} it gives me null, and {{ student.user_id }} also is null.


Solution

  • Modify your code as follows

     <?php
    
    /**
     * User
     *
     * @ORM\Table(name="user")
     * @ORM\Entity(repositoryClass="BackendBundle\Repository\UserRepository")
     */
    class User  implements UserInterface, \Serializable
    {
        /**
        * @ORM\OneToOne(targetEntity="Student", mappedBy="user", cascade={"persist"})
        */
        private $student;
    
        // ...
    
        /**
         * Set student
         *
         * @param \BackendBundle\Entity\Student $student
         *
         * @return User
         */
        public function setStudent(\BackendBundle\Entity\Student $student)
        {
            $this->student = $student;
            $student->setUser($this);
    
            return $this;
        }
    
        // ...
    }
    

    public function editAction(Request $request, User $user)
    {
        $student = new Student();
        $user->setStudent($student);
    
        $em->flush();
    }
    

    Why this edit?

    Because doctrine "listen" only for changes into owning side (so Student entity). If you want to persist user without headaches for student, you need to:

    1 - Set user into student (owning side) when you set a student into user
    2 - Use cascade persist on student property of user

    PS.: If you retrieve user (more in general an entity) from db with doctrine (even with parameter converter) you don't need to call explicitly persist onto this entity.