2012-01-09 17 views
5

ho entità Basket e BasketItem:Come a persistere un oggetto con molti oggetti correlati

/** 
* Acme\BasketBundle\Entity\Basket 
* 
* @ORM\Entity(repositoryClass="Acme\BasketBundle\Repository\BasketRepository") 
* @ORM\Table(name="orders") 
* @ORM\HasLifecycleCallbacks() 
*/ 
class Basket 
{ 
    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    // ... 

    /** 
    * @ORM\OneToMany(targetEntity="BasketItem", mappedBy="order_id",cascade={"all"}) 
    */ 
    protected $items; 

    // ... 

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

    /** 
    * Add item 
    * 
    * @param BasketItem $item 
    */ 
    public function addItem(BasketItem $item) 
    { 
    $key = $this->find($item->getProduct()->getId()); 

    if ($key === false) { 
     $this->items->add($item); 
    } else { 
     $this->items->get($key)->raiseQuantity($item->getQuantity()); 
    } 
    } 

    /** 
    * Find an item (if present) 
    * 
    * @param integer $id 
    * @return integer 
    */ 
    public function find($id) 
    { 
    foreach ($this->items as $key => $item) { 
     if ($item->getProduct()->getId() == $id) 
      return $key; 
    } 
    return false; 
    } 
} 


/** 
* Acme\BasketBundle\Entity\BasketItem 
* 
* @ORM\Entity 
* @ORM\Table(name="order_items") 
*/ 
class BasketItem 
{ 
    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    // ... 

    /** 
    * @ORM\ManyToOne(targetEntity="Basket", inversedBy="items") 
    * @ORM\JoinColumn(name="order_id", referencedColumnName="id") 
    */ 
    private $basket; 

    // ... 
} 

Ora, quando creo un cesto e riempirlo con oggetti, io avere problemi a persistere nel db.

In seguito non funziona come previsto.

$basket = new Basket(); 
$basket->addItem(new BasketItem($product1, 1)); 
$basket->addItem(new BasketItem($product2, 2)); 

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

poi ho provato a seguito della manual più da vicino:

$basket = new Basket(); 
$basket->addItem(new BasketItem($product1, 1)); 
$basket->addItem(new BasketItem($product2, 2)); 

$em->persist($basket); 
foreach ($basket->getItems() as $item) { 
    $em->persist($item); 
} 
$em->flush(); 

Che non ha funzionato come previsto nessuno dei due.

In entrambi i casi tutti i dati viene salvato nel database ma gli elementi paniere non sono legati a canestro, vale a dire order_id dell'entità BasketItem è NULL.

Qualcuno può spiegarmi cosa sto facendo male, per favore? Si prega di notare che sono nuovo di Doctrine. Grazie!




EDIT:

Sono davvero confuso già. Ecco la mia prova semplificata:

<?php 

namespace Amsel\BasketBundle\Entity; 

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

/** 
* Amsel\BasketBundle\Entity\Basket 
* 
* @ORM\Entity(repositoryClass="Amsel\BasketBundle\Repository\BasketRepository") 
* @ORM\Table(name="orders") 
*/ 
class Basket 
{ 
    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var ArrayCollection $items 
    * 
    * @ORM\OneToMany(targetEntity="BasketItem", mappedBy="basket", cascade={"all"}) 
    */ 
    protected $items; 

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

    /** 
    * Add item 
    * 
    * @param BasketItem $item 
    */ 
    public function addItem(BasketItem $item) 
    { 
     $this->items->add($item); 
    } 

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

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


<?php 

namespace Amsel\BasketBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 


/** 
* Amsel\BasketBundle\Entity\BasketItem 
* 
* @ORM\Entity(repositoryClass="Amsel\BasketBundle\Repository\BasketItemRepository") 
* @ORM\Table(name="order_items") 
*/ 
class BasketItem 
{ 
    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var Basket $basket 
    * 
    * @ORM\ManyToOne(targetEntity="Basket", inversedBy="items") 
    * @ORM\JoinColumn(name="order_id", referencedColumnName="id") 
    */ 
    protected $basket; 


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

    /** 
    * Set basket 
    * 
    * @param Amsel\BasketBundle\Entity\Basket $basket 
    */ 
    public function setBasket(\Amsel\BasketBundle\Entity\Basket $basket) 
    { 
     $this->basket = $basket; 
    } 

    /** 
    * Get basket 
    * 
    * @return Amsel\BasketBundle\Entity\Basket 
    */ 
    public function getBasket() 
    { 
     return $this->basket; 
    } 
} 


public function testAction(Request $request) { 

    $em = $this->getDoctrine()->getEntityManager(); 

    $basket = new Basket(); 
    $basket->addItem(new BasketItem()); 
    $basket->addItem(new BasketItem()); 

    $em->persist($basket); 

    try { 
     $em->flush(); 
    } catch(Exception $e) { 
     die('ERROR: '.$e->getMessage()); 
    }   
    die ('end'); 
} 

Ma ancora - gli articoli di ordine (BasketItem) vengono memorizzati, ma sono non legato all'ordine (Basket).

+0

Can pubblichi il contenuto della tua funzione addItem? Fa internamente $ this-> items-> add ($ item); ? Il resto sembra ok .. –

+0

@Kees Schepers, grazie per la tua risposta! Ho aggiunto il metodo 'addItem' (e' find'). Se il resto è ok, sono davvero perso - altre idee che cosa potrei provare? – Czechnology

+0

Ho avuto qualche problema simile qualche tempo fa, specifichi il tuo campo $ order_id nella tua classe BasketItem forse? Perché questo può causare questi problemi. Se dubiti di poter postare la tua intera classe di entità basketitem. Il mio amico ha parlato di questo con me: http://pietervogelaar.nl/doctrine-2-use-foreign-key-as-field-in-dql/ –

risposta

3

Se comprendo correttamente il sistema, devo anche - perché è una relazione bidirezionale - assegnare manualmente controllante Basket ad ogni BasketItem entità.

public function testAction(Request $request) { 

    $em = $this->getDoctrine()->getEntityManager(); 

    $basket = new Basket(); 

    $bi1 = new BasketItem(); 
    $bi1->setBasket($basket); 

    $bi2 = new BasketItem(); 
    $bi2->setBasket($basket); 

    $basket->addItem($bi1); 
    $basket->addItem($bi2); 

    $em->persist($basket); 

    try { 
     $em->flush(); 
    } catch(Exception $e) { 
     die('ERROR: '.$e->getMessage()); 
    }   
    die ('end'); 
} 

Funziona bene come questo, ma se sto andando in un modo sbagliato, per favore correggetemi.

Grazie a tutti coloro che hanno avuto il tempo di guardare la mia domanda!

+0

Sì, è corretto. Tuttavia, dovresti renderlo facile con te stesso e associare il basket all'elemento _inside_ il metodo 'addItem' dell'entità basket. Kees Schepers lo ha sottolineato sopra. Questa è la cosa giusta da fare (in quanto significa che non puoi mai "dimenticare" di farlo in uno dei tuoi controller) – calumbrodie

+0

@kissmyface, sì, è così che l'ho fatto (il precedente è solo la prima versione che ho lavorato). Se l'ho capito bene, Kees mi ha appena chiesto se lo aggiungo alla collezione di oggetti. Ed è quello che ho pensato è abbastanza ... – Czechnology

3

La mappatura delle annotazioni è errata nell'entità Carrello: l'attributo "mappedBy" deve fare riferimento a un campo di entità, non a una colonna di database.

/** 
* @ORM\OneToMany(targetEntity="BasketItem", mappedBy="basket",cascade={"all"}) 
*/ 
protected $items; 
+0

Grazie, l'ho modificato ma non funziona ancora - la colonna 'order_id' rimane' NULL'. – Czechnology

+0

Cosa fa il costruttore BasketItem? Puoi pubblicare il suo contenuto? – AlterPHP

+0

Ho editato in un esempio semplificato che è 1: 1 quello che faccio. Non riesco a capire perché continua a fallire. – Czechnology

1

Sono nuovo a Symfony e Doctrine ma è strano. Ho insegnato che dovrebbe funzionare in entrambi i modi, ma sembra che u deve impostare carrello su BasketItem

$bi->setBasket($basket); 

se u vuole fare funzionare in entrambi i modi, ad esempio:

$basket->addItem($bi); 

u have per modificare il metodo addItem e removeItem metodo

/** 
* Add item 
* 
* @param BasketItem $item 
*/ 
public function addItem(BasketItem $item) 
{ 
    $item->setBasket($this); 
    $this->items->add($item); 
} 

/** 
* Remove item 
* 
* @param BasketItem $item 
*/ 
public function removeItem(BasketItem $item) 
{ 
    $item->setBasket(null); 
    $this->items->removeElement($item); 
} 

[EDIT] guardare questo: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#owning-and-inverse-side-on-a-manytomany-association

Problemi correlati