如何在 Cakephp4 的关联字段 JSON 中显示验证错误?

How to display validation errors in JSON of associated fields in Cakephp4?

我正在寻找一种在 ajax 中发送表单后在 jQuery 中显示验证错误的方法,而 return 在 JSON 中出现验证错误。

我的代码适用于简单的表单,但对于更复杂的表单,尤其是包含关联数据输入的表单,会出现困难。

例如:

这是一个包含用于编写字幕的输入文件和相关数据的表单:

// Articles/edit.php
$this->Form->create($article);
echo $this->Form->control('title');
echo $this->Form->control('photos.0.legend');
echo $this->Form->control('photos.1.legend');
$this->Form->end();

我 post ajax 中的表单到我的 ArticlesController 的编辑方法看起来像这样:

// ArticlesController.php
public function edit($id)
{
    $article = $this->Articles->findById($id)->firstOrFail();

    if ($this->request->is(['post', 'put'])) {
        $article = $this->Articles->patchEntity($article, $this->request->getData());

        if ($this->Articles->save($article)) {
            $redirection = ['action' => 'index'];

            if ($this->request->is('ajax')) {
                die(json_encode(['error' => false, 'redirection' => Router::url($redirection)]));
            }
            return $this->redirect($redirection);
        }
        else {
            if ($this->request->is('ajax')) {
                die(json_encode(['error' => true, 'validationErrors' => $article->getErrors()]));
            }
        }
    }
    $this->set(compact('article'));
}

这是 JSON 中的 return 验证错误:

{
  "error": true,
  "validationErrors": {
    "title": {
      "_empty": "The title please."
    },
    "photos": { // validation errors are nested
      "1": {
        "legend": {
          "_empty": "The legend please."
        }
      }
    }
  }
}

以下是我尝试显示验证错误的方式:

// Articles/edit.php
$('form')
    .fileupload({   // It sends the form in ajax
        dataType: 'json',
        // [...]
        done: function (e, data) {
                var responseJSON = data.jqXHR.responseJSON;
                if (!responseJSON.error) { // There's no error => redirect
                    window.location = responseJSON.redirection;
                }
                else { // The form contains validation errors
                    $.each(responseJSON.validationErrors, function (field, errors) {
                        displayFieldErrors(field, errors);
                    });
                }
            },
         // [...]
     });

// Display validation errors in a field 
function displayFieldErrors(field, errors)
{
    var fieldId = field.replace(/_/, '-');
    var input = $("#" + fieldId);
    var errorMessage = '';
    $.each(errors, function (key, message) {
        errorMessage = errorMessage + message + '<br>';
    });
    input.parents('.input').addClass('error');
    input.after('<div class="error-message">' + errorMessage + '</div>');
}

问题是关联数据字段的验证错误是嵌套的(例如photos),那么如何获取输入的id?

谁能帮我找到 jQuery 函数 displayFieldErrors() 的正确实现?

我已经通过从 JSON 视图(服务器端)返回格式化的验证错误解决了这个问题:

// in Articles/json/edit.php
$errors = [];
// Recursive function to build `$errors[]` associating each field in error to one or many error message(s)
$fieldsInError = function ($err, $buildingField = '') use (&$errors, &$fieldsInError) {
    foreach ($err as $key => $value) {
        if (is_array($value)) {
            $fieldsInError($value, empty($buildingField) ? $key : $buildingField . '.' . $key); // recursive
        }
        else { // string
            if (isset($errors[$buildingField])) {
                if (is_array($errors[$buildingField])) {
                    $errors[$buildingField][] = $value;
                }
                else {
                    $errors[$buildingField] = [$errors[$buildingField], $value];
                }
            }
            else {
                $errors += [$buildingField => $value];
            }
        }
    }
};
$fieldsInError($article->getErrors());

echo json_encode(['error' => true, 'validationErrors' => $errors]));

JSON 现在看起来像这样:

{
  "error": true,
  "validationErrors": {
    "title": "The title please.",
    "photos.1.legend": "The legend please."
  }
}