I have a CakePHP (latest version) web app with forms and validation all working properly using traditional postback, but now I’m switching some of the forms to submit via ajax. When there are validation errors, I would like to get them back on the client as JSON formatted like so:
{
"success":false,
"errors":{
"data[User][username]":["This is not a valid e-mail address"],
"data[User][password]":["You must choose a password"]
}}
The keys for the errors array need to correspond to the name attribute on the form fields. We have some prebuilt client script that is expecting JSON formatted in this way. The good news is that this is very close to what the validationErrors object looks like in CakePHP. So I’m currently doing this in my controller:
if ($this->User->save($this->request->data)) {
} else {
if ($this->request->is('ajax')) {
$this->autoRender = $this->layout = false;
$response['success'] = false;
$response['errors'] = $this->User->validationErrors;
echo json_encode($response);
exit(0);
}
}
However, this is what the JSON response looks like:
{
"success":false,
"errors":{
"username":["This is not a valid e-mail address"],
"password":["You must choose a password"]
}}
Note that the errors keys have just the basic database table field names in them. They are not converted into data[User][username] format, which the FormHelper usually takes care of.
Is there some easy way to adjust the array before I return it? I don’t want to simply loop through and prepend “data[User]” because that is not robust enough. I’d like some code I can put in one place and call from various controllers for various models. What does FormHelper use to come up with the input name attributes? Can I tap into that? Should I somehow use a JSON view?
That’s because that’s the way the
$validationErrorsarray is formatted. To obtain the output you want you will have to loop through, there’s no way around it.I would suggest instead passing all errors to
json_encode().$this->validationErrorsis a combined list of all model validation errors for that request available on the view (compiled after render). You should move your display logic (echoing json) into your view, and loop through it there.in the view
This would output something like this: