How Laravel implements MVC and how to use it effectively

laravel-mvc-use-header.png

In this brief tutorial, become familiar with the concept of MVC architecture, then build a simple Laravel app following an MVC design pattern.

Introduction

In this article, how the Laravel framework implements MVC architecture. By the end, you will have some knowledge of MVC and how Laravel helps with structuring your application.

If you are not new to software programming, you must have heard of MVC. MVC is a software architecture pattern and it stands for Model View Controller.

Prerequisites

  • Basic understanding of programming concepts.
  • Laravel installer installed on your machine.
  • Knowledge of PHP.
  • Basic knowledge of the command line.
  • SQLite installed on your machine. Installation guide.

What is MVC?

MVC is an acronym for ‘Model View Controller’. It represents architecture developers adopt when building applications. With the MVC architecture, we look at the application structure with regards to how the data flow of our application works

MVC is a software architecture…that separates domain/application/business…logic from the rest of the user interface. It does this by separating the application into three parts: the model, the view, and the controller.

The model manages fundamental behaviors and data of the application. It can respond to requests for information, respond to instructions to change the state of its information, and even notify observers in event-driven systems when information changes. This could be a database or any number of data structures or storage systems. In short, it is the data and data-management of the application.

The view effectively provides the user interface element of the application. It’ll render data from the model into a form that is suitable for the user interface.
The controller receives user input and makes calls to model objects and the view to perform appropriate actions.

All in all, these three components work together to create the three basic components of MVC.
Bob, Stack Overflow

We have a structure that looks like this:

Diagram illustrating MVC concepts

A Model is a representation of a real-life instance or object in our code base. The View represents the interface through which the user interacts with our application. When a user takes an action, the Controller handles the action and updates the Model if necessary.

Let’s look at a simple scenario.

If you go to an e-commerce website, the different pages you see are provided by the View layer. When you click on a particular product to view more, the Controller layer processes the user’s action. This may involve getting data from a data source using the Model layer. The data is then bundled up together and arranged in a View layer and displayed to the user. Rinse and repeat.

Other software architectural patterns

As with most things in software, there are other ways things can be done. For architecture, there are several others that developers can use when building their applications. Here are some of them:

  • Client-Server Architecture – This consists of two parts, client and server systems that communicate over a computer network. The clients make requests to servers and the server waits for requests.
  • Layered Architecture – components are organized into layers with each layer performing a specific role within the application. Layers may vary based on the size of the application
  • Peer-to-Peer Architecture – the tasks are partitioned between the different peers and is commonly used with file-sharing services

There are more architectural patterns. You can read more here.

Why use MVC?

⚠️ This article is not a comparison between architecture types but information on a single type, which is MVC.

When building PHP applications, it may be okay to have a lot of files flying around in very very small projects. However, when the project becomes even slightly bigger than five files or entry points having a structure can drastically improve maintainability.

When you have to work with codebases that have no architecture, it will become extremely grueling, especially if the project is big and you have to deal with unstructured code laying everywhere. Using MVC can give your code some structure and make it easier to work with.

On a more technical note, when you build using the MVC architecture, you have the following strategic advantages:

  • Splitting roles in your project are easier.
    When the MVC architecture is adopted, you have the advantage of splitting roles in the project. You can have a backend developer working on the controller logic, while a frontend developer works on the views. This is a very common way to work in companies and having MVC makes it much easier than when the codebase has spaghetti code.
  • Structurally ‘a-okay’.
    MVC can force you to split your files into logical directories which makes it easier to find files when working on large projects.
  • Responsibility isolation.
    When you adopt MVC, each broad responsibility is isolated. For instance, you can make changes in the views and the models separately because the model does not depend on the views.
  • Full control of application URLs.
    With MVC architecture, you have full control over how your application appears to the world by choosing the application routes. This comes in handy when you are trying to improve your application for SEO purposes.
  • Writing SOLID code is easier.
    With MVC it is easier to follow the SOLID principle.

What is Laravel?

Laravel is a PHP-based web framework that is largely based on the MVC architecture. Laravel was created to make it easier for developers to get started on PHP projects. With Laravel, you think less about the setup, architecture, and dependencies of a project and go straight into the meat of the project.

How Laravel requests work

Before diving into how Laravel implements MVC let us take a look at how requests are handled in Laravel.

When you create a new Laravel project, (you can create one by running the command laravel new project-name), the project has the following structure:

Laravel Project Structure

There is a file in the routes/ directory called web.php. That file is where you handle the requests when users visit your app. The file looks like this:

1<?php
2
3    /*
4    |--------------------------------------------------------------------------
5    | Web Routes
6    |--------------------------------------------------------------------------
7    |
8    | [...]
9    |
10    */
11
12    Route::get('/', function () {
13        return view('welcome');
14    });

In this file, you can route URLs to controllers in your application, for example, what happens when a user goes to ’yourapp.com/home’ or ‘yourapp.com’.

How MVC is implemented in Laravel applications

Let’s take a look at how Laravel uses MVC during development. To do this, let’s create a sample Laravel project that displays products for a shop.

To create a new project run the command below in your terminal:

1$ laravel new product-store

To see the starter app at work, update the APP_URL in your .env file to http://localhost:8000 then run the following command in your terminal:

1$ php artisan serve

? All artisan commands for a Laravel project have to be run inside the root of the Laravel project so you have to cd there first before running the command.

This will run your app and you can visit it on 127.0.0.1:8000/. You should see a welcome view in your browser. Great. To stop the server press ctrl + c on your keyboard for Windows, Mac, and Linux.

Models: creating our product model

Let us create our first model, M in MVC, for our application. As we have noted before, the model usually, interfaces with a data storage like an SQL database. In Laravel, the Model is usually a class with properties that match the columns in the database.

In our database, a product will have the following properties:

  • Name (name) – Name of product.
  • Short Description (description) – Short description of a product.
  • Count (count) – The number of products available.
  • Unit Price (price) – How much a single product costs.

To create a model in Laravel, run the command in your terminal:

1$ php artisan make:model Product

When you run this command, Laravel will create a Product.php file in the app directory. This will be a PHP class with the name Product and it will be the model for our products table in the database.

In the Product model, add the $fillable property as shown below:

1<?php
2
3    namespace App;
4
5    use Illuminate\Database\Eloquent\Model;
6
7    class Product extends Model {
8
9        protected $fillable = [
10           'name',
11           'count',
12           'price',
13           'description',
14        ];
15
16    }

? The fillable property is used to represent mass assignable attributes for our model

That is all about models in Laravel, however, as a bonus let’s talk about migrations in Laravel.

Migration lets developers make and undo changes to a project’s database. Migrations can be used to make managing databases easy and predictable. To create a migration, run the following in your terminal:

1$ php artisan make:migration create_products_table

When the command is executed, we should see a new *_create_products_table.php file in the database/migrations directory and we can edit it to have our products table schema like this:

1<?php
2
3    [...]
4
5    class CreateProductsTable extends Migration
6    {
7        public function up()
8        {
9            Schema::create('products', function (Blueprint $table) {
10                $table->increments('id');
11                $table->string('name');
12                $table->text('description');
13                $table->integer('count');
14                $table->integer('price');
15                $table->softDeletes();
16                $table->timestamps();
17            });
18        }
19
20        public function down()
21        {
22            Schema::dropIfExists('products');
23        }
24    }

That’s all for the migration file. However, before we run the migration we need Laravel to connect to a database. In this tutorial, we will be using SQLite.

As part of the prerequisites mentioned earlier, you need SQLite installed on your machine. To make it possible for Laravel connect to an SQLite database, create a new empty database/database.sqlite file.

Next copy the .env.example file in the root of your project to .env and then in the copied file, replace the following lines:

1DB_CONNECTION=mysql
2    DB_DATABASE=homestead
3    DB_USERNAME=username
4    DB_PASSWORD=password

with

1DB_CONNECTION=sqlite
2    DB_DATABASE=/full/path/to/database.sqlite

That is all for our database setup. Now to run the migrations, run the command below in your terminal:

1$ php artisan migrate

Before running the command, you need to have set up your database and set the connection details in your .env file in the root of the project.

You can read about how to set up your database here and you can read more about migrations here.

Controllers: creating our controller

Earlier we mentioned that controllers are responsible for completing user actions and the managing the business logic of our applications. For our make-believe project, we are going to use Resource Controllers.

Laravel resource routing assigns the typical “CRUD” routes to a controller with a single line of code. For example, you may wish to create a controller that handles all HTTP requests for “photos” stored by your application. – Laravel documentation

To create a resource controller in Laravel, run the following command:

1$ php artisan make:controller ProductController -r

? The -r flag makes it a resource controller and thus creates all the methods required for CRUD operation.

When the command is run, Laravel will create a new file in the app/Http/Controllers directory called ProductController.php.

Before we start adding logic to the controller, go to the routes/web.php file and add the following route:

1Route::resource('/products', 'ProductController');

This tells Laravel to create all the routes necessary for a resource controller and map them to the ProductController class.

You can see the list of routes by running the command php artisan route:list in your terminal. You get the following result showing the routes and the request types to use when accessing the routes:

Laravel Routes List

Looking at the image above, you can see the action that each URI is mapped to. This means when a user goes to 127.0.0.1:8000/products/create, the create function in the ProductController will process the user’s request.

Now let’s go to the controller file and update the methods in them with the following logic:

The create method:

1public function create()
2    {
3        return view('createproduct');
4    }

The above is for the create (C in CRUD). The controller loads a view (V in MVC) called create product and serves that as the response for anytime someone visits the route /products/create with a GET HTTP method.

The store method:

1public function store(Request $request) {
2        \App\Product::create([
3          'name' => $request->get('name'),
4          'description' => $request->get('description'),
5          'price' => $request->get('price'),
6          'count' => $request->get('count'),
7        ]);
8
9        return redirect('/products');
10    }

The store method is called when a user sends a POST HTTP request to the /products endpoint. This logic above gets the data from the request and stores it in the database using the Product model.

The index method:

1public function index()
2    {
3        $products = \App\Product::all();
4
5        return view('viewproducts', ['allProducts' => $products]);
6    }

The index method is called when the /products route is loaded with a GET HTTP method. In this method, we fetch all the products available in the products table using the Product model and pass it on to the view as a variable. This means in the view, the $allProducts variable will be available.

To keep the article short, we will limit the controller logic to these three methods. Let’s create the views that are loaded by the controller methods above.

Views: creating the projects views

In Laravel, all the views are stored in the resources/views directory. Your views usually store the HTML of your page and are the presentation layer of the MVC architecture.

Let’s create the home page view. Update the welcome.blade.php file in the resources/views directory to include the following code inside the body tag of the existing HTML:

1[...]
2
3    <div class="flex-center position-ref full-height">
4      <div class="content">
5        <div class="title m-b-md">Product Store</div>
6        <div class="links">
7          <a href="{{ config('app.url')}}/products/create">Create Product</a>
8          <a href="{{ config('app.url')}}/products">View Products</a>
9        </div>
10      </div>
11    </div>
12
13    [...]

Laravel uses Blade as it’s templating engine. Blade is pretty much HTML but with some injectable PHP-like syntax. You can read more about blade here.

If you go back to the routes/web.php you see it stated that the welcome view should be rendered to the user when the / is visited. If you visit the webpage URL http://127.0.0.1:8000/ you will see this page:

Home View

Next, let’s make the ‘Create Product’ view. Create a createproduct.blade.php file in the resources/views directory of our project. In there add the following:

1<!doctype html>
2    <html lang="{{ app()->getLocale() }}">
3    <head>
4      <title>Create Product | Product Store</title>
5      <!-- styling etc. -->
6    </head>
7    <body>
8        <div class="flex-center position-ref full-height">
9            <div class="content">
10                <form method="POST" action="{{ config('app.url')}}/products">
11                    <h1> Enter Details to create a product</h1>
12                    <div class="form-input">
13                        <label>Name</label> <input type="text" name="name">
14                    </div>
15
16                    <div class="form-input">
17                        <label>Description</label> <input type="text" name="description">
18                    </div>
19
20                    <div class="form-input">
21                        <label>Count</label> <input type="number" name="count">
22                    </div>
23
24                    <div class="form-input">
25                        <label>Price</label> <input type="number" name="price">
26                    </div>
27
28                    <button type="submit">Submit</button>
29                </form>
30            </div>
31        </div>
32    </body>
33    </html>

This view above is a simple form that collects and submits requests to create products. When the form is submitted, a POST request is made to the /products route of the application which is handled by the store method in our ProductController.

Here is how the /products/create route will look after adding the view and visiting the route:

Create Product View

The next view we want to add is the viewproducts.blade.php view. Create that file in the resources/views directory and add the following code to the file:

1<!doctype html>
2    <html lang="{{ app()->getLocale() }}">
3    <head>
4        <title>View Products | Product Store</title>
5        <!-- Styles etc. -->
6    </head>
7    <body>
8        <div class="flex-center position-ref full-height">
9            <div class="content">
10                <h1>Here's a list of available products</h1>
11                <table>
12                    <thead>
13                        <td>Name</td>
14                        <td>Description</td>
15                        <td>Count</td>
16                        <td>Price</td>
17                    </thead>
18                    <tbody>
19                        @foreach ($allProducts as $product)
20                            <tr>
21                                <td>{{ $product->name }}</td>
22                                <td class="inner-table">{{ $product->description }}</td>
23                                <td class="inner-table">{{ $product->count }}</td>
24                                <td class="inner-table">{{ $product->price }}</td>
25                            </tr>
26                        @endforeach
27                    </tbody>
28                </table>
29            </div>
30        </div>
31    </body>
32    </html>

In the view above, the data that was sent from the controller, $allProducts, is iterated on and displayed to the user.

Now, if you visit the /products route you should see something like this:

Products List View

Conclusion

In this article, we considered how MVC works and how Laravel implements it. We considered why you should use MVC and how to implement it in a real-world Laravel application.

The source code to the article is available on GitHub.