Laravel is the most widely used PHP framework for building web applications: it provides routing, controllers, a template engine (Blade), an ORM (Eloquent), validation, queues, testing… This course follows Laravel 13, which requires PHP 8.3 or higher (we use PHP 8.5) and Composer 2.
Creating a project
# With the official installer
composer global require laravel/installer
laravel new boutique # asks a few questions (starter kit, database, Pest or PHPUnit...)
# Or directly with Composer
composer create-project laravel/laravel boutique
cd boutique
php artisan serve # http://127.0.0.1:8000
# or: php artisan dev # server + queue + logs + Vite (also: composer run dev)
By default, a new project uses SQLite (database/database.sqlite, created and migrated at installation): no database server is needed to get started. composer create-project installs PHPUnit for tests; the installer lets you choose between Pest and PHPUnit.
The essential directory structure
| Folder / file | Role |
|---|---|
routes/web.php |
web page routes |
app/Http/Controllers |
controllers |
app/Models |
Eloquent models |
resources/views |
Blade views |
database/migrations |
schema evolution |
bootstrap/app.php |
application configuration (middleware, routes, exceptions) |
.env |
local configuration: database, APP_KEY, debug mode |
The .env file contains secrets: it is listed in .gitignore, and it is .env.example that is committed.
First route
// routes/web.php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome'); // displays resources/views/welcome.blade.php
});
Route::get('/bonjour', fn () => 'Hello Laravel!'); // a string becomes an HTML response
A route associates an HTTP verb (get, post, put, patch, delete) and a URI with an action.
Parameters and constraints
Route::get('/articles/{id}', function (string $id) {
return "Article no. $id";
})->whereNumber('id'); // /articles/abc will return 404
Route::get('/auteurs/{nom?}', fn (?string $nom = null) => $nom ?? 'All authors'); // optional parameter
Parameters are injected into the function in the order in which they appear in the URI.
Named routes
Route::get('/articles/{id}', [ArticleController::class, 'show'])->name('articles.show');
// Elsewhere (controller, view):
$url = route('articles.show', ['id' => 42]); // http://127.0.0.1:8000/articles/42
return redirect()->route('articles.show', ['id' => 42]);
Naming routes lets you change a URI without breaking all the application’s links.
Artisan, your command-line assistant
php artisan route:list # all routes, their names and actions
php artisan make:controller ArticleController
php artisan tinker # interactive console
API routes (routes/api.php) are no longer present by default since Laravel 11: you add them with php artisan install:api, which we will see in the advanced course.
In the runnable exercises, you will re-implement the core of a router in plain PHP, to understand what Laravel does for you; the tasks will then have you practice in a real project.
Exercises
Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.
Match a route
Re-implement the core of a router. Write
matchRoute(string $pattern, string $uri): ?array:$patterncontains parameters in curly braces, e.g./articles/{id};- if the URI matches, return a
name => valuearray of the parameters (empty array if there are none); - otherwise return
null.
A parameter matches a non-empty segment without
/. Ignore leading and trailing/.function matchRoute(string $pattern, string $uri): ?array { }Generate a URL from a route name
Write
urlPour(array $routes, string $nom, array $params = []): stringthat reproduces theroute()function:$routesassociates a name with a URI, e.g.['articles.show' => '/articles/{article}'];- replace each
{param}with the provided value (encoded withrawurlencode); - throw an
InvalidArgumentExceptionif the name is unknown or if a parameter is missing.
function urlPour(array $routes, string $nom, array $params = []): string { }Create a Laravel project and its first routes
In your environment, create a Laravel 13 project named
boutique, then add toroutes/web.php:- a
GET /bonjourroute that returns the textBonjour Laravel !; - a named route
articles.showon/articles/{id}constrained to numbers, which returnsArticle n° {id}.
Start the server and test the URLs in the browser or with
curl.- `composer create-project laravel/laravel boutique` (or `laravel new boutique`) finished without error
- `curl http://127.0.0.1:8000/bonjour` displays Bonjour Laravel !
- `/articles/7` displays Article n° 7 and `/articles/abc` returns a 404
- `php artisan route:list` displays the named route articles.show
- a
Route order
The routes
GET /articles/{id}thenGET /articles/createare declared in that order, without constraints. What happens for/articles/create?- The /articles/{id} route is used with id = 'create'
- Laravel always picks the most specific route
- A 500 error is thrown
End-of-lesson quiz
What minimum PHP version does Laravel 13 require?
- PHP 8.1
- PHP 8.3
- PHP 8.5
What is the point of ->name(‘articles.show’)?
- Speeding up the route
- Generating URLs with route('articles.show', ...) without hard-coding them
- Making the route private
Which command displays all the application routes?
- php artisan route:list
- php artisan routes
- composer routes
The rest of the course
- Controllers, Requests and Responses20 min
- Blade Views: Templates, Layouts and Components20 min
- Migrations and Eloquent Models20 min
- Validation and Forms20 min