Master Laravel Controllers: From Basics to Advanced Resource Routing

This guide explains how to organize request handling with Laravel controllers, covering basic controller creation, namespace handling, single‑action controllers, middleware assignment, resource controllers with custom routes, dependency injection techniques, and route caching for production performance.

Laravel Tech Community
Laravel Tech Community
Laravel Tech Community
Master Laravel Controllers: From Basics to Advanced Resource Routing

Controller Overview

Laravel controllers replace closure‑based route definitions by grouping related request‑handling logic into dedicated classes stored in app/Http/Controllers.

Basic Controller

A typical controller extends Laravel’s base Controller class, gaining helper methods such as middleware for attaching middleware to controller actions.

<?php
namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Show a user profile.
     *
     * @param int $id
     * @return View
     */
    public function show($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

Register the route:

Route::get('user/{id}', 'UserController@show');
Tip: Controllers do not have to extend the base class, but without it you lose convenient methods like middleware , validate , and dispatch .

Controller & Namespace

When defining routes you only need the class name after App\Http\Controllers because RouteServiceProvider automatically prefixes the namespace. For deeper directories, specify the relative class name:

Route::get('foo', 'Photos\AdminController@method');

Single‑Action Controllers

Define an __invoke method to handle a single behavior. The route does not need a method name:

<?php
namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;

class ShowProfile extends Controller
{
    /**
     * Show a given user profile.
     *
     * @param int $id
     * @return View
     */
    public function __invoke($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}
Route::get('user/{id}', 'ShowProfile');

Generate it with Artisan:

php artisan make:controller ShowProfile --invokable

Controller Middleware

Middleware can be attached directly in the route definition:

Route::get('profile', 'UserController@show')->middleware('auth');

It is often more convenient to assign middleware inside the controller’s constructor, optionally limiting it to specific actions:

class UserController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('log')->only('index');
        $this->middleware('subscribed')->except('store');
    }
}

You can also register a closure as middleware for a single controller without creating a separate middleware class:

$this->middleware(function ($request, $next) {
    // ...
    return $next($request);
});
Tip: Assigning middleware to only a subset of actions can indicate a controller is becoming too complex; consider splitting it into smaller controllers.

Resource Controllers

Laravel’s make:controller --resource command scaffolds a controller with the conventional CRUD methods. Register the controller with a single resource route declaration:

php artisan make:controller PhotoController --resource
Route::resource('photos', 'PhotoController');

The resource route creates multiple routes (index, create, store, show, edit, update, destroy). You can limit the generated actions with only or except:

Route::resource('photos', 'PhotoController')->only(['index', 'show']);

Route::resource('photos', 'PhotoController')->except(['create', 'store', 'update', 'destroy']);

For API‑only controllers, use apiResource to omit the HTML‑related create and edit routes:

Route::apiResource('photos', 'PhotoController');

Multiple API resources can be registered at once:

Route::apiResources([
    'photos' => 'PhotoController',
    'posts'  => 'PostController',
]);

Custom route names are possible via the names method:

Route::resource('photos', 'PhotoController')->names([
    'create' => 'photos.build',
]);

Override the default route‑parameter name with the parameters option:

Route::resource('users', 'AdminUserController')->parameters([
    'users' => 'admin_user',
]);

Localize the resource verbs (e.g., Spanish) in AppServiceProvider::boot:

use Illuminate\Support\Facades\Route;

public function boot()
{
    Route::resourceVerbs([
        'create' => 'crear',
        'edit'   => 'editar',
    ]);
}

After localization, a resource route such as Route::resource('fotos', 'PhotoController') will generate URIs like /fotos/crear and /fotos/{foto}/editar.

Supplementary Resource Routes

Define additional routes before the resource declaration to avoid them being overridden:

Route::get('photos/popular', 'PhotoController@popular');
Route::resource('photos', 'PhotoController');
Tip: Keep controllers focused; if you need many extra actions, split the logic into separate, smaller controllers.

Dependency Injection & Controllers

Constructor Injection

Laravel’s service container resolves controller dependencies automatically. Example injecting a repository:

<?php
namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    protected $users;

    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}

Method Injection

Inject the request object or other services directly into controller methods. Route parameters can follow the injected services:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        $name = $request->name;
        // ...
    }

    public function update(Request $request, $id)
    {
        // Update user $id using data from $request
    }
}

Route Caching

Note: Routes defined with closures cannot be cached. Convert them to controller routes before using the cache.

When the application uses only controller‑based routes, enable route caching to dramatically speed up route registration:

php artisan route:cache

After caching, every request loads the compiled route file. Add new routes by regenerating the cache. In production you should run the cache command only, and clear it with:

php artisan route:clear
Route cache illustration
Route cache illustration
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

middlewareroutingPHPdependency-injectionLaravelControllers
Laravel Tech Community
Written by

Laravel Tech Community

Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.