Search code examples
zend-formzend-framework3

Is it a bad idea to manipulate zend forms with parameters from the controller?


I'm currently creating forms for my project and already wasted time with fieldsets. First I had to find out that you can't define filters and validators in fieldsets and then after countless tries to fix that in the form itself I gave up on it. After having a mixed bag of fieldset form elements and form elements I decided that it's too complicated for the simple forms I have.

So now I thought I'd create a general Form class and pass parameters from the controller to it in order to only create the elements I need. Is this a bad idea? And if yes, why?

Something like this:

Controller:

$include_title = true
$screening_form->setData($include_title);

Form

public function __construct($include_title)
{
    if ($include_title)
    {
        $this->add([
           'type' => 'text',
           'name' => 'title',
           'options' => [
                'label' => 'text',
                'placeholder' => 'Test',
            ],
        ]);
    }
}

Solution

  • I would suggest retaining different forms for different context's don't have one big Form class for your whole application. It's quite difficult to change the form appearance based on data passed in via setData() and might have been what was causing you issues with your fieldsets and validation

    If you wanted to have "generic" forms which are adaptable to different context's - that is possible I'd implement it like this:

    <?php
    namespace ConferenceTools\Attendance\Form;
    
    use Zend\Form\Element\DateTime;
    use Zend\Form\Element\Submit;
    use Zend\Form\Form;
    
    class DateTimeForm extends Form
    {
        public function init()
        {
            $this->add([
                'type' => DateTime::class,
                'name' => 'datetime',
                'options' => [
                    'label' => $this->getOption('fieldLabel'),
                ],
                'attributes' => [
                    'class'=> 'datetimepicker-input',
                    'id' => "dtpicker",
                    'data-toggle' => "datetimepicker",
                    'data-target' => "#dtpicker",
                    'autocomplete' => 'off',
                ],
            ]);
        }
    }
    

    This is a generic date time form use in this project: https://github.com/conferencetools/attendance-module/blob/master/src/Form/DateTimeForm.php

    The differences to your form are the $this->getOption('fieldLabel') call, this is a better way to pass options into the form than using the constructor. It also builds the form in the init method instead of the constructor, this is important to make use of the options field and any custom form elements which won't be available until the class has been fully constructed.

    For this to work properly, you need to retrieve it from the FormPluginManager (service name: 'Zend\Form\FormElementManager') which is a standard service locator. You can inject this into your controller in it's factory and then use it as follows:

    // in controller method
    $form = $this->formElementManager->get(FormName::class, ['fieldLabel' => 'Arrival time']);
    

    This is not quite how I do it in the project linked above; instead of injecting the formElementManager into every controller that needed it, I created a controller plugin which makes it available in every controller. (The code is the same, just in a plugin instead)