← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

MVC Pattern

Architecture PHP 5.0+ Beginner
debt(d7/e5/b7/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints note automated=no, and while tools like phpmd, deptrac, and phpstan are listed, they can flag proxy signals (controller method >50 lines, DB query in controller) but cannot reliably detect the full spectrum of layer violations — especially anemic models, business logic misplacement, or views with logic that belongs in a presenter. These require human judgment in code review.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes keeping controllers thin and moving logic to services/use cases, but fat controllers and fat models are typically pervasive — extraction into service layers touches multiple controllers, models, and introduces new files (services, use cases, presenters). This is more than a single-line swap but usually contained within the application layer rather than a full architectural rework.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7). MVC is an architectural pattern that applies across all web/api contexts (per applies_to). Every controller, model, and view written is shaped by the team's understanding of MVC layer responsibilities. Misapplied MVC (fat controllers, anemic models) creates a persistent structural gravity — every new feature added to the codebase either reinforces or fights the existing layer misuse, shaping all future development decisions.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field explicitly states that developers wrongly believe MVC strictly defines where all application logic must live, leading to fat controllers and anemic models. This is a well-documented, common misunderstanding that most developers encounter and eventually correct, but it is not as catastrophic as contradicting an entirely different paradigm — it maps to t5.

About DEBT scoring →

Also Known As

Model View Controller MVC pattern MVC architecture

TL;DR

Model-View-Controller — an architectural pattern that separates data (Model), presentation (View), and request handling (Controller).

Explanation

MVC divides an application into three layers: the Model represents business logic and data; the View renders the UI from model data; the Controller handles HTTP requests, coordinates models, and selects views. This separation makes each layer independently testable and replaceable. PHP frameworks (Laravel, Symfony, CodeIgniter) implement MVC with routing, ORM, and templating engines. In practice, Controllers are often overloaded — move business logic into dedicated Service or Domain classes, leaving Controllers thin orchestrators.

Common Misconception

MVC strictly defines where all application logic must live. MVC separates presentation from data from control flow — but does not prescribe where business logic, validation, or service calls belong. Fat controllers and anemic models are MVC violations caused by misunderstanding, not the pattern itself.

Why It Matters

MVC separates presentation, domain logic, and input handling — keeping these concerns in their correct layer prevents the 'fat controller, fat model' anti-patterns that make applications unmaintainable.

Common Mistakes

  • Fat controllers with business logic — controllers should only coordinate, not compute.
  • Fat models that are aware of HTTP, session, or rendering — models should be pure domain logic.
  • Views with PHP loops and conditionals that belong in a presenter or view model.
  • Treating MVC as a complete architecture — it describes layers, not where to put all business logic.

Code Examples

✗ Vulnerable
// Fat controller — business logic in the wrong layer:
class OrderController {
    public function place(Request $req): Response {
        $total = 0;
        foreach ($req->items as $item) { // Business logic
            $total += $item['price'] * $item['qty'] * (1 - ($item['discount'] ?? 0));
        }
        if ($total < 0) throw new InvalidOrderException();
        // Should delegate to OrderService — controller only orchestrates
    }
}
✓ Fixed
// Model — domain data and business rules
class Order extends Model {
    public function isPaid(): bool { return $this->status === 'paid'; }
    public function total(): Money { return Money::of($this->total_cents, 'GBP'); }
}

// View — presentation only (Blade template)
// resources/views/orders/show.blade.php
// <h1>Order #{{ $order->id }}</h1>
// <p>Total: {{ $order->total() }}</p>

// Controller — thin glue: validate input, call service, return view
class OrderController extends Controller {
    public function show(int $id): View {
        $order = Order::findOrFail($id);
        $this->authorize('view', $order);
        return view('orders.show', compact('order'));
    }
}
// Business logic lives in services/domain, not the controller

Added 15 Mar 2026
Edited 5 Apr 2026
Views 101
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 1 ping T 2 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T
No pings yet today
No pings yesterday
Amazonbot 14 PetalBot 11 Ahrefs 8 ChatGPT 8 SEMrush 8 Scrapy 6 Bing 4 Google 3 Perplexity 3 Unknown AI 2 Twitter/X 2 Applebot 2 Majestic 1 Brave Search 1 Qwen 1
crawler 70 crawler_json 4
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Keep controllers thin — they should only: validate input, call a service/use case, and return a response; never put business logic or database queries directly in controllers
📦 Applies To
PHP 5.0+ any web api laravel symfony
🔗 Prerequisites
🔍 Detection Hints
Controller method >50 lines; DB query directly in controller; business rule in controller instead of service/domain; fat controller thin model
Auto-detectable: ✗ No phpmd deptrac phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: File Tests: Update


✓ schema.org compliant