Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Nested collections and setValidationGroup() #6363

Closed
ant7 opened this issue Jun 10, 2014 · 8 comments
Closed

Nested collections and setValidationGroup() #6363

ant7 opened this issue Jun 10, 2014 · 8 comments

Comments

@ant7
Copy link
Contributor

ant7 commented Jun 10, 2014

I have the following setup:
form > fieldset > collection > fieldset > collection > fieldset (planId)

The issue appears when:

  1. set the validation group on the form, including the nested collection elements
  2. pass incomplete form data for the nested collection to setData()
  3. call isValid() for the form

Result: an error is thrown

Zend\InputFilter\BaseInputFilter.php:568: setValidationGroup() expects a list of valid input names; "planId" was not found.

This doesn't happen if I remove the nested collection and pass incomplete data for the first collection.

PlanComparison Form:

namespace PlanComparison\Form;

use Zend\Form\Form;
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator;

class PlanComparison extends Form
{   
    public function __construct()
    {
        parent::__construct('planComparison');

        $this->setAttribute('method', 'post')
             ->setHydrator(new ClassMethodsHydrator(false));

        $this->add(array(
            'type' => '\PlanComparison\Form\PlanComparisonFieldset',
            'options' => array(
                 'use_as_base_fieldset' => true,
             ),
        ));

        $this->add(array(
            'name' => 'submit',
            'type' => 'Button',
            'options' => array(
                'label' => 'Compare'
            ),
            'attributes' => array(
                'type' => 'submit'
            )
        ));
    }

PlanComparisonFieldset:

namespace PlanComparison\Form;

use Zend\Form\Fieldset;
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator;

class PlanComparisonFieldset extends Fieldset
{
    public function __construct()
    {
        parent::__construct('planComparison');
        $this->setHydrator(new ClassMethodsHydrator(false));

        $this->add(array(
            'type' => 'Collection',
            'name' => 'groups',
            'options' => array(
                'count' => 3,
                'allow_add' => false,
                'target_element' => array(
                    'type' => '\PlanComparison\Form\GroupFieldset',
                ),
            ),
        ));
    }
}

GroupFieldset:

namespace PlanComparison\Form;

use Zend\Form\Fieldset;
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator;


class GroupFieldset extends Fieldset
{
    public function __construct()
    {
        parent::__construct('group');
        $this->setHydrator(new ClassMethodsHydrator(false));

        $this->add(array(
            'name' => 'id',
            'type' => 'Hidden',
        ));

        $this->add(array(
            'name' => 'name',
            'type' => 'Text',
        ));

        $this->add(array(
            'name' => 'plans',
            'type' => 'Collection',
            'options' => array(
                'count' => 0,
                'should_create_template' => true,
                'allow_add' => true,
                'target_element' => array(
                    'type' => '\PlanComparison\Form\PlanFieldset',
                ),
            ),
        ));
    }

}

PlanFieldset:

namespace PlanComparison\Form;

use Zend\Form\Fieldset;
use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator;

class PlanFieldset extends Fieldset
{
    public function __construct()
    {
        parent::__construct('plan');
        $this->setHydrator(new ClassMethodsHydrator(false));

        $this->add(array(
            'name' => 'planId',
            'type' => 'Hidden',
        ));
    }

}

In the controller:

$form = new PlanComparisonForm();
$form->setValidationGroup(array(
            'planComparison' => array(
                'groups' => array(
                    'id',
                    'name',
                    'plans' => array(
                        'planId',
                    ),
                ),
            ),
        ));

$form->setData(array(
            'planComparison' => array(
                'groups' => array(
                    array(
                        'id' => null,
                        'name' => 'first group',
                        'plans' => array(
                            array(
                                'planId' => 152,
                            ),
                            array(
                                'planId' => 260,
                            ),
                        )
                    ),
                    array(
                        'id' => null,
                        'name' => 'second group',
                        'plans' => array(
                            array(
                                'planId' => 152,
                            ),
                        )
                    ),
                    array(
                        'id' => null,
                        'name' => 'third group',
                    ),
                )
            )
        ));

var_dump($form->isValid());
@ant7
Copy link
Contributor Author

ant7 commented Jun 10, 2014

I'm not really sure, but it seems that the problem originates in prepareValidationGroup().
When the fieldset is a Collection, the method only prepares the un-nested collections, ignoring the nested ones. This results in some problematic behaviour, like populating only the first element of nested collections or like the problem reported in the first comment.

For me, it worked by just moving the line:
$this->prepareValidationGroup($fieldset, $data[$key], $validationGroup[$key]);
outside of the else statement, so it will be working recursive even for collections. But, considering that I don't know the whole scenario, it may need some other verifications / tests.

Thank you

@ant7
Copy link
Contributor Author

ant7 commented Jun 10, 2014

The quick change that seems to fix this issue (any feedback is welcomed): ant7@95390fe

@Ocramius
Copy link
Member

@ant7 can you write a test case for this first?

@ant7
Copy link
Contributor Author

ant7 commented Jun 10, 2014

@Ocramius I'll try and come back. Thank you

@ant7
Copy link
Contributor Author

ant7 commented Jun 10, 2014

@Ocramius I've wrote two failing tests to prove the described issues (reverted to the original Form.php, so the tests can pass). See ant7@add3060

Thank you

P.S. This is my first test unit, so I may have got it wrong: for both tests I've asserted the contrary of what should be a correct result, so both tests pass to prove the issues.

ant7 added a commit to ant7/zf2 that referenced this issue Jun 20, 2014
ant7 added a commit to ant7/zf2 that referenced this issue Jun 20, 2014
@ant7
Copy link
Contributor Author

ant7 commented Jun 20, 2014

I've changed the tests a little: ant7@2492f1f .
@Ocramius , can you please check if I should change anything ? Thank you

P.S. I'm not very good at working with Git and I made some mistakes along the way. Sorry for this.

@adamlundrigan
Copy link
Contributor

I came across this issue today myself. I pulled down @ant7's changes and everything now works as expected.

@ezimuel
Copy link
Contributor

ezimuel commented Aug 7, 2014

Solved by #6400

@ezimuel ezimuel closed this as completed Aug 7, 2014
Jhiino added a commit to Jhiino/zf2 that referenced this issue Oct 8, 2014
CaporalDead added a commit to Astek-GO/zf2 that referenced this issue Oct 8, 2014
CF zendframework#6363 zendframework#6400 - Problème d'hydratation des nested collection sur les form, import d'une correction de Zf 2.3
fabiocarneiro pushed a commit to fabiocarneiro/zend-form that referenced this issue Feb 4, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants