2012-01-31 12 views
17

सबसे पहले के रूप में एक OneToMany साथ एक इकाई को फिर से बचाने के लिए, इस सवाल का How to re-save the entity as another row in Doctrine 2Symfony2/सिद्धांत: कैसे एक व्यापक नई पंक्ति

के समान है अंतर यह है कि मैं एक इकाई के भीतर डेटा को बचाने के लिए कोशिश कर रहा हूँ यह है कि एक बहुत से रिश्ते है। मैं इकाई को मूल इकाई ("एक" तरफ) पर एक नई पंक्ति के रूप में फिर से सहेजना चाहता हूं और फिर प्रत्येक अनुवर्ती बच्चे ("कई" तरफ) पर नई पंक्तियों के रूप में।

मैंने कक्षाओं का एक बहुत ही सरल उदाहरण उपयोग किया है जिसमें कई विद्यार्थियों को इसे सरल रखना है।

तो मेरे पास कक्षा = 1 के साथ कक्षा कक्ष हो सकता है और इसमें 5 छात्र हैं (आईडी 1 से 5)। मैं जानना चाहता हूं कि मैं कैसे कर सकता हूं, सिद्धांत 2 के भीतर, उस इकाई को ले लो और इसे डेटाबेस में वापस ले जाएं (संभावित डेटा परिवर्तनों के बाद) सभी नए आईडी के साथ और मूल पंक्तियों को लगातार/फ्लश के दौरान छूटा जा रहा है।

पहले हमारी सिद्धांत संस्थाओं को परिभाषित करते हैं।

कक्षा निकाय:

namespace Acme\TestBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Doctrine\Common\Collections\ArrayCollection; 

/** 
* @ORM\Entity 
* @ORM\Table(name="classroom") 
*/ 
class Classroom 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

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

    /** 
    * @ORM\OneToMany(targetEntity="Pupil", mappedBy="classroom") 
    */ 
    protected $pupils; 

    public function __construct() 
    { 
     $this->pupils = new ArrayCollection(); 
    }  
    // ========== GENERATED GETTER/SETTER FUNCTIONS BELOW ============ 

} 

छात्र इकाई:

namespace Acme\TestBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Doctrine\Common\Collections\ArrayCollection; 

/** 
* @ORM\Entity 
* @ORM\Table(name="pupil") 
*/ 
class Pupil 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

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

    /** 
    * @ORM\ManyToOne(targetEntity="Classroom", inversedBy="pupils") 
    * @ORM\JoinColumn(name="classroom_id", referencedColumnName="id") 
    */ 
    protected $classroom; 

    // ========== GENERATED FUNCTIONS BELOW ============ 
} 

और हमारे सामान्य कार्रवाई समारोह:

public function someAction(Request $request, $id) 
{ 
    $em = $this->getDoctrine()->getEntityManager(); 

    $classroom = $em->find('AcmeTestBundle:Classroom', $id); 

    $form = $this->createForm(new ClassroomType(), $classroom); 

    if ('POST' === $request->getMethod()) { 
     $form->bindRequest($request); 

     if ($form->isValid()) { 
      // Normally you would do the following: 
      $em->persist($classroom); 
      $em->flush(); 

      // But how do I create a new row with a new ID 
      // Including new rows for the Many side of the relationship 

      // ... other code goes here. 
     } 
    } 

    return $this->render('AcmeTestBundle:Default:index.html.twig'); 
} 

मैं क्लोन का उपयोग कर की कोशिश की है, लेकिन वह केवल बचाया एक ताजा आईडी के साथ अभिभावक संबंध (हमारे उदाहरण में कक्षा), जबकि बच्चों के डेटा (विद्यार्थियों) को एजी अपडेट किया गया था मूल आईडी को छोड़ दें।

किसी भी सहायता के लिए अग्रिम धन्यवाद।

उत्तर

30

clone साथ बात है ...

जब एक वस्तु क्लोन है, PHP 5 ऑब्जेक्ट के गुणों के सभी की एक उथले प्रतिलिपि प्रदर्शन करेंगे। कोई भी गुण जो अन्य चर के संदर्भ हैं, संदर्भ बने रहेंगे।

आप सिद्धांत> = 2.0.2 का उपयोग कर रहे हैं, तो आप अपने स्वयं के कस्टम __clone लागू कर सकते हैं() विधि:

public function __clone() { 
    // Get current collection 
    $pupils = $this->getPupils(); 

    $this->pupils = new ArrayCollection(); 
    foreach ($pupils as $pupil) { 
     $clonePupil = clone $pupil; 
     $this->pupils->add($clonePupil); 
     $clonePupil->setClassroom($this); 
    } 
} 

नोट: इससे पहले कि सिद्धांत आप में एक __clone() विधि लागू नहीं कर सकते 2.0.2 अपने जेनरेट प्रॉक्सी क्लास के रूप में इकाई अपने __clone() लागू करती है जो parent::__clone() को चेक या कॉल नहीं करती है। इसलिए आपको इसके लिए clonePupils() (Classroom में) के लिए एक अलग विधि बनाना होगा और उस इकाई को क्लोन करने के बाद उसे कॉल करना होगा। किसी भी तरह से, आप अपने __clone() या clonePupils() विधियों के अंदर एक ही कोड का उपयोग कर सकते हैं।

जब आप अपने मूल वर्ग को क्लोन करते हैं, तो यह फ़ंक्शन बाल ऑब्जेक्ट क्लोन से भरा एक नया संग्रह भी बनाएगा।

$cloneClassroom = clone $classroom; 
$cloneClassroom->clonePupils(); 

$em->persist($cloneClassroom); 
$em->flush(); 

आप शायद अपने $pupils संग्रह बनी हुई हैं आसान बने बनाने के लिए झरना चाहता हूँ, जैसे

/** 
* @ORM\OneToMany(targetEntity="Pupil", mappedBy="classroom", cascade={"persist"}) 
*/ 
protected $pupils; 
+4

कि यह किया, धन्यवाद। मैं एक समारोह में लूप होने से बचने की उम्मीद कर रहा था लेकिन अंत में यह सबसे आसान समाधान था। मैंने देखा कि सिद्धांत की इकाई प्रबंधक वर्ग में एक "प्रतिलिपि" फ़ंक्शन है जिसे "दी गई इकाई की एक प्रति बनाता है। एक उथली या गहरी प्रतिलिपि बना सकता है।" एकमात्र पकड़ यह है कि फ़ंक्शन में एक पंक्ति होती है जो अपवाद फेंकता है "लागू नहीं किया गया।" – dividebyzeroZA

+2

वर्तमान सिद्धांत 2 में एफवाईआई आप अपने '__clone' को कार्यान्वित कर सकते हैं और इसे कॉल किया जाएगा। – jcbwlkr

-3

मैं यह कर:

if ($form->isValid()) { 
    foreach($classroom->getPupils() as $pupil) { 
     $pupil->setClassroom($classroom); 
    } 
    $em->persist($classroom); 
    $em->flush(); 
} 
+3

ऐसा नहीं लगता है कि यह नए छात्र उदाहरण बनाएगा; यह प्रत्येक छात्र को दो कक्षाओं के बीच साझा करेगा। –

2

मैं इसे इस और यह पसंद आया ठीक काम करता है।

क्लोन इकाई के अंदर हमारे पास जादू __clone() है। वहां हम अपने को एक से कई भी नहीं भूलते हैं।

/** 
* Clone element with values 
*/ 
public function __clone(){ 
    // we gonna clone existing element 
    if($this->id){ 
     // get values (one-to-many) 
     /** @var \Doctrine\Common\Collections\Collection $values */ 
     $values = $this->getElementValues(); 
     // reset id 
     $this->id = null; 
     // reset values 
     $this->elementValues = new \Doctrine\Common\Collections\ArrayCollection(); 
     // if we had values 
     if(!$values->isEmpty()){ 
      foreach ($values as $value) { 
       // clone it 
       $clonedValue = clone $value; 
       // add to collection 
       $this->addElementValues($clonedValue); 
      } 
     } 
    } 
} 
/** 
* addElementValues 
* 
* @param \YourBundle\Entity\ElementValue $elementValue 
* @return Element 
*/ 
public function addElementValues(\YourBundle\Entity\ElementValue $elementValue) 
{ 
    if (!$this->getElementValues()->contains($elementValue)) 
    { 
     $this->elementValues[] = $elementValue; 
     $elementValue->setElement($this); 
    } 

    return $this; 
} 

कहीं बस इसे क्लोन:

// Returns \YourBundle\Entity\Element which we wants to clone 
$clonedEntity = clone $this->getElement(); 
// Do this to say doctrine that we have new object 
$this->em->persist($clonedEntity); 
// flush it to base 
$this->em->flush();