Путаница между валидацией и правилами приложения в CakePHP3

Несколько вопросов о валидации, которые могут быть связаны друг с другом, потому что все они касаются новой концепции валидации в CakePHP 3.

Я прочитал главы (1, 2 , 3) в cookbook несколько раз, но, честно говоря, я не понимаю, как это сделать правильно. Я также знаю, что в настоящее время существует проблема/ обсуждение на GitHub валидации в CakePHP3, которое может касаться той же темы.

Ошибки проверки запускаются, например. с patchEntity. Поэтому я думаю, что лучше ВСЕГДА проверять/отображать ошибки ПЕРЕД выполнением действия сохранения:

// src/Controller/UsersController.php
public function add() {
  $user = $this->Users->newEntity();
  if ($this->request->is('post')) {
    $user = $this->Users->patchEntity($user, $this->request->data, ['validate' => 'default'] );
    if ( $user->errors() ) {
      $this->Flash->error('There was a Entity validation error.');
    } else {
      // Optional: Manipulate Entity here, e.g. add some automatic values
      // Be aware: Entity content will not be validated again by default
      if ( $this->Users->save($user) ) {
        $this->Flash->succeed('Saved successfully.');
        return $this->redirect(['controller' => 'Users', 'action' => 'index']);
      } else {
        $this->Flash->error('Not saved - ApplicationRule validation error.');
      }
    }
  }
  $this->set('user', $user);
}

Почему в учебных пособиях по кулинарным книгам не используется $user->errors() перед сохранением данных? Насколько я понимаю, save не нужно вызывать, если уже была ошибка валидации?! Другим способом было бы объединить проверку ошибок и действие сохранения:

if ( !$user->errors() && $this->Users->save($user) ) {
  $this->Flash->succeed('Saved successfully.');
  return $this->redirect(['controller' => 'Users', 'action' => 'index']);
} else {
  $this->Flash->error('There was a validation OR ApplicationRule error.');
}

Вы используете это? Должен ли я использовать его? А если нет, то почему?

Почему CakePHP показывает ошибки проверки, даже если я НЕ использую $user->errors() в контроллере, как во всех примерах кулинарной книги? Я думал, что save НЕ будет проверять валидацию сущности?!

Пример: isUnique

Согласно поваренная книга «Обеспечение уникальности электронной почты» — пример использования правил приложения.

// src/Model/Table/UsersTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\ORM\RulesChecker;
use Cake\ORM\Rule\IsUnique;
// Application Rules
public function buildRules(RulesChecker $rules) {
  $rules->add($rules->isUnique(['email'], 'This email is already in use'));
  return $rules;
}

Ошибка будет вызвана только вызовом save в контроллере. Но также можно проверить уникальность в валидации. Почему лучше НЕ делать это таким образом?

// src/Model/Table/UserTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
public function validationDefault(Validator $validator) {
  $validator
    ->add('email', [
      'unique' => [
        'rule' => 'validateUnique',
        'provider' => 'table',
        'message' => 'This email is already in use'
        ],
      ])
  return $validator;
}

Если я могу добавить ApplicationRule в валидацию, зачем/должен ли я вообще использовать ApplicationRules?

Как я могу определить в ApplicationRule, КОГДА правило должно применяться только в определенном действии (не во всех вызовах создания/обновления)?

Я также не вижу и не понимаю преимущества двух разделенных состояний проверки, когда объектом манипулируют после вызова patchEntity.

В случае, если я автоматически добавляю некоторые значения в объект, я хочу убедиться, что все значения все еще действительны, прежде чем сохранять их в базе данных (как в CakePHP2). Поэтому я бы предположил, что лучше/необходимо ВСЕГДА Использование проверки в качестве правил приложения?!

Как вы с этим вообще справляетесь? Имеются ли другие примеры для демонстрации/демонстрации преимуществ и некоторых вариантов использования правил проверки и приложений?


person Oops D'oh    schedule 27.06.2015    source источник


Ответы (1)


Я думаю, что ваш основной источник путаницы заключается в том, что вы не знаете, что save() не сохранит сущность, если она уже содержит ошибки. Например:

$entity = $users->newEntity(['email' => 'not an email']);
$users->save($entity); // Returns false

Причина, по которой он вернет false, заключается в том, что save() считывает результат $entity->errors(), прежде чем приступить к фактическому процессу сохранения. В этом случае нет необходимости вручную проверять наличие ошибок перед вызовом save(), как показывают примеры в руководстве.

Пример уникальности электронной почты довольно сложен, потому что это то, что вы хотите проверить как для пользовательских форм (для чего предназначена проверка), так и для правил приложения.

Важно помнить, что Validation, как и методы validation*(), предназначены для обратной связи с людьми по поводу данных, которые они предоставляют. Вы хотите представить все ошибки в форме (включая ошибки для вложенных свойств) до начала процесса сохранения.

Поскольку Validation редко происходит внутри транзакции базы данных, нет фактической гарантии того, что между проверкой и сохранением электронная почта все еще будет уникальной. Это одна из проблем, которую пытаются решить правила приложения: правила приложения выполняются в той же транзакции, что и остальная часть процесса сохранения, поэтому любые проверки, выполненные там, будут иметь гарантию согласованности.

Еще одна проблема, которую решают правила приложения, заключается в том, что они могут работать с данными, которые уже были установлены для объекта, поэтому у вас есть полный доступ к текущему состоянию объекта. Это невозможно при исправлении сущности или при создании новой, поскольку любые переданные данные потенциально несовместимы.

person José Lorenzo Rodríguez    schedule 27.06.2015
comment
Таким образом, чтобы избежать неожиданностей при сохранении данных, лучше всего всегда использовать проверку в качестве правил приложения? Я думаю, что это был бы единственный способ убедиться, что данные все еще действительны, если объектом манипулируют между созданием и сохранением объекта? Можете ли вы привести несколько конкретных примеров, когда правила приложения абсолютно лучше, чем валидация (без кода, только случаи использования, где есть большое преимущество)? Поскольку я думаю, что с условной проверкой я могу делать в основном то же, что и с правилами применения - person Oops D'oh; 27.06.2015
comment
Я уже приводил пример в своем ответе: правила приложения выполняются в транзакции, поэтому они являются единственным способом гарантировать, что данные останутся согласованными. Специально для правил, связанных с вычислениями. - person José Lorenzo Rodríguez; 27.06.2015
comment
И да, если вы сомневаетесь, откуда могут поступать данные вашего приложения, я бы предложил использовать проверку в качестве правил приложения. - person José Lorenzo Rodríguez; 27.06.2015
comment
Хорошо, это имеет смысл - при условной проверке я не могу быть уверен, что данные контекста действительны. Но еще один вопрос заключался в том, как сделать так, чтобы правило приложения выполнялось только в определенном действии? Пример: бесплатная доставка всегда должна подтверждаться (как правило приложения), когда пользователь вводит форму, но не в том случае, если администратор использует другую форму в той же таблице (плохой пример, но вы должны понять). Я могу определить, какую проверку использовать в patchEntity с помощью ['validate' => 'customValidationForThisAction'], но не какие правила приложения (кроме общих addCreate/addUpdate)? - person Oops D'oh; 28.06.2015
comment
Нет, ты не можешь. Когда правила зависят от вариантов использования, это означает, что они принадлежат Validation. Правила приложения касаются абсолютной правды в вашем приложении. Что вы можете иметь, так это правило, определяющее исходного пользователя и проверяющее его. Вы также можете изменить правила во время выполнения, вызвав $table->rulesChecker() и работая непосредственно с объектом перед вызовом save(). - person José Lorenzo Rodríguez; 28.06.2015