0

I have an issue with the values of a child collection not being hydrated properly. I'm using zend framework 3 with doctrine 2.

Since it's a lot of code that I would have to copy, I will describe what I'm doing and if needed I will update with code.

We have the following:

  • VillaForm which is a Form element
  • VillaFieldset which is a Fieldset element and is the base fieldset of VillaForm
  • FacilityCategoriesFieldset which is a Fieldset that is used for a Collection element in the VillaFieldset

        $this->add([
        'type' => 'Zend\Form\Element\Collection',
        'name' => 'facilityCategories',
        'options' => [
            'count' => 1,
            'allow_add' => true,
            'allow_remove' => true,
            'create_new_objects' => true,
            'target_element' => [
                'type' => FacilityCategoryFieldset::class,
            ],
        ],
    ]);
    
  • FacilitiesFieldset which is a a Fieldset that is used for a Collection element in the FacilityCategoriesFieldset

        $this->add([
        'type' => 'Zend\Form\Element\Collection',
        'name' => 'facilities',
        'options' => [
            'count' => 1,
            'allow_add' => true,
            'allow_remove' => true,
            'create_new_objects' => true,
            'target_element' => [
                'type' => FacilityFieldset::class,
            ],
        ],
    ]);
    

So viewing from above we have

VillaForm contains VillaFieldset that contains Collection of FacilityCategoriesFieldset which contains a Collection of FacilitiesFieldset

Let's say we have this example on the actual form page.

- Row A of FacilityCategoriesFieldset 
  - Row 1 of FacilitiesFieldset
  - Row 2 of FacilitiesFieldset
  - Row 3 of FacilitiesFieldset

- Row B of FacilityCategoriesFieldset 
  - Row x of FacilitiesFieldset
  - Row y of FacilitiesFieldset
  - Row z of FacilitiesFieldset

My issue is that after the form is submitted, although the post data is correct, after the hydration the result will be like so:

- Row A of FacilityCategoriesFieldset 
  - Row x of FacilitiesFieldset
  - Row y of FacilitiesFieldset
  - Row z of FacilitiesFieldset

- Row B of FacilityCategoriesFieldset 
  - Row x of FacilitiesFieldset
  - Row y of FacilitiesFieldset
  - Row z of FacilitiesFieldset

The rows of the FacilitiesFieldset of the very last row of the FacilityCategoriesFieldset are used for all the rows of FacilitiesFieldset.

This only happens when a have a fieldset with a collection with another collection. Does anyone have a hint of what I might be doing wrong? I will give you any other info/code if you need it.

Thanks a lot.

Systemfreak
  • 327
  • 7
  • 13
  • 1
    I've written several questions and answers about this and recently created [zf-doctrine-form repository](https://github.com/rkeet/zf-doctrine-form) and an [example implementation repository](https://github.com/rkeet/zf-doctrine-form-examples) for these exact issues. Also created [possible bugfix](https://github.com/zendframework/zend-inputfilter/pull/169) for nested Collection in zend-inputfilter repo. My repo implements fix. Feel free to check out both ;) Would advise [Gedmo categories](http://atlantic18.github.io/DoctrineExtensions/doc/tree.html), easy implementation. – rkeet Jul 27 '18 at 11:15
  • Thanks for your comment, I will definitely check it out :) – Systemfreak Jul 27 '18 at 14:56

1 Answers1

1

Your implementation of a Collection is slightly off. You shouldn't give the type of a Collection as the FQCN, but the actual object (Fieldset).

Try this:

/**
 * @var CustomFieldset
 */
protected $customFieldset;

public function __construct(CustomFieldset $customFieldset) {
    $this->customFieldset = $customFieldset;
}

// init()
$this->add(
    [
        'type'     => Collection::class,
        'required' => true,
        'name'     => 'customFieldset',
        'options'  => [
            'label'                  => 'Custom fieldsets',
            'count'                  => 1,
            'allow_add'              => true,
            'allow_remove'           => true,
            'should_create_template' => true,
            'target_element'         => $this->customFieldset,
        ],
    ]
);
rkeet
  • 3,406
  • 2
  • 23
  • 49
  • Yep, that was it. I didn't even know I had to do it with injection, because for a single collection my method worked fine. Weird. Anyway, thanks a lot! – Systemfreak Jul 27 '18 at 14:33
  • 1
    All good. But it's the difference between a `Fieldset > Fieldset` implementation (nested Fieldsets) and a `Fieldset > Collection#Fieldset` implementation. A Collection simply clones (a bit more nuanced internally) the target Fieldset, as such, it needs the object itself. Though, in my opinion, a similar implementation of getting the required object by FQCN could've been implemented there. Might be something for a feature request (or a small side-project once there's time :) ). – rkeet Jul 27 '18 at 15:35