How to decorate Elements of a Fieldset in a Collection in ZF2?

181 Views Asked by At

In my current project I'm using nested Zend\Form\Fieldsets and Zend\Form\Collections, that provide an extremely comfortable way to map complex object structures to the form, in order to get a complete object (ready to be saved) from the form input.

To the problem: I have a Fieldset FooFieldset containing an Element foo_element with a Label "foo element" (code see below) and need to use this twice: 1. as a single Fieldset; 2. in a Collection. At the first place in the form I want its elements to be displayed; at the the second place I want to disable the labels (or maybe change them). (I also want to format it another way in the second case, but the most important thing now is the label.)

How to decorate Zend\Form\Elements of a Zend\Form\Fieldset in a Zend\Form\Element\Collection depending on the context?


Code

class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function init()
    {
        $this->add([
            'type' => 'text',
            'name' => foo_element',
            'options' => ['label' => _('foo element')]
        ]);
    }
    public function getInputFilterSpecification() { ... }
}

class BarFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function init()
    {
        $this->add([
            'name' => 'foo',
            'type' => 'My\Form\Fieldset\Foo',
            'options' => []
        ]);
    }
    public function getInputFilterSpecification() { ... }
}

class BuzFieldset extends Fieldset implements InputFilterProviderInterface
{
        $this->add(
            [
                'name' => 'foos',
                'type' => 'Zend\Form\Element\Collection',
                'options' => [
                    'label' => _('multiple foos'),
                    'count' => 5,
                    'should_create_template' => true,
                    'template_placeholder' => '__placeholder__',
                    'allow_add' => true,
                    'target_element' => [
                        'type' => 'Order\Form\Fieldset\Foo',
                    ],
                    'label_attributes' => [
                        'class' => 'col-md-12'
                    ]
                ]
            ]);
    public function getInputFilterSpecification() { ... }
}

echo $this->formRow($myForm->get('main_fieldset')->get('bar')->get('foo')->get('foo_element');
echo $this->formRow($myForm->get('main_fieldset')->get('buz')->get('foos');

Workaround 1

It would be possible to use another Fieldset, e.g. a sub-class of FooFieldst (sometnig like FooFieldsetForUsingInCollection extends FooFieldst) and adjust the Label (and other settings) there.

Workaround 2

It also would be possible to access the Collection's Elements in the view script and manipulate them there (as here demonstrated). But I don't really like this solution, since then the Fieldset is defined at multiple places. And it also need further effort, if the number of the Collection elements is variable.

1

There are 1 best solutions below

1
On

It seems like you need to reuse the 'foos' collection and the 'bar' element together in their own fieldset while keeping how it is currently created.

I would

  • Move the collection element foo out of the BuzFieldset::init and into it's own factory (create the element and all it's options in the factory).

  • Register it with the form element manager as and new service, lets call it FooCollection. This element is now reusable and can be called from the form element manager as $fem->get('FooCollection').

  • Replace removed $fieldset->add('type' => 'Zend\Form\Element\Collection') with $fieldset->add('type' => 'FooCollection') in BuzFieldset.

  • Repeat for foo_element with a new service name of FooElement.

  • Then you need to create a new fieldset factory called FooCollectionAndFooElementFieldsetFactory this factory will return a new fieldset with both the FooCollection and FooElement attached.

  • In the factory of main_fieldset decide if you need to attach FooCollectionAndFooElementFieldsetFactory or the existing bar or baz fieldsets.