In this brief tutorial, become familiar with the concept of MVC architecture, then build a simple Laravel app following an MVC design pattern.
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.
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:
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.
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:
There are more architectural patterns. You can read more here.
⚠️ 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:
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.
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:
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’.
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.
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 of product.description
) – Short description of a product.count
) – The number of products available.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.
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:
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.
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:
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:
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:
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.