← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

MVC Pattern

architecture PHP 5.0+ Beginner

Also Known As

MVC Model View Controller model-view-controller fat model thin controller

TL;DR

Model-View-Controller — an architectural pattern separating data (Model), presentation (View), and request handling (Controller), the foundation of Laravel, Symfony, and most PHP frameworks.

Explanation

MVC separates an application into three layers: Model — represents data and business rules, queries the database, validates constraints, and enforces domain logic. View — renders the output (HTML, JSON, XML) from data provided by the controller. Controller — handles incoming requests, calls the appropriate model methods, and passes results to the view. The flow: HTTP request → Router → Controller → Model → Controller → View → HTTP response. PHP frameworks implement MVC with variations: Laravel uses Eloquent Active Record models, Blade view templates, and thin controllers; Symfony uses Doctrine Data Mapper models, Twig templates, and richer controllers. Common MVC violations: fat controllers (business logic in controllers), smart views (queries or logic in templates), and dumb models (models as mere database wrappers). The fat model / thin controller principle pushes business logic into models or dedicated service classes.

Common Misconception

Controllers should contain business logic because they handle requests. Controllers should be thin orchestrators — they receive a request, call a service or model method, and return a response. Business rules, validation logic, and data transformation belong in the Model layer or dedicated Service classes. A controller method exceeding 20 lines is usually a sign that business logic has leaked into it.

Why It Matters

MVC is the default architecture of every major PHP framework. Understanding it correctly prevents the most common structural mistake in PHP applications: fat controllers that become impossible to test because business logic is tightly coupled to the HTTP layer. A controller method that validates input, queries the database, sends emails, formats responses, and logs events cannot be unit tested without bootstrapping the entire framework. Separating these concerns into models and services makes each part independently testable and reusable.

Common Mistakes

  • Fat controllers — putting database queries, validation logic, and email sending directly in controller methods.
  • Logic in views — performing database queries or complex calculations in Blade/Twig templates.
  • Models as data bags — models that only have fillable/casts with no business methods are not using MVC correctly; models should enforce their own invariants.
  • One controller per table — controllers should be organised around user actions and HTTP resources, not database tables.

Code Examples

✗ Vulnerable
// Fat controller — untestable, all concerns mixed
class OrderController {
    public function store(Request $r) {
        if (!$r->user()->can('create-orders')) abort(403);
        $total = array_sum(array_column($r->items, 'price'));
        if ($total > 10000) throw new Exception('Order too large');
        $order = Order::create(['user_id' => $r->user()->id, 'total' => $total]);
        foreach ($r->items as $item) OrderItem::create([...]);
        Mail::to($r->user())->send(new OrderConfirmed($order));
        Slack::notify('#orders', 'New order: ' . $order->id);
        return response()->json($order, 201);
    }
}
✓ Fixed
// Thin controller — delegates to service
class OrderController {
    public function store(Request $r, OrderService $service) {
        $this->authorize('create', Order::class);
        $order = $service->createOrder($r->user(), $r->validated());
        return new OrderResource($order);
    }
}

// Service holds business logic — independently testable
class OrderService {
    public function createOrder(User $user, array $data): Order {
        $order = Order::createFromItems($user, $data['items']);
        OrderConfirmation::dispatch($order); // queued job
        return $order;
    }
}

Added 23 Mar 2026
Edited 5 Apr 2026
Views 24
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 0 pings S 2 pings S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S
No pings yet today
No pings yesterday
Amazonbot 8 Perplexity 6 ChatGPT 1 Google 1 Meta AI 1 Ahrefs 1
crawler 18
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: Medium
⚡ Quick Fix
Move any logic in controllers that is not directly request/response handling into a Service class or model method — controllers should be 5–15 lines per action
📦 Applies To
PHP 5.0+ web cli

✓ schema.org compliant