You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Backpack PRO中image字段异常:保存时图片路径被清空

更新表单时未修改图片却丢失数据库中logo及stickylogo路径的问题

问题代码(HotelCrudController)

<?php

namespace App\Http\Controllers\Admin;

use App\Http\Requests\HotelRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;

/**
 * Class HotelCrudController
 * @package App\Http\Controllers\Admin
 * @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
 */
class HotelCrudController extends CrudController
{
    use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;

    /**
     * Configure the CrudPanel object. Apply settings to all operations.
     *
     * @return void
     */
    public function setup()
    {
        CRUD::setModel(\App\Models\Hotel::class);
        CRUD::setRoute(config('backpack.base.route_prefix') . '/hotel');
        CRUD::setEntityNameStrings('hotel', 'hotels');
    }

    /**
     * Define what happens when the List operation is loaded.
     *
     * @see  https://backpackforlaravel.com/docs/crud-operation-list-entries
     * @return void
     */
    protected function setupListOperation()
    {
        CRUD::addColumn([
            'name'         => 'company', // name of relationship method in the model
            'type'         => 'relationship',
            'label'        => 'Empresa', // Table column heading
        ]);
        CRUD::addColumn([
            'name'         => 'name', // name of relationship method in the model
            'label'        => 'Nombre', // Table column heading
        ]);
        /**
         * Columns can be defined using the fluent syntax:
         * - CRUD::column('price')->type('number');
         */
    }

    /**
     * Define what happens when the Create operation is loaded.
     *
     * @see https://backpackforlaravel.com/docs/crud-operation-create
     * @return void
     */
    protected function setupCreateOperation()
    {
        CRUD::setValidation(HotelRequest::class);
        //CRUD::setFromDb(); // set fields from db columns.

        // section General information
        CRUD::field([
            'name'  => 'company',
            'label' => 'Compañía',
            'wrapper'   => [
                'class' => 'form-group col-md-10'
            ],
        ])->tab('Información general');

        CRUD::field([
            'name'  => 'enabled',
            'type'  => 'switch',
            'label' => 'Habilitado',
            'color'    => 'primary',
            'wrapper'   => [
                'class' => 'form-group col-md-2 text-center d-flex align-items-center pt-5'
            ],
            'tab' => 'Información general'
        ]);

        CRUD::field([
            'name'  => 'internalname',
            'type'  => 'text',
            'label' => 'Nombre interno',
            'tab' => 'Información general'
        ]);

        CRUD::field([
            'name'  => 'logo',
            'type'  => 'image',
            'label' => 'Logo',
            'wrapper' => [
                'class' => 'form-group col-md-3'
            ],
            'withFiles' => true,
            'tab' => 'Información general'
        ]);

        CRUD::field([
            'name'  => 'stickylogo',
            'type'  => 'image',
            'label' => 'Logo Sticky',
            'wrapper' => [
                'class' => 'form-group col-md-3'
            ],
            'withFiles' => true,
            'tab' => 'Información general'
        ]);

        CRUD::field([
            'name'  => 'name',
            'type'  => 'text',
            'label' => 'Título',
            'wrapper'   => [
                'class' => 'form-group col-md-6'
            ],
            'tab' => 'Información general'
        ]);

        CRUD::field([
            'name'  => 'slug',
            'type'  => 'slug',
            'target' => 'name',
            'label' => 'Slug',
            'wrapper'   => [
                'class' => 'form-group col-md-6'
            ],
            'attributes' => [
                'readonly' => 'readonly'
            ],
            'tab' => 'Información general'
        ]);

        CRUD::field([
            'name'  => 'email',
            'type'  => 'email',
            'label' => 'Correo electrónico',
            'prefix' => '<i class="la la-envelope"></i>',
            'wrapper'   => [
                'class' => 'form-group col-md-6'
            ],
            'tab' => 'Información general'
        ]);

        CRUD::field([
            'name'  => 'telephone',
            'type'  => 'phone',
            'label' => 'Teléfono',
            'wrapper'   => [
                'class' => 'form-group col-md-6'
            ],
            'config' => [
                'initialCountry' => 'es',
                'nationalMode' => true,
                'autoHideDialCode' => false
            ],
            'tab' => 'Información general'
        ]);
        
    }

    /**
     * Define what happens when the Update operation is loaded.
     *
     * @see https://backpackforlaravel.com/docs/crud-operation-update
     * @return void
     */
    protected function setupUpdateOperation()
    {
        $this->setupCreateOperation();
    }
}

问题描述

执行更新操作时,即便没有修改logo和stickylogo字段,数据库中这两个字段的图片路径仍会被清空。

环境信息

  • PHP版本:
    PHP 8.3.4 (cli) (built: Mar 16 2024 08:40:08) (NTS)
    Copyright (c) The PHP Group
    Zend Engine v4.3.4, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.4, Copyright (c), by Zend Technologies
    with Xdebug v3.3.1, Copyright (c) 2002-2023, by Derick Rethans

  • Laravel版本:
    10.45.1.0

  • Backpack包版本:

    • backpack/basset: 1.2.4
    • backpack/crud: 6.6.4
    • backpack/devtools: 3.0.4
    • backpack/editable-columns: 3.0.7
    • backpack/generators: v4.0.3
    • backpack/pagemanager: 3.3.0
    • backpack/permissionmanager: 7.2.0
    • backpack/pro: 2.1.7
    • backpack/theme-tabler: 1.2.3

解决方法

方法1:修改字段配置,禁止空值删除

在setupCreateOperation方法中,给logo和stickylogo字段添加delete_on_null => false,这样未上传新图片时不会清空原有路径:

// Logo字段修改后
CRUD::field([
    'name'  => 'logo',
    'type'  => 'image',
    'label' => 'Logo',
    'wrapper' => [
        'class' => 'form-group col-md-3'
    ],
    'withFiles' => true,
    'delete_on_null' => false, // 新增配置
    'tab' => 'Información general'
]);

// Stickylogo字段修改后
CRUD::field([
    'name'  => 'stickylogo',
    'type'  => 'image',
    'label' => 'Logo Sticky',
    'wrapper' => [
        'class' => 'form-group col-md-3'
    ],
    'withFiles' => true,
    'delete_on_null' => false, // 新增配置
    'tab' => 'Información general'
]);

方法2:在请求类中过滤空文件字段

打开HotelRequest,添加规则并过滤空文件请求,避免空值覆盖原有数据:

public function rules()
{
    return [
        // 其他字段规则...
        'logo' => 'nullable|image|max:2048',
        'stickylogo' => 'nullable|image|max:2048',
    ];
}

// 过滤未上传文件的字段
protected function prepareForValidation()
{
    if (empty($this->file('logo'))) {
        $this->request->remove('logo');
    }
    if (empty($this->file('stickylogo'))) {
        $this->request->remove('stickylogo');
    }
}

方法3:在模型中控制属性赋值逻辑

在Hotel模型中定义属性setter,仅当传入有效文件时更新字段:

public function setLogoAttribute($value)
{
    if ($value instanceof \Illuminate\Http\UploadedFile) {
        // 替换为你的文件存储逻辑
        $path = $value->store('hotels/logos', 'public');
        $this->attributes['logo'] = $path;
    }
    // 非文件输入时不修改原有值
}

public function setStickylogoAttribute($value)
{
    if ($value instanceof \Illuminate\Http\UploadedFile) {
        $path = $value->store('hotels/sticky_logos', 'public');
        $this->attributes['stickylogo'] = $path;
    }
}

内容的提问来源于stack exchange,提问作者Miquel Ángel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 15:49:52