cakephp: [3.1] FormHelper & Nesting Validators: No error messages in the form

When using nested validators the error messages for the nested fields do exist, but they are not shown in the form. I think the form helper Display and Checking Errors can’t handle the “nested” error messages and field names like Model.nested.array.fieldname.

Example: I’m trying to apply validation rules for translation input fields. Let’s assume the regular title field has minLength of 5 and the translated field should have a minLength of 10.

// The nested validation is set up in the table class as described in the book.
// http://book.cakephp.org/3.0/en/core-libraries/validation.html#nesting-validators

// Example input data array ($this->request->data)
[
  'title' => 'abc',
  '_translations' => [
    'fr' => [
      'title' => 'abc'
    ],
  ]
]

// Then in controller
...
$item = $this->Items->patchEntity($item, $this->request->data);
debug($item);
...

// The validation is working, errors are available in the debug result:
object(App\Model\Entity\Item) {
    '[new]' => true,
    '[accessible]' => [
        '*' => true
    ],
    '[dirty]' => [],
    '[original]' => [],
    '[virtual]' => [],
    '[errors]' => [
        'title' => [
            'minLength' => 'minLengh is set to 5'
        ],
        '_translations' => [
            'fr' => [
                'title' => [
                    'minLength' => 'minLengh is set to 10.'
                ]
            ]
        ],
    ],
    '[repository]' => 'Items'
}

// But in the form (view) you can't show the error:
echo $this->Form->error('items._translations.fr.title');
// Result: Nothing :(
// Also the input field does not get marked with the css error class...

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 21 (15 by maintainers)

Commits related to this issue

Most upvoted comments

Here’s my dirty, but simple solution for the problem - we’re using JsonType fields a lot and by overriding FormHelper’s error() method like this we get error messages for nested validations:

public function error($field, $text = null, array $options = [])
{
    $parts = explode('.', $field);
    if (count($parts) > 1 && is_array($this->context()->entity()->get($parts[0]))) {
        $errors = $this->context()->entity()->errors();
        if (Hash::check($errors, $field)) {
            $error = Hash::extract($errors, $field);
            if (is_array($error)) {
                if (count($error) > 1) {
                    $errorText = [];
                    foreach ($error as $err) {
                        $errorText[] = $this->formatTemplate('errorItem', ['text' => $err]);
                    }
                    $error = $this->formatTemplate('errorList', [
                        'content' => implode('', $errorText)
                    ]);
                } else {
                    $error = array_pop($error);
                }
            }
            return $this->formatTemplate('error', ['content' => $error]);
        }
    }
    return parent::error($field, $text, $options);
}

@markstory can we re-open this and try @robertscherer solution? We have exactly the same use case here that we need to validate nested JSON data. Looks like his solution works for me.

As of 3.3.0 (#9225) TranslateBehavior can have a validator option set. This validator will be used to validate translated records, and the errors are propagated up to the root entity so articles._translations.fr.title will work as you’d expect.

@beporter Awesome. I started off with the EntityContext and it got out of hand really quickly.