Laravel Controllers Reference Guide

A Laravel controllers reference guide: organizing route logic into controller classes, resource controllers, and route model binding.

Basic controllers

A controller groups related request-handling logic into a single class instead of stacking closures in the routes file. Generate one with Artisan:

php artisan make:controller PostController
namespace App\Http\Controllers;

class PostController extends Controller
{
    public function index()
    {
        return view('posts.index', [
            'posts' => Post::latest()->get(),
        ]);
    }

    public function show(Post $post)
    {
        return view('posts.show', compact('post'));
    }
}
use App\Http\Controllers\PostController;

Route::get('/posts', [PostController::class, 'index']);
Route::get('/posts/{post}', [PostController::class, 'show']);

Route model binding

When a route or controller method's type-hinted parameter name matches a route segment, Laravel automatically resolves the model instance (or throws a 404 if it isn't found) — no manual findOrFail() needed.

Route::get('/posts/{post}', [PostController::class, 'show']);

public function show(Post $post)
{
    return view('posts.show', compact('post'));
}

// Bind by a different column, e.g. a slug
Route::get('/posts/{post:slug}', [PostController::class, 'show']);

Single action (invokable) controllers

For a controller that only ever does one thing, define __invoke() instead of a named method, and omit the method when registering the route.

php artisan make:controller ProvisionServer --invokable
class ProvisionServer extends Controller
{
    public function __invoke(Request $request)
    {
        // ...
    }
}

Route::post('/servers', ProvisionServer::class);

Resource controllers

Generate a controller with stub methods for the seven conventional CRUD actions:

php artisan make:controller PostController --resource
php artisan make:controller PostController --resource --model=Post
Route::resource('posts', PostController::class);

// Only some of the seven actions
Route::resource('posts', PostController::class)->only(['index', 'show']);
Route::resource('posts', PostController::class)->except(['destroy']);

// A read-only, JSON-only version for an API
Route::apiResource('posts', PostController::class);
VerbURIActionRoute name
GET/postsindexposts.index
GET/posts/createcreateposts.create
POST/postsstoreposts.store
GET/posts/{post}showposts.show
GET/posts/{post}/editeditposts.edit
PUT/PATCH/posts/{post}updateposts.update
DELETE/posts/{post}destroyposts.destroy

Dependency injection

The service container automatically resolves type-hinted class dependencies in both constructors and individual methods (in addition to any route-bound models).

class PostController extends Controller
{
    public function __construct(
        protected PostRepository $posts,
    ) {}

    public function store(StorePostRequest $request)
    {
        $post = $this->posts->create($request->validated());

        return redirect()->route('posts.show', $post);
    }
}

Middleware

Attach middleware to a controller's routes either in the route definition or, in Laravel 11+, via a static middleware() method on the controller itself.

Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware('auth');

class PostController extends Controller implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            'auth',
            new Middleware('log', only: ['store']),
        ];
    }
}