4.1Understanding the MVC pattern
The essentials in 30 seconds
- MVC = 3 separate responsibilities: the Model handles data and business logic, the View renders HTML, the Controller orchestrates (request → model → view).
- Typical flow: request → routing to the right controller → controller calls the model → model returns the data → controller picks the view.
- Riad's reflex: thin controllers, rich models — never any SQL queries in views, never any business logic in the display.
Running case — Riad tidies up his catalogue in Constantine
Riad, web developer in Constantine, maintains the catalogue of a local shop: his file mixes SQL queries, price calculations and HTML, and every change breaks something else. He decides to tidy up: a model that fetches products by category, a controller that orchestrates the "products" page, a view that displays the list it receives. When the client asks for a new display, Riad only touches the view; when the pricing rule changes, he only touches the model. First milestone of the thread: from messy PHP to architected PHP.
This same case returns in the lesson, the diagram, the script and the 48h challenge — and continues in 4.2, 4.3, 4.4 and 4.5.
1. The three responsibilities
The MVC (Model-View-Controller) pattern splits the application into three layers. The Model handles DATA and BUSINESS LOGIC: database access, entities (Product, User), rules (discounted price, unique e-mail) — independently of the display. The View handles DISPLAY: HTML with minimal insertions (showing a variable, looping over a list), with no business logic or database access. The Controller is the LINK: it receives the request, calls the model, prepares the data, then picks the view. Like Riad, aim for "thin" controllers and "rich" models.
The golden rule: every piece of code has ONE obvious place. Data or business rule? Model. HTML? View. Request → data → display coordination? Controller. This clarity eliminates "spaghetti code" where everything is mixed in a single file.
2. The request flow & the benefits
The typical flow: (1) the user requests a URL; (2) routing directs to the right CONTROLLER and its method; (3) the controller calls the MODEL (e.g. fetching the products); (4) the controller passes the data to the VIEW; (5) the view generates the HTML. Riad follows this path for every page instead of doing everything in a single script.
The benefits: clarity (you know where to find what), maintainability (change the view without touching the data, and vice versa), reuse and testing (the same models serve an HTML page or a JSON API), collaboration (everyone works on their own layer). It is the DOMINANT pattern of frameworks (Laravel, Symfony): Models, Controllers, views/templates folders plus routing — understanding it BEFORE a framework means using it wisely instead of imitating it blindly.
🔎 Concrete example — 🔎 Concrete example — The product list in MVC
Riad's breakdown for the catalogue page:
Model → Produit::recupererParCategorie($cat) // SQL + rules here
Controller → $produits = Produit::recupererParCategorie($cat);
afficher('liste', ['produits' => $produits]);
View → foreach ($produits as $p) { show $p['nom'], $p['prix'] }
Rule → change the display = touch the view only
Reading: three blocks, three roles, one direction of travel.
Lesson: the view receives ready-made data; it does not build it.
Section vocabulary
- MVC (Model-View-Controller)
- Architecture pattern separating the application into three responsibilities: Model (data/business logic), View (display), Controller (coordination). The foundation of web frameworks.
Simple example: Riad tidies his catalogue: model for products, view for HTML, controller to orchestrate.
What it is not: a single script mixing SQL, calculations and HTML.
Reflex: for each line of code, ask: data, display or coordination?
- Model
- Handles DATA and BUSINESS LOGIC: database access, entities, rules — independently of the display.
Simple example: Riad's Product model fetches products and computes the discounted price.
What it is not: an SQL query written inside a display template.
Reflex: every business rule lives in the model, testable without HTML.
- View
- Handles DISPLAY: the HTML, what the user sees; receives prepared data and presents it.
Simple example: Riad's list view loops over the received products and displays them escaped.
What it is not: a template that queries the database or applies discounts.
Reflex: "dumb" view: display, loop, simple condition — nothing more.
- Controller
- Is the LINK: receives the request, calls the model, picks the view with the data; it orchestrates, thin and readable.
Simple example: Riad's catalogue controller fetches the products then renders the list view.
What it is not: a 300-line controller doing SQL + calculations + HTML.
Reflex: thin controller: coordinate, delegate, render.
- Routing / MVC flow
- Routing directs the request to the right controller; flow: request → routing → controller → model → view.
Simple example: Riad's /produits URL reaches the catalogue controller, index method.
What it is not: one file per URL with no central coordination.
Reflex: follow the flow on every debug: where does the chain break?
In practice — In practice — Understand and apply MVC
- Identify the three responsibilities: Model (data/logic), View (HTML display), Controller (coordination) — and why to separate them.
- Follow a request's flow: request → routing → controller → model (data) → view (display).
- On a small example (Riad's product list), distribute the code: model that fetches, controller that calls, view that displays.
- Observe the benefits: change the view without touching the model, and vice versa — clarity, maintainability, testing.
Ready-to-say script — explain your MVC tidy-up (30 s)
"This is Riad: I moved the queries and pricing rules into the model, the HTML into the view, and the controller only orchestrates — request, model, view. Result: I change the display without touching the data, and I can test the logic without a browser."
Say it in a code review; show the three files side by side.
Copy-paste template — mini-MVC in plain PHP (tested code)
prepare('SELECT nom, prix FROM produits WHERE categorie = :cat');
$stmt->execute(['cat' => $cat]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public static function prixRemise(float $prix, float $taux): float {
return round($prix * (1 - $taux), 2);
}
}
// --- Controller: thin, it orchestrates ---
function indexCatalogue(PDO $pdo, string $cat): void {
$produits = Produit::recupererParCategorie($pdo, $cat);
afficherVue('liste', ['produits' => $produits]); // picks the view
}
// --- View: dumb, it displays (data already prepared, escaped) ---
function afficherVue(string $nom, array $vars): void {
$produits = $vars['produits'];
foreach ($produits as $p) {
echo '' . htmlspecialchars($p['nom']) . ' — ' . htmlspecialchars((string) $p['prix']) . ' DA ';
}
}
Small personal script
A light separation (3 functions or 3 files) is enough, but keep the discipline: no queries in the display.
Team project
Like Riad: models/, controllers/, views/ folders — everyone knows where to work without conflicts.
Same models, two outputs
Reuse the model for an HTML page and for a JSON API: only the view changes.
Before a framework
Practise this breakdown in plain PHP: Laravel and Symfony will feel obvious instead of magical.
✓ Best practices
- Separate the 3 roles: data, display, coordination.
- Aim for thin controllers and rich models.
- Understand MVC before tackling a framework.
✗ Common pitfalls
- Putting SQL queries in views.
- Putting business logic in controllers.
- Reproducing spaghetti INSIDE the framework.
Key takeaways
- MVC = 3 responsibilities: MODEL (data + business logic), VIEW (HTML display), CONTROLLER (request → model → view coordination).
- FLOW: request → ROUTING (right controller) → CONTROLLER → MODEL (data) → VIEW (display).
- BENEFITS: clarity, maintainability, reuse/testing, collaboration.
- Understanding MVC BEFORE a framework = using it wisely. Moving from messy PHP to ARCHITECTED PHP.
48h challenge — apply it tomorrow
Take 1 mixed page and split it into model + controller + view: the model fetches, the controller orchestrates, the view displays.
- I can name the 3 layers and their roles.
- I can follow a request's flow.
- I have split 1 page into clean MVC.
Frequently asked questions
Why understand MVC before learning a framework directly?
Because frameworks impose an MVC structure (Models, Controllers, views folders, routing): without understanding the WHY, you imitate tutorials without knowing where to put what, you mix responsibilities INSIDE the framework, and you are lost as soon as you leave the tutorial's case. With MVC understood, the structure becomes obvious, you keep the separation (benefits preserved), you debug by following the flow, and the concepts transfer (Laravel, Symfony, and beyond).
How to distribute the code concretely — and which mistakes to avoid?
Model: database access (CRUD), entities, business rules — independent of display. View: HTML + minimal insertions of already-prepared data (loop, escaped display), never SQL or rules. Controller: receives the request, calls the model, picks the view — it orchestrates, thin. Classic mistakes: queries in views, business logic in controllers, 300-line controllers. "Dumb" views, "rich" models, "thin" controllers.
Where do business logic and database access belong?