背景
有几个业务相关的配置信息需要管理后台灵活配置,且返回的数据要进行排序
为了保证业务接口的请求速度,我们把这些配置信息接口做了缓存
在管理后台进行form表单提交的时候清空缓存,保证数据及时更新(比如删除、修改之后要刷新缓存)
测试阶段发现一个问题,laravel-admin
的 sortable
扩展和框架本身的form表单提交没有关系,执行排序的时候没有回调函数,导致排序操作后无法主动清除缓存。
实现原理分析
我们可以在 form()
函数中 调用 $form->saved(function () { HobbyInfo::flushCache(); });
进行相关操作
但是拖拽排序保存是不会触发这个函数的。
<?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; } }
定位问题
- 点击【保存排序】按钮时查看网络请求,发现了一个不是我定义的路由
_grid-sortable_
- 在项目中搜索这个路由,发现是扩展中的一个路由
- 查看这个扩展相关的源码,发现拖拽排序是不会执行我们写的 form 表单提交相关方法的,源码内容如下:
<?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')); } }
解决问题
- 因为我们有好几个配置模块,需要找到一种通用的配置方式,经过再三考虑,决定修改扩展的源码
- 自定义回调函数
afterSort
,意为在排序之后执行 - 通过阅读源码我们不难发现,我们是能够获得model对象的
- 我们做下兼容判断,如果model中有
afterSort
的话,我们就执行 - 这样,我们就可以在需要执行排序的model中,自定义
afterSort
方法,执行我们的操作,比如刷新缓存。
<?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')); } }
- 我们在自己的model中,比如我的兴趣爱好model,自定义
afterSort
函数就可以了
<?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缓存'); } }
- 这样我们就通过修改源码,实现了自定义回调,在其他model中也可以通过这种方法触发排序后的操作。