Skip to content

A Gentle Introduction to Laravel

Chapter 20: A Gentle Introduction to Laravel

Overview

Congratulations on building a complete application from scratch! In doing so, you have manually implemented simplified versions of the key components that make up a professional web framework: routing, controllers, models, views, and a database connection. This was a fantastic learning experience, but as you can imagine, building all of that plumbing for every single project would be a lot of work.

This is why we use frameworks. A framework is a collection of pre-built, reusable components and a guiding structure that handles all the common, repetitive tasks for you. This lets you focus on what makes your application unique: its business logic.

In this chapter, we'll take a brief look at Laravel, the most popular PHP framework in the world. You'll see how the concepts you've learned map directly to Laravel's features, and you'll appreciate how much faster development can be when you stand on the shoulders of giants.

Prerequisites

Before starting this chapter, ensure you have:

  • PHP 8.4 installed and available in your terminal
  • Composer 2.x installed (getcomposer.org)
  • Completed Chapter 19 (Building a Simple Blog) or understand MVC concepts
  • A terminal/command line and text editor
  • Estimated time: 35–40 minutes (20 minutes for hands-on, 15-20 minutes for reading comparisons)

Verify your setup:

bash
# Check PHP version (should be 8.4.x)
php --version

# Check Composer version (should be 2.x)
composer --version

What You'll Build

By the end of this chapter, you will have:

  • A new Laravel 11 project installed and running
  • A database-backed "Posts" feature with:
    • A posts database table created via migrations
    • An Eloquent Post model
    • A PostController with an index method
    • A route mapped to /posts
    • A Blade view displaying all posts
  • Sample post data to verify everything works
  • Understanding of how Laravel maps to the MVC concepts you've learned

Objectives

  • Understand the benefits of using a framework like Laravel.
  • Install a new Laravel project using Composer.
  • Learn about Artisan, Laravel's command-line tool.
  • Define a route and a controller.
  • Use the Eloquent ORM to interact with the database.
  • Render a view using the Blade templating engine.

Quick Start

If you want to dive straight in, here's the complete sequence to create a working Laravel blog posts feature:

bash
# Create project and navigate into it
composer create-project laravel/laravel laravel-blog
cd laravel-blog

# Configure SQLite database
echo "DB_CONNECTION=sqlite" >> .env
touch database/database.sqlite

# Generate model, migration, and controller
php artisan make:model Post -m
php artisan make:controller PostController

# Run migrations
php artisan migrate

# Start development server
php artisan serve

Then follow the detailed steps below to configure the migration, controller, route, and view. The step-by-step sections will explain what each command does and why.

Step 1: Why Use a Framework?

The simple blog you built in Chapter 19 is great for learning, but a real-world application needs much more:

  • A more powerful and flexible router that can handle complex URL parameters, middleware, and API routes
  • Robust security features to prevent XSS, CSRF, and SQL injection attacks
  • A templating engine with layouts, components, and reusable partials
  • A way to manage database schema changes (migrations)
  • User authentication and authorization systems
  • Form validation, file uploads, email sending, queues, caching, and testing tools
  • And much, much more...

A framework like Laravel provides battle-tested solutions for all of these problems out of the box, saving you thousands of hours of development time.

From Scratch to Laravel: A Quick Comparison

Here's how the components you built manually map to Laravel features:

Your Simple BlogLaravel EquivalentWhat Laravel Adds
$routes array in public/index.phpRoute::get() in routes/web.phpNamed routes, route parameters, middleware, route grouping, route caching
Manual require for controllersController classes with dependency injectionAutomatic class loading, type-hinted dependencies, resource controllers
PDO connectionEloquent ORM + Query BuilderObject-oriented queries, relationships (one-to-many, many-to-many), eager loading, soft deletes
Manual include of view filesBlade templating engineLayouts, components, slots, automatic XSS escaping, view caching
No database versioningMigrations and seedersVersion-controlled schema, easy rollback, shareable database structure
Manual htmlspecialchars()Automatic in Blade ({{ }})Built-in XSS protection
No structureMVC architectureClear separation of concerns, testable code

This isn't to say your from-scratch blog was bad—far from it! Understanding how to build these components manually gives you deep knowledge of why frameworks work the way they do. You're now in a perfect position to appreciate Laravel's elegance.

Step 1: Install Laravel (~5 min)

Goal

Install Laravel 11 via Composer and confirm the project boots.

Actions

  1. Create a new Laravel project:
bash
# Create project and navigate into it
composer create-project laravel/laravel laravel-blog
cd laravel-blog
  1. Configure the .env file for SQLite (or your preferred database):
bash
echo "DB_CONNECTION=sqlite" >> .env
touch database/database.sqlite
  1. Serve the application to confirm everything runs:
bash
php artisan serve

Visit http://127.0.0.1:8000 in your browser and ensure the default Laravel welcome page loads.

Expected Result

The default Laravel homepage appears at http://127.0.0.1:8000, confirming the framework was installed successfully.

Why It Works

  • composer create-project downloads Laravel and all dependencies.
  • The .env configuration tells Laravel to use SQLite and where the database lives.
  • php artisan serve launches the built-in PHP development server with Laravel’s routing.

Troubleshooting

  • composer command not found — Ensure Composer is installed and available in your PATH.
  • Permission errors creating the SQLite file — Verify the database/ directory exists and is writable.
  • Blank page or 500 error — Check storage/logs/laravel.log for detailed error messages.

Step 2: Configure the Database (~2 min)

Goal - Set up SQLite as your database and verify Laravel can connect to it.

Laravel is pre-configured to use MySQL, but we can easily switch it to SQLite for simplicity.

  1. Update Environment Configuration

    Open the .env file in your project root. This file holds your application's environment-specific configuration. Find the database configuration section and update it:

    bash
    # filename: .env
    # Update the DB_CONNECTION line (around line 11)
    DB_CONNECTION=sqlite
    # DB_HOST=127.0.0.1      # Comment out or remove
    # DB_PORT=3306           # Comment out or remove
    # DB_DATABASE=laravel    # Comment out or remove
    # DB_USERNAME=root       # Comment out or remove
    # DB_PASSWORD=           # Comment out or remove
  2. Create the Database File

    SQLite uses a single file for the entire database. Create it:

    bash
    # Create an empty SQLite database file
    touch database/database.sqlite
  3. Verify Database Connection

    Run a simple Artisan command to test the connection:

    bash
    # Test database connectivity
    php artisan migrate:status

    Expected output:

    Migration table not found.

    This is normal—we haven't run any migrations yet. The important thing is that you didn't get a connection error.

Why it works: The .env file controls which database driver Laravel uses. By setting DB_CONNECTION=sqlite and creating the database file, Laravel knows to use SQLite instead of MySQL. Migrations (which we'll run next) are Laravel's way of managing database schema changes.

Troubleshooting

Problem: "SQLSTATE[HY000]: Unable to open database file"

Solution: Ensure you created the database/database.sqlite file and that the web server has write permissions to the database/ directory.

Step 4: Create the Model and Migration (~3 min)

Goal: Generate a Post model and define the database table schema.

Artisan can generate boilerplate code for us. Let's create a Post model and a database migration file at the same time. A migration is like version control for your database schema.

  1. Generate the Model and Migration

    bash
    # -m flag creates a migration file alongside the model
    php artisan make:model Post -m

    Expected output:

    INFO  Model [app/Models/Post.php] created successfully.
    INFO  Migration [database/migrations/YYYY_MM_DD_HHMMSS_create_posts_table.php] created successfully.
  2. Define the Table Schema

    Open the newly created migration file in database/migrations/ (it will have a timestamp in the filename). Update the up() method:

    php
    # filename: database/migrations/YYYY_MM_DD_HHMMSS_create_posts_table.php
    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        public function up(): void
        {
            Schema::create('posts', function (Blueprint $table) {
                $table->id();
                $table->string('title');
                $table->text('content');
                $table->timestamps(); // Automatically creates `created_at` and `updated_at`
            });
        }
    
        public function down(): void
        {
            Schema::dropIfExists('posts');
        }
    };
  3. Run the Migration

    Execute the migration to create the posts table:

    bash
    # Run all pending migrations
    php artisan migrate

    Expected output:

    INFO  Running migrations.
    YYYY_MM_DD_HHMMSS_create_posts_table ............. 15ms DONE
  4. Verify Table Creation

    You can use Artisan Tinker (Laravel's REPL) to verify:

    bash
    php artisan tinker

    Then run:

    php
    >>> \DB::select('SELECT name FROM sqlite_master WHERE type="table"');

    You should see posts in the list. Type exit to leave Tinker.

Why it works: Migrations allow you to define your database structure using PHP code, making it version-controllable and shareable. The up() method defines what happens when you run the migration, and down() defines how to reverse it.

Troubleshooting

Problem: "Syntax error or access violation: 1071 Specified key was too long"

Solution: This error occurs with MySQL, not SQLite. Ensure your .env file has DB_CONNECTION=sqlite.

Problem: "Nothing to migrate"

Solution: You may have already run migrations. Check php artisan migrate:status to see which migrations have run.

Step 5: Create the Controller (~2 min)

Goal: Generate a controller to handle post-related HTTP requests.

  1. Generate the Controller

    bash
    # Create a new PostController
    php artisan make:controller PostController

    Expected output:

    INFO  Controller [app/Http/Controllers/PostController.php] created successfully.
  2. Add the Index Method

    Open app/Http/Controllers/PostController.php and add an index method:

    php
    # filename: app/Http/Controllers/PostController.php
    <?php
    
    namespace App\Http\Controllers;
    
    use App\Models\Post;
    
    class PostController extends Controller
    {
        public function index()
        {
            // Eloquent query to get all posts, newest first
            $posts = Post::latest()->get();
    
            return view('posts.index', ['posts' => $posts]);
        }
    }

Why it works - Notice how we can use the Post model directly to query the database. This is Laravel's Eloquent ORM in action. The latest() method orders by created_at descending, and get() executes the query. No manual SQL required!

Step 6: Define the Route (~1 min)

Goal: Map a URL path to your controller method.

  1. Add the Route

    Open routes/web.php and add the following route:

    php
    # filename: routes/web.php
    <?php
    
    use App\Http\Controllers\PostController;
    use Illuminate\Support\Facades\Route;
    
    Route::get('/', function () {
        return view('welcome');
    });
    
    // Add this new route
    Route::get('/posts', [PostController::class, 'index']);

Why it works: The Route::get() method registers a GET route at /posts that will call the index method on PostController. The syntax [PostController::class, 'index'] is modern PHP's way of referencing a class method.

Understanding Laravel's Request Flow

In Chapter 18, you built this flow:

Browser → public/index.php → Router → Controller → view() helper → Layout + View

Laravel's flow is remarkably similar:

Browser → public/index.php → Laravel's Router → Controller → view() helper → Blade Layout + View

The key difference: Laravel's infrastructure is more robust with automatic dependency injection, middleware support, and extensive error handling, but the fundamental pattern is identical to what you built!

Step 7: Create the View (~2 min)

Goal: Build a Blade template to display the list of posts.

Laravel uses a powerful templating engine called Blade. Blade files end in .blade.php and provide a cleaner syntax than raw PHP.

  1. Create the Directory Structure

    bash
    # Create the posts views directory
    mkdir -p resources/views/posts
  2. Create the View File

    Create resources/views/posts/index.blade.php with this content:

blade
# filename: resources/views/posts/index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>All Posts - Laravel Blog</title>
    <style>
        body { font-family: sans-serif; max-width: 800px; margin: 50px auto; padding: 0 20px; }
        article { border: 1px solid #ddd; padding: 20px; margin-bottom: 20px; border-radius: 5px; }
        h1 { color: #333; }
        h2 { color: #666; margin-top: 0; }
    </style>
</head>
<body>
    <h1>All Posts</h1>

    @forelse ($posts as $post)
        <article>
            <h2>{{ $post->title }}</h2>
            <p>{{ $post->content }}</p>
            <small>Posted on {{ $post->created_at->format('F j, Y') }}</small>
        </article>
    @empty
        <p>No posts yet. Create some posts using Tinker!</p>
    @endforelse
</body>
</html>
  1. Verify the Route

    Visit http://localhost:8000/posts in your browser. You should see the heading "All Posts" and the message "No posts yet."

Why it works:

  • @forelse is a Blade directive that combines a foreach loop with an empty check
  • {{ $post->title }} is Blade's syntax for echoing data—it automatically escapes output to prevent XSS attacks (no need for htmlspecialchars)
  • $post->created_at->format() works because Eloquent automatically casts timestamp columns to Carbon objects (a powerful date/time library)

Blade vs. Your Layout System

In Chapter 18, you built a layout system using output buffering:

php
// Your approach in Chapter 18
function view(string $viewName, array $data = [], ?string $layout = 'layout'): void {
    ob_start();
    require $viewPath;
    $content = ob_get_clean();
    require $layoutPath; // Layout uses $content variable
}

Laravel's Blade uses a different (more elegant) approach with @extends and @section directives:

blade
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html>
<head>
    <title>@yield('title', 'Laravel Blog')</title>
</head>
<body>
    <nav><!-- Navigation --></nav>
    @yield('content')
    <footer><!-- Footer --></footer>
</body>
</html>

{{-- resources/views/posts/index.blade.php --}}
@extends('layouts.app')

@section('title', 'All Posts')

@section('content')
    <h1>All Posts</h1>
    @foreach ($posts as $post)
        <article>
            <h2>{{ $post->title }}</h2>
        </article>
    @endforeach
@endsection

Key differences:

Your Approach (Chapter 18)Laravel's BladeAdvantage
view('home', $data, 'layout')@extends('layouts.app')Blade: Declared in the child view, more intuitive
Layout uses $content variableLayout uses @yield('content')Blade: Named sections, can have multiple yield points
One content areaMultiple @section/@yield pairsBlade: Can inject different content into multiple layout slots
Output buffering with PHPTemplate inheritanceBlade: Compiled to optimized PHP, cached automatically

Both approaches accomplish the same goal—eliminating duplicate HTML—but Blade's syntax is cleaner and more powerful. You can have separate sections for @yield('sidebar'), @yield('scripts'), etc.

Step 8: Understanding Eloquent Models (~2 min)

Goal: Configure the Post model to work properly with mass assignment.

Before adding data, let's update the Post model to explicitly allow mass assignment of the title and content fields.

Why This Matters

In Chapter 19, you wrote:

php
Post::create($title, $content);  // Passed as individual parameters

Laravel's Eloquent uses:

php
Post::create(['title' => $title, 'content' => $content]);  // Passed as array

This is called mass assignment. For security, Laravel blocks it by default unless you specify which fields are safe to mass-assign.

Update the Post Model

Open app/Models/Post.php and add the $fillable property:

php
# filename: app/Models/Post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = ['title', 'content'];
}

Why it works: The $fillable property is a whitelist of attributes that can be mass-assigned. This protects against malicious users trying to set fields like is_admin or user_id through form submissions.

Alternative approach: You can use $guarded instead to blacklist specific fields:

php
protected $guarded = ['id']; // Everything except 'id' can be mass-assigned

Choose $fillable (whitelist) for maximum security, especially when working with user input.

Step 9: Add Sample Data (~3 min)

Goal: Create sample posts to verify everything works end-to-end.

Let's use Tinker, Laravel's interactive PHP shell, to create some posts.

  1. Start Tinker

    bash
    php artisan tinker
  2. Create Sample Posts

    Run these commands in Tinker:

    php
    >>> use App\Models\Post;
    >>> Post::create(['title' => 'My First Laravel Post', 'content' => 'Laravel makes building web applications incredibly fast and enjoyable.']);
    >>> Post::create(['title' => 'Understanding Eloquent', 'content' => 'Eloquent is Laravel\'s ORM that makes database interactions elegant and intuitive.']);
    >>> Post::create(['title' => 'Blade Templating', 'content' => 'Blade provides a clean and powerful way to build views with minimal PHP code.']);
    >>> exit

    Expected output (for each create):

    php
    => App\Models\Post {#...
         title: "My First Laravel Post",
         content: "Laravel makes building web applications...",
         updated_at: "2024-01-15 10:30:00",
         created_at: "2024-01-15 10:30:00",
         id: 1,
       }
  3. Verify in Browser

    Refresh http://localhost:8000/posts. You should now see all three posts displayed with their titles, content, and formatted dates.

Why it works: Eloquent's create() method inserts a new row into the database and returns the model instance. The timestamps() we defined in the migration automatically populate created_at and updated_at.

Troubleshooting

Problem: Posts not showing up after creating them

Solution: Ensure you're viewing the correct URL (http://localhost:8000/posts, not just http://localhost:8000).

Understanding Laravel's Directory Structure

Coming from your simple-blog project in Chapter 19, Laravel's directory structure might look different but follows the same MVC pattern you built.

Directory Comparison

Your Project (Chapter 18-19)Laravel EquivalentPurpose
src/Controllers/app/Http/Controllers/Controller classes
src/Models/app/Models/Eloquent model classes
src/Views/resources/views/Blade templates
src/Routing/Router.phpapp/Http/ + routes/Routing infrastructure
src/Core/Database.phpconfig/database.php + Laravel's DBDatabase configuration
public/index.phppublic/index.phpFront controller (entry point)
data/database.sqlitedatabase/database.sqliteSQLite database file
vendor/vendor/Composer dependencies
composer.jsoncomposer.jsonProject dependencies

Key Laravel Directories

app/ - Your application code

  • app/Http/Controllers/ - Controller classes
  • app/Models/ - Eloquent models
  • app/Http/Middleware/ - HTTP middleware (authentication, CSRF, etc.)

resources/ - Non-PHP resources

  • resources/views/ - Blade templates
  • resources/css/ - Stylesheets
  • resources/js/ - JavaScript files

routes/ - Route definitions

  • routes/web.php - Web routes (what you used)
  • routes/api.php - API routes (for REST APIs)
  • routes/console.php - Artisan commands

database/ - Database files

  • database/migrations/ - Database version control
  • database/seeders/ - Sample data generators
  • database/factories/ - Model factories for testing

config/ - Configuration files

  • config/app.php - Application settings
  • config/database.php - Database connections
  • And many more...

public/ - Web server document root

  • public/index.php - Entry point
  • Static assets (images, compiled CSS/JS)

Why This Structure?

Laravel's structure is more elaborate because it supports many more features out of the box:

  • Multiple database connections
  • Queue workers for background jobs
  • Scheduled tasks (cron jobs)
  • API development
  • Testing infrastructure
  • Broadcasting (WebSockets)
  • And much more...

Your simpler structure was perfect for learning the fundamentals!

What Else Laravel Offers

You've only scratched the surface. Here's what Laravel provides beyond what you built:

1. Form Validation

In Chapter 19, you wrote:

php
$errors = [];
if (empty(trim($title))) {
    $errors[] = 'Title is required.';
}

Laravel's validation is much more powerful:

php
$validated = $request->validate([
    'title' => 'required|max:255',
    'content' => 'required|min:10',
    'email' => 'required|email|unique:users',
]);

It automatically handles error messages, redirection, and even old input preservation.

2. Relationships Between Models

In Chapter 19, you had a standalone Post model. Laravel makes relationships easy:

php
// A User has many Posts
class User extends Model {
    public function posts() {
        return $this->hasMany(Post::class);
    }
}

// A Post belongs to a User
class Post extends Model {
    public function author() {
        return $this->belongsTo(User::class, 'user_id');
    }
}

// Usage
$user->posts;           // Get all posts by this user
$post->author->name;    // Get the author's name

3. Authentication Scaffolding

You didn't build authentication, but Laravel includes it:

bash
# Install Laravel Breeze (authentication starter kit)
composer require laravel/breeze --dev
php artisan breeze:install blade

This gives you login, registration, password reset, email verification, and more—all out of the box.

4. Middleware (What You Learned About in Chapter 17)

In Chapter 17, you learned about middleware conceptually. Laravel implements it:

php
// Protect routes with authentication
Route::get('/admin', [AdminController::class, 'index'])
    ->middleware('auth');

// Create custom middleware
php artisan make:middleware CheckAge

// Apply to routes
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware(['auth', CheckAge::class]);

Middleware runs before your controller, perfect for authentication, logging, CORS, etc.

5. Request Objects & Dependency Injection

In Chapter 19, you accessed $_POST directly:

php
public function store(): void {
    $title = $_POST['title'] ?? '';
}

Laravel's router automatically injects a Request object:

php
public function store(Request $request): RedirectResponse {
    $validated = $request->validate([...]);
    Post::create($validated);
    return redirect('/posts')->with('success', 'Post created!');
}

This is dependency injection—Laravel automatically provides dependencies to your controller methods. You can type-hint any class (Request, Post, custom services) and Laravel will inject them.

6. Collections

Eloquent returns Collections, not plain arrays:

php
$posts = Post::all();

// Instead of foreach, use collection methods
$titles = $posts->pluck('title');
$publishedPosts = $posts->filter(fn($post) => $post->is_published);
$sorted = $posts->sortBy('created_at');

Collections have 80+ methods for manipulating data elegantly.

7. Artisan Commands

You've used php artisan serve and php artisan make:model. There are dozens more:

bash
php artisan make:controller PostController --resource    # CRUD methods
php artisan make:request StorePostRequest                # Form request validation
php artisan make:middleware CheckAge                      # Middleware
php artisan route:list                                   # Show all routes
php artisan tinker                                       # REPL
php artisan migrate:fresh --seed                         # Reset database with sample data

You can even create your own custom commands!

8. Testing Support

Laravel includes PHPUnit and a testing API:

php
public function test_can_create_post(): void
{
    $response = $this->post('/posts/store', [
        'title' => 'Test Post',
        'content' => 'Test content',
    ]);

    $response->assertRedirect('/posts');
    $this->assertDatabaseHas('posts', ['title' => 'Test Post']);
}

9. Queues for Background Jobs

Send emails, process images, or handle heavy tasks in the background:

php
// Dispatch a job to the queue
ProcessPodcast::dispatch($podcast);

// Job runs in the background
class ProcessPodcast implements ShouldQueue {
    public function handle() {
        // Heavy processing here
    }
}

10. Caching, Sessions, File Storage, and More

Laravel provides unified APIs for:

  • Caching (Redis, Memcached, file, database)
  • Session management (you used cookies in Chapter 15)
  • File storage (local, S3, FTP)
  • Email sending (SMTP, Mailgun, SendGrid)
  • Event broadcasting (WebSockets via Pusher or Laravel Echo)

All configured through simple config files, swappable without code changes.

The Laravel Ecosystem

Beyond the framework:

  • Laravel Forge - Server management and deployment
  • Laravel Vapor - Serverless deployment on AWS
  • Laravel Nova - Administration panel
  • Laravel Cashier - Subscription billing (Stripe, Paddle)
  • Laravel Socialite - OAuth authentication (Google, GitHub, etc.)
  • Laravel Telescope - Debugging and monitoring tool
  • Laravel Horizon - Queue monitoring dashboard

Exercises

Test your understanding by extending the application:

Exercise 1: Show a Single Post

Create a route /posts/{id} that displays a single post. You'll need to:

  • Add a new route in routes/web.php with a parameter
  • Create a show method in PostController that finds a post by ID
  • Create a resources/views/posts/show.blade.php view
  • Use Post::findOrFail($id) to retrieve the post (returns 404 if not found)

Update resources/views/posts/index.blade.php to add a "Back to Welcome" link at the top that goes to /. Then update the welcome page at resources/views/welcome.blade.php to add a "View Posts" link.

Exercise 3: Style Improvement

The current posts view is very basic. Use Tailwind CSS (which Laravel 11 includes via Vite) or write custom CSS to make the posts page more visually appealing. Consider:

  • A card-based layout
  • Hover effects on articles
  • Better typography
  • A responsive design for mobile devices

Exercise 4: Add Post Excerpts

Modify the posts index to show only the first 100 characters of content followed by "..." and a "Read more" link. Hint: Use PHP's substr() function or Blade's Str::limit() helper.

Wrap-up

Congratulations! You've just built your first Laravel application. In less than 30 minutes, you created a working blog post listing feature complete with:

  • Database migrations for version-controlled schema changes
  • An Eloquent model for clean, object-oriented database interactions
  • A controller to handle HTTP requests
  • A Blade view with automatic XSS protection
  • Sample data to demonstrate the complete workflow

What You Learned

This brief introduction showed you how Laravel's components map directly to the concepts you built from scratch:

What You BuiltLaravel EquivalentBenefit
Manual routing arrayRoute::get()Powerful route definitions with parameters, middleware, and grouping
PDO database connectionEloquent ORMObject-oriented queries, relationships, and automatic timestamps
Simple view renderingBlade templatingLayouts, components, and automatic XSS protection
Manual SQL queriesMigrationsVersion-controlled, shareable database schema

All the fundamental concepts you learned—OOP, MVC, PSR standards, and database interactions—are the foundation upon which Laravel is built. You now have the knowledge to understand how and why it works, which is the most valuable skill a developer can have.

Next Steps

To continue your Laravel journey:

  1. Add more features - Try implementing a "show single post" page, a create form, and edit/delete functionality
  2. Learn authentication - Laravel includes built-in authentication scaffolding with Laravel Breeze or Jetstream
  3. Explore relationships - Add authors, categories, or comments to your posts using Eloquent relationships
  4. Deploy your app - Try deploying to platforms like Laravel Forge, Vapor, or standard hosting

In the next chapter, we'll take a quick look at another major framework, Symfony, to see a different approach to solving the same problems.

Code Examples

Exercise solutions from this chapter are available in:

Note: These are Laravel-specific Blade template examples. The main code for this chapter is your Laravel application created with composer create-project laravel/laravel blog.

Further Reading