简体   繁体   中英

ZF3 - Callback validator attaches error message to wrong input

I have a form where a radio button field should be required based on an option from a select field. Also there's a text field that also should be required if the radio button option "yes" is selected. I'm using a callback validator for both fields to check this dependency but the problem is that the error message is being attached to the wrong field. For example if I select an option from the select and leave the radio buttons unchecked, the validator works, but the error message is shown in the select input and not in the radio button.

I wrote two validators for this fields based on an answer by "rkeet" on this post:

https://github.com/zendframework/zend-inputfilter/issues/146

$inputFilter->add([
            'name' => 'regimenPreferencia',
            'required' => true,
            'validators' => [
                [
                    'name' => NotEmpty::class,
                    'options' => [
                        'message' => [
                            NotEmpty::IS_EMPTY => 'Ingrese el régimen de preferencia para este artículo'
                        ]
                    ],
                ],
                [
                    'name' => Callback::class,
                    'options' => [
                        'callback' => function($value, $context) {

                            var_dump($value, $context);
                            if($value === 'agricultura_familiar' && empty($context['esCompraCentralizada'])) {
                                $validatorChain = $this->getInputFilter()->getInputs()['esCompraCentralizada']->getValidatorChain();
                                $validatorChain->attach(new NotEmpty(['type' => NotEmpty::NULL]));
                                $this->getInputFilter()->getInputs()['esCompraCentralizada']->setValidatorChain($validatorChain);

                                return false;
                            }

                            return true;
                        },
                        'messages' => [
                            Callback::INVALID_VALUE => 'Indique si esta compra es centralizada'
                        ]
                    ],
                ]
            ],
            'allow_empty' => false,
            'continue_if_empty' => false,
        ]);

        $inputFilter->add([
            'name' => 'esCompraCentralizada',
            'required' => false,
            'allow_empty' => true,
            'validators' => [
                [
                    'name' => Callback::class,
                    'options' => [
                        'callback' => function($value, $context) {

                            if(strlen($value) > 0 && empty($context['porcAdjudicacionReservaMercado'])) {
                                $validatorChain = $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->getValidatorChain();
                                $validatorChain->attach(new NotEmpty(['type' => NotEmpty::NULL]));
                                $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->setValidatorChain($validatorChain);

                                return false;
                            }

                            return true;
                        },
                        'messages' => [
                            'callbackValue' => 'Ingrese el porcentaje de adjudicación de reserva de mercado'
                        ]
                    ],
                ]
            ],

            'continue_if_empty' => true
        ]);

        $inputFilter->add([
            'name' => 'porcAdjudicacionReservaMercado',
            'allow_empty' => true,
            'filters' => [
                ['name' => ToInt::class]
            ],
            'validators' => [

            ],
        ]);

Ok I made it work as I expected. I added a Callback validator to esCompraCentralizada to check if it's empty and the rest of the validators where added to the porcAdjudicacionReservaMercado field.

This is how the validators ended up being:

$inputFilter->add([
        'name' => 'esCompraCentralizada',
        'required' => false,
        'allow_empty' => true,
        'validators' => [
            [
                'name' => Callback::class,
                'brake_chain_on_failure' => true,
                'options' => [
                    'callback' => function($value, $context) {
                        if(!isset($context['esCompraCentralizada']) && $context['regimenPreferencia'] === 'agricultura_familiar') {
                            $validatorChain = $this->getInputFilter()->getInputs()['esCompraCentralizada']->getValidatorChain();
                            $validatorChain->attach(new NotEmpty(['type' => NotEmpty::NULL]));
                            $this->getInputFilter()->getInputs()['esCompraCentralizada']->setValidatorChain($validatorChain);

                            return false;
                        }

                        return true;
                    },
                    'messages' => [
                        Callback::INVALID_VALUE => 'Indique si esta compra es centralizada'
                    ]
                ],
            ]
        ]
    ]);

    $inputFilter->add([
        'name' => 'porcAdjudicacionReservaMercado',
        'required' => false,
        'allow_empty' => true,
        'filters' => [
            ['name' => ToInt::class]
        ],
        'validators' => [
            [
                'name' => Callback::class,
                'break_chain_on_failure' => true,
                'options' => [
                    'callback' => function($value, $context) {
                        if($context['porcAdjudicacionReservaMercado'] === '' && $context['esCompraCentralizada'] === '1' && $context['regimenPreferencia'] === 'agricultura_familiar') {
                            $validatorChain = $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->getValidatorChain();
                            $validatorChain->attach(new NotEmpty(['type' => NotEmpty::NULL]));
                            $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->setValidatorChain($validatorChain);

                            return false;
                        }

                        return true;
                    },
                    'messages' => [
                        Callback::INVALID_VALUE => 'Ingrese el porcentaje de adjudicación de reserva de mercado'
                    ]
                ],
            ],
            [
                'name' => Callback::class,
                'break_chain_on_failure' => true,
                'options' => [
                    'callback' => function($value, $context) {
                        if (!is_numeric($context['porcAdjudicacionReservaMercado']) && $context['regimenPreferencia'] === 'agricultura_familiar' && $context['esCompraCentralizada'] === '1') {
                            $validatorChain = $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->getValidatorChain();
                            $validatorChain->attach(new LessThan());
                            $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->setValidatorChain($validatorChain);

                            return false;
                        }

                        return true;
                    },
                    'message' => [
                        Callback::INVALID_VALUE => 'El porcentaje de adjudicación de reserva de mercado debe ser un valor numérico'
                    ]
                ],
            ],
            [
                'name' => Callback::class,
                'break_chain_on_failure' => true,
                'options' => [
                    'callback' => function($value, $context) {
                        if ($value > 100 && $context['regimenPreferencia'] === 'agricultura_familiar' && $context['esCompraCentralizada'] === '1') {
                            $validatorChain = $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->getValidatorChain();
                            $validatorChain->attach(new LessThan());
                            $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->setValidatorChain($validatorChain);

                            return false;
                        }

                        return true;
                    },
                    'message' => [
                        Callback::INVALID_VALUE => 'El porcentaje de adjudicación de reserva de mercado debe ser menor o igual a 100'
                    ]
                ],
            ],
            [
                'name' => Callback::class,
                'break_chain_on_failure' => true,
                'options' => [
                    'callback' => function($value, $context) {
                        if ($value < 30 && $context['regimenPreferencia'] === 'agricultura_familiar' && $context['esCompraCentralizada'] === '1') {
                            $validatorChain = $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->getValidatorChain();
                            $validatorChain->attach(new GreaterThan());
                            $this->getInputFilter()->getInputs()['porcAdjudicacionReservaMercado']->setValidatorChain($validatorChain);

                            return false;
                        }

                        return true;
                    },
                    'message' => [
                        Callback::INVALID_VALUE => 'El porcentaje de precio de materiales nacionales debe ser mayor o igual a 30'
                    ]
                ],
            ],
        ],
    ]);

I added four validators to the second field to check:

  • empty field
  • field value not numeric
  • field value less than 30 (functional requirement)
  • field value greater than 100 (functional requirement)

All this applys if 'regimen_preferencia' is 'agricultura_familiar' and 'esCompraCentralizada' is true.

Thank you very much rkeet for all your help!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM