How do you attach validators to the form elements?

How do you attach validators to the form elements ?

You will find some examples in the documentation. Here is the recommended way:

Internally, the validator plugin manager is used, which can also load custom validator classes.

Hey,

it 's as easy as creating forms itself. All you need is the laminas/laminas-inputfilter package additional to your laminas/laminas-form package. Let us take a small tour.

The Form

First of all I gues you still have a form. We 'll use an example form here.

<?php
declare(strict_types=1);
namespace Application\Form;

use Laminas\Form\Element\Text;
use Laminas\Form\Element\Submit;
use Laminas\Form\Form;

class ExampleForm extends Form
{
    public function init()
    {
        $this->add([
            'type' => Text::class,
            'name' => 'example',
            'attributes' => [
                'id' => 'example',
                'required' => true,
            ],
            'options' => [
                'label' => 'Example Text Input',
            ],
        ]);

        $this->add([
            'type' => Submit::class,
            'name' => 'submit',
            'attributes' => [
                'value' => 'Send',
            ],
        ]);
    }
}

Our form got two input elements. First a simple text input called “example” and the other one is just a submit button.

The Input Filter

We want to ensure, that all that is entered into our example input field is valid. It should be minimum 1 char and maximum 10 chars. We want to strip all tags and trim whitespaces from the end end the beginning. Therefore you can use an input filter class.

<?php
declare(strict_types=1);
namespace Application\InputFilter;

use Laminas\Filter\StringTrim;
use Laminas\Filter\StripTags;
use Laminas\Filter\ToNull;
use Laminas\InputFilter\InputFilter;
use Laminas\Validator\StringLength;

class ExampleInputFilter extends InputFilter
{
    public function init()
    {
        $this->add([
            'name' => 'email',
            'required' => true,
            'allow_empty' => false,
            'filters' => [
                [ 'name' => StripTags::class ],
                [ 'name' => StringTrim::class ],
                [
                    'name' => ToNull::class,
                    'options' => [
                        'type' => ToNull::TYPE_STRING,
                    ],
                ],
            ],
            'validators' => [
                [
                    'name' => StringLength::class,
                    'options' => [
                        'min' => 1,
                        'max' => 10,
                        'messages' => [
                            StringLength::TOO_SHORT => 'Well, our example must be at least 1 char long.',
                            StringLength::TOO_LONG => 'Well, that was a bit to long. The example can be 10 chars long.',
                        ],
                    ],
                ],
            ],
        ]);
    }
}

Well that 's a simple Input Filter. It filters the example input and removes all tags. After that the input is trimmed. If the example value is empty after stripping tags and trimming, it results into null. After all filters have been executed the validators will be executed. In this case we check the string length. It should be minimum 1 char and maximum 10 chars long.

Bring it all together

First of all we have to tell the form, which input filter it should use. We need a factory for this purpose.

<?php
declare(strict_types=1);
namespace Application\Form\Factory;

class ExampleFormFactory
{
    public function __invoke(ContainerInterface $container): ExampleForm
    {
        $inputFilterManager = $container->get('InputFilterManager');
        $inputFilter = $inputFilterManager->get(ExampleInputFilter::class);

        $form = new ExampleForm();
        $form->setInputFilter($inputFilter);

        return $form;
    }
}

First of all we have to tell our application, that there is an input filter and a form. Just edit the module.config.php file of your application.

<?php
namespace Application;
...
'form_elements' => [
    'factories' => [
        Form\ExampleForm::class => Form\Factory\ExampleFormFactory::class,
    ],
],
'input_filters' => [
    'factories' => [
        InputFilter\ExampleInputFilter::class => \Laminas\ServiceManager\Factory\Invokable::class,
    ],
],
...

From now on you can call your form everywhere, e.g. in a controller factory, by the form elements plugin manager (service locator). The form will always be initialized with the input filter.

Example in a controller

For example puprose here 's a small snippet, that could be used in a controller.

...
<?php
declare(strict_types=1);
namespace Application\Controller;

use Application\Form\ExampleForm;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class ExampleController extends AbstractActionController
{
    public function __construct(
        protected readonly ExampleForm $form
    )

    public function indexAction(): ViewModel
    {
        $this->form->setAttribute(
            'action',
            $this->url()->fromRoute('your-route/example', [
                'action' => 'index',
            ])
        );

        if ($this->getRequest()->isPost()) {
            $this->form->setData($this->getRequest()->getPost());
            if ($this->form->isValid()) {
                 // form is valid - do something with the valid data
            }
        }

        return new ViewModel([
            'form' => $this->form,
        ]);
    }
}
...

@ezkimo
Too complicated! :stuck_out_tongue_winking_eye:

  • No need to create a factory for the form.
  • No need to register form and input filter in the configuration
class ExampleForm extends Form
{
    public function init()
    {
        $this->setInputFilterByName(ExampleInputFilter::class);

        // …
    }
}

Then use the form element manager to fetch the form and your are done!

2 Likes

If no separate factory is required for the form, then the form element manager will instantiating the form class. Otherwise the form must be registered.

The same applies to:

  • input filter plugin manager
  • validator plugin manager
  • filter plugin manager
  • view helper plugin manager
  • hydrator manager

I am always delighted when I learn something new. Thank you for that. Didn 't know this one. Guess I 've to do more forms. :wink:

I will extend the official documentation and have almost completed the topic for the form element manager. A diagram is still missing.

Thanks! Truly helpful