如何封装laravel-admin管理后台控制器功能与调用?

我们在开发管理时候,会发现大部分代码与普通管理代码在控制器中是相同的,如果我们添加新的网站功能(比如众筹秒杀等),在编写代码过程中还需要将重复的代码重新编写一遍或者复制过来,如果后期对于系统有所更改那么就需要同时修改所有控制器中的代码。这样不仅会让系统代码过于庞大也不利于后期的维护与升级,这里就需要对通用代码进行代码封装,这样以后添加新的商品类型只需要编写与通用代码不相同的部分代码即可,laravel-admin管理后台为例子。

1.laravel-admin控制器代码分析

  1. 接下来我们来分析一下哪些地方是可以共用的:
  2. index() / create() / edit() 这三个方法除了里面的页面标题不同,其他代码都是一样的;
  3. 都需要 grid() 和 form() 方法;
  4. grid() 方法中都需要按 type 字段过滤;
  5. grid() 方法中都需要禁用『查看』、『删除』 和『批量删除』按钮;
  6. form() 方法中都需要添加一个隐藏的 type 字段;
  7. 这里我们将“Xxxx”定义为模型文件
Xxxx模型代码如下:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class Xxxx extends Model
{
    const TYPE_NORMAL = 'normal';
    const TYPE_CROWDFUNDING = 'crowdfunding';
    public static $typeMap = [
        self::TYPE_NORMAL  => '普通商品',
        self::TYPE_CROWDFUNDING => '众筹商品',
    ];
    protected $fillable = [
        'title', 'description', 'image', 'on_sale',
        'rating', 'sold_count', 'review_count', 'price',
        'type',
    ];
    protected $casts = [
        'on_sale' => 'boolean', // on_sale 是一个布尔类型的字段
    ];
}

2. 开始封装

针对上面的分析逐步来实现代码封装。

2.1创建一个公共的控制器文件

$ touch app/Admin/Controllers/CommonController.php

之后需要在这个文件中创建相应的抽象类CommonController,以来完成代码的封装

app/Admin/Controllers/CommonController.php
<?php

namespace App\Admin\Controllers;

use App\Http\Controllers\Controller;

abstract class CommonController extends Controller
{

}

2.2封装增改查页面

接下来我们要封装 index() / create() / edit() 这三个方法,

app/Admin/Controllers/CommonController.php
<?php

namespace App\Admin\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Xxxx;
use Encore\Admin\Controllers\HasResourceActions;
use Encore\Admin\Layout\Content;

abstract class CommonController extends Controller
{
    use HasResourceActions;

    // 定义一个抽象方法,返回当前管理的模型类型
    abstract public function getXxxxType();

    public function index(Content $content)
    {
        return $content
            ->header(Xxxx::$typeMap[$this->getXxxxType()].'列表')
            ->body($this->grid());
    }

    public function edit($id, Content $content)
    {
        return $content
            ->header('编辑'.Xxxx::$typeMap[$this->getXxxxType()])
            ->body($this->form()->edit($id));
    }

    public function create(Content $content)
    {
        return $content
            ->header('创建'.Xxxx::$typeMap[$this->getXxxxType()])
            ->body($this->form());
    }
}

2.3现在修改 XxxxController,使其继承 CommonController 类,添加 getXxxxType() 方法,移除 index() / create() / edit() 这三个方法,以及移除 HasResourceActions 这个 Trait:

app/Admin/Controllers/XxxxController.php
class XxxxController extends CommonController
{
    // 移除 HasResourceActions
    public function getXxxxType()
    {
        return Xxxx::TYPE_NORMAL;//这里是调用定义的模型中的常量
    }
    // 移除 `index()` / `create()` / `edit()` 这三个方法
}

这样就将index() / create() / edit() 这三个方法封装完毕了。

2.4接下来封装 grid() 和 form() 两个方法到 CommonController 类中:

app/Admin/Controllers/CommonController.php
use Encore\Admin\Grid;
use Encore\Admin\Form;
.
.
.
abstract class CommonProductsController extends Controller
{
    .
    .
    .
    protected function grid()
    {
        $grid = new Grid(new Product());

        // 筛选出当前类型的商品,默认 ID 倒序排序
        $grid->model()->where('type', $this->getXxxxType())->orderBy('id', 'desc');
        // 调用自定义方法
        $this->customGrid($grid);

        $grid->actions(function ($actions) {
            $actions->disableView();
            $actions->disableDelete();
        });
        $grid->tools(function ($tools) {
            $tools->batch(function ($batch) {
                $batch->disableDelete();
            });
        });

        return $grid;
    }

    // 定义一个抽象方法,各个类型的控制器将实现本方法来定义列表应该展示哪些字段
    abstract protected function customGrid(Grid $grid);

    protected function form()
    {
        $form = new Form(new Product());
        // 在表单页面中添加一个名为 type 的隐藏字段,值为当前商品类型
        $form->hidden('type')->value($this->getXxxxTyp());
        $form->text('title', '商品名称')->rules('required');
        
        $form->image('image', '封面图片')->rules('required|image');
        $form->editor('description', '商品描述')->rules('required');
        $form->radio('on_sale', '上架')->options(['1' => '是', '0' => '否'])->default('0');

        // 调用自定义方法
        $this->customForm($form);

        

        return $form;
    }

    // 定义一个抽象方法,各个类型的控制器将实现本方法来定义表单应该有哪些额外的字段
    abstract protected function customForm(Form $form);

2.5接下来我们需要在需要调用封装代码的控制器上实现customGrid() 和 customForm() 这两个方法,当然还要删除原本控制器中的grid()和form()方法:

app/Admin/Controllers/XxxxController.php
<?php

namespace App\Admin\Controllers;

use App\Models\Xxxx;
use Encore\Admin\Form;
use Encore\Admin\Grid;

class XxxxController extends CommonProductsController
{
    public function getXxxxType()
    {
        return Xxxx::TYPE_NORMAL;
    }

    protected function customGrid(Grid $grid)
    {
        $grid->model()->with(['category']);
        $grid->id('ID')->sortable();
        $grid->title('商品名称');
        $grid->column('category.name', '类目');
        $grid->on_sale('已上架')->display(function ($value) {
            return $value ? '是' : '否';
        });
        $grid->price('价格');
        $grid->rating('评分');
        $grid->sold_count('销量');
        $grid->review_count('评论数');
    }

    protected function customForm(Form $form)
    {
        // 普通商品没有额外的字段,因此这里不需要写任何代码
    }
}

OK这样laravel-admin后台控制功能封装与调用就完成了。

阅读 223

Comments