2015-04-07 2 views
0

У меня есть следующие настройки:ZF2: Форма с вложенным Fieldsets - Учение Hydrator пытается добавить новые объекты для всех объектов

У меня есть Product Doctrine объект с некоторыми другими соответствующими подразделениями доктрины.

/** 
* 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, 
    )); 
} 
} 

Я покажу вам два FieldSets один для продукта и один для соответствующего объекта:

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 
} 

Как-то Доктрина пытается добавить все связанные сущности в качестве нового объекта, а не обнаруживать, что существующий объект связан с именем, которое я вводил.

Может ли кто-нибудь помочь мне?

- Edit

Так на самом деле у меня нет идентификационного НАСТОЯЩЕЕ связанных лиц. Код контроллера выглядит так:

Привет, поэтому идентификатор отсутствует, потому что я использую это имя для идентификации связанного объекта. Мой контроллер выглядит так:

// 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 
    )); 
} 

Должен ли я получить связанные идентификаторы в контроллере или есть более тонкий способ сделать это? В официальном примере https://github.com/doctrine/DoctrineModule/blob/master/docs/hydrator.md#a-complete-example-using-zendform никаких идентификаторов не получено в коде контроллера.

+0

Я думаю, что вам нужно, чтобы показать код контроллера (предполагается, что контроллер это место, где вы фактически сохраняете/связываете объект с формой. –

ответ

1

Я не могу полностью выяснить, какие поля/данные вы передаете из огромного количества кода, который вы разместили здесь, но чтобы заставить гидратор DoctrineObject найти и использовать существующие сущности из базы данных и впоследствии использовать их для увлажнения вашего нового объекта вам необходимо передать поле, соответствующее идентификаторам ассоциируемых объектов.

Предположим, вы хотите создать новый 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 не будет собирать какие-либо объекты, используя поля, отличные от идентификатора. Поэтому, если вы передадите какие-либо поля с идентификатором, предполагается, что вы хотите создать новую связь с новым сущностью и будете использовать данные, которые вы передаете, для гидратации нового связанного объекта.

Если прохождения поля идентификатора является то, что вы делаете, и это не работает, то, пожалуйста, объясните подробно, какие данные вы точно передавая ...

Смежные вопросы