Laravel-admin特殊路由操作

背景

最近在重构项目, 针对之前的数据库表做了 分表设计 设计结构如下:

1
2
3
apps 应用表
app_channel_appuuid 渠道表 (渠道表的表名是 app_channel_拼接对应的 appuuid 生成)
app_versions_appuuid 版本表(版本表的表名是 app_version_拼接对应的appuuid 生成)

结构如上所示,所以整个路由不在使用 resource路由,路由如下:

1
2
3
4
5
6
// 渠道管理
$router->get('/channel/{app_id?}', 'ChannelController@index')->name('channel');
$router->get('/channel/{app_id}/create', 'ChannelController@create')->name('channel.create');
$router->post('/channel/{app_id}', 'ChannelController@store')->name('channel.store');
$router->get('/channel/{app_id}/{id}/edit', 'ChannelController@edit')->name('channel.edit');
$router->put('/channel/{app_id}/{id}', 'ChannelController@update')->name('channel.update');

修改 (编辑添加操作路径)

由于后台框架使用的是 laravel-admin 增加按钮和编辑按钮的路径是如下图所示:

发现没有带上 指定的 app_id, 搜索官方文档 未找到有效的说明,翻看源码 在 Grid.php 找到了一个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Set resource path for grid.
*
* @param string $path
*
* @return $this
*/
public function setResource($path)
{
$this->resourcePath = $path;

return $this;
}

然后在 控制器的 grid 方法中加一行:

1
$grid->setResource(route('admin.channel') . '/' . $app_info->id);

路径就会正确:

修改(删除操作)

laravel-admin 提供的删除操作,在这里不太适用,所以先屏蔽掉了

1
$actions->disableDelete();

然后自定义了一个删除操作:

1
php artisan admin:action Channel\\DeleteAppChannel --grid-row --name="删除"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace App\Admin\Actions\Channel;

use Encore\Admin\Actions\RowAction;
use Illuminate\Database\Eloquent\Model;

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

public function handle(Model $model)
{
// $model ...

return $this->response()->success('Success message.')->refresh();
}
}
1
2
3
$grid->actions(function ($actions) {
$actions->add(new DeleteAppChannel);
});

在这里遇到一个问题, 就是由于 model 对应的表示动态拼接的,所以 如果直接这样操作,就会出现 表找不到的情况, 所以做了如下改动,给DeleteAppChannel 类加了一个 属性 app_Info 并且加了一个方法:

1
2
3
4
5
public function setAppId($app_info): static
{
$this->app_info = $app_info;
return $this;
}

然后修改 grid 如下:

1
2
$obj = new DeleteAppChannel();
$actions->add($obj->setAppId($app_info));

然后在 handle 的 model 里指定 表名 发现不太行, 最后只能 翻源码, 发现 系统提供的删除 是通过 pajax 传递指定的 model 然后传递指定 key 来操作的, 传递参数如下图所示:

然后 通过 反射操作 先通过 _model 参数的值 和 _key 的值进行了 查询操作, 查询对应的数据 然后删除的,最后想的办法是 在这个 传递的时候 能否把 app_uuid 也传递过去 然后 查询的时候 指定一下 对应的表名, 在不修改 框架代码的情况下 找到了如下的方法:

1
2
3
4
5
6
7
8
/**
* @return array
*/
public function parameters()
{
return ['_model' => $this->getModelClass()];
}

该方法在 GridAction 中, 然后 RowAction 继承了 GridAction,然后自定义的操作又继承了 RowAction

所以在自定义的 DeleteAppChannel 方法中重写了一下 parameters

1
2
3
4
5
6
7
8
public function parameters(): array
{
$arr = parent::parameters();
if ($this->app_info) {
$arr['app_uuid'] = $this->app_info->uuid;
}
return $arr;
}

传递了一下对应APP 的 app_uuid传递过去

最后重写了一下 RowAction 中的 retrieveModel 方法,指定一下model对应的表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @param Request $request
*
* @return mixed
*/
public function retrieveModel(Request $request): mixed
{
if (!$key = $request->get('_key')) {
return false;
}
$modelClass = str_replace('_', '\\', $request->get('_model'));
if ($this->modelUseSoftDeletes($modelClass)) {
return $modelClass::withTrashed()->findOrFail($key);
}
if ($app_uuid = $request->get('app_uuid')) {
$obj = new $modelClass;
$obj->setTable('app_channel_' . $app_uuid);
return $obj->findOrFail($key);
}
return $modelClass::findOrFail($key);
}