Skip to main content
Chapter 2 Routing, Controllers, and Middleware

Controllers and Form Requests

22 min read Lesson 6 / 28

Organizing Logic with Controllers

Controllers handle HTTP requests and return responses. Keep them thin by delegating business logic to services.

Resource Controller

php artisan make:controller PostController --resource --model=Post
class PostController extends Controller
{
    public function index(): View
    {
        $posts = Post::with(['author', 'category'])
            ->published()
            ->latest()
            ->paginate(12);

        return view('posts.index', compact('posts'));
    }

    public function show(Post $post): View
    {
        // Route model binding automatically finds the post
        $post->load(['comments.user', 'tags']);

        return view('posts.show', compact('post'));
    }

    public function store(StorePostRequest $request): RedirectResponse
    {
        $post = Post::create($request->validated());

        return redirect()
            ->route('posts.show', $post)
            ->with('success', 'Post created successfully.');
    }

    public function update(UpdatePostRequest $request, Post $post): RedirectResponse
    {
        $post->update($request->validated());

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

    public function destroy(Post $post): RedirectResponse
    {
        $post->delete();

        return redirect()
            ->route('posts.index')
            ->with('success', 'Post deleted.');
    }
}

Form Request Validation

Never validate inline. Always use Form Request classes:

php artisan make:request StorePostRequest
class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true; // Or check user permissions
    }

    public function rules(): array
    {
        return [
            'title' => ['required', 'string', 'max:255'],
            'slug' => ['required', 'string', 'unique:posts,slug'],
            'body' => ['required', 'string', 'min:100'],
            'category_id' => ['required', 'exists:categories,id'],
            'published_at' => ['nullable', 'date', 'after:now'],
        ];
    }

    public function messages(): array
    {
        return [
            'body.min' => 'Post content must be at least 100 characters.',
        ];
    }
}

Form Requests keep controllers clean and validation logic reusable and testable.