php - Form with more than one collection -
i want realize form, quite simple. thing makes things complicated 'm using 2 collections in form. displaying 2 collections in view works charme. problem validation , associated hydration of bound entity of form. if validated , no errors occur form instance tries hydrate bound entity , ends exception:
zend\hydrator\arrayserializable::hydrate expects provided object implement exchangearray() or populate()
but first example code ...
the form classes
namespace application\form; use zend\form\element\collection; use zend\form\element\text; use zend\form\form; class myform extends form { public function __construct($name = '', $options = []) { parent::__construct($name, $options); $this->setattribute('method', 'post'); $this->setattribute('id', 'my-form'); } public function init() { $this->add([ 'name' => 'my-text-field', 'type' => text::class, 'attributes' => [ ... ], 'options' => [ ... ], ]); // first collection $this->add([ 'name' => 'first-collection', 'type' => collection::class, 'options' => [ 'count' => 2, 'should_create_template' => true, 'template_placeholder' => '__index__', 'allow_add' => true, 'allow_remove' => true, 'target_element' => [ 'type' => fieldsetone::class, ], ], ]); // second collection $this->add([ 'name' => 'second-collection', 'type' => collection::class, 'options' => [ 'count' => 2, 'should_create_template' => true, 'template_placeholder' => '__index__', 'allow_add' => true, 'allow_remove' => true, 'target_element' => [ 'type' => fieldsettwo::class, ], ], ]); } }
the metioned fieldset classes bound collections pretty same.
namespace application\form; use zend\form\element\number; use zend\form\fieldset; use zend\inputfilter\inputfilterproviderinterface; class fieldsetone extends fieldset implements inputfilterproviderinterface { public function init() { $this->add([ 'name' => 'my-number', 'type' => number::class, 'options' => [ ... ], 'attributes' => [ ... ], ]); } public function getinputfilterspecification() { return [ 'my-number' => [ 'required' => true, 'filters' => [ [ 'name' => striptags::class, ], [ 'name' => toint::class, ], ], 'validators' => [ [ 'name' => notempty::class, ], [ 'name' => isint::class, 'options' => [ 'locale' => 'de_de', ], ], ], ], ]; } }
summed form got 2 collections of number elements. data provided on form should end in following entity.
the input filter class
the form gets filtered , validated following input filter. input filter bound form via factory. factory shown later.
class myforminputfilter extends inputfilter { public function init() { $this->add([ 'name' => 'my-text-field', 'required' => true, 'filters' => [ [ 'name' => striptags::class, ], [ 'name' => stringtrim::class, ], ], ]); } }
the input filter contains settings my-text-field
element. collections validated implemented inputfilterproviderinterface
in fieldsets set target elements. input filter class created on factory , notated in input_filters
section in module.config.php
.
the form entity
the entity bound object form in factory looks following example.
namespace application\entity; class myformentity { protected $mytextfield; protected $firstcollection; protected $secondcollection; public function getmytextfield() { return $this->mytextfield; } public function setmytextfield($mytextfield) { $this->mytextfield = $mytextfield; return $this; } public function getfirstcollection() { return $this->firstcollection; } public function setfirstcollection(array $firstcollection) { $this->firstcollection = $firstcollection; return $this; } public function getsecondcollection() { return $this->secondcollection; } public function setsecondcollection(array $secondcollection) { $this->secondcollection = $secondcollection; return $this; } }
this entity bound object form. form hydrated zend 's own classmethods
hydrator class. collections 2 hydrator strategies added hydrator. hydrator strategies collections this.
namespace application\hydrator\strategy; class firstcollectionstrategy extends defaultstrategy { public function hydrate($value) { $aentities = []; if (is_array($value)) { foreach ($value $key => $data) { $aentities[] = (new classmethods(false))->hydrate($data, new collectiononeentity()); } } return $aentities; } }
this strategy hydrate data collection 1 corresponding entity.
all wrapped in factory
this factory creates form instance.
class myformfactory implements factoryinterface { public function createservice(servicelocatorinterface $servicelocator) { $parentlocator = $servicelocator->getservicelocator(); $filter = $parentlocator->get('inputfiltermanager')->get(myforminputfilter::class); $hydrator = (new classmethods()) ->addstrategy('first-collection', new firstcollectionstrategy()) ->addstrategy('second-collection', new secondcollectionstrategy()); $object = new myformentity(); $form = (new myform()) ->setinputfilter($filter) ->sethydrator($hydrator) ->setobject($object); return $form; } }
this factory mentionend in form_elements
section in module.config.php
file.
the problem
everything works fine. input element , collections rendered in view. if form submitted , $form->isvalid()
method gets called in controller ends in badmethodcallexception
.
zend\hydrator\arrayserializable::hydrate expects provided object implement exchangearray() or populate()
i have not bound collection entities form in controller because hydrator strategies added form hydrator should hydrate form entity. makes sense me, because zend form can bind 1 object. if call bind
method twice in controller, first bound object overwritten.
is possible add more 1 object bind
method of form 2 collections can handled? alternatives like? 'm doing wrong?
Comments
Post a Comment