zendframework / zend-inputfilter

InputFilter component from Zend Framework
BSD 3-Clause "New" or "Revised" License
64 stars 50 forks source link

Duplicate error messages for collection input field items #147

Closed tigran-m-dev closed 6 years ago

tigran-m-dev commented 6 years ago

This happens when items of first element more then second Here is an example

Configuration file

0 => [
    'name' => 'test1',
    'type' => \Zend\InputFilter\InputFilter::class,
    'test1-child' => [
        'type' => \Zend\InputFilter\CollectionInputFilter::class,
        'input_filter' => [
            'field' => [
                'type' => \Zend\InputFilter\CollectionInputFilter::class,
                'input_filter' => [
                    'type' => [
                        'required' => true,
                        'validator' => [
                            0 => [
                                'name' => \Zend\Validator\Between::class,
                                'options' => [],
                            ]
                        ],
                    ],
                    'price' => [
                        'required' => true,
                        'validator' => [
                            0 => [
                                'name' => \Zend\Validator\Between::class,
                                'options' => [],
                            ]
                        ],
                    ],
                ]
            ],
        ]
    ],
]

Sending data

test1[test1-child][1][field][0][type] = 159s -> wrong data
test1[test1-child][1][field][0][price] = 15.2568s -> wrong data
test1[test1-child][1][field][1][type] = 2180s -> wrong data
test1[test1-child][1][field][1][price] = 25.2568s -> wrong data
test1[test1-child][1][field][2][type] = 2180s -> wrong data
test1[test1-child][1][field][2][price] = 25.2568s -> wrong data
test1[test1-child][1][field][4][type] = 2180s -> wrong data
test1[test1-child][1][field][4][price] = 25.2568s -> wrong data

test1[test1-child][2][field][0][type] = 159 -> corect data
test1[test1-child][2][field][0][price] = 15.2568 -> wrong data
test1[test1-child][2][field][1][type] = 2180 -> corect data
test1[test1-child][2][field][1][price] = 25.2568 -> corect data

Validation Response

"validation_messages": {
    "test1-child": {
        "1": {
            "field": [
                {
                    "type": {
                        "error_key": "Error message",
                    },
                    "price": {
                        "error_key": "Error message"
                    }
                },
                {
                    "type": {
                        "error_key": "Error message",
                    },
                    "price": {
                        "error_key": "Error message"
                    }
                },
                {
                    "type": {
                        "error_key": "Error message",
                    },
                    "price": {
                        "error_key": "Error message"
                    }
                },
                {
                    "type": {
                        "error_key": "Error message",
                    },
                    "price": {
                        "error_key": "Error message"
                    }
                }
            ]
        },
        "2": {
            "field": [
                {
                    "type": {
                        "error_key": "Error message",
                    },
                    "price": {
                        "error_key": "Error message"
                    }
                },
                {
                    "type": {
                        "error_key": "Error message",
                    },
                    "price": {
                        "error_key": "Error message"
                    }
                },
                {
                    "type": {
                        "error_key": "Error message",
                    },
                    "price": {
                        "error_key": "Error message"
                    }
                },
                {
                    "type": {
                        "error_key": "Error message",
                    },
                    "price": {
                        "error_key": "Error message"
                    }
                }
            ]
        },
    }
}

@weierophinney Can you have a look and improve this as soon as you can

froschdesign commented 6 years ago

@developer-devPHP Please do not ping a single person in the problem description. There is no need for this.

And please provide a simple and working example. Your example is too complicated and includes errors. (validators not validator!)

Here a simple and working example:

$factory     = new \Zend\InputFilter\Factory();
$inputFilter = $factory->createInputFilter(
    [
        'collection-element' => [
            'type'         => \Zend\InputFilter\CollectionInputFilter::class,
            'required'     => true,
            'input_filter' => [
                'type'  => [
                    'validators' => [
                        [
                            'name'    => \Zend\Validator\Between::class,
                            'options' => [
                                'min' => 50,
                                'max' => 100,
                            ],
                        ],
                    ],
                ],
                'price' => [
                    'validators' => [
                        [
                            'name'    => \Zend\Validator\Between::class,
                            'options' => [
                                'min' => 50,
                                'max' => 100,
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ]
);

$inputFilter->setData(
    [
        'collection-element' => [
            [
                'type'  => 10,
                'price' => 10,
            ],
            [
                'type'  => 20,
                'price' => 20,
            ],
        ],
    ]
);
var_dump($inputFilter->isValid());
var_dump($inputFilter->getMessages());

Result:

false

array (size=1)
  'collection-element' => 
    array (size=2)
      0 => 
        array (size=2)
          'type' => 
            array (size=1)
              'notBetween' => string 'The input is not between '50' and '100', inclusively' (length=52)
          'price' => 
            array (size=1)
              'notBetween' => string 'The input is not between '50' and '100', inclusively' (length=52)
      1 => 
        array (size=2)
          'type' => 
            array (size=1)
              'notBetween' => string 'The input is not between '50' and '100', inclusively' (length=52)
          'price' => 
            array (size=1)
              'notBetween' => string 'The input is not between '50' and '100', inclusively' (length=52)
froschdesign commented 6 years ago

And to solve your problem, you must add break_on_failure to an input:

'type'  => [
    'break_on_failure' => true,
    'validators'       => [
        [
            'name'    => \Zend\Validator\Between::class,
            'options' => [
                'min' => 50,
                'max' => 100,
            ],
        ],
    ],
],
tigran-m-dev commented 6 years ago

@froschdesign got your note related person ping.

Here is an example as you want.

$factory = new \Zend\InputFilter\Factory();
$inputFilter = $factory->createInputFilter(
    [
        'element' => [
            'type' => \Zend\InputFilter\InputFilter::class,
            'type1' => [
                'type' => \Zend\InputFilter\CollectionInputFilter::class,
                'input_filter' => [
                    'test_field' => [
                        'type' => \Zend\InputFilter\CollectionInputFilter::class,
                        'input_filter' => [
                            'test_field1' => [
                                'required' => false,
                                'validators' => [
                                    [
                                        'name' => \Zend\Validator\Between::class,
                                        'options' => [
                                            'min' => 50,
                                            'max' => 100,
                                            'message' => '%value% is incorrect',
                                        ],
                                    ],
                                ],
                            ],
                            'price' => [
                                'required' => false,
                                'validators' => [
                                    [
                                        'name' => \Zend\Validator\Between::class,
                                        'options' => [
                                            'min' => 50,
                                            'max' => 100,
                                            'message' => '%value% is incorrect',
                                        ],
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ]
);

$inputFilter->setData(
    [
        'element' => [
            'type1' => [
                [
                    'test_field' => [
                        [
                            'test_field1' => -20,
                            'price' => 20,
                        ],
                        [
                            'test_field1' => -15,
                            'price' => 15,
                        ],
                        [
                            'test_field1' => -10,
                            'price' => 10,
                        ],
                    ],
                ],
                [
                    'test_field' => [
                        [
                            'test_field1' => -5,
                            'price' => 5,
                        ],
                    ],
                ],
            ],
        ],
    ]
);
var_dump($inputFilter->isValid());
var_dump($inputFilter->getMessages());

Result


false

array(1) {
  'element' =>
  array(1) {
    'type1' =>
    array(2) {
      [0] =>
      array(1) {
        'test_field' =>
        array(3) {
          [0] =>
          array(2) {
            'test_field1' =>
            array(1) {
              'notBetween' =>
              string(16) "-20 is incorrect"
            }
            'price' =>
            array(1) {
              'notBetween' =>
              string(15) "20 is incorrect"
            }
          }
          [1] =>
          array(2) {
            'test_field1' =>
            array(1) {
              'notBetween' =>
              string(16) "-15 is incorrect"
            }
            'price' =>
            array(1) {
              'notBetween' =>
              string(15) "15 is incorrect"
            }
          }
          [2] =>
          array(2) {
            'test_field1' =>
            array(1) {
              'notBetween' =>
              string(16) "-10 is incorrect"
            }
            'price' =>
            array(1) {
              'notBetween' =>
              string(15) "10 is incorrect"
            }
          }
        }
      }
      [1] =>
      array(1) {
        'test_field' =>
        array(3) {
          [0] =>
          array(2) {
            'test_field1' =>
            array(1) {
              'notBetween' =>
              string(15) "-5 is incorrect"
            }
            'price' =>
            array(1) {
              'notBetween' =>
              string(14) "5 is incorrect"
            }
          }
          [1] =>
          array(2) {
            'test_field1' =>
            array(1) {
              'notBetween' =>
              string(16) "-15 is incorrect"
            }
            'price' =>
            array(1) {
              'notBetween' =>
              string(15) "15 is incorrect"
            }
          }
          [2] =>
          array(2) {
            'test_field1' =>
            array(1) {
              'notBetween' =>
              string(16) "-10 is incorrect"
            }
            'price' =>
            array(1) {
              'notBetween' =>
              string(15) "10 is incorrect"
            }
          }
        }
      }
    }
  }
}
froschdesign commented 6 years ago

@developer-devPHP Sorry, but your example is still too complicated. One collection element illustrates the same problem. Reduce your example to a minimum and it is easier to understand your problem. This helps us and also you!

Have you seen and tested the solution?

tigran-m-dev commented 6 years ago

If it's just one simple collection, in that case no this kind of problem. Problem coming, during this situation, when inside of collection new collection.

Please just run my previous example and you can see what's the problem.

I used your solution break_on_failure to an input field, but it's not helpful. I think problem in $collectionMessages in CollectionInputFilter class during recursive get and set messages (in isValid method) Zend\InputFilter\CollectionInputFilter Line 203

froschdesign commented 6 years ago

Please just run my previous example and you can see what's the problem.

This was my first problem, I could not reproduce your problem. Therefore I asked for a working example. Now I can see what you mean. (Thanks!)

I used your solution break_on_failure to an input field, but it's not helpful.

Right, because break_on_failure works only for a single input.

I think problem in $collectionMessages in CollectionInputFilter class during recursive get and set messages…

This not a problem, it's a feature. If you provide 6 inputs and all inputs are invalid, then 6 error messages are returned. I would override the getMessages method for this special use case, if not all error messages are needed.

tigran-m-dev commented 6 years ago

Let me clarify one thing. I need all messages, but in example as you can see the messages for first item is duplicated on second item. In first item I send 3 fields value, in second item only 1, but in error messages you can see 3 error messages in second item.

froschdesign commented 6 years ago

…or first item is duplicated on second item.

Ah, you mean the second test_field after -5 and 5. Right, all these messages are wrong. I will test it.

(A hard nut to crack! 😉 )

tigran-m-dev commented 6 years ago

Do you have any news related this issue?

tigran-m-dev commented 6 years ago

@froschdesign Is this issue abandoned,or maybe you or staff working on it? Can you tell me any update.

Thanks.

froschdesign commented 6 years ago

@developer-devPHP

Is this issue abandoned…

No. The issue is still open.

…or maybe you or staff working on it?

This is a community project and everyone can help. It would be great, if you have time and write the unit test. We will review it.

tigran-m-dev commented 6 years ago

Thanks @svycka For me issue solved. @froschdesign If it's not breaking other logical part please push it with next release.

Thanks.

froschdesign commented 6 years ago

@developer-devPHP

For me issue solved.

Thanks for the feedback!

…please push it with next release.

A review is needed and then we can merge and release it.

tigran-m-dev commented 6 years ago

@froschdesign do we have any updates related review statuses?