Pourquoi Laravel avec PostgreSQL : guide pratique ?
Dans un monde où les applications web deviennent de plus en plus complexes, la gestion des données est cruciale pour l'efficacité et la performance de l'application. Laravel, bien connu pour sa simplicité et son efficacité, offre une intégration parfaite avec PostgreSQL, qui est un système de gestion de base de données relationnelle performant, extensible et open source. En utilisant Laravel avec PostgreSQL, vous pouvez tirer parti des avantages de ces deux technologies ensemble.
Un cas d'usage concret serait la création d'une application de gestion de tâches, où les fonctionnalités comme l'ajout, la modification et le suivi des tâches nécessitent une gestion efficace des données. Avec Laravel et PostgreSQL, vous pouvez créer une application robuste et performante pour gérer ces tâches.
Prerequis
- Connaissance de base de PHP
- Familiarité avec les concepts d'architecture MVC (Model-View-Controller)
- Installation de Composer (gestionnaire de dépendances PHP)
- Installation de Node.js (pour les outils front-end)
- Installation de PostgreSQL
- Installation de Laravel (via Composer)
Concepts fondamentaux
1. Migrations
Les migrations sont un moyen de définir et d'appliquer des modifications à votre base de données. Elles vous permettent de garder une trace historique de vos modifications et de les appliquer facilement sur n'importe quelle instance de la base de données.
## Création d'une migration pour créer une table 'tasks'
php artisan make:migration create_tasks_table --create=tasks
## Migration créée dans database/migrations/xxxx_xx_xx_xxxxxx_create_tasks_table.php
return new class extends Migration
{
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description')->nullable();
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('tasks');
}
};
2. Eloquent ORM
Eloquent est un ORM (Object-Relational Mapping) intégré à Laravel qui vous permet de manipuler les données de la base de données en utilisant des objets PHP.
## Création d'un modèle 'Task'
php artisan make:model Task
## Model créé dans app/Models/Task.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
use HasFactory;
protected $fillable = ['title', 'description', 'completed'];
}
## Utilisation du modèle pour créer une nouvelle tâche
use App\Models\Task;
$task = new Task();
$task->title = 'Faire les courses';
$task->save();
3. Factories
Les factories sont un moyen de générer des données de test et de développement. Elles vous permettent de créer des objets avec des valeurs aléatoires ou spécifiques.
## Création d'une factory pour le modèle 'Task'
php artisan make:factory TaskFactory --model=Task
## Factory créée dans database/factories/TaskFactory.php
namespace Database\Factories;
use App\Models\Task;
use Illuminate\Database\Eloquent\Factories\Factory;
class TaskFactory extends Factory
{
protected $model = Task::class;
public function definition()
{
return [
'title' => fake()->sentence(),
'description' => fake()->paragraph(),
'completed' => fake()->boolean,
];
}
}
## Utilisation de la factory pour créer une nouvelle tâche
use App\Models\Task;
use Database\Factories\TaskFactory;
$task = Task::factory()->create();
4. Relations
Les relations Eloquent vous permettent de définir des relations entre les modèles, comme les associations un-à-un, un-à-plusieurs et plusieurs-à-plusieurs.
## Ajout d'une relation 'user' dans le modèle 'Task'
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Task extends Model
{
use HasFactory;
protected $fillable = ['title', 'description', 'completed'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
## Ajout d'une relation 'tasks' dans le modèle 'User'
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Authenticatable
{
use HasFactory;
protected $fillable = ['name', 'email', 'password'];
public function tasks(): HasMany
{
return $this->hasMany(Task::class);
}
}
## Utilisation des relations dans le code
use App\Models\Task;
use App\Models\User;
$user = User::find(1);
$tasks = $user->tasks;
Mise en pratique : projet fil rouge
Étape 1 : Création du projet Laravel
composer create-project --prefer-dist laravel/laravel task-manager
cd task-manager
npm install
php artisan migrate
Étape 2 : Création des modèles et migrations
php artisan make:model Task -m
php artisan make:model User -m
Migration pour tasks :
## database/migrations/xxxx_xx_xx_xxxxxx_create_tasks_table.php
return new class extends Migration
{
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('description')->nullable();
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('tasks');
}
};
Migration pour users :
## database/migrations/xxxx_xx_xx_xxxxxx_create_users_table.php
return new class extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
};
Étape 3 : Création des controllers
php artisan make:controller TaskController --resource
php artisan make:controller UserController --resource
Controller TaskController :
## app/Http/Controllers/TaskController.php
namespace App\Http\Controllers;
use App\Models\Task;
use Illuminate\Http\Request;
class TaskController extends Controller
{
public function index()
{
$tasks = Task::all();
return view('tasks.index', compact('tasks'));
}
public function create()
{
return view('tasks.create');
}
public function store(Request $request)
{
$task = new Task($request->all());
$task->save();
return redirect()->route('tasks.index');
}
public function show(Task $task)
{
return view('tasks.show', compact('task'));
}
public function edit(Task $task)
{
return view('tasks.edit', compact('task'));
}
public function update(Request $request, Task $task)
{
$task->update($request->all());
return redirect()->route('tasks.index');
}
public function destroy(Task $task)
{
$task->delete();
return redirect()->route('tasks.index');
}
}
Controller UserController :
## app/Http/Controllers/UserController.php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function index()
{
$users = User::all();
return view('users.index', compact('users'));
}
public function create()
{
return view('users.create');
}
public function store(Request $request)
{
$user = new User($request->all());
$user->save();
return redirect()->route('users.index');
}
public function show(User $user)
{
return view('users.show', compact('user'));
}
public function edit(User $user)
{
return view('users.edit', compact('user'));
}
public function update(Request $request, User $user)
{
$user->update($request->all());
return redirect()->route('users.index');
}
public function destroy(User $user)
{
$user->delete();
return redirect()->route('users.index');
}
}
Étape 4 : Création des vues
Vue resources/views/tasks/index.blade.php :
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Tâches</h1>
<a href="route('tasks.create')" class="btn btn-primary mb-3">Nouvelle tâche</a>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Titre</th>
<th>Description</th>
<th>Complétée</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@foreach($tasks as $task)
<tr>
<td>$task->id</td>
<td>$task->title</td>
<td>$task->description</td>
<td>$task->completed ? 'Oui' : 'Non'</td>
<td>
<a href="route('tasks.edit', $task)" class="btn btn-primary">Éditer</a>
<form action="route('tasks.destroy', $task)" method="POST" style="display: inline-block;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger" onclick="return confirm('Êtes-vous sûr?')">Supprimer</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endsection
Vue resources/views/tasks/create.blade.php :
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Nouvelle tâche</h1>
<form action="route('tasks.store')" method="POST" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="title" class="form-label">Titre</label>
<input type="text" name="title" id="title" class="form-control" required>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea name="description" id="description" class="form-control"></textarea>
</div>
<div class="mb-3">
<label for="completed" class="form-label">Complétée</label>
<input type="checkbox" name="completed" id="completed" value="1">
</div>
<button type="submit" class="btn btn-primary">Enregistrer</button>
</form>
</div>
@endsection
Vue resources/views/tasks/edit.blade.php :
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Éditer tâche</h1>
<form action="route('tasks.update', $task)" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="mb-3">
<label for="title" class="form-label">Titre</label>
<input type="text" name="title" id="title" class="form-control" value="$task->title" required>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea name="description" id="description" class="form-control">$task->description</textarea>
</div>
<div class="mb-3">
<label for="completed" class="form-label">Complétée</label>
<input type="checkbox" name="completed" id="completed" value="1" $task->completed ? 'checked' : ''>
</div>
<button type="submit" class="btn btn-primary">Enregistrer</button>
</form>
</div>
@endsection
Vue resources/views/users/index.blade.php :
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Utilisateurs</h1>
<a href="route('users.create')" class="btn btn-primary mb-3">Nouvel utilisateur</a>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Nom</th>
<th>Email</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@foreach($users as $user)
<tr>
<td>$user->id</td>
<td>$user->name</td>
<td>$user->email</td>
<td>
<a href="route('users.edit', $user)" class="btn btn-primary">Éditer</a>
<form action="route('users.destroy', $user)" method="POST" style="display: inline-block;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger" onclick="return confirm('Êtes-vous sûr?')">Supprimer</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endsection
Vue resources/views/users/create.blade.php :
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Nouvel utilisateur</h1>
<form action="route('users.store')" method="POST" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="name" class="form-label">Nom</label>
<input type="text" name="name" id="name" class="form-control" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" name="email" id="email" class="form-control" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Mot de passe</label>
<input type="password" name="password" id="password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Enregistrer</button>
</form>
</div>
@endsection
Vue resources/views/users/edit.blade.php :
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Éditer utilisateur</h1>
<form action="route('users.update', $user)" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="mb-3">
<label for="name" class="form-label">Nom</label>
<input type="text" name="name" id="name" class="form-control" value="$user->name" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" name="email" id="email" class="form-control" value="$user->email" required>
</div>
<button type="submit" class="btn btn-primary">Enregistrer</button>
</form>
</div>
@endsection
Étape 5 : Configuration des routes
Fichier routes/web.php :
use App\Http\Controllers\TaskController;
use App\Http\Controllers\UserController;
Route::resource('tasks', TaskController::class);
Route::resource('users', UserController::class);
Étape 6 : Création des migrations et du modèle
Migration pour la table tasks :
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTasksTable extends Migration
{
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description')->nullable();
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('tasks');
}
}
Migration pour la table users :
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
Modèle Task :
use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
protected $fillable = ['title', 'description', 'completed'];
}
Modèle User :
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
}
Étape 7 : Migration des bases de données
php artisan migrate
Étape 8 : Création d'un utilisateur administrateur (facultatif)
php artisan tinker
$User = new App\Models\User;
$User->name = 'admin';
$User->email = 'admin@example.com';
$User->password = bcrypt('password');
$User->save();
Étape 9 : Configuration de l'authentification (facultatif)
Fichier config/auth.php :
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
];
Fichier routes/web.php :
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Auth\LoginController;
use App\Http\Controllers\Auth\LogoutController;
Route::get('login', [LoginController::class, 'showLoginForm'])->name('login');
Route::post('login', [LoginController::class, 'login']);
Route::post('logout', [LogoutController::class, 'logout'])->name('logout');
Route::middleware(['auth'])->group(function () {
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
});
Fichier app/Http/Controllers/Auth/LoginController.php :
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
Fichier app/Http/Controllers/Auth/LogoutController.php :
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\LogsOutUsers;
class LogoutController extends Controller
{
use LogsOutUsers;
protected $guard = 'web';
protected function redirectTo()
{
return '/login';
}
}
Étape 10 : Création de la vue de base
Vue resources/views/layouts/app.blade.php :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Application</title>
<link href="asset('css/app.css')" rel="stylesheet">
</head>
<body>
@yield('content')
</body>
</html>
Étape 11 : Compilation des assets (facultatif)
npm install
npm run dev
Conclusion
Vous avez maintenant une application Laravel avec PostgreSQL, gérant les tâches et les utilisateurs. Vous pouvez personnaliser davantage l'application en ajoutant d'autres fonctionnalités et en améliorant la sécurité. N'oubliez pas de tester soigneusement toutes les fonctionnalités pour vous assurer qu'elles fonctionnent correctement.
N'hésitez pas à poser des questions ou à partager vos commentaires si vous avez besoin d'aide supplémentaire!