Question

In this problem Deep Cloning I thought my issue was due to a deep/shallow copy.

I have vainly tested clone() and unserialize(serialize()) methods.

So I tried to write my own clone function using all setters/getters and then I realized what was really my issue, a persisting one.

The fact is I already succeeded in persisting a clone of my entity, in another context.

The main difference between my two situations is that in one case my original object is already managed by doctrine (this is the case where i'm blocked), and in the second case, my original object is just persisted, I don't have called flush() yet (and it's works fine).

So this is the situation when persist do not persist the many to many relations :

public function duplicateCourseAction(Request $request) {
    if ($this->getRequest()->isXmlHttpRequest() == false) {
        return new Response("Bad request", 405);
    }

    $em = $this->getDoctrine()->getManager();
    $parameters = $request->request->all();
    $course = $em->getRepository('EntTimeBundle:Course')->findOneById($parameters['id']);
    $duplicate = clone $course;
    $duplicate->setId(null);
    $duplicate->setDate(new \DateTime($parameters['date']));
    $em->persist($duplicate);
    $em->flush();
    return new Response("200");
}

And this is the situation whe it's works like a charm

        $em->persist($obj);
        while ($new_date < $up_to) {
            if ($this->isAvailable($holidays, $new_date)) {
                $new_course = clone $obj;
                $new_course->setDate($new_date);
                $new_course->setUuid($uuid);
                $new_date = clone $new_date;
                $em->persist($new_course);
            }
            $new_date->modify($modifier);
        }
        $em->flush();

Why is it working for only one situation ? There are almost identical...

EDIT 1 : Entities Mapping

-Course :

class Course {

/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue(strategy="AUTO")
 */
protected $id;

/**
 * @ORM\Column(type="string", length=50, unique=true, nullable=true)
 */
protected $name;

/**
* @ORM\JoinColumn(onDelete="CASCADE")
* @ORM\ManyToOne(targetEntity="Ent\HomeBundle\Entity\Campus", inversedBy="courses")
* @Assert\NotBlank
**/
protected $campus;

/**
* @ORM\JoinColumn(onDelete="CASCADE")
* @ORM\ManyToOne(targetEntity="Ent\HomeBundle\Entity\Room", inversedBy="courses")
* @Assert\NotBlank
**/
protected $room;

/**
 * @ORM\ManyToMany(targetEntity="Ent\UserBundle\Entity\User", inversedBy="courses", cascade={"persist"})
 * @ORM\JoinTable(name="course_teacher",
 *  joinColumns={@ORM\JoinColumn(name="course_id", referencedColumnName="id", onDelete="CASCADE")},
 *  inverseJoinColumns={@ORM\JoinColumn(name="teacher_id", referencedColumnName="id", onDelete="CASCADE")}
 * )
 * @Assert\NotBlank
 */
private $teachers;

/**
* @ORM\JoinColumn(onDelete="CASCADE")
* @ORM\ManyToOne(targetEntity="Matter", inversedBy="courses")
* @Assert\NotBlank
**/
protected $matter;

/**
* @ORM\JoinColumn(onDelete="CASCADE")
* @ORM\ManyToOne(targetEntity="\Ent\UserBundle\Entity\Grade", inversedBy="courses")
* @Assert\NotBlank
**/
protected $grade;

/**
* @ORM\Column(type="datetime")
* @Assert\NotBlank
**/
protected $date;

/**
* @ORM\Column(type="time")
* @Assert\NotBlank
**/
protected $duration;

/**
 * @ORM\Column(type="string", length=30, nullable=true)
 */
protected $uuid;

/**
 * @ORM\ManyToMany(targetEntity="Ent\TimeBundle\Entity\Course", mappedBy="courses")
 * @Exclude
*/
protected $alerts;

public function __toString() {
    if (empty($this->getName())) {
        $string = $this->getMatter().' - '.$this->getRoom().' - ';
        foreach ($this->getTeachers() as $count => $teacher) {
            $string = $string . $teacher;
            if ($count < count($this->getTeachers()) - 1) {
                $string = $string . ', ';
            }
        }
        return $string;
    } else {
        return $this->getName().' - '.$this->getRoom();
    }
}
/**
 * Constructor
 */
public function __construct() {
    $this->teachers = new ArrayCollection();
    $this->alerts = new ArrayCollection();
}

public function __clone() {
    // $this->id = null;
    // $this->teachers = clone $this->teachers;
}
}

-User (Teacher) :

class User implements UserInterface, \Serializable {
/**
 * @ORM\Column(type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
protected $id;

/**
 * @ORM\Column(type="string", length=30)
 * @Assert\NotBlank
 */
protected $firstName;

/**
 * @ORM\Column(type="string", length=30)
 * @Assert\NotBlank
 */
protected $lastName;

/**
 * @ORM\Column(type="string", length=70, unique=true)
 * @Assert\NotBlank
 */
protected $username;

/**
 * @Gedmo\Slug(fields={"username"}, updatable=false)
 * @ORM\Column(length=50, unique=true)
 */
protected $slug;

/**
 * @ORM\Column(type="string", length=32)
 * @Exclude
 */
protected $salt;

/**
 * @ORM\Column(type="string", length=40)
 * @Exclude
 */
protected $password;

/**
 * @ORM\Column(type="string", length=255, nullable=true)
 */
protected $picture_path;

/**
 * @Assert\File(maxSize="10M", mimeTypesMessage="Please upload a valid Image")
 */
protected $picture;

/**
 * @ORM\Column(type="string", length=60, unique=true)
 * @Exclude
 * @Assert\NotBlank
 */
protected $email;

/**
 * @ORM\Column(name="is_active", type="boolean")
 */
protected $isActive;

/**
 * @ORM\ManyToOne(targetEntity="Group", inversedBy="users")
 * @ORM\JoinColumn(name="role_group", referencedColumnName="role", onDelete="CASCADE")
 */
protected $group;

/**
* @ORM\ManyToMany(targetEntity="Ent\HomeBundle\Entity\Campus", inversedBy="users")
* @Exclude
**/
protected $campuses;

/**
 * @ORM\OneToMany(targetEntity="\Ent\NewsBundle\Entity\News", mappedBy="user")
 * @Exclude
 */
protected $news;

/**
 * @ORM\ManyToMany(targetEntity="\Ent\TimeBundle\Entity\Matter", inversedBy="teachers", cascade={"persist"})
 * @ORM\JoinTable(name="user_matter",
 *  joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")},
 *  inverseJoinColumns={@ORM\JoinColumn(name="matter_id", referencedColumnName="id", onDelete="CASCADE")}
 * )
 */
protected $matters;

/**
* @ORM\ManyToMany(targetEntity="Ent\UserBundle\Entity\Grade")
* @Assert\NotBlank
* @Exclude
**/
protected $grades;

/**
* @ORM\ManyToMany(targetEntity="Ent\TimeBundle\Entity\Course", mappedBy="teachers")
* @Exclude
**/
protected $courses;

/**
* @ORM\OneToMany(targetEntity="\Ent\TimeBundle\Entity\Alert", mappedBy="teacher")
* @Exclude
**/
protected $alerts;

protected $temp;

public function __construct() {
    $this->isActive = true;
    $this->salt = md5(uniqid(null, true));
}

public function __toString() {
    return $this->getFullName();
}
}

EDIT 2 : Solution

Thanks to Paul Andrieux this is the function we made to clone my object :

public function course_deep_clone($course) {
    $em = $this->getDoctrine()->getManager();
    $clone = clone $course;

    $clone->setTeachers(array());
    $teachers = $course->getTeachers();
    foreach ($teachers as $teacher) {
        $clone->addTeacher($teacher);
    }

    return $clone;
}
Was it helpful?

Solution

Thing is that ManyToMany related entities are not cloned, try that:

public function duplicateCourseAction(Request $request) {
    if ($this->getRequest()->isXmlHttpRequest() == false) {
        return new Response("Bad request", 405);
    }

    $em = $this->getDoctrine()->getManager();
    $parameters = $request->request->all();
    $course = $em->getRepository('EntTimeBundle:Course')->findOneById($parameters['id']);
    $duplicate = clone $course;

    $teachers = $course->getTeachers();
    $duplicate->setTeachers($teachers);

    $duplicate->setId(null);
    $duplicate->setDate(new \DateTime($parameters['date']));
    $em->persist($duplicate);
    $em->flush();
    return new Response("200");
}

This way, you are persisting new relationship and new join table between you two entities

EDIT: Maybe its a cascading problem, what gives you this ? :

$teachers = $course->getTeachers();

foreach ($teachers as $teacher) { 
    $teacher->addCourse($duplicate); 
    $em->persist($teacher); 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top