Par Valentin Brosseau / @c4software
Ensemble d'outils et de composants logiciels à la base d'un logiciel ou d'une application.
Le choix du framework dépend du projet en question… Et parfois pas de framework du tout…
La communauté s’est rapidement formée autour du projet. C’est bon signe !
Taylor Otwell était un utilisateur de CodeIgniter. Mais il le trouvait trop compliqué, trop lourd, et chaque modification était trop complexe…
Il a donc voulu quelque chose de plus souple, simple et simple à apprendre
Le pitch de lancement, c’est « Un framework connu pour sa simplicité »
Requiert PHP 8.4 : à votre avis pourquoi ?


Technique de programmation informatique qui crée l'illusion d'une base de données orientée objet à partir d'une base de données relationnelle en définissant des correspondances entre cette base de données et les objets.

Avant de commencer, il est important de comprendre que Laravel est un framework PHP. Il utilise donc les fonctionnalités de PHP.
$_GET['id'] <=> $request->query('id')$_POST['id'] <=> $request->input('id')$_FILES['photo'] <=> $request->file('photo')$_SESSION['user'] <=> $request->session()->get('user')$_SESSION = [] <=> $request->session()->flush()$_SESSION <=> $request->session()->all()isset($_SESSION['user']) <=> $request->session()->has('user')Et la base de données ?
// Eloquent
$users = User::where('name', 'John')->get();
// PDO
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = :name');
$stmt->execute(['name' => 'John']);// Eloquent
$user = new User();
$user->name = 'John';
$user->save();
// Eloquent (alternative)
User::create(['name' => 'John']);
// PDO
$stmt = $pdo->prepare('INSERT INTO users (name) VALUES (:name)');
$stmt->execute(['name' => 'John']);$ composer create-project laravel/laravel projectName
laravel new projectName
Crafting application...
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 68 installs, 0 updates, 0 removals
- Installing doctrine/inflector (v1.2.0): Loading from cache
- Installing doctrine/lexer (v1.0.1): Loading from cache
- Installing erusev/parsedown (1.6.3): Loading from cache
[…]
Application ready! Build something amazing.$ php artisan
Laravel Framework X.Y.Z
Usage:
command [options] [arguments]
Options:
-h, --help Display this help message
[…]$ php artisan serve$ composer installRoute::get('/', function () {
return "Bonjour Monde";
});Route::get('/demo/{id}', [DemoController::class, "voir"]);Consulter la page /demo/3 chargera automatiquement le bon contrôleur et la bonne méthode en passant le paramètre 3
Route::post('/demo/ajout', [DemoController::class, 'ajout']);(get, post, put, patch, delete, options)
Route::put('/demo/{id}', [DemoController::class, "modifier"]);
Route::delete('/demo/{id}', [DemoController::class, "supprimer"]);
Route::get('/demo/{id}', [DemoController::class, "voir"])->middleware('auth');Auth est un middleware fourni par Laravel Breeze. Il permet de vérifier que l’utilisateur est connecté.
Un middleware est un « filtre » qui va être exécuté avant l’action demandée. Il sera exécuté avant le contrôleur. Il permettra de vérifier des choses avant d’exécuter le contrôleur.
Ex: L'authentification, token, etc…
Vous pouvez également créer vos propres middlewares.
php artisan make:middleware IsEquipeConnectedExemple dans l'AP 3 :
class IsEquipeConnected
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
// Si l'équipe n'est pas connectée, on la redirige vers la page de connexion
if (!SessionHelpers::isConnected()) {
return redirect("/login");
}
return $next($request);
}
}Route::get('/me', [EquipeController::class, "me"])->middleware(IsEquipeConnected::class);
Gestion de la logique « métier » pour traiter chaque demande
$ php artisan make:controller DemoControllernamespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function voir(Request $request, $id)
{
return "Identifiant => ".$id;
}
} // […]
public function voir(Request $request, $id)
// […] // […]
public function voir(Request $request, $id)
{
$nom = $request->input('nom');
$nom = $request->input('nom', 'John'); // Valeur par défaut
$all = $request->all(); // Récupérer toutes les données
}// Retourne une vue
return view('view.name', ['name' => 'John']);
// Retourne une vue avec un message flash (session)
return redirect('/home')->with('status', 'Task was successful!');
// Retourne une redirection vers une route nommée
return redirect()->route('profile');
// Retourne une redirection vers une route nommée avec des paramètres
return redirect()->route('profile', ['id' => 1]);
// Retourne une redirection vers une route nommée avec des paramètres et un message flash
return redirect()->route('profile', ['id' => 1])->with('status', 'Task was successful!');
// Retourner une réponse JSON
$user = App\Models\User::find(1);
return response()->json($user);
// Retourner une réponse JSON avec un code de statut
$allUsers = App\Models\User::all();
return response()->json($allUsers);// routes/web.php Route::get('/users', [UserController::class, 'liste']); Route::get('/users/{id}', [UserController::class, 'voir']); Route::get('/bienvenue', [UserController::class, 'bienvenue']);
// routes/web.php Route::get('/users', [UserController::class, 'liste']); Route::get('/users/{id}', [UserController::class, 'voir']); Route::get('/bienvenue', [UserController::class, 'bienvenue']);
// routes/web.php Route::get('/users', [UserController::class, 'liste']); Route::get('/users/{id}', [UserController::class, 'voir']); Route::get('/bienvenue', [UserController::class, 'bienvenue']);
public function liste() { return response()->json(User::all()); } public function voir(Request $request, $id) { return response()->json(User::find($id)); } public function bienvenue() { return redirect('/') ->with('message', 'Bienvenue'); }
public function liste() { return response()->json(User::all()); } public function voir(Request $request, $id) { return response()->json(User::find($id)); } public function bienvenue() { return redirect('/') ->with('message', 'Bienvenue'); }
public function liste() { return response()->json(User::all()); } public function voir(Request $request, $id) { return response()->json(User::find($id)); } public function bienvenue() { return redirect('/') ->with('message', 'Bienvenue'); }
1 de l'URL ?Afficher un template
Route::get('/', function () {
return view('accueil');
});
<!-- Sauvegardé dans resources/views/layouts/app.blade.php -->
<html>
<head>
<title>Site Exemple - @yield('titre')</title>
</head>
<body>
@section('sidebar') « Section » barre latérale principale @show
<div class="container">@yield('content')</div>
</body>
</html><!-- Sauvegardé dans resources/views/child.blade.php -->
@extends('layouts.app')
@section('titre', 'Page enfant')
@section('sidebar')
@parent // <-- Hérite des données du parent
Données de l’enfant
@endsection
@section('content')
<p>Contenu de la page enfant.</p>
@endsectionBlade intègre également un système de composant permettant de découper son travail.
<x-votre-composant nom="Valentin"></x-votre-composant>
@auth <div>Bienvenue {{ $user->name }}</div> @endauth <table> @forelse ($diplomes as $diplome) <tr> <td>{{ $diplome->nom }}</td> <td>{{ $diplome->date }}</td> </tr> @empty <tr><td>Aucun diplôme</td></tr> @endforelse </table>
@auth <div>Bienvenue {{ $user->name }}</div> @endauth <table> @forelse ($diplomes as $diplome) <tr> <td>{{ $diplome->nom }}</td> <td>{{ $diplome->date }}</td> </tr> @empty <tr><td>Aucun diplôme</td></tr> @endforelse </table>
@auth <div>Bienvenue {{ $user->name }}</div> @endauth <table> @forelse ($diplomes as $diplome) <tr> <td>{{ $diplome->nom }}</td> <td>{{ $diplome->date }}</td> </tr> @empty <tr><td>Aucun diplôme</td></tr> @endforelse </table>
$user et $diplomes ?@auth
// L'utilisateur est authentifié...
@endauth
@guest
// L'utilisateur n'est pas authentifié...
@endguestZone dans le code où il sera possible « d'injecter » ultérieurement du code.
Exemple, zone dans le header pour injecter des scripts JS utiles que dans certaines pages.
<head>
[…] @stack('scripts') […]
</head>@push('scripts')
<script src="/demo.js"></script>
@endpush@csrf<form method="POST" action="/compte/supprimer"> @csrf <button>Supprimer mon compte</button> </form>
<form method="POST" action="/compte/supprimer"> @csrf <button>Supprimer mon compte</button> </form>
<form method="POST" action="/compte/supprimer"> <input type="hidden" name="_token" value="Xk9fQ2mP7vLr..."> <button>Supprimer mon compte</button> </form>
<form method="POST" action="/compte/supprimer"> <input type="hidden" name="_token" value="Xk9fQ2mP7vLr..."> <button>Supprimer mon compte</button> </form>
@csrf une fois la page générée ?La requête est refusée : 419 Page Expired.
La vérification est automatique, aucun code à écrire.
La représentation objet de la base de données
$ php artisan make:model TodoListnamespace App\Models;
use Illuminate\Database\Eloquent\Model;
class TodoList extends Model
{
protected $table = "todoList";
protected $fillable = array('texte', 'termine');
}$ php artisan make:migration create_todoList_table --create=todoListCréation d'un script PHP qui représente la définition de la base de données.
// database/migrations/####_##_##_######_create_todoList_table.php
Schema::create('todoList', function(Blueprint $table)
{
$table->increments('id');
$table->string('texte');
$table->boolean('termine');
$table->timestamps();
});$ php artisan migrateuse App\Models\TodoList;
$todos = App\Models\TodoList::all();
// Ou pour le Todo avec l’identifiant « 42 »
$todo = App\Models\TodoList::find(42); $todos = App\Models\TodoList::where('termine', 1)
->orderBy('id', 'desc')
->take(10)
->get();$users = DB::table('users')->paginate(15);
// Ou avec un where
$users = User::where('votes', '>', 100)->paginate(15);Quel est l'avantage à votre avis de faire ce genre de requêtes ?
// Créer une Todo
App\Models\TodoList::create(array(
'texte' => 'Super Cool',
'termine' => false
));
// La sauvegarde est automatique.// Rechercher celui avec l’id 1
$todo = App\Models\TodoList::find(1);
// Le passer à terminer
$todo->termine = true;
// Le sauvegarder en base de données
$todo->save();// Rechercher celui avec l’id 1
$todo = App\Models\TodoList::find(1);
// Le supprimer
$todo->delete();
// Le supprimer directement
App\Models\TodoList::destroy(1);
// En supprimer plusieurs directement
App\Models\TodoList::destroy(1,2,3);
// Supprimer avec une condition
App\Models\TodoList::where('termine', '=', 1)->delete();Quel type de jointure connaissez-vous ?
class Todo extends Model
{
public function categorie()
{
return $this->hasOne(Categorie::class);
}
}
Éloquent supposera que le modèle Categorie contiendra une colonne todo_id.
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
}
Éloquent supposera que la colonne de clé étrangère sur le modèle Comment est post_id.
class Comment extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
}Post dont l'identifiant correspond à la colonne post_id du modèle Comment.Post sur la table des commentaires est post_id.
class User extends Model
{
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
class Role extends Model
{
public function users()
{
return $this->belongsToMany(User::class);
}
}
Via le modèle, il est possible de récupérer les données de l’autre modèle.
// Récupérer les rôles d’un utilisateur
$roles = App\Models\User::find(1)->roles;
// Récupérer les utilisateurs d’un rôle
$users = App\Models\Role::find(1)->users;Ou automatiquement via la méthode with
$users = App\Models\User::with('roles')->get();La différence ?
->roles : la requête est exécutée au moment où on accède à la relation (lazy loading).with('roles') : les rôles sont chargés en même temps que les utilisateurs, lors du get (eager loading).$user = User::find(1); // Rôles actuels : 1 (admin), 2 (éditeur)
$user->roles()->attach([2, 3]); // 3 = modérateur
// ou
$user->roles()->sync([2, 3]);Quels rôles aura l'utilisateur dans chaque cas ?
attach ou sync ?Rôles actuels : 1 et 2. On passe [2, 3].
attach |
sync |
|
|---|---|---|
| Rôles après | 1, 2, 2, 3 | 2, 3 |
| Rôle 1 (absent) | Conservé | Supprimé |
| Usage | Ajouter | Cases à cocher |
Le sync
$user->roles()->sync([1, 2, 3]);Le attach
// Ajouter un commentaire à un post
$comment = new App\Models\Comment(['message' => 'A new comment.']);
$post = App\Models\Post::find(1);
$post->comments()->save($comment);
// Attacher un rôle à un utilisateur
$user = App\Models\User::find(1);
$user->roles()->attach($roleId);
// Attacher des rôles à un utilisateur nouvellement créé
$user = App\Models\User::create($attributes);
$user->roles()->attach([1, 2, 3]);
class Article extends Model { public function comments() { return $this->hasMany(Comment::class); } public function categories() { return $this->belongsToMany(Category::class); } public function user() { return $this->belongsTo(User::class); } } class User extends Model { public function articles() { return $this->hasMany(Article::class); } } class Comment extends Model { public function article() { return $this->belongsTo(Article::class); } public function user() { return $this->belongsTo(User::class); } } class Category extends Model { public function articles() { return $this->belongsToMany(Article::class); } } class ArticleCategory extends Model {} class ArticleComment extends Model {}
class Article extends Model { public function comments() { return $this->hasMany(Comment::class); } public function categories() { return $this->belongsToMany(Category::class); } public function user() { return $this->belongsTo(User::class); } } class User extends Model { public function articles() { return $this->hasMany(Article::class); } } class Comment extends Model { public function article() { return $this->belongsTo(Article::class); } public function user() { return $this->belongsTo(User::class); } } class Category extends Model { public function articles() { return $this->belongsToMany(Article::class); } } class ArticleCategory extends Model {} class ArticleComment extends Model {}
class Article extends Model { public function comments() { return $this->hasMany(Comment::class); } public function categories() { return $this->belongsToMany(Category::class); } public function user() { return $this->belongsTo(User::class); } } class User extends Model { public function articles() { return $this->hasMany(Article::class); } } class Comment extends Model { public function article() { return $this->belongsTo(Article::class); } public function user() { return $this->belongsTo(User::class); } } class Category extends Model { public function articles() { return $this->belongsToMany(Article::class); } } class ArticleCategory extends Model {} class ArticleComment extends Model {}
class Article extends Model { public function comments() { return $this->hasMany(Comment::class); } public function categories() { return $this->belongsToMany(Category::class); } public function user() { return $this->belongsTo(User::class); } } class User extends Model { public function articles() { return $this->hasMany(Article::class); } } class Comment extends Model { public function article() { return $this->belongsTo(Article::class); } public function user() { return $this->belongsTo(User::class); } } class Category extends Model { public function articles() { return $this->belongsToMany(Article::class); } } class ArticleCategory extends Model {} class ArticleComment extends Model {}
class Article extends Model { public function comments() { return $this->hasMany(Comment::class); } public function categories() { return $this->belongsToMany(Category::class); } public function user() { return $this->belongsTo(User::class); } } class User extends Model { public function articles() { return $this->hasMany(Article::class); } } class Comment extends Model { public function article() { return $this->belongsTo(Article::class); } public function user() { return $this->belongsTo(User::class); } } class Category extends Model { public function articles() { return $this->belongsToMany(Article::class); } } class ArticleCategory extends Model {} class ArticleComment extends Model {}
$users = User::all(); $articles = User::find(4)->articles; $article = Article::find(1); $article->title = 'Nouveau titre'; $article->save(); Comment::where('user_id', 10)->delete(); $article->comments()->save( new Comment(['content' => 'Super article']) ); $article->categories()->attach([1, 2, 3]);
$users = User::all(); $articles = User::find(4)->articles; $article = Article::find(1); $article->title = 'Nouveau titre'; $article->save(); Comment::where('user_id', 10)->delete(); $article->comments()->save( new Comment(['content' => 'Super article']) ); $article->categories()->attach([1, 2, 3]);
$users = User::all(); $articles = User::find(4)->articles; $article = Article::find(1); $article->title = 'Nouveau titre'; $article->save(); Comment::where('user_id', 10)->delete(); $article->comments()->save( new Comment(['content' => 'Super article']) ); $article->categories()->attach([1, 2, 3]);
$users = User::all(); $articles = User::find(4)->articles; $article = Article::find(1); $article->title = 'Nouveau titre'; $article->save(); Comment::where('user_id', 10)->delete(); $article->comments()->save( new Comment(['content' => 'Super article']) ); $article->categories()->attach([1, 2, 3]);
$users et $articles ?attach et pas sync ?Créer les modèles peut être fastidieux, il existe un outil pour automatiser la création des modèles depuis la base de données.
Une console interactive (REPL) pour interagir avec votre application.
$ php artisan tinkerPermet de :
Laravel Breeze installe en quelques commandes la connexion, l'inscription et la réinitialisation du mot de passe.
Effectivement Laravel est un « gros » Framework. Dans certains cas on veut plus simple.
Dans quel cas par exemple ?
(Il doit y en avoir beaucoup)