2014-02-28 102 views
0

我正在努力设置实体正确的时刻。 Here's情况:学说和ZF2:存储ManyToOne关系没有级联

“国家”有一个或多个“客户”

从来就与所有国家的国家表,我想保存与每个客户一个参考的国家。非常简单并且经常需要。

但我无法正确配置实体。如果我不在“客户”类中定义级联方法,则会发生异常。如果我添加一个级联方法,那么country对象也会作为新记录添加到country表中,但我只想在Customer表中引用此对象。

Customer类

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

/** 
* @ORM\ManyToOne(targetEntity="Country",inversedBy="id") 
* @ORM\JoinColumn(name="country_id", referencedColumnName="id") 
*/ 
protected $country; 
} 

国家类

/** 
* @ORM\Entity 
* @ORM\Table(name="PS_Country") 
*/ 
class Country { 
    /** 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    * @ORM\Column(type="integer") 
    * @ORM\OneToMany(targetEntity="Customer", mappedBy="country") 
    */ 
    protected $id; 

    /** @ORM\Column(type="string") */ 
    protected $name; 

    /** @ORM\Column(type="string") */ 
    protected $iso2; 

} 

如果我想存储的客户对象与此定义,我收到以下错误:

A new entity was found through the relationship 'Photoshop\Entity\Customer#country' that was not configured to cascade persist operations for entity: Photoshop\Entity\[email protected] To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Photoshop\Entity\Country#__toString()' to get a clue. 

的ActionController(提取):

$forms = $this->getServiceLocator()->get('FormElementManager'); 
$form = $forms->get('Photoshop\Form\CheckoutForm'); 
$customer = new Customer; 
$form->bind($customer); 

$order = new Order; 
$order->setCustomer($customer); 

// Order object is put into a session during checkout process here... 

/** 
* Commit Order to database 
*/ 
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager'); 
$em->persist($sessionCheckout->order); // Fetch the order object from session 
$em->flush(); 

检验表

class CheckoutForm extends Form implements ObjectManagerAwareInterface { 

    protected $objectManager; 

    public function __construct() { 
     parent::__construct('checkout'); 

    } 

    public function init() { 

     $this->setAttribute('action', 'checkout'); 
     $this->setAttribute('method', 'post'); 
     $this->setHydrator(new DoctrineHydrator($this->getObjectManager())); 
     $this->setInputFilter(new \Photoshop\Form\CheckoutFilter()); 

     $this->add(array(
      'name' => 'country', 
      'type' => 'DoctrineModule\Form\Element\ObjectSelect', 
      'options' => array(
       'label' => 'Country:', 
       'empty_option' => 'Please choose...', 
       'object_manager' => $this->getObjectManager(), 
       'target_class' => 'Photoshop\Entity\Country', 
       'property' => 'name', 
      ), 
     )); 

     $this->add(array(
      'type' => 'Zend\Form\Element\Select', 
      'name' => 'gender', 
      'options' => array(
       'label' => 'Title*:', 
       'empty_option' => 'Please choose...', 
       'value_options' => array(
        'f' => 'Mrs.', 
        'm' => 'Mr.' 
       ), 
      ) 
     )); 

     $this->add(array(
      'name' => 'firstName', 
      'attributes' => array(
       'type' => 'text', 
       'id' => 'firstName' 
      ), 
      'options' => array(
       'label' => 'First name*:' 
      ), 
     )); 

     $this->add(array(
      'name' => 'lastName', 
      'attributes' => array(
       'type' => 'text', 
       'id' => 'lastName' 
      ), 
      'options' => array(
       'label' => 'Last name*:' 
      ), 
     )); 


     $this->add(array(
      'name' => 'submit', 
      'attributes' => array(
       'type' => 'submit', 
       'value' => 'Pay with PayPal or Credit Card now', 
       'class' => 'btn btn-primary btn-lg btn-block' 
      ) 
     )); 

    } 

    public function setObjectManager(ObjectManager $objectManager) { 
     $this->objectManager = $objectManager; 
    } 

    /** 
    * Get the object manager 
    * 
    * @return ObjectManager 
    */ 
    public function getObjectManager() { 
     return $this->objectManager; 
    } 

} 

I'm相当肯定,这将是简单的解决。但目前我无法看到解决方案:)

也许有人可以给我一个提示?!?应该理解,...

感谢, 迈克尔

+0

您可以添加创建和存储客户的代码吗? – jkavalik

+0

当然,我已经添加了控制器(一个提取的版本)和上面的表单类。 – Michael

回答

2

//订单对象在这里结帐过程中放入会话... ----这就是重要组成部分

所以,如果我的理解,您可以在一个请求中创建订单和客户,然后通过会话将其转移到其他请求并将其保存在那里。真正发生的事情是,你有对象图,像order-> customer-> country,前两个是新实体,所以序列化反序列化没有任何问题,但国家是DB中已经存在的管理实体。通过将它序列化到会话中,它从实体管理器中分离出来,并且在反序列化之后,它被呈现给新的实体管理器实例,该实例管理器实例不知道它曾经被管理过,因此决定坚持是新的实体管理器实例。

通常你需要序列化的实体合并到当前实体管理器

$managedOrder = $em->merge($sessionCheckout->order); 

,并与$ managedOrder工作。为此,您可能需要在Customer :: country和Order :: customer上设置cascade = {“merge”}。

主义有Entities in session有关此主题的文档页面。

+0

好吧..听起来像一个很好的计划:)我会尝试,谢谢你的提示 – Michael

+0

太棒了,非常感谢解决方案!我只需另外将级联更改为与订单中n:m关系的订单项“合并”(未在以上示例中显示)。 – Michael