How to validate array inputs?

Hi,
Is there any example validating the array input fields using laminas validator. I could not see in the documentation.

Example inputs;

partners[0][membership_id]
partners[0][policy_start_date]
partners[0][policy_end_date]

A foreach loop comes to mind to get through your partners[X], followed by $this->inputFilter->setData([<whatever_comes_out_of_your_loop>]);

I mean is it possible to build validation rules dynamically.


namespace Album\InputFilter;

use Laminas\Filter\ToInt;
use Laminas\I18n\Validator\IsInt;
use Laminas\InputFilter\InputFilter;

class TestInputFilter extends InputFilter
{
    public function init()
    {            
        $this->add(
            [
                'name' => 'partners[0][membership_id]',
                'validators'  => [
                    [
                        'name' => IsInt::class,
                    ],
                ],
            ]
        );
    }
}

After search on the google i found zend docs which is about CollectionInputFilter.

use Laminas\InputFilter\CollectionInputFilter;
use Laminas\InputFilter\InputFilter;

class TestFilter extends InputFilter
{
    public function __construct()
    {
        $partners = new CollectionInputFilter();
        $partnersInputFilter = new InputFilter();
        $partnersInputFilter->add([
            'name' => 'membership_id',
            'required' => true,
            'validators' => [
                ['name' => Uuid::class],
            ],
        ]);   
        $partnersInputFilter->add([
            'name' => 'policy_start_Date',
            'required' => true,
        ]);
        $partners->setInputFilter($partnersInputFilter);

        // partners collection
        // 
        $this->add($partners, 'partners');
    }

    public function init()
    {
        // $this->add(...);
    }
}

An another example for multi language supported version.

public function __construct(InputFilterPluginManager $inputFilterPluginManager)
{
        $partnersCollection = new CollectionInputFilter();
        $partnersInputFilter = $inputFilterPluginManager->get(PartnersInputFilter::class);
        $partnersInputFilter->add([
            'name' => 'membership_id',
            'required' => true,
            'validators' => [
                ['name' => Uuid::class],
                [
                    'name' => NoRecordExists::class,
                    'options' => [
                        'table'   => 'user_partners',
                        'field'   => 'membership_id',
                        'adapter' => $adapter,
                    ],
                ]
            ],
        ]);   
        $partnersInputFilter->add([
            'name' => 'partner_id',
            'required' => false,
            'validators' => [
                [
                    'name' => InArray::class,
                    'options' => [
                        'haystack' => [1,2],
                    ]
                ],
            ],
        ]);
        $partnersInputFilter->add([
            'name' => 'partner_type',
            'required' => false,
            'validators' => [
                [
                    'name' => InArray::class,
                    'options' => [
                        'haystack' =>['a','b'],
                    ]
                ],
            ],
        ]);
        $partnersInputFilter->add([
            'name' => 'policy_or_member_no',
            'required' => false,
            'validators' => [
                ['name' => Digits::class],
            ],
        ]);
        $partnersCollection->setInputFilter($partnersInputFilter);

        // partners collection
        // 
        $this->add($partnersCollection, 'partners');
}

When you create an input filter, a factory is used internally, which also uses the plugin manager. Therefore you can shorten your example:

class ExampleInputFilter extends InputFilter
{
    public function init(): void
    {
        $this->add(
            [
                'type'         => CollectionInputFilter::class,
                'input_filter' => [
                    'type' => PartnersInputFilter::class,
                    [
                        'name'       => 'membership_id',
                        'required'   => true,
                        'validators' => [
                            // …
                        ],
                    ],
                    [
                        'name'       => 'partner_id',
                        'required'   => false,
                        'validators' => [
                            // …
                        ],
                    ],
                    // …
                ],
            ],
            'partners'
        );
    }
}

Then use the input filter manager to get this input filter.

(The database adapter can be set once via a delegator directly for the validator. No need to inject it into every input filter.)

Ok good informations thanks, but translation object not initialized for CollectionInputFilter class.
However its initialized for InputFilter::class.

Any idea for this issue ?

        $serviceLanguagesCollection = $this->filter->get(CollectionInputFilter::class);
        $serviceLanguagesCollection->setIsRequired(true); // translation does not work for collection

        $serviceLanguagesInputFilter = $this->filter->get(InputFilter::class);
        $serviceLanguagesInputFilter->add([
            'name' => 'lang_id',  // translation works well here
            'required' => true,
            'validators' => [
                [
                    'name' => InArray::class,
                    'options' => [
                        'haystack' => $languages
                    ],
                ]
            ],
        ]);
        $serviceLanguagesCollection->setInputFilter($serviceLanguagesInputFilter);
        $this->add($serviceLanguagesCollection, 'service_languages');

Unfortunately, I’m not a magician or wizard. :wink:
I don’t know what the “translation object” is.

But basically every input filter must be registered in the input filter manager then the factory of laminas-inputfilter will find the requested input filter. There is one exception: if the input-filter does not need a factory then it does not need to be registered because it is called automatically.

For your case it means: register the input filter with name CollectionInputFilter .

Thanks, you are right i guess its related about naming.

I have an another question:

I could not see any setIsRequired() method in the OptionalInputFilter object how can i set it as required.

Please create a new topic because the current is solved and your question is unrelated. This helps all other readers here. Thanks!