How to properly hydrate and extract Doctrine Entities from Zend Forms

608 views Asked by At

I'm just starting out with Doctrine and was rewriting some code to use Doctrine entities in some Forms.

I have an Entity Business which has some 1:n relations with addresses, employees, emails etc. the Setup is really basic and working fine.

To add new Businesses i created a BusinessForm and Fieldsets for each of my entities. Here the constructor of the form:

public function __construct($scenario='create', $entityManager = null) {
    parent::__construct('business_form');
    $this->scenario = $scenario;
    $this->entityManager = $entityManager;
    $this->setAttribute('method', 'post');

    $businessFieldset = new BusinessFieldset($this->entityManager);
    $businessFieldset->setUseAsBaseFieldset(true);
    $this->add($businessFieldset);

    $hydrator = new DoctrineHydrator($this->entityManager, new Business());
    $this->setHydrator($hydrator);
    $this->addElements();
    $this->addInputFilter();
}

addElements just adds a Submit and CSRF input.

And here the Controller action:

public function addAction(){
    $form = new BusinessForm('create', $this->entityManager);
    if ($this->getRequest()->isPost()) {
        $data = $this->params()->fromPost();                
        $form->setData($data);
        if($form->isValid()) {
            // save Object
            return $this->redirect()->toRoute('subcontractor', ['action'=>'index']);                
        }      
    } 
    return new ViewModel([
        'form' => $form
    ]);
}

The form validates and i can get the Data from the form with $form->getData(). But i cant figure out how to get a populated Object from the form using the form's hydrator. When I use setObject(new Business()) at the start of the controller i get an error while $form->isValid() is running :

Zend\Hydrator\ArraySerializable::extract expects the provided object to implement getArrayCopy()

Isnt that the wrong hydrator being called ?

If i dont setObject() but instead use $form->bind(new Business()) after the validation i get an empty Object from $form->getObject(). If i get the data and hydrate a new Object with the form's hydrator like so : $form->getHydrator()->hydrate($data['business], new Business()) i do get the populated Object i was expecting. (Business being the name of the base fieldset)

So my question is, how to i get the result of the last call from just using $form->getObject() after the validation?

[EDIT]

The Problem seems to be with the Collections of Fieldsets used as sub-fieldsets in the businessfieldset. If i validate the form without using the collections i do get the expected Business Object from $form->getData()

Here an example how i add the collection (in the business fieldset):

$this->add([
        'name' => 'emails',
        'type' => 'Zend\Form\Element\Collection',
        'attributes' => [
            'id' => 'business_emails',
        ],
        'options' => [
            'label' => 'Emails',
            'count' => 1,
            'should_create_template' => true,
            'template_placeholder' => '__index__',
            'allow_add' => true,
            'target_element' => [
                'type' => 'LwsSubcontractor\Form\EmailFieldset',
            ],
            'target_class' => 'LwsSubcontractor\Entity\Email'
        ],
    ]);

and here the EmailFieldset:

public function __construct() {
    parent::__construct('email');
    $this->setObject(new Email());
    $this->addElements();        
}

protected function addElements() {
    $this->add([
        'name' => 'email',
        'type' => 'Zend\Form\Element\Email',
        'attributes' => [
            'placeholder' => 'E-Mail (z.B. [email protected])',
            'class' => 'form-control',
            'required' => true,
            'size' => 50,
        ],
        'options' => [
            'label' => 'Email',
        ],
    ]);        

}

}

If using the Collections i get the Error message from above. So after adding a hydrator to each Fieldset i was fine.

Although i was under the impression that setting the hydrator for the form would result in the used fieldsets to inherit that hydrator.Or was this because of using the fieldsets as collections and not directly ?

1

There are 1 answers

0
Garry On BEST ANSWER

You have to add the hydrator to all your fieldsets, personally I use DoctrineModule\Stdlib\Hydrator\DoctrineObject for doctrine entities.

I would also look at using the init() method to initialize your forms and add elements then register and retrieve your form and fieldsets through the FormElementManager, $serviceLocator->get('FormElementManager')->get(yourFieldsetorForm::class). The form can than be injected into your controller.

I hope this helps.