Laravel - Reusable resource controller Laravel - Reusable resource controller php php

Laravel - Reusable resource controller


After the comments I could understand better.I had the same issue here and that's my workaround

class BaseController extends Controller{     protected function _store($request)     {     ....     } ... } class MyController extends BaseController { ....      public function store(MyRequest $request)      {          //do something          return parent::_store($request);      } }


Short answer:

Bindings.

One Route::model.

And one Simple Binding for each Form Request type, using Interfaces for the Method Injection in the Controller.

Long answer applied to your example:

Models binding in routes/web.php:

<?phpRoute::model('example', App\Example::class);Route::resource('example', 'Admin\ExampleController');

Requests bindings in the Controller Base:

<?phpnamespace App\Http\Controllers\Admin;use App\Http\Requests;use App\Http\Controllers\Controller;class BaseController extends Controller{    // Your code...    /**     * @var string[]|callable[]     */    protected $bindings = [];    /**     * Controller constructor.     */    public function __construct()    {        $this->addBindings();    }    /**     * Add controller specific bindings.     */    protected function addBindings()    {        $app = Container::getInstance();        foreach ($this->getBindings() as $abstract => $concrete) {            $app->bind($abstract, $concrete);        }    }    // Your code...    public function store(Requests\StoreRequestInterface $request)    {        // Your code...    }    public function show(Model $item)    {        // Your code...    }    public function edit(Model $item)    {        // Your code...    }    public function update(Requests\UpdateRequestInterface $request, Model $model)    {        // Your code...    }    public function status(Requests\StatusRequestInterface $request, Model $model)    {        // Your code...    }    public function destroy(Model $item)    {        // Your code...    }    // Your code...}

And the Example Controller:

<?phpnamespace App\Http\Controllers\Admin;use App\Http\Requests;class ExampleController extends BaseController{    // Your code...    /**     * @var string[]|callable[]     */    protected $bindings = [        Requests\StatusRequestInterface::class => Requests\ExampleStatusRequest::class,        Requests\StoreRequestInterface::class  => Requests\ExampleStoreRequest::class,        Requests\UpdateRequestInterface::class => Requests\ExampleUpdateRequest::class,    ];    // Your code...}

So the Requests interfaces would look something like:

<?phpnamespace App\Http\Requests;interface StoreRequestInterface{}

And you should use it as an interface in your Form Requests:

<?phpnamespace App\Http\Requests;use Illuminate\Foundation\Http\FormRequest;class ExampleStoreRequest extends FormRequest implements StoreRequestInterface{    /**     * Determine if the user is authorized to make this request.     *     * @return bool     */    public function authorize()    {        return false;    }    /**     * Get the validation rules that apply to the request.     *     * @return array     */    public function rules()    {        return [            //        ];    }}

Opinionated alternative answer:

General controller base:

<?phpnamespace App\Http\Controllers;use Illuminate\Container\Container;use Illuminate\Foundation\Bus\DispatchesJobs;use Illuminate\Routing\Controller as BaseController;use Illuminate\Foundation\Validation\ValidatesRequests;use Illuminate\Foundation\Auth\Access\AuthorizesRequests;abstract class Controller extends BaseController{    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;    /**     * The view subdirectory that must be used.     *     * @var string     */    protected $viewDir;    /**     * Bindings     *     * @var string[]|callable[]     */    protected $bindings = [];    /**     * Controller constructor.     */    public function __construct()    {        $this->addViewPath();        $this->addBindings();        $this->init();    }    /**     * @return void     */    protected function init()    {        //    }    /**     * @return string     */    protected function getViewDir()    {        return $this->viewDir;    }    /**     * @return callable[]|string[]     */    protected function getBindings()    {        return $this->bindings;    }    /**     * Add controller specific view path.     */    protected function addViewPath()    {        if (null !== ($dir = $this->getViewDir()) && ($path = realpath(base_path('resources/views/' . $dir)))) {            view()->getFinder()->addLocation($path);        }    }    /**     * Add controller specific bindings.     */    protected function addBindings()    {        $app = Container::getInstance();        foreach ($this->getBindings() as $abstract => $concrete) {            $app->bind($abstract, $concrete);        }    }}

Resource Controller Base:

<?phpnamespace App\Http\Controllers;use Illuminate\Database\Eloquent\Model;use App\Http\Requests\StoreRequestInterface;use App\Http\Requests\UpdateRequestInterface;use App\Http\Requests\StatusRequestInterface;abstract class ResourceController extends Controller{    /**     * Model class     *     * @var string     */    protected $modelClass;    /**     * @var string     */    protected $viewDirPrefix;    /**     * @return string     */    protected function getViewDir()    {        return $this->viewDir ?:            ltrim($this->viewDirPrefix . DIRECTORY_SEPARATOR . 'pages', DIRECTORY_SEPARATOR) .            DIRECTORY_SEPARATOR . strtolower(class_basename($this->modelClass));    }    /**     * @return \Illuminate\Database\Eloquent\Builder     */    protected function getQuery()    {        return call_user_func($this->modelClass . '::query');    }    /**     * @return string     */    protected function getName()    {        return __(class_basename($this->modelClass));    }    /**     * Display a listing of the resource.     *     * @return \Illuminate\Http\Response     */    protected function index()    {        $title = __('resource.title.index', ['name' => str_plural($this->getName())]);        $models = $this->getQuery()->paginate();        return view('index', compact('title', 'models'));    }    /**     * Show the form for creating a new resource.     *     * @return \Illuminate\Http\Response     */    protected function create()    {        $title = __('resource.title.create', ['name' => $this->getName()]);        return view('create', compact('title'));    }    /**     * Store a newly created resource in storage.     *     * @param  \Illuminate\Http\Request|StoreRequestInterface $request     *     * @return \Illuminate\Http\Response     */    public function store(StoreRequestInterface $request)    {        $model = $this->getQuery()->create($request->all());        return redirect()            ->route(substr($request->route()->getName(), 0, -5) . 'show', $model);    }    /**     * Display the specified resource.     *     * @param  \Illuminate\Database\Eloquent\Model $model     *     * @return \Illuminate\Http\Response     */    public function show(Model $model)    {        $title = __('resource.title.show', ['name' => $this->getName()]);        return view('show', compact('title', 'model'));    }    /**     * Show the form for editing the specified resource.     *     * @param  \Illuminate\Database\Eloquent\Model $model     *     * @return \Illuminate\Http\Response     */    public function edit(Model $model)    {        $title = __('resource.title.edit', ['name' => $this->getName()]);        return view('edit', compact('title', 'model'));    }    /**     * Update the specified resource in storage.     *     * @param  \Illuminate\Http\Request|UpdateRequestInterface $request     * @param  \Illuminate\Database\Eloquent\Model             $model     *     * @return \Illuminate\Http\Response     */    public function update(UpdateRequestInterface $request, Model $model)    {        $model->update($request->except(['_token', '_method']));        return redirect()            ->route(substr($request->route()->getName(), 0, -6) . 'show', $model);    }    /**     * Remove the specified resource from storage.     *     * @param  \Illuminate\Database\Eloquent\Model $model     *     * @return \Illuminate\Http\Response     * @throws \Exception     */    public function destroy(Model $model)    {        $model->delete();        return redirect()            ->route(substr(request()->route()->getName(), 0, -7) . 'index');    }    /**     * @param \Illuminate\Http\Request|StatusRequestInterface $request     * @param \Illuminate\Database\Eloquent\Model             $model     *     * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse     */    protected function status(StatusRequestInterface $request, Model $model)    {        $model->update($request->except('_method'));        return response()->json([            'message' => __('resource.status.success'),        ]);    }}

Resource controller for Example model:

<?phpnamespace App\Http\Controllers\Admin;use App\Example;use App\Http\Requests;use App\Http\Controllers\ResourceController;class ExampleController extends ResourceController{    /**     * Model class     *     * @var string     */    protected $modelClass = Example::class;    /**     * @var string     */    protected $viewDirPrefix = 'admin';    /**     * @var string[]|callable[]     */    protected $bindings = [        Requests\StatusRequestInterface::class => Requests\Example\StatusRequest::class,        Requests\StoreRequestInterface::class  => Requests\Example\StoreRequest::class,        Requests\UpdateRequestInterface::class => Requests\Example\UpdateRequest::class,    ];}

English Language file in resources/lang/en/resource.php:

<?phpreturn [    'title'  => [        'index'  => 'All :Name',        'create' => 'Create :Name',        'show'   => 'Show :Name',        'edit'   => 'Edit :Name',    ],    'status' => [        'success' => 'Status updated successfully',    ],];

Portuguese Language file in resources/lang/pt/resource.php:

<?phpreturn [    'title'  => [        'index'  => 'Todos os :Name',        'create' => 'Cadastrar :Name',        'show'   => 'Show :Name',        'edit'   => 'Editar :Name',    ],    'status' => [        'success' => 'O status foi alterado com sucesso',    ],];

Web Routes in routes/web.php:

<?phpRoute::group([    'as'        => 'admin.',    'prefix'    => 'admin',    'namespace' => 'Admin',], function () {    Route::model('example', App\Example::class);    Route::resource('example', 'ExampleController');});

Request interfaces (for binding):

<?phpnamespace App\Http\Requests;interface StoreRequestInterface{}

Same for App\Http\Requests\UpdateRequestInterface and App\Http\Requests\StatusRequestInterface...

Example Form Request:

<?phpnamespace App\Http\Requests\Example;use Illuminate\Foundation\Http\FormRequest;use App\Http\Requests\StoreRequestInterface;class StoreRequest extends FormRequest implements StoreRequestInterface{    /**     * Determine if the user is authorized to make this request.     *     * @return bool     */    public function authorize()    {        return false;    }    /**     * Get the validation rules that apply to the request.     *     * @return array     */    public function rules()    {        return [            //        ];    }}

Same for App\Http\Requests\Example\UpdateRequest and App\Http\Requests\Example\StatusRequest...

Documentation applied for this reply:

Notice: This reply is for Laravel 5.6. Some code used in this reply is not supported in previews versions. If you want it for a specific version, let me know and I will try to adapt it.


Any CustomFormRequest that you will use, will be an instance of FormRequest.. a class that in turn extends the Request class. So in your BaseController do this:

BaseController.php

use Illuminate\Http\Request;// some code    public function store(Request $request)    {        $item = $this->model::create($request->all());        return redirect()            ->route($this->viewFolder.'.'.$this->viewType.'.show', item[$this->key]);        }// The rest of your code..

Then in your child Controllers:

AChildController.php

class AChildController extends BaseController{use App\Http\Requests\ACustomFormRequest;// Some code  public function store(ACustomFormRequest $request)  {      //do something      return parent::_store($request);  }

}

Give it a try.