验证后 CakePHP 访问上传的文件

CakePHP access uploaded file after validation

我有一个字段 'screenshot',当我尝试在 beforeSave 回调中访问该字段时,它是空的。

我做的是访问 beforeMarshal 回调中的 $data 并存储数组 进入模型设置,然后我可以在 beforeSave 中访问它并将 'screenshot' 字段设置为 filename.ext 如果 move_uploaded_file 为真。

这是当前代码:

型号

// Using CakePHP 3.8.5
public function validationDefault(Validator $validator)
    {
        $validator
            ->allowEmptyFile('screenshot', 'update')
            ->uploadedFile('screenshot' , [
                'types' => ['image/jpeg', 'image/jpg', 'image/pjpeg'],
                'maxSize' => 1000000 // 1MB
            ]);

        return $validator;
    }

public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
    {
        if (isset($data['screenshot']) && $data['screenshot']['error'] === UPLOAD_ERR_OK) {
            $this->config([ 'file_array' => $data['screenshot'] ])
        }
    }

public function beforeSave(Event $event, EntityInterface $entity, ArrayObject $options)
{
    ...
    $file = $this->config([ 'file_array');
    if (move_uploaded_file($file['tmp_name'], $file_path)) {
        return true;
    } else {
        throw new Exception(__('Unable to move...'));
    }

}

表格

<?= $this->Form->create($project, ['type' =>  'file']) ?>
<?= $this->Form->control('screenshot', ['type' => 'file', 'class' => 'form-control-file']) ?>
<?= $this->Form->button(__('Submit'), ['class' => 'btn btn-primary col-md-3 offset-md-9']) ?>
<?= $this->Form->end() ?>

我期望的代码

public function validationDefault(Validator $validator)
    {
        $validator
            ->allowEmptyFile('screenshot', 'update')
            ->uploadedFile('screenshot' , [
                'types' => ['image/jpeg', 'image/jpg', 'image/pjpeg'],
                'maxSize' => 1000000 // 1MB
            ]);

        return $validator;
    }

public function beforeSave(Event $event, EntityInterface $entity, ArrayObject $options)
{
    ...
    $file = $entity->screenshot; // this is empty
    if (move_uploaded_file($file['tmp_name'], $file_path)) {
        return true;
    } else {
        throw new Exception(__('Unable to move...'));
    }

}

为什么保存前 $entity->screenshot 是空的?

这是正确的方法吗?

在编组时(当 patching/creating 个实体时),CakePHP 将 cast/convert 根据为字段映射的 database types 输入。

对于您的数据库字段 screenshot,即 VARCHAR,那将是 \Cake\Database\Type\StringType,如有必要,将是 returns an empty string for arrays. The reasoning being that the marshalling stage shouldn't cause "crashes", but ideally create entities with data compatible to the respective database types, which can finally be validated via application rules,其错误可以很容易地显示出来给用户作为验证规则。

处理这个恕我直言的两种最流行的方法是:

  • 为上传使用不同的字段名称,一个未映射到现有数据库列的名称,例如 screenshot_upload

  • 对字段使用 custom database type,不转换数组

个人比较喜欢前者