Skip to content

Laravel-admin 重写源码 自定义排序回调

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

laravel-admin 是比较流程的Laravel管理后台框架

背景

有几个业务相关的配置信息需要管理后台灵活配置,且返回的数据要进行排序

为了保证业务接口的请求速度,我们把这些配置信息接口做了缓存

在管理后台进行form表单提交的时候清空缓存,保证数据及时更新(比如删除、修改之后要刷新缓存)

测试阶段发现一个问题,laravel-adminsortable 扩展和框架本身的form表单提交没有关系,执行排序的时候没有回调函数,导致排序操作后无法主动清除缓存。

实现原理分析

我们可以在 form() 函数中 调用 $form->saved(function () { HobbyInfo::flushCache(); }); 进行相关操作

但是拖拽排序保存是不会触发这个函数的。

php
<?php namespace App\Admin\Controllers; . . . class HobbyInfoController extends AdminController {     /**      * Title for current resource.      *      * @var string      */     protected $title = '用户爱好-一级分类';     /**      * Make a grid builder.      *      * @return Grid      */     protected function grid()     {         $grid = new Grid(new HobbyInfo());         $grid->sortable();         .         .         .         return $grid;     }     /**      * Make a show builder.      *      * @param mixed $id      * @return Show      */     protected function detail($id)     {         $show = new Show(HobbyInfo::findOrFail($id));         return $show;     }     /**      * Make a form builder.      *      * @return Form      */     protected function form()     {         $form = new Form(new HobbyInfo());                  .         .         .         //清空缓存         $form->saved(function () {             HobbyInfo::flushCache();         });         return $form;     } }

定位问题

  1. 点击【保存排序】按钮时查看网络请求,发现了一个不是我定义的路由 _grid-sortable_ image.png

  2. 在项目中搜索这个路由,发现是扩展中的一个路由

image.png

  1. 查看这个扩展相关的源码,发现拖拽排序是不会执行我们写的 form 表单提交相关方法的,源码内容如下:
php
<?php namespace Encore\Admin\GridSortable\Controllers; use Exception; use Illuminate\Http\Request; use Illuminate\Routing\Controller; class GridSortableController extends Controller {     public function sort(Request $request)     {         $sorts = $request->get('_sort');         $sorts = collect($sorts)             ->pluck('key')             ->combine(                 collect($sorts)->pluck('sort')->sort()             );         $status = true;         $message = trans('admin.save_succeeded');         $modelClass = $request->get('_model');         try {             /** @var \Illuminate\Database\Eloquent\Collection $models */             $models = $modelClass::find($sorts->keys());             foreach ($models as $model) {                 $column = data_get($model->sortable, 'order_column_name', 'order_column');                 $model->{$column} = $sorts->get($model->getKey());                 $model->save();             }         } catch (Exception $exception) {             $status = false;             $message = $exception->getMessage();         }         return response()->json(compact('status', 'message'));     } }

解决问题

  1. 因为我们有好几个配置模块,需要找到一种通用的配置方式,经过再三考虑,决定修改扩展的源码
  • 自定义回调函数 afterSort ,意为在排序之后执行
  • 通过阅读源码我们不难发现,我们是能够获得model对象的
  • 我们做下兼容判断,如果model中有 afterSort 的话,我们就执行
  • 这样,我们就可以在需要执行排序的model中,自定义afterSort方法,执行我们的操作,比如刷新缓存。
php
<?php namespace Encore\Admin\GridSortable\Controllers; use Exception; use Illuminate\Http\Request; use Illuminate\Routing\Controller; class GridSortableController extends Controller {     public function sort(Request $request)     {         $sorts = $request->get('_sort');         $sorts = collect($sorts)             ->pluck('key')             ->combine(                 collect($sorts)->pluck('sort')->sort()             );         $status = true;         $message = trans('admin.save_succeeded');         $modelClass = $request->get('_model');         try {             /** @var \Illuminate\Database\Eloquent\Collection $models */             $models = $modelClass::find($sorts->keys());             foreach ($models as $model) {                 $column = data_get($model->sortable, 'order_column_name', 'order_column');                 $model->{$column} = $sorts->get($model->getKey());                 $model->save();             }             //自定义回调             if (method_exists($model, 'afterSort')) {                 $model->afterSort();             }         } catch (Exception $exception) {             $status = false;             $message = $exception->getMessage();         }         return response()->json(compact('status', 'message'));     } }
  1. 我们在自己的model中,比如我的兴趣爱好model,自定义 afterSort 函数就可以了
php
<?php namespace App\Model; use App\Model\Cache\CacheKey; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; use Spatie\EloquentSortable\Sortable; use Spatie\EloquentSortable\SortableTrait; class HobbyInfo extends CustomModel implements Sortable {     protected $table = 'tbl_hobby_info';     protected $connection = 'footprint';     protected $primaryKey = 'id';     public $incrementing = true;     use SortableTrait;     public $sortable = [         'order_column_name' => 'sort',         'sort_when_creating' => true,     ];     //改了源码 添加了自定义回调     public static function afterSort()     {         self::flushCache();     }     //清空缓存     public static function flushCache()     {         $cacheKey = CacheKey::getCacheKey(CacheKey::TYPE_USER_SETTING_HOBBY_ALL);         Cache::forget($cacheKey);         Log::info('清空Hobby缓存');     } }
  1. 这样我们就通过修改源码,实现了自定义回调,在其他model中也可以通过这种方法触发排序后的操作。

image.png

Last but not least

技术交流群请到 这里来。 或者添加我的微信 wangzhongyang0601 ,一起学习。

感谢大家的点赞、评论、关注,谢谢大佬们的支持,感谢。

🚀 学习遇到瓶颈?想进大厂?

看完这篇技术文章,如果还是觉得不够系统,或者想在实战中快速提升?
王中阳的就业陪跑训练营,提供定制化学习路线 + 企业级实战项目 + 简历优化 + 模拟面试。

了解训练营详情