Dcat-admin 是一个基于 laraval-admin 二次开发的框架。Dcat Admin 中文文档

安装的时候比较轻松,想的是可以摆脱后台繁琐的 CURD 操作和权限控制,但也具有一定的学习成本。用的时候好用,出现问题了也难改。

这次是一个简单的新闻+分类内容,接口可以自由发挥,后台部分就比较难搞了。考虑到新闻可能会遇到多个分类的情况,即创建了关系表,并按照多对多的关系创建模型。

Dcat-admin 是不需要创建 view 的,内容全都靠控制器里的三个方法来输出。Dcat\Admin\Grid 对应数据表格,即列表的显示,数据仓库 repos 因为是 mysql 数据库可加可不加;Dcat\Admin\Form 对应数据表单,表单包含了创建、修改页面;Dcat\Admin\Show 对应数据详情页显示,是一个不能编辑只做展示的页面。三个类型的方法主要通过配置字段和扩展方法来定义页面。

我一开始使用 select 单选控件,通过接口返回 select 需要的数据,并且创建表单提交是成功的。

    protected function form()
    {
        return Form::make(SiteNews::with(['metas']), function (Form $form) {
            ...
            $form->select('metas', '分类')
                ->required()
                ->options('api/news-metas');
     ...

SiteNews 对应新闻,metas 是新闻里定义的分类关联关系。但是在修改页面报错了:Array to string conversion。由于 php 框架的通病,压根找不到关键代码片段,搞的人很烦躁。再去看 Dcat 的文档就更烦躁了。前面提到过 Form 方法定义了创建和修改页面,即创建和修改使用的同一个方法返回的对象。

Dcat 文档中关于 select 单选部分内容并不多:

// 正常调用
$form->select($column[, $label])->options([1 => 'foo', 2 => 'bar', 'val' => 'Option name']);
// ajax 方式动态分页载入
$form->select('user_id')->options(function ($id) {
    $user = User::find($id);

    if ($user) {
        return [$user->id => $user->name];
    }
})->ajax('api/users');

文档让人困惑的点是,$column[, $label] 前面没有定义过,就这么突然出现了,那个是变量,那个是需要替换的部分完全没办法去理解。

一开始我以为是可以通过 ajax 方式筛选出当前选择的项,结果依然报数组转字符串的错误。想找 laravel-admin 的原始文档,但文档建在 github 上,太卡了根本看不了。

我也注意到文档中的 关联关系 部分,按照模型结构来讲我的表应该是多对多的关系,但既然创建表单可以提交,为什么到了修改就不行呢?这说不通。

针对这种多对多的关系,可以选择多选框,也可以选择树状结构。最后参考 menu 与 permission 部分,选择了树状结构。主要是需要针对模型新闻分类做增加一些方法,使其可以返回树状结构数据。然后按照示例代码作修改就可以:

    protected function form()
    {
        return Form::make(SiteNews::with(['metas']), function (Form $form) {
            ...
            $form->tree('metas', '分类')
                ->treeState(false)
                ->setTitleColumn('name')
                ->nodes(function () {
                    return (new NewsMeta)->allNodes();
                })
                ->customFormat(function ($v) {
                    if (! $v) {
                        return [];
                    }

                    return array_column($v, 'id');
                });
    ...

其中的 setTitleColumn('name') 是设置节点标题显示内容的,这里就用了分类名;allNodes() 就是需要参考已有的菜单模型里的改改的。

然后这样就好了,这又是令人印象深刻的情况。

分类树状结构