【问题标题】:Confusing Validation vs. Application Rules in CakePHP3CakePHP3 中令人困惑的验证与应用程序规则
【发布时间】:2015-06-27 10:55:18
【问题描述】:

关于验证的多个问题可能属于一起,因为它们都在处理 CakePHP 3 中的新验证概念。

我已多次阅读食谱中的章节(123),但老实说,我不明白如何以正确的方式进行操作。我也知道目前有一个 issue/discussion at GitHub 关于 CakePHP3 中的验证可能涉及相同的主题。

触发验证错误,例如与补丁实体。所以我认为在执行保存操作之前总是检查/显示错误会更好:

// 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.');
}

你在用这个吗?我应该使用它吗?如果没有,为什么不呢?

为什么即使我没有在控制器中使用$user->errors(),CakePHP 也会显示验证错误,就像在所有食谱示例中一样?我以为save 不会检查实体验证?!

示例:isUnique

根据cookbook“确保电子邮件唯一性”是应用程序规则的一个用例。

// 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-call 之后操纵实体时,我也看不到或理解这两个单独的验证状态的好处。

如果我自动向实体添加一些值,我想确保这些值在将它们保存到数据库之前仍然有效(如在 CakePHP2 中)。所以我想总是 Using Validation as Application Rules?!

更好/必要

您一般是如何处理这个问题的?是否有其他示例可用于展示/展示验证与应用程序规则的好处和一些用例?

【问题讨论】:

    标签: validation cakephp-3.0 cakephp-3.1 cakephp-3.x


    【解决方案1】:

    我认为您的主要困惑来源是您不知道save() 不会保存已包含错误的实体。例如:

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

    它返回 false 的原因是因为save() 在继续实际保存过程之前读取了$entity->errors() 结果。因此,无需在调用 save() 之前手动检查错误,就像手册中的示例所示。

    电子邮件唯一性示例有点棘手,因为您要检查面向用户的表单(验证的目标)和应用程序规则。

    请务必记住,Validationvalidation*() 方法一样,旨在向人类提供有关他们提供的数据的反馈。您希望在保存过程开始之前在表单中显示所有错误(包括嵌套属性的错误)。

    由于Validation 很少发生在数据库事务中,因此无法实际保证在验证和保存电子邮件之间仍然是唯一的。这是应用程序规则试图解决的问题之一:应用程序规则确实与保存过程的其余部分在同一事务中运行,因此那里的任何检查都将具有一致性保证。

    应用程序规则解决的另一个问题是它们可以处理已经在实体上设置的数据,因此您可以完全访问对象的当前状态。在修补实体或创建新实体时这是不可能的,因为任何传递的数据都可能不一致。

    【讨论】:

    • 因此,为了避免在保存数据时出现意外,始终将验证也用作应用程序规则的最佳方式是?我认为如果在创建和保存实体之间操纵实体,这将是确保数据仍然有效的唯一方法?当应用程序规则绝对优于验证时(没有代码,只是有很大优势的用例),你能给出一些具体的例子吗?因为我认为使用 conditional validation 我可以做与应用程序规则大致相同的操作
    • 这里有example with the free shipping as application rule。我也可以通过条件验证来做到这一点return $context['data']['price'] < 100 && $context['data']['shipping_mode'] === 'free';
    • 我已经在我的回答中举了一个例子:应用程序规则在事务中运行,因此它们是确保数据保持一致的唯一方法。特别适用于涉及计算的规则。
    • 是的,如果您对应用程序数据的来源有疑问,我建议您使用验证作为应用程序规则。
    • 好的,这是有道理的——在条件验证中,我无法确定上下文数据是否有效。但另一个问题是我如何才能使应用程序规则仅在特定操作中运行?示例:当用户输入表单时,应始终验证免费送货(作为应用程序规则),但如果管理员在同一个表中使用另一个表单,则不需要验证(不好的示例,但您应该明白这一点)。我可以用['validate' => 'customValidationForThisAction'] 定义在patchEntity 使用哪个验证,但不能定义哪个应用程序规则(除了一般的addCreate/addUpdate)?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 2016-12-10
    相关资源
    最近更新 更多