Courses

Design Patterns in Laravel 11

MVC: Pattern You Use By Default

To understand what a design pattern even is, let's start with something very simple and obvious that we're all familiar with.

  • Models
  • Views
  • Controllers

Those are parts of the MVC pattern. Its concept is much older than Laravel. MVC was initially created way back in the 1970s and is widely used in other languages and frameworks.

On the surface, it's very simple to understand:

  • First, you create the DB Model
  • Then, you process the request/inputs via Controller and call the Model's functions
  • Finally, you pass the result data to the View to show it properly

app/Http/Controllers/TaskController.php:

public function index(): View // CONTROLLER METHOD
{
$tasks = Task::all(); // USING MODEL METHOD
 
return view('tasks.index', compact('tasks')); // CALLING THE VIEW
}

But then, as the project grows, we start adding more logic layers to the code. The inevitable question is raised: "Where do we put EXTRA logic?"

In the upcoming lessons, we will discuss those extra layers, with examples of Service/Actions/Observers and other classes. But if we try to stay within the MVC pattern, I would vaguely assign those extra classes to the Model layer. In other words, it's a "Model with Extra Helpers".


Why MVC? Benefits of Patterns.

That MVC pattern allows us to recognize the familiar structure of Laravel projects and immediately know where to search for DB structure, HTML code, or other stuff.

This is what you need to understand about design patterns in general.

The goal is for developers to become familiar with the pattern so they can recognize and use it in other projects and navigate them more easily.

It's kind of like a common agreement between developers. Similar to road traffic: a few dozen rules are more like "patterns" and are more or less similar worldwide.

While driving abroad, you would probably understand most of the signs / lines / traffic lights, like the image above.

Notice: Now, I know there are some geographical/cultural exceptions in traffic, but that's the whole idea: a pattern is not the rule :)


Separation of (Concerns) Jobs

In theory, MVC is an excellent separation of concerns. We could even divide the tasks for different professions of developers:

  • Database developer (Model)
  • PHP back-end developer (Controller)
  • HTML/CSS/JS front-end developer (View)

That said, this separation made sense 5-10 years ago, when front-end and back-end were often different people/teams. These days, everyone needs to be full-stack (at least a little), right?

So, these days, there are different "variants" of applying MVC and its parts. Let's take a look.


MVC to just V with No Models?

A simple one. If you need to show just a simple page like "About us", you don't need a Model. Or a Controller.

Route::view('about-us', 'pages.about');

And from here, you just work with resources/views/pages/about.blade.php file.


MVC to MV with JavaScript

So, if one full-stack person may write or touch all the code in all those projects, is there any real benefit to MVC?

This is proved with SPA or heavy front-end projects, where most of the work is done by JavaScript, so there's no need for Controllers.

MVC becomes MV.

So, sometimes, only one Laravel Route may be needed:

Route::view('/', 'main');

And then, all the logic is in that main.blade.php, which loads the JavaScript framework, such as Vue, React, etc.

Of course, Controllers return in the form of the API layer to manage the data, but that may be considered a separate application.


MVC to MV with... no JavaScript?

What about back-end developers who don't like writing JavaScript?

With the release of Livewire, the concept of a Laravel Controller was replaced by Livewire Components, with no need for writing JS.

But in 2023, they went even further to remove the need for those, too, with Livewire Volt.

Indeed, for smaller projects with just a few pages and a few dynamic elements, it may make sense to get back to the good old days of a single index.php.

Do you think I'm joking? But that's exactly what the essence of Livewire Volt is. Take a look at this all-in-one Blade file:

Laravel Route:

Volt::route('/counter', 'counter');

resources/views/pages/counter.blade.php:

<?php
 
use function Livewire\Volt\{state};
 
state(['count' => 0]);
 
$increment = fn () => $this->count++;
 
?>
 
<div>
<h1>{{ $count }}</h1>
<button wire:click="increment">+</button>
</div>

And that's it, no need for a Controller.


MVC is an OPTIONAL Design Pattern

With those MVC-breaking examples above, I wanted to show that MVC is a pattern but not a strict rule. Developers may choose to structure their code differently if that suits their situation or preference.

That said, the whole goal of the patterns is to be recognizable, so the more widely-used approaches you use in your applications, the better your code will be for maintainability by other developers or even external teams in the future.

For example, if you use Livewire Volt, other team members (present or future) would need to learn how it works on top of default Laravel. With classic MVC, you have a bigger chance that developers would quickly take over the code and work with it without learning anything extra.


So, that's it about the "default" Laravel with MVC. Now, let's dive deeper, exploring other patterns that may help your code be structured in a recognizable way.

avatar

Beautifully simple explanation. Learned something about Laravel routes too I didn't realise before. Thank you.