controller中重复代码是使用BaseController还是trait,或者?

1. 运行环境

1). 当前使用的 Laravel 版本?

Laravel 9

2). 当前使用的 php/php-fpm 版本?

PHP 版本:
8.1

2. 问题描述?

在多个controller中有大量重复代码,各位大佬是怎么操作的

use App\Models\Test;

class TestController extends Controller
{
    /**
     * Display a listing of the resource.
     * @return View
     */
    public function index(): View
    {
        return view('test.index')
            ->with('dicts', Test::dicts());
    }

    /**
     * Display a listing of the resource.
     * @return JsonResponse
     */
    public function data(): JsonResponse
    {
        list($where, $offset, $limit) = search_param(request());
        $query = Test::where('status', 1)->extWhere($where);
        $list = $query->skip($offset)->limit($limit)->get();
        return json($list, $query->count());
    }

    /**
     * Show the form for creating a new resource.
     * @return View
     */
    public function create(): View
    {
        return view('test.create')->with('dicts', Test::dicts());
    }

    /**
     * Store a newly created resource in storage.
     * @return JsonResponse
     */
    public function store(): JsonResponse
    {
        Test::create(request('af_row'))->save();
        return succ();
    }
    /**
     * Show the form for editing the specified resource.
     *
     * @param    $id
     * @return View
     */
    public function edit($id): View
    {
        return view('test.edit')
            ->with('dicts', Test::dicts())
            ->with('item', Test::findOrFail($id));
    }
    /**
     * Update the specified resource in storage.
     * @return JsonResponse
     */
    public function update(): JsonResponse
    {
        $data = Test::find(request('id'));
        $data->fill(request('af_row'))->save();
        return succ();
    }
    /**
     * Remove the specified resource from storage.
     * @param    $id
     * @return JsonResponse
     */
    public function destroy($id): JsonResponse
    {
        return json(Test::destroy($id));
    }

    /**
     * Display the specified resource.
     * @param  $id
     * @return Response
     */
    public function show($id): Response
    {
        return view('test.show')
            ->with('dicts', Test::dicts())
            ->with('item', Test::findOrFail($id));
    }
}

如上,这是一个简单的curd的控制器,其中各个方法的内容大部分都是可以复用的,
只有视图名、模型名有变化,请问如何优雅的处理这些重复的代码,而不用反复的复制粘贴,修改模型名称?
目前我直接考虑了两种,BaseController或者trait,大概逻辑如下:

class BaseController extends Controller
{
    protected $model ;
    protected $viewPath = '';
    /**
     * Display a listing of the resource.
     * @return View
     */
    public function index(): View
    {
        return view($this->viewPath . 'index')
            ->with('dicts', $this->model::dicts());
    }
}
trait Curd
{
    protected $model ;
    protected $viewPath = '';
    /**
     * Display a listing of the resource.
     * @return View
     */
    public function index(): View
    {
        return view($this->viewPath . 'index')
            ->with('dicts', $this->model::dicts());
    }
}
class TestController extends BaseController
{
    //不继承BaseController,使用trait
    //use Curd;
    protected $model ;
    protected $viewPath = '';
    public function __construct(Request $request)
    {
        $this->viewPath = 'test.';
        $this->model = Test::class;
    }
}

还有其他更优雅的处理方法吗?

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
fatrbaby
最佳答案

你举例的重复代码,这两种解决方案都不太好。代码不仅包含“复用”问题,还包含“职责”问题。这两种方案代码是复用了,但职责不清了。这种情况个人觉得比较好的方法是使用脚手架生成CRUD代码。

但是Spring框架的创始人Rod Johnson说过:如果是能生成的代码为什么要生成它?

所以更好的方案是设计一套机制,类似于 Laravel 的 资源型控制器 机制来处理他。

1年前 评论
____Laravel (楼主) 1年前
fatrbaby (作者) 1年前
____Laravel (楼主) 1年前
fatrbaby (作者) 1年前
____Laravel (楼主) 1年前
讨论数量: 8
fatrbaby

你举例的重复代码,这两种解决方案都不太好。代码不仅包含“复用”问题,还包含“职责”问题。这两种方案代码是复用了,但职责不清了。这种情况个人觉得比较好的方法是使用脚手架生成CRUD代码。

但是Spring框架的创始人Rod Johnson说过:如果是能生成的代码为什么要生成它?

所以更好的方案是设计一套机制,类似于 Laravel 的 资源型控制器 机制来处理他。

1年前 评论
____Laravel (楼主) 1年前
fatrbaby (作者) 1年前
____Laravel (楼主) 1年前
fatrbaby (作者) 1年前
____Laravel (楼主) 1年前
fatrbaby

你举例的重复代码,这两种解决方案都不太好。代码不仅包含“复用”问题,还包含“职责”问题。这两种方案代码是复用了,但职责不清了。这种情况个人觉得比较好的方法是使用脚手架生成CRUD代码。

但是Spring框架的创始人Rod Johnson说过:如果是能生成的代码为什么要生成它?

所以更好的方案是设计一套机制,类似于 Laravel 的 资源型控制器 机制来处理他。

1年前 评论
____Laravel (楼主) 1年前
fatrbaby (作者) 1年前
____Laravel (楼主) 1年前
fatrbaby (作者) 1年前
____Laravel (楼主) 1年前
class MacroServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     * @return void
     */
    public function boot()
    {
        $this->registerRouteMacro();
    }

    public function registerRouteMacro()
    {
        if (!Route::hasMacro('curd')) {
            Route::macro('curd', function ($path, $model) {
                Route::get($path . '/index', function () use ($path, $model) {
                    $prefix = request()->route()->getPrefix();
                    $viewPath = str((filled($prefix) ? $prefix . '/' : '') . $path)
                        ->replace('/', '.')->trim('.');
                    return view($viewPath . '.index')
                        ->with('dicts', $model::dicts())
                        ->with('searchList', $model::dictAppends());
                });
                Route::post($path . '/data', function () use ($path, $model) {
                    list($where, $offset, $limit) = search_param(request());
                    $query = $model::extWhere($where);
                    $list = $query->skip($offset)->limit($limit)->get()
                               ->append($model::dictAppends());
                    return json($list, $query->count());
                });
            });
        }
    }
}

感谢@fatrbaby 大佬 实现了,后续考虑加入一个控制器是否存在判断,如果存在控制器且存在控制器方法,优先使用控制器方法。

1年前 评论
九霄道长

trait 属于 has a 继承 属于 is a

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!