Mastering Laravel Controller – Part 2

aravel Laravel Views & Blade Templates – Beginner’s Guide

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 photos
  • create() → Show form to create a new photo
  • store() → Save a new photo
  • show() → Display a single photo
  • edit() → Show form to edit a photo
  • update() → Update a photo
  • destroy() → 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:

VerbURIActionRoute Name
GET/photosindexphotos.index
GET/photos/createcreatephotos.create
POST/photosstorephotos.store
GET/photos/{photo}showphotos.show
GET/photos/{photo}/editeditphotos.edit
PUT/PATCH/photos/{photo}updatephotos.update
DELETE/photos/{photo}destroyphotos.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 → show
  • GET /profile/edit → edit
  • PUT /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.