在验证失败时,beforeMarshal不会修改请求数据

时间:2015-07-03 01:14:39

标签: cakephp-3.0

错误或功能?如果我使用beforeMarshal更改请求数据并且存在验证错误,则不会回复修改请求数据。

此问题可能与How to use Trim() before validation NotEmpty?有关。

  

在构建实体之前修改请求数据   如果需要在将请求数据转换为实体之前对其进行修改,则可以使用Model.beforeMarshal事件。此事件允许您在创建实体之前操作请求数据。 Source: CakePHP 3 Documentation

根据该书,无论是否存在验证错误,我都希望请求数据始终更改。

示例或测试用例:

// /src/Model/Table/UsersTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
// Required for beforeMarshal event:
use Cake\Event\Event;
use ArrayObject;
// Required for Validation:
use Cake\Validation\Validator;

class UsersTable extends Table {

  public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options) {
    $data['firstname'] = trim($data['firstname']);
  }

  public function validationDefault(Validator $validator) {
    $validator
      ->add('firstname', [
        'minLength'   => [ 'rule' => ['minLength', 2], 'message' => 'Too short.' ],
      ])
      ;
    return $validator;
  }
}

如果我进入" d" (空格-d)显示验证错误,但空格本身未在表单中删除。我会表示只显示" d"因为使用beforeMarshal事件从请求数据中删除了空格。那么......错误还是功能?

我的解决方案是在控制器中使用trim() - 函数而不是beforeMarshal事件:

// /src/Controller/UsersController.php
// ...
public function add() {
  $user = $this->Users->newEntity();
  if ($this->request->is('post')) {
    // Use trim() here instead of beforeMarshal?
    $this->request->data['firstname'] = trim($this->request->data['firstname']);
    $user = $this->Users->patchEntity($user, $this->request->data );
    if ( $this->Users->save($user) ) {
      $this->Flash->succeed('Saved');
      return $this->redirect(['controller' => 'Users', 'action' => 'index']);
    } else {
      $this->Flash->error('Error');
    }
  }
  $this->set('user', $user);
}

这样即使存在验证错误,也会删除空格。或者我是否错过了另一个类似于beforeMarshal的功能,它真正修改了请求数据?

2 个答案:

答案 0 :(得分:7)

beforeMarshal的主要目的是帮助用户在可以自动解决简单错误时,或者在需要重新构建数据以便将其放入正确的列时,通过验证过程。

beforMarshal事件仅在验证过程开始时触发,其中一个原因是允许beforeMarshal更改验证规则和保存选项,例如字段白名单。在此事件结束后触发验证。

正如文档所解释的,如果某个字段未通过验证,它将自动从数据数组中删除,将被复制到实体中。这是为了防止实体对象中存在不一致的数据。

此外,beforeMarshal中的数据是请求的副本。这是因为保留原始用户输入很重要,因为它可能在其他地方使用。

如果您需要修剪列并向用户显示修剪结果,我建议您在控制器中执行此操作:

$this->request->data = array_map(function ($d) {
    return is_string($d) ? trim($d) : $d;
}, $this->request->data);

答案 1 :(得分:0)

不起作用。这是我的beforeMarshal

 public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
    {   
        $schema =  $this->schema(); 
        foreach($schema->columns() as $idx => $field  ) {                        
            $sc = $schema->getColumn($field);

            if (isset($data[$field]) &&  $data[$field] != null) { 


     if ($sc['type'] == 'date') {
              $date = DateTime::createFromFormat('d/m/Y',$data[$field]);
              if ($date)
                $data[$field] = $date->format('Y-m-d');
            }
            if ($sc['type'] == 'datetime') {
                debug($data[$field]); 
              $date = DateTime::createFromFormat('d/m/Y',$data[$field]);
              if ($date)
                $data[$field] = $date->format('Y-m-d H:i:s');
            }
        } 
      }  
    debug($data);
}

日期commission_approved_date已在beforeMarshal中正确修改:

/src/Model/Table/AccountsTable.php (line 265)
object(ArrayObject) {
    _referer => 'http://localhost/gessin/Accounts/edit/ODc?filter=eyJBY2NvdW50cy51c2VyX2lkIjoiMTA4NSIsIjAiOiJNT05USChBY2NvdW50cy5jb21taXNzaW9uX2RhdGUpID4gMCIsIllFQVIoQWNjb3VudHMuY29tbWlzc2lvbl9kYXRlKSI6IjIwMjAifQ=='
    description => 'Provvigione su attivazione prodotto vod002'
    notes => 'asd'
    totalpaid => '0'
    commission_approved_date => '2020-02-23 18:34:22'
}

但是在patchEntity之后没有相同的日期:

/src/Controller/AccountsController.php (line 203)
object(App\Model\Entity\Account) {

    'id' => (int) 87,
    'identifier' => null,
    'company_id' => null,
    'created' => object(Cake\I18n\FrozenTime) {

        'time' => '2020-02-29 14:01:50.000000+00:00',
        'timezone' => 'UTC',
        'fixedNowTime' => false

    },
    'modified' => object(Cake\I18n\FrozenTime) {

        'time' => '2020-02-29 18:30:24.000000+00:00',
        'timezone' => 'UTC',
        'fixedNowTime' => false

    },
    'notes' => 'asd',
    'total' => null,
    'totaltax' => null,
    'invoice_id' => null,
    'description' => 'Provvigione su attivazione prodotto vod002',
    'in_out' => null,
    'is_refund' => null,
    'client_id' => null,
    'contract_id' => (int) 32,
    'totalpaid' => (float) 0,
    'user_id' => (int) 1085,
    'commission_date' => object(Cake\I18n\FrozenTime) {

        'time' => '2020-02-04 00:00:00.000000+00:00',
        'timezone' => 'UTC',
        'fixedNowTime' => false

    },
    'commission_approved_date' => object(Cake\I18n\FrozenTime) {

        'time' => '2028-08-12 00:00:00.000000+00:00',
        'timezone' => 'UTC',
        'fixedNowTime' => false

    },
相关问题