Hi,
I am trying to create some more complex forms (involving One-to-Many
relations in my case).entirelly using annotations (no separated
fieldsets created).
Is this entirely possible using annotations or I still need to create
separated fieldsets aggregate manually ?
After submitting the form it seems to have a hydrator issue I cant find
a solution to fix. I used 2 very simple entities illustrating my problem.
=================================
=== ERROR ===
=================================
AN ERROR OCCURRED
An error occurred during execution; please try again later.
Additional information:
Zend\Stdlib\Exception\BadMethodCallException
File:
/home/demo/vendor/zendframework/zendframework/library/Zend/Stdlib/Hydrator/ArraySerializable.php:78
Message:
Zend\Stdlib\Hydrator\ArraySerializable::hydrate expects the provided
object to implement exchangeArray() or populate()
Stack trace:
#0
/home/demo/vendor/zendframework/zendframework/library/Zend/Form/Fieldset.php(597):
Zend\Stdlib\Hydrator\ArraySerializable->hydrate(Array, NULL)
#1
/home/demo/vendor/zendframework/zendframework/library/Zend/Form/Element/Collection.php(273):
Zend\Form\Fieldset->bindValues(Array)
#2
/home/demo/vendor/zendframework/zendframework/library/Zend/Form/Fieldset.php(585):
Zend\Form\Element\Collection->bindValues(Array)
#3
/home/demo/vendor/zendframework/zendframework/library/Zend/Form/Form.php(364):
Zend\Form\Fieldset->bindValues(Array)
#4
/home/demo/vendor/zendframework/zendframework/library/Zend/Form/Form.php(513):
Zend\Form\Form->bindValues()
#5
/home/demo/module/Imagis/src/Imagis/Controller/AnnotationController.php(....):
Zend\Form\Form->isValid()
#7
/home/demo/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractActionController.php(83):
Test\Controller\AnnotationController->addAction()
#8 [internal function]:
Zend\Mvc\Controller\AbstractActionController->onDispatch(Object(Zend\Mvc\MvcEvent))
#9
/home/demo/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(468):
call_user_func(Array, Object(Zend\Mvc\MvcEvent))
#10
/home/demo/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(207):
Zend\EventManager\EventManager->triggerListeners('dispatch',
Object(Zend\Mvc\MvcEvent), Object(Closure))
#11
/home/demo/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php(117):
Zend\EventManager\EventManager->trigger('dispatch',
Object(Zend\Mvc\MvcEvent), Object(Closure))
#12
/home/demo/vendor/zendframework/zendframework/library/Zend/Mvc/DispatchListener.php(114):
Zend\Mvc\Controller\AbstractController->dispatch(Object(Zend\Http\PhpEnvironment\Request),
Object(Zend\Http\PhpEnvironment\Response))
#13 [internal function]:
Zend\Mvc\DispatchListener->onDispatch(Object(Zend\Mvc\MvcEvent))
#14
/home/demo/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(468):
call_user_func(Array, Object(Zend\Mvc\MvcEvent))
#15
/home/demo/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(207):
Zend\EventManager\EventManager->triggerListeners('dispatch',
Object(Zend\Mvc\MvcEvent), Object(Closure))
#16
/home/demo/vendor/zendframework/zendframework/library/Zend/Mvc/Application.php(313):
Zend\EventManager\EventManager->trigger('dispatch',
Object(Zend\Mvc\MvcEvent), Object(Closure))
#17 /home/demo/public_html/index.php(17): Zend\Mvc\Application->run()
#18 {main}
=================================
=== Brand entity ===
=================================
/**
* @ORM\Entity
* @ORM\Table(name="test_brands",
uniqueConstraints={@ORM\UniqueConstraint(name="name", columns={"name"})})
*/
class Brand {
/**
* @var int
* @ORM\Id
* @ORM\Column(type="integer", nullable=false,
options={"unsigned"=true})
* @ORM\GeneratedValue(strategy="IDENTITY")
* @Annotation\Exclude()
*
*/
protected $id;
/**
* @var string
* @Annotation\Type("Zend\Form\Element\Text")
* @Annotation\Options({"label":"Brand Name"})
* @Annotation\Required(true)
* @ORM\Column(type="string", length=32, unique=true, nullable=false)
*/
protected $name;
/**
*
@Annotation\ComposedObject({"target_object":"\Test\Entity\Model",
"is_collection":"true", "options":{"count":2,
"should_create_template":"true", "allow_add":"true",
"allow_remove":"true"}})
* @ORM\OneToMany(targetEntity="Test\Entity\Model",
mappedBy="product", cascade={"persist"})
*/
protected $models;
public function __construct() {
$this->models = new ArrayCollection();
}
/**
* Get id.
*
* @return int
*/
public function getId() {
return $this->id;
}
/**
* Set id.
*
* @param int $id
*
* @return void
*/
public function setId($id) {
$this->id = (int) $id;
}
/**
* Set name
*
* @param string $name
* @return Brand
*/
public function setName($name) {
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Add models
*
* @param \Doctrine\Common\Collections\Collection $models
*/
public function addModels($models) {
foreach ($models as $model) {
$model->setBrand($this);
$this->models->add($model);
}
}
/**
* Remove models
*
* @param \Doctrine\Common\Collections\Collection $models
*/
public function removeModels($models) {
foreach ($models as $model) {
$model->setBrand(null);
$this->models->removeElement($model);
}
}
/**
* Get models
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getModels() {
return $this->models;
}
}
=================================
=== Model entity ===
=================================
/**
* @ORM\Entity
* @ORM\Table(name="test_models")
* @Annotation\Name("Model")
* @Annotation\Type("fieldset")
*/
class Model {
/**
* @var int
* @ORM\Id
* @ORM\Column(type="integer", nullable=false,
options={"unsigned"=true})
* @ORM\GeneratedValue(strategy="IDENTITY")
* @Annotation\Exclude()
*/
protected $id;
/**
* @var string
* @Annotation\Flags({"priority": 100})
* @Annotation\AllowEmpty(true)
* @Annotation\Type("Zend\Form\Element\Text")
* @Annotation\Options({"label":"Model name"})
* @ORM\Column(type="string", nullable=false)
*/
protected $name;
/**
* @Annotation\Exclude()
* @ORM\ManyToOne(targetEntity="Test\Entity\Brand",
inversedBy="models")
* @ORM\JoinColumn(name="brand", referencedColumnName="id",
onDelete="CASCADE")
*/
protected $brand;
/**
* Get id
*
* @return integer
*/
public function getId() {
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Model
*/
public function setName($name) {
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName() {
return $this->name;
}
public function setBrand(Brand $brand = null) {
$this->brand = $brand;
}
public function getBrand() {
return $this->brand;
}
}
=================================
=== Controller ===
=================================
$entityClass = '\Test\Entity\Brand';
$id = $this->params()->fromRoute('id');
//update
if (!empty($id)) {
$repository = $this->getObjectManager()->getRepository($entityClass);
$this->entity = $repository->find($id);
} else {//create
$this->entity = new $entityClass();
}
//form generation
$builder = new DoctrineAnnotationBuilder($this->getObjectManager());
$this->form = $builder->createForm($this->entity);
$this->form->setHydrator(new DoctrineHydrator($this->getObjectManager(),
$entityClass))
->setObject($this->entity);
$this->form->add(array(
'type' => 'Zend\Form\Element\Csrf',
'name' => 'security',
'options' => array(
'csrf_options' => array(
'timeout' => 600
)
)
));
$this->form->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'save',
),
));
//end form generation
$this->form->bind($this->entity);
$request = $this->getRequest();
if ($request->isPost()):
$dataForm = array_replace_recursive(
$request->getPost()->toArray(), $request->getFiles()->toArray()
);
$this->form->setData($dataForm);
if ($this->form->isValid()):
$this->getObjectManager()->persist($this->entity);
$this->getObjectManager()->flush();
endif;
endif;
Thank you,
Cristian