CN
Piotr Jura·
November 26, 2023

Laravel 11 and MVC Fundamentals Tutorial

Why Laravel is a very good choice?

Laravel, the most popular PHP framework, is known for its elegant syntax and robust features. This post will get you started with Laravel and the Model-View-Controller (MVC) architecture.

By the end of this tutorial, you'll have a locally running Laravel 11 application, connected to a (SQLite) database.

What does MVC mean and how does it work?

MVC is a design pattern that separates an application into three interconnected components:

  1. Model: Manages data and business logic.
  2. View: Presents data to the user.
  3. Controller: Interfaces between Model and View, handling user requests.

This is a very simple yet robust concept and a basic structure for any application. MVC is not unique to Laravel.

The diagram representing MVC

How to setup a new Laravel project?

You need to have PHP and Composer running locally. Your options are:

  1. The easiest way (Mac/Windows) these days is to use Laravel Herd.
  2. Direct installation. Here's a tutorial explaining PHP installation on Windows.

Ensure you have Composer installed, then create a new Laravel project:

composer create-project --prefer-dist laravel/laravel laravel11

This commands will create a new Laravel project. Couple points here:

  • --prefer-dist avoids using Git (a basic guide to Git), which is the default.
  • laravel/laravel is the base boilerplate of a project (the command can be used to create any PHP project)
  • laravel11 is the project name (directory name)

What is an Eloquent model?

Laravel has an 1st party ORM (Object-Relational-Mapper) called Eloquent. ORMs abstract the databases, so you can use PHP classes and methods to fetch and store data, instead of writing and running SQL queries (though that's still possible).

Model is a PHP Class that's typically mapped to a database table (I said typically, as that's 98% of use cases). You can create a model by running this command in your project directory:

php artisan make:model -m Post

This command generates a Post model. You can define attributes and relationships within this model. The -m flag generates a so-called migration.

Models work with database tables by trying to guess the table name. For the Post model, the default table name is posts so lower-cased Post + plural form(s).

This is configurable though.

Why should you start with an SQLite database?

To run this app, you don't need a MySQL or Postgres database, as we're using SQLite. SQLite is a database inside a single file database/database.sqlite.

People often think SQLite is not good enough for serious traffic. Think again. Most apps won't ever reach the traffic that's beyond SQLite capabilities.

With Eloquent, you don't need to worry about your database choice so much, as it's easy to switch to MySQL or Postgres when you need that.

What are database migrations?

Instead of adding the database table manually, you can do that using migrations. Migration is a file that changes the database schema. When you add -m flag when creating a model, this will automatically create a migration file for you.

Let's change the migration file, found inside database/migrations, and the name will look like 2024_03_26_133049_create_posts_table:

database/migrations/2024_03_26_133049_create_posts_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

// Migrations are anonymous classes
return new class extends Migration
{
public function up(): void
{
// Schema::create() creates a new table
// Blueprint class helps with adding table fields
// "posts" is the table name
Schema::create('posts', function (Blueprint $table) {
// Every table needs an ID
$table->id();
// timestamps() will create auto-updated
// created_at and updated_at timestamp fileds
$table->timestamps();
// The post title
$table->tinyText('title');
// The post text
$table->longText('text');
});
}

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }

};

To apply unapplied migrations, run php artisan migrate. This would create/update the tables in your database. Okay, at this point we should have the posts table, so we're ready to use the model.

How to add fake data to the database using seeding

It's very useful to be able to see how models can fetch data from the database, but how to get some data to fetch? Just use data seeding to populate the database with data. Open database/seeders/DatabaseSeeder.php:

database/seeders/DatabaseSeeder.php
<?php

namespace Database\Seeders;

use App\Models\User;
use App\Models\Post; // Import the Post model
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // Add the following line
        Post::factory(10)->create();
        User::factory()->create([
            'name' => 'Test User',
            'email' => 'test@example.com',
        ]);
    }
}

By adding this line Post::factory(10)->create(); you'll be able to generate 10 "dummy" post entries inside the database.

But wait, we need to create the model factory first!

How to generate fake data using model factories?

Model factory defines how to create the dummy data for models inside seeder. Type php artisan make:factory PostFactory to create the factory file for Post model, and open the database/factories/PostFactory.php file. Inside the definition method "tell" Laravel how values for certain columns should be generated.

database/factories/PostFactory.php
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/\*\*

- @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Post>
  _/
  class PostFactory extends Factory
  {
  /\*\*
  _ Define the model's default state. \*
  _ @return array<string, mixed>
  _/
  public function definition(): array
  {
  return [
  'title' => fake()->sentence,
  'text' => fake()->realText
  ];
  }
  }

Then, run php artisan db:seed - this should generate 10 rows inside posts table.

What are the controllers?

Controllers are used to handle requests and return responses. You handle all the query parameters, read/write data to the database, and display a result using views - either HTML or JSON. Create a controller using a command:

php artisan make:controller PostController

This creates PostController.php in the app/Http/Controllers directory.

The file would be pretty empty, let's add an action called index. Actions are basically class methods.

app/Http/Controllers/PostController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;

class PostController extends Controller
{
public function index()
{
$posts = Post::all();
return view('posts.index', compact('posts'));
}
}

This action retrieves all posts (Post:all()) from the database and passes them to the view - essentially generating a HTML response with all the posts.

What are views, templates and what is Blade?

View is the output that the user will see in the browser.

Views in Laravel are usually Blade templates located in the resources/views directory.

Blade has a special syntax that lets you generate HTML based on some data or conditions, and use @if statements and @foreach loops, among others.

Directives in Blade refer to the syntax constructs that start with the @ symbol, which provide a more concise and readable way to write common PHP control structures and output expressions.

Blade processor will compile directives into PHP code.

You can pass data to Blade templates from your controllers or other parts of your application. This allows you to generate the same document structure but with different dynamic content.

The diagram representing MVC

Add the following file:

resources/views/posts/index.blade.php
@foreach ($posts as $post)
    <h2>{{ $post->title }}</h2>
    <p>{{ $post->content }}</p>
@endforeach

Views are not limited to generating HTML output. You can use them to generate emails or JSON.

How do you add pages and what's routing?

The final step is to add a route. Laravel routes define URLs and associate them with controller actions or just an anonymous functions, then the logic can be written directly inside the routes/web.php file - this works best for small apps. Here's how to define a basic route:

routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/', function () {
return view('welcome');
});

Route::get('/posts', [PostController::class, 'index']);

This route calls the index method of PostController when /posts URL is accessed.

How do you run the Laravel application?

Now, to start the built-in PHP server, run php artisan serve inside the project root directory.

Then, navigate to http://127.0.0.1:8000/posts and you should see the list of posts.