# Understanding MVC for real: stop bloating your controllers

> What each layer of MVC is actually responsible for, what a controller should not do, and how to keep controllers thin by moving logic into the model.

- Published: 2015-01-04
- Category: Languages
- Tags: PHP
- Reading time: 3 min read
- Source: https://muhammetsafak.com/blog/understanding-mvc-stop-bloating-your-controllers/
- Language: en-US
- Author: Muhammet Şafak

---
> **TL;DR:** MVC splits an application into the Model for data and business rules, the View for presentation and the Controller that coordinates them. A controller should not run SQL, decide business rules or send email; that goes to the model or a helper class. MVC is a guideline; knowing its purpose beats blind use.

After a while I would open a controller file and ask myself, "when did this get so big?" Database queries, business logic, format conversions, email sending — all tangled together inside a single method. Those queries belonged in the model; the tools I described in [simplifying database operations with Eloquent ORM](/blog/simplifying-database-operations-with-eloquent-orm/) were already at hand — they were just sitting in the wrong layer. I thought I was using the MVC (Model-View-Controller) pattern, but in practice I had turned the controller into the one place that did everything.

In this post I want to explain what the three layers of MVC actually mean, and where responsibilities should live. It took me several passes and the pain of a real project to internalize this; hopefully it can save you some of that time.

## What is MVC and what does each layer do?

**MVC (Model-View-Controller)** is a software architecture pattern that divides an application into three distinct layers.

- **Model:** The application's data and business rules. It talks to the database, validates data, and performs calculations.
- **View:** Produces the output shown to the user. HTML, JSON, XML — whatever the format, its only job is presentation.
- **Controller:** The bridge between request and response. It receives the incoming request, calls the appropriate model method, and passes the result to the view.

On paper this looks clean. The problem is how easy it is for the controller to become the place that "knows everything."

## What should the controller NOT do?

When an HTTP request arrives, the controller should not:

- Execute raw SQL queries directly
- Make business-logic decisions ("if the user is a premium member, do this")
- Send emails or notifications
- Perform complex data transformations

It is perfectly possible to write all of this inside the controller — PHP will not stop you. But a few months later when you open that method again, 150 lines of code will greet you and you will spend real time figuring out what each part does.

A bloated controller method looks something like this:

```php
public function store(Request $request)
{
    // Validation
    if (empty($request->input('email'))) {
        return redirect()->back()->with('error', 'E-posta zorunlu.');
    }

    // Write to the database
    $user = new User();
    $user->name  = $request->input('name');
    $user->email = $request->input('email');
    $user->save();

    // Send email
    mail($user->email, 'Hoş geldiniz', 'Kayıt oldunuz.');

    return redirect('/dashboard');
}
```

Three different responsibilities inside a single method. If validation changes, you open this method. If the email template changes, you come back here. If the user registration logic changes, you are here again.

## What should move to the Model layer?

All business logic related to a user should live on the model side. A simple example:

```php
class User extends Model
{
    public static function kaydet(array $veri)
    {
        $user        = new self();
        $user->name  = $veri['name'];
        $user->email = $veri['email'];
        $user->save();

        return $user;
    }

    public function hosGeldinGonder()
    {
        mail($this->email, 'Hoş geldiniz', 'Kayıt oldunuz.');
    }
}
```

Now the controller does nothing but coordinate:

```php
public function store(Request $request)
{
    $user = User::kaydet($request->only('name', 'email'));
    $user->hosGeldinGonder();

    return redirect('/dashboard');
}
```

The controller no longer shows *what* is being done — it shows *in what order* calls are made. It is much easier to read.

## Keeping the View layer clean

The same kind of mess can happen on the view side. Making business-logic decisions inside the view — templates full of growing conditionals like "if the user is an admin, show this button" — quickly becomes hard to manage.

The view should only ask: "How do I display the data I was given?" Deciding which data to send is the controller's job. How that data was calculated is the model's.

## Small methods, single responsibility

A practical way to keep controller methods small is to ensure each one does exactly one thing. Registration, update, deletion — each gets its own method, and each method is a handful of lines. When a method starts growing in line count, that is a signal that something is off.

When I first started applying this, I struggled with "where do I put this?" The answer was almost always the model, or a separate helper class. Over time I memorized where to look, and following the code became much easier.

MVC is not a rule — it is a guideline. But understanding the *purpose* of the guideline is far more valuable than following it blindly.

Note: I described a solution I found in later years to the question of slimming down controllers in [my post on Action classes](/blog/slimming-laravel-controllers-with-action-classes/).

## Frequently asked

### What is MVC and what does each layer do?

MVC (Model-View-Controller) divides an application into three layers. The Model holds the data and business rules: it talks to the database, validates data and performs calculations. The View produces the output shown to the user, and its only job is presentation. The Controller is the bridge between request and response: it receives the request, calls the right model method and passes the result to the view.

### What should a controller not do?

It should not execute raw SQL, make business-logic decisions, send emails or notifications, or perform complex data transformations. If it does all of that, you come back to the same long method every time validation, the email template or the registration logic changes.

### What should move to the Model layer?

All business logic related to a user: in my example, saving the record and sending the welcome email. The controller then no longer shows what is being done, only in what order calls are made, which is much easier to read.

### What belongs in the View?

Only the question of how to display the data it was given. Deciding which data to send is the controller's job, and how that data was calculated is the model's. Business-logic decisions inside templates quickly become hard to manage.

### How do you keep controller methods small?

Make each method do exactly one thing: registration, update and deletion each get their own method of a handful of lines. A method that keeps growing is a signal that something is off. When I asked where to put something, the answer was almost always the model or a separate helper class.
