Laravel Controllers: Creating and Using Them to Handle Logic

Published on November 05, 2025
Laravel Controllers PHP WebDevelopment CRUD InterviewPrep

What are Controllers in Laravel?

Controllers are the "traffic cops" of your Laravel application. They handle incoming HTTP requests, process business logic, and return responses to users. Instead of putting all your application logic in route files, controllers help you organize code into dedicated classes.

Think of controllers as:

  • The brain that processes requests
  • The coordinator between models and views
  • The organizer that keeps your code clean and maintainable

Creating Your First Controller

Using Artisan Command

php artisan make:controller UserController

This creates a new controller file at app/Http/Controllers/UserController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    // Controller methods will go here
}

Basic Controller Structure

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function index()
    {
        // Display a list of users
    }
    
    public function show($id)
    {
        // Show a single user
    }
    
    public function create()
    {
        // Show user creation form
    }
    
    public function store(Request $request)
    {
        // Store new user
    }
}

Connecting Routes to Controllers

Single Method Routes

// routes/web.php
Route::get('/users', [UserController::class, 'index']);
Route::get('/users/{id}', [UserController::class, 'show']);
Route::post('/users', [UserController::class, 'store']);

Controller with Multiple Methods

// Using the same controller for related routes
Route::controller(UserController::class)->group(function () {
    Route::get('/users', 'index');
    Route::get('/users/create', 'create');
    Route::post('/users', 'store');
    Route::get('/users/{id}', 'show');
    Route::get('/users/{id}/edit', 'edit');
    Route::put('/users/{id}', 'update');
    Route::delete('/users/{id}', 'destroy');
});

Types of Controllers

1. Basic Controllers - For Custom Logic

class PageController extends Controller
{
    public function home()
    {
        return view('home');
    }
    
    public function about()
    {
        return view('about', ['team' => Team::all()]);
    }
    
    public function contact()
    {
        return view('contact');
    }
}

2. Resource Controllers - For CRUD Operations

Create a resource controller with Artisan:

php artisan make:controller PostController --resource

This generates a controller with all resource methods:

class PostController extends Controller
{
    public function index() {}      // List posts
    public function create() {}     // Show create form
    public function store() {}      // Save new post
    public function show() {}       // Show single post
    public function edit() {}       // Show edit form
    public function update() {}     // Update post
    public function destroy() {}    // Delete post
}

Connect to routes with:

Route::resource('posts', PostController::class);

3. API Resource Controllers - For APIs

php artisan make:controller Api/PostController --api

Generates only API-relevant methods (no create/edit):

class PostController extends Controller
{
    public function index() {}    // GET /posts
    public function store() {}    // POST /posts
    public function show() {}     // GET /posts/{id}
    public function update() {}   // PUT/PATCH /posts/{id}
    public function destroy() {}  // DELETE /posts/{id}
}

Connect with:

Route::apiResource('posts', PostController::class);

4. Single Action Controllers - For One Task

php artisan make:controller WelcomeEmailController --invokable

Creates a controller with single __invoke method:

class WelcomeEmailController extends Controller
{
    public function __invoke(User $user)
    {
        // Send welcome email
        Mail::to($user->email)->send(new WelcomeEmail($user));
        
        return response()->json(['message' => 'Welcome email sent!']);
    }
}

Route to it with:

Route::post('/welcome-email/{user}', WelcomeEmailController::class);

Controller Methods in Action

Index Method - Listing Resources

public function index()
{
    $users = User::with('posts')
                ->orderBy('created_at', 'desc')
                ->paginate(10);
    
    return view('users.index', compact('users'));
}

Show Method - Display Single Resource

public function show(User $user) // Route Model Binding
{
    return view('users.show', compact('user'));
}

Create Method - Show Creation Form

public function create()
{
    return view('users.create');
}

Store Method - Save New Resource

public function store(Request $request)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users',
        'password' => 'required|min:8|confirmed',
    ]);
    
    $user = User::create($validated);
    
    return redirect()->route('users.show', $user)
                    ->with('success', 'User created successfully!');
}

Edit Method - Show Edit Form

public function edit(User $user)
{
    return view('users.edit', compact('user'));
}

Update Method - Update Resource

public function update(Request $request, User $user)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users,email,' . $user->id,
    ]);
    
    $user->update($validated);
    
    return redirect()->route('users.show', $user)
                    ->with('success', 'User updated successfully!');
}

Destroy Method - Delete Resource

public function destroy(User $user)
{
    $user->delete();
    
    return redirect()->route('users.index')
                    ->with('success', 'User deleted successfully!');
}

Working with Requests

Type-Hinting Request Object

use Illuminate\Http\Request;

public function store(Request $request)
{
    // Get all input data
    $data = $request->all();
    
    // Get specific input
    $name = $request->input('name');
    $email = $request->email; // Alternative syntax
    
    // Get only specific fields
    $data = $request->only(['name', 'email']);
    $data = $request->except(['password', 'token']);
    
    // Check if input exists
    if ($request->has('newsletter')) {
        // Subscribe to newsletter
    }
}

Form Request Validation

Create custom request classes for complex validation:

php artisan make:request StoreUserRequest
// app/Http/Requests/StoreUserRequest.php
class StoreUserRequest extends FormRequest
{
    public function authorize()
    {
        return true; // Set authorization logic
    }
    
    public function rules()
    {
        return [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users',
            'password' => 'required|min:8|confirmed',
        ];
    }
    
    public function messages()
    {
        return [
            'name.required' => 'The name field is required.',
            'email.unique' => 'This email is already taken.',
        ];
    }
}

Use in controller:

public function store(StoreUserRequest $request)
{
    // Validation already passed!
    $user = User::create($request->validated());
    
    return redirect()->route('users.show', $user);
}

Controller Responses

Returning Views

public function show(User $user)
{
    return view('users.show', [
        'user' => $user,
        'posts' => $user->posts()->paginate(5)
    ]);
}

JSON Responses

public function apiIndex()
{
    $users = User::all();
    
    return response()->json([
        'data' => $users,
        'count' => $users->count()
    ]);
}

Redirects

public function store(Request $request)
{
    // After successful operation
    return redirect('/users');
    
    // With route name
    return redirect()->route('users.index');
    
    // With flash data
    return redirect()->route('users.index')
                    ->with('success', 'User created!');
    
    // Back to previous page
    return back()->withInput();
}

Custom Responses

public function download()
{
    return response()->download($pathToFile);
}

public function pdf()
{
    return response()->streamDownload(function () {
        // Generate PDF content
    }, 'document.pdf');
}

Middleware in Controllers

Applying Middleware in Constructor

class UserController extends Controller
{
    public function __construct()
    {
        // Apply to all methods
        $this->middleware('auth');
        
        // Apply to specific methods
        $this->middleware('log')->only('index', 'show');
        $this->middleware('admin')->except('index', 'show');
        
        // Apply to multiple methods
        $this->middleware('throttle:60,1')->only('store', 'update');
    }
}

Route Middleware

Route::middleware(['auth', 'verified'])->group(function () {
    Route::resource('users', UserController::class);
});

Dependency Injection in Controllers

Laravel automatically resolves dependencies through type-hinting:

use App\Services\UserService;
use App\Repositories\PostRepository;
use Illuminate\Http\Request;

class UserController extends Controller
{
    protected $userService;
    
    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }
    
    public function store(Request $request, PostRepository $postRepo)
    {
        // Laravel automatically injects these dependencies
        $user = $this->userService->createUser($request->all());
        $posts = $postRepo->getUserPosts($user->id);
        
        return view('users.show', compact('user', 'posts'));
    }
}

Practical Example: Blog Controller

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use App\Http\Requests\StorePostRequest;
use App\Http\Requests\UpdatePostRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class PostController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth')->except(['index', 'show']);
        $this->middleware('can:update,post')->only(['edit', 'update']);
        $this->middleware('can:delete,post')->only('destroy');
    }
    
    public function index()
    {
        $posts = Post::with('user', 'categories')
                    ->published()
                    ->latest()
                    ->paginate(10);
        
        return view('posts.index', compact('posts'));
    }
    
    public function show(Post $post)
    {
        // Increment views
        $post->increment('views');
        
        return view('posts.show', compact('post'));
    }
    
    public function create()
    {
        return view('posts.create');
    }
    
    public function store(StorePostRequest $request)
    {
        $post = Post::create($request->validated());
        
        // Handle image upload
        if ($request->hasFile('image')) {
            $path = $request->file('image')->store('posts', 'public');
            $post->update(['image_path' => $path]);
        }
        
        // Sync categories
        $post->categories()->sync($request->categories);
        
        return redirect()->route('posts.show', $post)
                        ->with('success', 'Post created successfully!');
    }
    
    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }
    
    public function update(UpdatePostRequest $request, Post $post)
    {
        $post->update($request->validated());
        
        return redirect()->route('posts.show', $post)
                        ->with('success', 'Post updated successfully!');
    }
    
    public function destroy(Post $post)
    {
        // Delete associated image
        if ($post->image_path) {
            Storage::disk('public')->delete($post->image_path);
        }
        
        $post->delete();
        
        return redirect()->route('posts.index')
                        ->with('success', 'Post deleted successfully!');
    }
}

Best Practices for Controller Design

1. Keep Controllers Thin

// ❌ DON'T: Put all logic in controller
public function store(Request $request)
{
    // Validation
    $validated = $request->validate([...]);
    
    // Business logic
    if ($request->has('discount')) {
        // Complex pricing logic...
    }
    
    // Database operations
    $order = Order::create([...]);
    
    // Email sending
    Mail::to($user)->send(...);
    
    // File handling
    if ($request->hasFile('file')) {
        // File processing...
    }
}

// ✅ DO: Delegate to services
public function store(StoreOrderRequest $request)
{
    $order = $this->orderService->createOrder($request->validated());
    
    return redirect()->route('orders.show', $order);
}

2. Use Form Requests for Validation

3. Follow RESTful conventions

4. Use meaningful method names

5. Leverage Route Model Binding

Common Interview Questions & Answers

1. What is a controller in Laravel?
Controllers handle HTTP requests, contain business logic, and return responses. They act as intermediaries between models and views.

2. How do you create a controller?
Use php artisan make:controller ControllerName. Add --resource for CRUD methods or --api for API controllers.

3. What are resource controllers?
Resource controllers provide built-in methods for CRUD operations: index, create, store, show, edit, update, destroy.

4. What is single action controller?
A controller with only one __invoke method, perfect for dedicated actions like sending emails or processing payments.

5. How do you apply middleware to controllers?
Either in the controller constructor using $this->middleware() or in route definitions using Route::middleware()->group().

6. What is dependency injection in controllers?
Laravel automatically resolves type-hinted dependencies in controller constructors and methods, making services available without manual instantiation.

Controller Artisan Commands Cheat Sheet

# Basic controller
php artisan make:controller UserController

# Resource controller
php artisan make:controller PostController --resource

# API resource controller
php artisan make:controller Api/PostController --api

# Single action controller
php artisan make:controller WelcomeEmailController --invokable

# Controller with model
php artisan make:controller CategoryController --model=Category

# Form request
php artisan make:request StoreUserRequest

Now you can create organized, efficient controllers for any Laravel application! In our next post, we'll explore Laravel Blade Templating: Master the Basics of Laravel's View Engine to learn how to create beautiful, dynamic views.