2015-04-07 37 views
0

我有以下設置:ZF2:表格嵌套字段集 - 學說保溼嘗試添加新實體的所有對象

我有一些相關的學說實體Product主義對象。

/** 
* Product 
* 
* @ORM\Table(name="products") 
* @ORM\Entity(repositoryClass="\Entities\ProductRepository") 
*/ 

class Product 
{ 
/** 
* @var integer 
* 
* @ORM\Column(name="id", type="integer", precision=0, scale=0, nullable=false, unique=false) 
* @ORM\Id 
* @ORM\GeneratedValue(strategy="IDENTITY") 
*/ 
private $id; 

/** 
* @var string 
* 
* @ORM\Column(name="artist", type="string", length=100, precision=0, scale=0, nullable=false, unique=false) 
*/ 
private $artist; 

/** 
* @var string 
* 
* @ORM\Column(name="title", type="string", length=100, precision=0, scale=0, nullable=false, unique=false) 
*/ 
private $title; 

/** 
* @var string 
* 
* @ORM\Column(name="subtitle", type="string", length=100, precision=0, scale=0, nullable=true, unique=false) 
*/ 
private $subtitle; 

/** 
* @var string 
* 
* @ORM\Column(name="labelcode", type="string", length=100, precision=0, scale=0, nullable=false, unique=false) 
*/ 
private $labelcode; 

/** 
* @var string 
* 
* @ORM\Column(name="description", type="string", length=100, precision=0, scale=0, nullable=true, unique=false) 
*/ 
private $description; 

/** 
* @var string 
* 
* @ORM\Column(name="hints", type="text", precision=0, scale=0, nullable=true, unique=false) 
*/ 
private $hints; 

/** 
* @var string 
* 
* @ORM\Column(name="price", type="decimal", precision=0, scale=2, nullable=false, unique=false) 
*/ 
private $price; 

/** 
* @var integer 
* 
* @ORM\Column(name="amount", type="integer", precision=0, scale=0, nullable=true, options={"default" = 0}, unique=false) 
*/ 
private $amount; 

/** 
* @var string 
* 
* @ORM\Column(name="image", type="string", length=100, precision=0, scale=0, nullable=true, unique=false) 
*/ 
private $image; 

/** 
* @var \DateTime 
* 
* @ORM\Column(name="instockdate", type="date", precision=0, scale=0, nullable=true, unique=false) 
*/ 
private $instockdate; 

/** 
* @var boolean 
* 
* @ORM\Column(name="ownrelease", type="boolean", precision=0, scale=0, nullable=true, columnDefinition="BOOLEAN DEFAULT FALSE", unique=false) 
*/ 
private $ownrelease; 

/** 
* @var \Entities\Label 
* 
* @ORM\ManyToOne(targetEntity="Entities\Label", inversedBy="products") 
* @ORM\JoinColumns({ 
* @ORM\JoinColumn(name="label_id", referencedColumnName="id", nullable=false) 
* }) 
*/ 
private $label; 

/** 
* @var \Entities\Genre 
* 
* @ORM\ManyToOne(targetEntity="Entities\Genre", inversedBy="products")) 
* @ORM\JoinColumns({ 
* @ORM\JoinColumn(name="genre_id", referencedColumnName="id", nullable=false) 
* }) 
*/ 
private $genre; 

/** 
* @var \Entities\Type 
* 
* @ORM\ManyToOne(targetEntity="Entities\Type") 
* @ORM\JoinColumns({ 
* @ORM\JoinColumn(name="type_id", referencedColumnName="id", nullable=false) 
* }) 
*/ 
private $type; 

/** 
* @var \Entities\Webshop 
* 
* @ORM\ManyToOne(targetEntity="Entities\Webshop", inversedBy="products") 
* @ORM\JoinColumns({ 
* @ORM\JoinColumn(name="webshop_id", referencedColumnName="id", nullable=true) 
* }) 
*/ 
private $webshop; 

/** 
* @var \Entities\Supplier 
* 
* @ORM\ManyToOne(targetEntity="Entities\Supplier") 
* @ORM\JoinColumns({ 
* @ORM\JoinColumn(name="supplier_id", referencedColumnName="id", nullable=true) 
* }) 
*/ 
private $supplier; 

/** Getters and Setters **/ 
} 

我有一個CreateProductForm

class CreateProductForm extends Form implements InputFilterProviderInterface 
{ 

protected $objectManager; 

public function __construct(ObjectManager $objectManager) 
{ 
    parent::__construct('create-product-form'); 
    $this->setObjectManager($objectManager); 

    $this->setHydrator(new DoctrineHydrator($this->getObjectManager())); 

    $this->addElements(); 
} 

public function addElements() 
{ 
    // Add the product fieldset, and set it as the base fieldset 
    $productFieldset = new ProductFieldSet($this->getObjectManager()); 
    $productFieldset->setUseAsBaseFieldset(true); 
    $this->add($productFieldset); 

    // Add a checkbox allowing creation of another \Entities\Product 
    $this->add(array(
     'type' => 'Zend\Form\Element\Checkbox', 
     'name' => 'create_another_product', 
     'attributes' => array(
      'required' => FALSE, 
      'allow_empty' => TRUE, 
     ), 
     'options' => array(
      'label' => 'Create another', 
      'use_hidden_element' => TRUE, 
      'checked_value' => TRUE, 
      'unchecked_value' => FALSE, 
      'label_attributes' => array(
       'class' => 'control-label' 
      ), 
     ), 
    )); 

    // … add CSRF and submit elements … 
    $this->add(array(
     'type' => 'Zend\Form\Element\Csrf', 
     'name' => 'create_product_csrf', 
     'options' => array(
      'csrf_options' => array(
       'timeout' => 600 
      ) 
     ) 
    )); 

    $this->add(array(
     'name' => 'submit', 
     'type' => 'Submit', 
     'attributes' => array(
      'value' => 'Go', 
      'id' => 'submitbutton', 
      'class' => 'btn btn-primary' 
     ), 
    )); 
} 

/** 
* Get objectManager 
* 
* @return type 
*/ 
public function getObjectManager() 
{ 
    return $this->objectManager; 
} 

/** 
* Set objectManager 
* 
* @param ObjectManager $objectManager 
* @return \Cms\Form\ProductForm 
*/ 
public function setObjectManager(ObjectManager $objectManager) 
{ 
    $this->objectManager = $objectManager; 

    return $this; 
} 

/** 
* Should return an array specification compatible with 
* {@link Zend\InputFilter\Factory::createInputFilter()}. 
* 
* @return array 
*/ 
public function getInputFilterSpecification() 
{ 
    return array(
     'create_another_product' => array(
      'required' => FALSE, 
      'allow_empty' => TRUE, 
    )); 
} 
} 

我會顯示兩個字段集一個產品和一個用於相關實體:

class ProductFieldSet extends Fieldset implements InputFilterProviderInterface 
{ 

/** 
* @var ObjectManager 
* 
*/ 
protected $objectManager; 

/** 
* @var InputFilter 
* 
*/ 
protected $inputFilter; 

public function __construct(ObjectManager $objectManager) 
{ 
    parent::__construct('product'); 

    $this->setObjectManager($objectManager); 


    $this->setHydrator(new DoctrineEntity($this->getObjectManager()))->setObject(new Product()); 

    $this->addElements(); 
} 

public function addElements() 
{ 
    $this->add(array(
     'name' => 'id', 
     'type' => 'Hidden', 
    )); 

    $this->addLabelCode(); 
    $this->addArtist(); 
    $this->addTitle(); 
    $this->addDescription(); 
    $this->addPrice(); 
    $this->addHints(); 

    $this->add(array(
     'name' => 'subtitle', 
     'type' => 'Text', 
     'options' => array(
      'label' => 'Subtitle', 
     ), 
     'attributes' => array(
      'class' => 'form-control', 
     ), 
    )); 


    $this->add(array(
     'name' => 'amount', 
     'type' => 'Text', 
     'options' => array(
      'label' => 'Amount', 
     ), 
    )); 

    $date = new Date('instockdate'); 
    $date 
      ->setLabel('In Stock Date') 
      ->setAttributes(array(
       'min' => '2012-01-01', 
       'max' => '2200-01-01', 
       'step' => '1', // days; default step interval is 1 day 
    )); 



    $this->addGenre(); 
    $this->addLabel(); 
    $this->addType(); 
} 
// A lot of add methods 

/** 
* Add Type to the Cms\Form\ProductFieldSet 
*/ 
private function addType() 
{ 
    $typeFieldset = new TypeFieldSet($this->getObjectManager()); 
    $typeFieldset->setName('type'); 
    //$labelFieldset->setAttribute('required', TRUE); 
    //$labelFieldset->setAttribute('class', 'form-control'); 

    $typeFieldset->setLabel('Type'); 
    //$labelFieldset->setLabelAttributes(array('class' => 'control-label')); 

    $this->add($typeFieldset); 
} 
} 

而現在的TypeFieldSet

class TypeFieldSet extends Fieldset implements InputFilterProviderInterface 
{ 

/** 
* @var ObjectManager 
* 
*/ 
protected $objectManager; 

/** 
* @var InputFilter 
* 
*/ 
protected $inputFilter; 

/** 
* Construct Cms\Form\GenreFieldSet. 
* 
* @param ObjectManager $objectManager 
*/ 
public function __construct(ObjectManager $objectManager) 
{ 
    parent::__construct('type'); 

    $this->setObjectManager($objectManager); 

    $this->setHydrator(new DoctrineEntity($this->getObjectManager()))->setObject(new Type()); 

    $this->addElements(); 
} 

/** 
* Method responsible for adding elements to \Cms\Form\Fieldset. 
*/ 
public function addElements() 
{ 
    $this->add(array(
     'name' => 'name', 
     'type' => 'Zend\Form\Element\Text', 
     'attributes' => array(
      'required' => true, 
      'id' => 'name', 
      'class' => 'form-control', 
      'placeholder' => 'Enter type name' 
     ), 
     'options' => array(
      'label' => 'Name', 
      'label_attributes' => array(
       'class' => 'control-label' 
      ), 

     ), 
    )); 
} 
// Additional methods 
} 

不知何故,學說試圖將所有相關實體添加爲新實體,並且根據我輸入的名稱未找到與現有實體相關的實體。

任何人都可以幫我嗎?

- 編輯

因此,實際上我沒有相關實體的ID存在。控制器代碼如下所示:

嗨,所以缺少ID,因爲我使用名稱來標識相關對象。我的控制器看起來是這樣的:

// Get your ObjectManager from the ServiceManager 
    $objectManager = $this->getServiceLocator()->get('Doctrine\ORM 
    \EntityManager'); 

    // Create the form and inject the ObjectManager 
    $form = new CreateProductForm($objectManager); 

    // Create a new, empty entity and bind it to the form 
    $product = new Product(); 
    $form->bind($product); 

    if ($this->request->isPost()) 
    { 
     $form->setData($this->request->getPost()); 

     if ($form->isValid()) 
     { 

      $this->getProductService()->saveProduct($product); 

      $this->flashMessenger()->addSuccessMessage('Product ' . $product->getName() . ' saved'); 

       return $this->redirect()->toRoute('product'); 
     } 
     else 
     { 
      $this->flashMessenger()->addErrorMessage($form->getMessages()); 
     } 
    } 

    return new ViewModel(array(
     'product' => $product, 
     'form' => $form 
    )); 
} 

我應該得到相關的ID在控制器或者是有一個更微妙的方式做到這一點? 在官方示例https://github.com/doctrine/DoctrineModule/blob/master/docs/hydrator.md#a-complete-example-using-zendform中沒有在控制器代碼中獲得ID。

+0

我認爲你需要顯示控制器代碼(假設控制器是您實際使用表單保存/綁定實體的位置。 –

回答

1

我不能完全弄清楚你在這裏發佈的大量代碼是通過什麼字段/數據,而是使水合物從數據庫中找到並使用現有實體,然後使用這些實體來水化新對象您需要傳遞與關聯對象的標識符對應的字段。

因此,假設您想要創建一個新的Product與現有的Genre這意味着將genre_id傳遞到數據中。因此,像這樣:

$hydrator = new DoctrineObject($objectManager); 

$data = array(
    "genre" => array(
     "genre_id" => 1 
    ) 
); 

$product = new Product(); 

$hydrator->hydrate($data, $product); 

在這個非常基本的代碼示例水化將從Genre實體識別標識字段中使用保溼新Product之前要收集它。所以如果你在你的數據集中傳遞標識符字段,它應該可以工作。

DoctrineObject將不會收集任何使用非標識符字段的實體。因此,如果您想通過除標識符字段之外的任何字段,則假定您希望與新實體建立新關聯,並且它將使用您傳遞的數據來爲新相關實體提供保溼。

如果通過標識符字段是你在做什麼,這是行不通的,那麼請詳細哪些數據是準確地傳遞解釋...