错误或功能?如果我使用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
的功能,它真正修改了请求数据?
答案 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
},