Laravel-Admin 自定义删除完整实现

在 Laravel-admin 后台开发附件/文件管理模块时,默认删除会直接硬删数据库,不删除物理文件、不执行自定义逻辑,极易造成服务器垃圾文件堆积。

本文提供可直接复制上线的完整方案:自定义单行删除 + 批量删除,统一删除逻辑、自动删文件、写日志、弹窗确认,完美解决原生删除的所有痛点。

目录

核心问题原理

整体实现

分步完整代码实现

模型层:封装文件删除逻辑

单条自定义删除(行操作)

创建行删除动作类

批量自定义删除

创建批量删除动作类

[控制器 Grid 配置](#控制器 Grid 配置)

[控制器原有 destroy 方法(可保留)](#控制器原有 destroy 方法(可保留))

完整执行流程

关键避坑点

不要使用默认删除

[必须禁用 actions-\>disableDelete()](#必须禁用 actions->disableDelete())

文件路径必须对应

编辑删除旧文件复用同一方法

[批量删除必须用 BatchAction 类](#批量删除必须用 BatchAction 类)

总结


核心问题原理

laravel-admin 默认删除按钮:前端直接 AJAX 硬删数据库,不进入控制器 destroy() 方法

所以:自定义逻辑(删文件、日志、权限判断)全部失效

解决方案:禁用系统默认删除 + 自定义行删除动作类 接管删除逻辑

整体实现

控制器:保留原生 destroy(备用),不再使用

自定义单行删除动作类:接管单条删除

自定义批量删除动作类:接管批量删除

模型封装 deleteFile():统一处理物理文件删除

Grid 配置:关闭默认删除、注入自定义删除按钮

分步完整代码实现

模型层:封装文件删除逻辑

模型文件Attachment.php统一处理本地文件删除、日志记录,所有删除场景复用。

代码如下:

php 复制代码
/**
     * 删除服务器上的文件
     */
    public function deleteFile()
    {
        try {
            // 正确用法:用 Storage 删除(你的上传驱动是 admin)
            $deleted = Storage::disk('admin')->delete($this->path);

            Log::info('删除文件结果:'.($deleted ? '成功' : '文件不存在'), [
                'path' => $this->path,
                'url'  => $this->url
            ]);

            return true;
        } catch (\Exception $e) {
            Log::error('删除文件失败:'.$e->getMessage());
            return false;
        }
    }
单条自定义删除(行操作)
创建行删除动作类

路径:app/Admin/Actions/DeleteAttachment.php

php 复制代码
<?php

namespace App\Admin\Actions;

use Encore\Admin\Actions\RowAction;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;

class DeleteAttachment extends RowAction
{
    public $name = '删除';

    public function dialog()
    {
        $this->confirm('确定删除这个附件吗?文件会被永久删除!');
    }

    public function handle(Model $model)
    {
        try {
            Log::info('===== 自定义单条删除执行 =====');
            
            // 删除文件
            $model->deleteFile();
            
            // 删除数据库
            $model->delete();

            return $this->response()->success('删除成功!')->refresh();
        } catch (\Exception $e) {
            Log::error('删除失败:'.$e->getMessage());
            return $this->response()->error('删除失败:'.$e->getMessage());
        }
    }
}
批量自定义删除
创建批量删除动作类

路径:app/Admin/Actions/BatchDeleteAttachment.php

php 复制代码
<?php

namespace App\Admin\Actions;

use Encore\Admin\Actions\BatchAction;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;

class BatchDeleteAttachment extends BatchAction
{
    public $name = '批量删除';

    public function handle(Collection $collection)
    {
        foreach ($collection as $model) {
            try {
                // 删除文件
                $model->deleteFile();
                // 删除数据库记录
                $model->delete();
            } catch (\Exception $e) {
                Log::error('批量删除失败:'.$e->getMessage());
                continue;
            }
        }

        return $this->response()->success('批量删除成功')->refresh();
    }

    // 确认弹窗
    public function dialog()
    {
        $this->confirm('确定删除选中的附件吗?文件会被永久删除!');
    }
}
控制器 Grid 配置

AttachmentController.php 中 grid() 方法内,关闭默认删除,注入自定义按钮

php 复制代码
/**
     * Make a grid builder.
     * @return Grid
     */
    protected function grid()
    {
        $grid = new Grid(new Attachment());

        $grid->column('id', __('ID'))->sortable();
        $grid->column('name', __('原文件名称'))->limit(30);
        
        $grid->column('thumbnail', __('预览'))->display(function () {
            // 判断是否为图片
            $isImage = in_array(strtolower($this->extension), ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']);
            if ($isImage) {
                return "<img src='{$this->url}' style='max-width:100px;max-height:100px;border-radius:4px;' />";
            } else {
                return "<i class='fa {$this->file_icon}' style='font-size:2rem;color:#1890ff;'></i>";
            }
        });
        
        $grid->column('filename', __('文件名'))->limit(20);
        $grid->column('type', __('类型'))->using(Attachment::getTypeOptions());
        $grid->column('extension', __('扩展名'));
        $grid->column('size', __('文件大小'))->display(function () {
            return Attachment::formatFileSize($this->size);
        });
        
        $grid->column('dimensions', __('尺寸'))->display(function () {
            // 判断是否为图片
            $isImage = in_array(strtolower($this->extension), ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']);
            if ($isImage && $this->width && $this->height) {
                return "{$this->width} x {$this->height}";
            }
            return '-';
        });
        
        $grid->column('uploaded_by', __('上传人'))->display(function () {
            return $this->uploader ? $this->uploader->name : '-';
        });
        
        $grid->column('created_at', __('上传时间'))->display(function ($time) {
            return date('Y-m-d H:i:s', strtotime($time));
        });

        $grid->disableFilter();
        $grid->disableExport();

        // ======================
        // 核心:禁用默认删除,使用自定义删除
        // ======================
        $grid->actions(function ($actions) {
            $actions->disableDelete(); // 关闭默认删除
            $actions->disableView(); // 关闭默认查看
            $actions->add(new \App\Admin\Actions\DeleteAttachment()); // 使用自定义删除
        });

        // 批量删除
        $grid->batchActions(function ($batch) {
            $batch->disableDelete();
            $batch->add(new \App\Admin\Actions\BatchDeleteAttachment());
        });

        return $grid;
    }
控制器原有 destroy 方法(可保留)

因为我们已经用自定义动作类接管删除,此方法不会执行,可保留做备用。

php 复制代码
public function destroy($id)
{
    // 原生销毁方法,当前方案不再使用
}

完整执行流程

列表点击【删除】按钮

触发自定义 DeleteAttachment 动作类

弹窗二次确认

执行 $model->deleteFile() 删除服务器文件

执行 $model->delete() 删除数据库记录

返回成功提示 + 刷新列表

自动写入日志,完整记录删除行为

关键避坑点

不要使用默认删除

默认删除不走控制器、不走自定义代码,只删库不删文件

必须禁用 $actions->disableDelete()

不禁用会同时存在两套删除,逻辑冲突

文件路径必须对应

使用 public_path() 拼接绝对路径,适配本地上传目录

编辑删除旧文件复用同一方法

编辑重新上传时,直接调用 $old->deleteFile() 复用逻辑

批量删除必须用 BatchAction 类

低版本 laravel-admin 不支持闭包批量操作,会直接报错

总结

本文完整实现了 Laravel-admin 附件模块安全删除方案,核心总结:

解决痛点:修复原生删除只删库不删文件的严重问题。

方案标准:使用官方 Action 扩展,无兼容风险、结构清晰。

功能完整:支持单行删除、批量删除、确认弹窗、文件删除、日志记录。

高度复用:模型封装删除方法,编辑 / 删除场景共用一套逻辑。

线上安全:异常捕获、错误提示、日志追踪,生产环境可直接使用。

该方案是 Laravel-admin 文件/附件管理的标准最佳实践,几乎所有后台项目都能直接套用。

相关推荐
wangl_922 小时前
Modbus TCP/IP 地址完全解析手册
网络·tcp/ip·php·modbus·kepware·kepserverex
%KT%2 小时前
Agent开发:自动查天气+景区推荐
linux·数据库·php
niucloud-admin4 小时前
PHP V6 单商户常见问题——升级/云编译目录读写权限状态不通过如何处理
php
JSON_L4 小时前
Laravel-Admin 新增和编辑差异化显示
php·laravel·laravel-admin
niucloud-admin4 小时前
PHP V6 单商户常见问题——卸载应用插件编译报错问题处理
php
学网安的肆伍18 小时前
【043-WEB攻防篇】PHP应用&SQL注入&符号拼接&请求方法&HTTP头&JSON&编码类
sql·安全·php
研究点啥好呢20 小时前
字节跳动Go后端开发工程师面试题精选:10道高频考题+答案解析
面试·golang·php·求职招聘
kybs199121 小时前
springboot租车系统--附源码68701
java·hadoop·spring boot·python·django·asp.net·php
wxin_VXbishe1 天前
springboot新能源车充电站管理系统小程序-计算机毕业设计源码29213
java·c++·spring boot·python·spring·django·php