Advanced Controller Middleware in Laravel: Using the HasMiddleware Interface

Advanced Controller Middleware in Laravel: Using the HasMiddleware Interface

Ever wished you could keep your middleware logic closer to your controllers? Laravel's HasMiddleware interface brings a new, elegant way to assign middleware right in your controller classes. Let's explore this powerful feature!

Traditional Route Middleware

Traditionally, we've assigned middleware in our route files:

Route::get('/profile', [UserController::class, 'show'])->middleware('auth');

Enter HasMiddleware Interface

Now, Laravel offers a more organized approach. By implementing the HasMiddleware interface, you can define middleware directly in your controller:

use App\Http\Controllers\Controller;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;

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

Different Ways to Define Middleware

  • Simple String Middleware:
'auth'  // Applies to all controller actions
  • Middleware with Constraints:
new Middleware('log', only: ['index'])  // Only for index action
new Middleware('subscribed', except: ['store'])  // All actions except store
  • Inline Closure Middleware:
use Closure;
use Illuminate\Http\Request;

public static function middleware(): array
{
    return [
        function (Request $request, Closure $next) {
            // Your middleware logic here
            return $next($request);
        }
    ];
}

Real-World Example

Here's a practical example of a controller that manages user subscriptions:

use App\Http\Controllers\Controller;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
use Illuminate\Http\Request;
use Closure;

class SubscriptionController extends Controller implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            'auth',  // Ensure user is logged in
            new Middleware('verified', only: ['upgrade', 'cancel']),  // Email verified for important actions
            new Middleware('subscribed', except: ['pricing', 'subscribe']),  // Check subscription status
            function (Request $request, Closure $next) {
                if ($request->user()->onGracePeriod()) {
                    // Add grace period warning to response
                    $response = $next($request);
                    $response->with('warning', 'Your subscription is ending soon!');
                    return $response;
                }
                return $next($request);
            }
        ];
    }

    public function upgrade()
    {
        // Upgrade subscription logic
    }

    public function cancel()
    {
        // Cancel subscription logic
    }
}

Using the HasMiddleware interface and keeping your middleware definitions in your controller classes can lead to cleaner, more maintainable code. It's especially useful for complex controllers that need different middleware rules for different actions.

If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!

Subscribe to Harris Raftopoulos

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe