为什么 patchEntity() 会截取图像信息? (CakePHP3)

Why does patchEntity() cut out image information? (CakePHP3)

使用 POST 方法 $data = $this->request->getData(); ,我得到了存档:

[
        'category_id' => '62',
        'title' => 'Name-1',
        'body' => '<p>Text</p>
    ',
        'price' => '30',
        'is_new' => '1',
        'img' => [
            'tmp_name' => 'D:\Web\OpenServer\userdata\temp\php70D9.tmp',
            'error' => (int) 0,
            'name' => 'IronMan.jpg',
            'type' => 'image/jpeg',
            'size' => (int) 131830
        ]
]

通过为数据库中的记录准备这些数据:

$product = $this->Products->patchEntity($product, $data);

但是 patchEntity() 方法删除了有关图像的所有信息。 我得到:

object(App\Model\Entity\Product) {

    'category_id' => (int) 62,
    'title' => 'Name-1',
    'body' => '<p>Text</p>
',
    'price' => (float) 30,
    'is_new' => (int) 1,
    'img' => '', // <--- empty :(
    '[new]' => true,
    '[accessible]' => [
        'category_id' => true,
        'title' => true,
        'body' => true,
        'price' => true,
        'img' => true,
        'is_new' => true,
        'created' => true,
        'modified' => true,
        'category' => true
    ],
    '[dirty]' => [
        'category_id' => true,
        'title' => true,
        'body' => true,
        'price' => true,
        'is_new' => true,
        'img' => true
    ],
    '[original]' => [],
    '[virtual]' => [],
    '[errors]' => [],
    '[invalid]' => [],
    '[repository]' => 'Products'

}

可以修复吗?至少告诉我一下。谢谢。

当 patching/creating 一个实体时,数据根据各自的列数据类型进行编组,正如您可以看到的其他属性,如 price,它从字符串转换为浮点数.

您的 img 列可能是字符串类型,导致编组器相应地转换数据(参见 \Cake\Database\Type\StringType::marshal())。

有多种方法可以避免这种情况,例如使用不映射到现有列的不同 属性 名称,例如 img_upload,然后在移动上传后,手动设置img 属性 的结果文件系统路径并保存。

这也可以在您的 ProductsTable class 的 beforeMarshal 事件中完成,以便视图模板可以继续使用 img 属性:

public function beforeMarshal(
    \Cake\Event\Event $event,
    \ArrayObject $data,
    \ArrayObject $options
) {
    if (isset($data['img'])) {
        $data['img_upload'] = $data['img'];
        unset($data['img']);
    }
}

您还可以为 img 列创建一个自定义数据库类型,它不会将数据编组为字符串,而只是将其传递:

namespace App\Database\Type;

use Cake\Database\Type;

class FileType extends Type
{
    public function marshal($value)
    {
        return $value;
    }
}

无论如何你都必须分配文件系统路径,你基本上只是避免使用 separate/temporary 属性.

另见

我不知道这在多大程度上是正确的,但最后我做了以下操作并且一切正常:

在 ProductsController:

 public function add()
{
    $product = $this->Products->newEntity();

    if ($this->request->is('post')) {
        $data = $this->request->getData();

        $product = $this->Products->patchEntity($product, $data);

        // If there is a picture that we checked (by the method of validationDefault, when calling patchEntity) and have already uploaded to the server in a temporary folder, then
        if($product->img_upload['name']){
            // We call the user method of processing the downloaded image
            $product = $this->_customUploadImg($product);
            // Leave only the name of the new file, adding it to the new property, with the name corresponding to the name of the table in the database
            $product->img = $product->img_upload['name'];
        }
        // Delete an unnecessary property
        unset($product->img_upload);

        if ($this->Products->save($product)) {
            // ...
        }
    // ...
}

在Product.php中:

    class Product extends Entity{
    protected $_accessible = [
        'category_id' => true,
        'title' => true,
        'body' => true,
        'price' => true,
        'is_new' => true,
        'created' => true,
        'modified' => true,
        'category' => true,

        // 'img' => true,
        // Here we specify not 'img' as in the database table, but 'img_upload', in order for ProductsController not to delete our data file about the uploaded file when patchEntity was called.
        'img_upload' => true,
    ];
}

在ProductsTable.php中:

public function validationDefault(Validator $validator)
{
    //...

     $validator
        ->allowEmpty('img_upload', 'create')
        ->add('img_upload', [
            'uploadError' => [
                'rule' => 'uploadError',
                'message' => 'Error loading picture'
            ],
            'mimeType' => [
                'rule' => ['mimeType', ['image/jpeg', 'image/jpg', 'image/png', 'image/gif']],
                'message' => 'Only image files are allowed to be uploaded: JPG, PNG и GIF'
            ],
            'fileSize' => [
                'rule' => ['fileSize', '<=', '2MB'],
                'message' => 'The maximum file size should be no more than 2 MB'
            ]
        ]);

    //...
}

在add.ctp中:

echo $this->Form->create($product, ['type' => 'file']) ?>
// ...
echo $this->Form->control('img_upload', ['type' => 'file', 'label'=>'Product photo']);
//...

谢谢 "ndm" 和 "mark"!