How to Build a Generic CRUD Controller in Laravel for Multiple Resources
Managing multiple CRUD operations in a Laravel application can be overwhelming, especially when handling a growing number of models. In this post, I'll guide you on creating a generic CRUD controller that allows you to handle existing and future CRUD operations in a single controller.
Why Use a Generic Controller?
A generic controller helps:
- Minimize repetitive code.
- Make adding new models a breeze.
- Provide a consistent structure for your application.
Let’s dive into the implementation step by step!
Step 1: Setting Up the Controller
Start by creating a new controller:
php artisan make:controller GenericController
Step 2: Writing the Controller Logic
Here’s how you can design your GenericController
to handle CRUD operations for any model:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class GenericController extends Controller
{
protected function getModel($modelName)
{
$modelClass = 'App\\Models\\' . Str::studly($modelName);
if (!class_exists($modelClass)) {
abort(404, "Model $modelName not found.");
}
return new $modelClass;
}
public function index($model)
{
$modelInstance = $this->getModel($model);
return response()->json($modelInstance::all());
}
public function show($model, $id)
{
$modelInstance = $this->getModel($model);
return response()->json($modelInstance::findOrFail($id));
}
public function store(Request $request, $model)
{
$modelInstance = $this->getModel($model);
$data = $request->validate($modelInstance->getFillable());
$created = $modelInstance::create($data);
return response()->json($created, 201);
}
public function update(Request $request, $model, $id)
{
$modelInstance = $this->getModel($model);
$item = $modelInstance::findOrFail($id);
$data = $request->validate($modelInstance->getFillable());
$item->update($data);
return response()->json($item);
}
public function destroy($model, $id)
{
$modelInstance = $this->getModel($model);
$item = $modelInstance::findOrFail($id);
$item->delete();
return response()->json(['message' => 'Deleted successfully.']);
}
}
Step 3: Dynamic Routing
Configure your routes to use dynamic endpoints:
use App\Http\Controllers\GenericController;
Route::controller(GenericController::class)->prefix('api/{model}')->group(function () {
Route::get('/', 'index');
Route::get('/{id}', 'show');
Route::post('/', 'store');
Route::put('/{id}', 'update');
Route::delete('/{id}', 'destroy');
});
Step 4: Prepare Your Models
Ensure each model has:
- A
$fillable
property to specify mass-assignable fields.
Example for a Post
model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = ['title', 'content'];
}
Key Advantages
- Scalability: Easily handle new models by adding only the model file.
- Code Reusability: Reduces redundancy.
- Simplifies Maintenance: Focus on business logic without worrying about boilerplate code.
When to Use This Approach?
This is ideal for:
- Applications with standard CRUD logic.
- Projects where models share common behavior.
For more complex business logic, you may still need dedicated controllers.
Top comments (0)