Search code examples
phpzend-framework2zend-form

ZF2 Form getData with multiple fieldsets only returns data for one fieldset


I have two fieldsets in my form. I can hydrate the fieldsets by using setUseAsBaseFieldset(true) on the fieldset, so I can see the existing data in the form. When I post the form and use getData() I am only getting the data for one fieldset.

I suspect this is linked to how I have added the fieldset and my need to use setUseAsBaseFieldset(true) to hydrate them.

My system has three types of accounts - customer and two others. All of them have a basic username, password, role fieldset named customer.

The way my code is structured: I have an AccountForm which loads the customer fieldset, and my controller then adds the editor fieldset.

//AccountForm.php
public function __construct($config = array()) {
    parent::__construct($name = null);

    parent::setAttribute('method', 'post');
    parent::setAttribute('action', $config['action']);


    $this->setHydrator( new ArraySerializable () );

    $this->add(new CustomerFieldset(array('adapter' => $config['adapter'])));

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


}

//CustomerFieldset.php
    public function __construct($config) {
        parent::__construct('user');

        $this->adapter = $config['adapter'];

        $this->setObject(new User())
             ->setHydrator( new ArraySerializable (false));

        $this->setUseAsBaseFieldset(true);
        $this->add(array(
            'name' => 'id',
            'attributes' => array(
                'type' => 'hidden',
            ),
        ));


        $this->add(array(
            'name' => 'email',
            'type' => 'email',
            'attributes' => array(
                'id' => 'email',
                'required' => 'required',
                'class' => 'form-control',
            ),
            'options' => array(
                'label' => 'Email: ',
            ),
        ));
        $this->add(array(
            'name' => 'firstname',
            'type' => 'text',
            'attributes' => array(
                'id' => 'firstname',
                'required' => 'required',
                'class' => 'form-control',
            ),
            'options' => array(
                'label' => 'First Name: ',
            ),
        ));
        $this->add(array(
            'name' => 'lastname',
            'type' => 'text',
            'attributes' => array(
                'id' => 'lastname',
                'required' => 'required',
                'class' => 'form-control',
            ),
            'options' => array(
                'label' => 'Last Name: ',
            ),
        ));

        $this->add(array(
            'name' => 'role_id',
            'type' => 'select',
            'attributes' => array(
                'id' => 'role',
                'required' => 'required',
                'class' => 'form-control',
            ),
            'options' => array(
                'label' => 'Role: ',
                'empty_option' => 'Please select role',
                'value_options' => $this->getDbValues('acl_roles'),
            ),
        ));
        $this->add(array(
            'name' => 'password',
            'type' => 'password',
            'attributes' => array(
                'id' => 'password',
                'class' => 'form-control',
            ),
            'options' => array(
                'label' => 'Password (leave blank to not change): ',
            ),
        ));

        $this->add(array(
            'name'       => 'confirm-password',
            'type'       => 'Password',
            'attributes' => array(
                'id' => 'confirm-password',
                'class' => 'form-control',
            ),
            'options' => array(
                'label' => 'Confirm Password: ',
            ),
        ));

    }

//EditorFieldset.php
public function __construct() {
    parent::__construct('editor');

    $this->setObject(new Editor())
         ->setHydrator( new ArraySerializable (false));

    $this->add(array(
        'name' => 'id',
        'type' => 'hidden',
        'attributes' => array(
            'required' => true,
        ),
    ));
    $this->add(array(
        'name' => 'additional',
        'type' => 'text',
        'attributes' => array(
            'required' => true,
            'class' => 'form-control',
            'id' => 'additional',
        ),
        'options' => array(
            'label' => 'Additional Details: ',
        ),
    ));
    //... more elements
}

//controller
//$form already has customer fieldset. Add editor fieldset.
$form = $this->getForm();
$fieldset = new EditorFieldset();
$fieldset->setUseAsBaseFieldset(true); //set so I can bind to this fieldset
$form->add($fieldset);
/** @var $editor = row object */
$form->bind($editor);

$user = $form->get('user')->setUseAsBaseFieldset(true); //set so later I can bind to this fieldset
$form->remove('user'); //remove fieldset and re-add it with above param set
$form->add($user, array('priority' => 100)); // 100 - high priority - appear at top of form.

$userTable = $this->getServiceLocator()->get('Application\Model\CustomerTable');
$form->bind($userTable->fetchRowById($id));
$request = $this->getRequest();
if($request->isPost()) {
    $form->getInputFilterSpecification();
    $data = $request->getPost();
    $form->setData($data);
    if ($form->isValid()) {
        $validatedData = $form->getData();
        var_dump($validatedData); //debug
    }
 }
 //...view model and other stuff

[edit]

When I remove the setUseAsBaseFieldset(true) from the fieldsets, then I get all the values when I use getData(), however the form does not populate the fields.


Solution

  • Based on my last comment, I have wrapped my setUseAsBaseFieldset(true) statements in glorious if statements:

    if(!$this->getRequest()->isPost()) {
        $fieldset->setUseAsBaseFieldset(true);
    }
    

    I do not feel this is the correct solution. More of a hacky fix to a problem I've created.