错误或功能?如果我使用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
的功能,它确实在修改请求数据?
beforeMarshal
的主要目的是在可以自动解决简单的错误或需要重构数据以便将其放入正确的列中时,帮助用户通过验证过程。
beforMarshal
事件仅在验证过程开始时触发,原因之一是允许beforeMarshal
更改验证规则和保存选项,例如字段白名单。此事件结束后立即触发验证。
如文档所述,如果字段未通过验证,则它将自动从数据数组中删除,并not复制到实体中。这是为了防止实体对象中的数据不一致。
此外,beforeMarshal
中的数据是请求的副本。这是因为保留原始用户输入很重要,因为它可能在其他地方使用。
如果需要修剪列并向用户显示修剪结果,建议在控制器中进行:
$this->request->data = array_map(function ($d) {
return is_string($d) ? trim($d) : $d;
}, $this->request->data);
不起作用。这是我的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
},