Laravel Resource Controllers Tutorial
In Laravel, Resource Controllers make it super easy to handle CRUD (Create, Read, Update, Delete) actions for your models. Instead of writing individual routes for each action, you can generate a whole set of routes and controller methods with just one command.
Creating a Resource Controller
Let’s say we have a Photo model and we want to manage photos in our app.
Run this command:
php artisan make:controller PhotoController --resource
This creates a PhotoController.php in app/Http/Controllers/.
Inside, you’ll find 7 methods:
index()→ Show all photoscreate()→ Show form to create a new photostore()→ Save a new photoshow()→ Display a single photoedit()→ Show form to edit a photoupdate()→ Update a photodestroy()→ Delete a photo
Registering Resource Routes
In routes/web.php:
use App\Http\Controllers\PhotoController;
Route::resource('photos', PhotoController::class);
This single line creates all routes for CRUD actions.
Run:
php artisan route:list
You’ll see routes like:
| Verb | URI | Action | Route Name |
|---|---|---|---|
| GET | /photos | index | photos.index |
| GET | /photos/create | create | photos.create |
| POST | /photos | store | photos.store |
| GET | /photos/{photo} | show | photos.show |
| GET | /photos/{photo}/edit | edit | photos.edit |
| PUT/PATCH | /photos/{photo} | update | photos.update |
| DELETE | /photos/{photo} | destroy | photos.destroy |
Registering Multiple Resource Controllers
You can register several at once:
Route::resources([
'photos' => PhotoController::class,
'posts' => PostController::class,
]);
For soft deletable resources:
Route::softDeletableResources([
'photos' => PhotoController::class,
'posts' => PostController::class,
]);
Handling Missing Models
If a photo doesn’t exist, Laravel normally returns 404.
You can customize this:
Route::resource('photos', PhotoController::class)
->missing(function (Request $request) {
return redirect()->route('photos.index');
});
Soft Deleted Models
By default, soft-deleted models return 404.
Enable access like this:
Route::resource('photos', PhotoController::class)->withTrashed();
Allow only specific actions:
Route::resource('photos', PhotoController::class)->withTrashed(['show']);
Binding Models Automatically
When generating the controller, bind the model automatically:
php artisan make:controller PhotoController --model=Photo --resource
Or also generate Form Requests:
php artisan make:controller PhotoController --model=Photo --resource --requests
Partial Resource Routes
Use only selected actions:
Route::resource('photos', PhotoController::class)->only(['index', 'show']);
Or exclude some:
Route::resource('photos', PhotoController::class)->except(['create', 'store']);
API Resource Controllers
APIs don’t need create and edit.
Use:
Route::apiResource('photos', PhotoController::class);
Generate an API controller:
php artisan make:controller PhotoController --api
Nested Resources
Example: Photos have Comments.
Route::resource('photos.comments', PhotoCommentController::class);
This creates routes like:
/photos/{photo}/comments/{comment}
Shallow Nesting
To simplify child routes:
Route::resource('photos.comments', CommentController::class)->shallow();
Now you’ll get:
/photos/{photo}/comments→ index/comments/{comment}→ show, edit, update, destroy
Customizing Routes
- Custom route names:
Route::resource('photos', PhotoController::class)->names([
'create' => 'photos.build',
]);
- Custom route parameters:
Route::resource('users', AdminUserController::class)->parameters([
'users' => 'admin_user'
]);
Result: /users/{admin_user}
- Localization:
Route::resourceVerbs([
'create' => 'crear',
'edit' => 'editar',
]);
Now routes look like:/publicacion/crear, /publicacion/{id}/editar
Singleton Resources
Some resources only exist once per user, e.g., Profile.
Route::singleton('profile', ProfileController::class);
This gives:
GET /profile→ showGET /profile/edit→ editPUT /profile→ update
Middleware on Resource Controllers
Apply middleware to all routes:
Route::resource('users', UserController::class)->middleware(['auth']);
Apply to specific methods:
Route::resource('users', UserController::class)
->middlewareFor('show', 'auth');
Exclude middleware:
Route::resource('users', UserController::class)
->withoutMiddlewareFor('index', 'auth');
Dependency Injection in Controllers
Constructor Injection
class UserController extends Controller
{
public function __construct(protected UserRepository $users) {}
}
Method Injection
public function store(Request $request)
{
$name = $request->name;
// save user...
}
With route params:
public function update(Request $request, string $id)
{
// update user with $id
}
Important
Laravel Resource Controllers save you time by generating all standard CRUD routes and controller methods in one go. You can:
- Customize them with
only,except,withTrashed - Use them for web apps or APIs
- Support nested or singleton resources
- Apply middleware selectively
- Take advantage of dependency injection
They keep your routes clean, your controllers organized, and your development faster.
