Laravel

Un framework qui rend heureux

Voir cette catégorie
Vers le bas
Albums – Les données
Lundi 1 avril 2024 18:59

Dans ce chapitre, nous nous concentrerons sur la gestion des données et la construction du schéma de base de données pour notre application de galerie photos. Laravel est équipé d'un système de migrations robuste et flexible couplé à un constructeur de schéma tout aussi puissant. De plus, nous disposons également d'un système de population de données (seeder) qui facilite grandement la création et le remplissage de tables de données. Nous compléterons cette étape en créant les modèles associés avec leurs relations.

Nous commencerons par travailler avec des données simples : les utilisateurs, les catégories et les images. Nous compléterons notre application avec des fonctionnalités plus complexes dans les étapes suivantes.

Les utilisateurs

Dans l’installation de base, on a déjà une migration pour les utilisateurs :

Avec en particulier ce code :
public function up(): void
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email')->unique();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });

    ...

Comme on doit distinguer les utilisateurs de base, qui peuvent juste ajouter et supprimer leurs photos, et les administrateurs qui ont tous les droits, il nous faut ajouter quelque chose.

Si on avait plus de distinctions à faire, on ferait appel à l’un des nombreux packages qui existent comme bouncer, laratrust, ou laravel-permission. Mais dans notre cas, ça serait vraiment excessif et on va se contenter d’ajouter une colonne pour préciser si quelq'un est administrateur :

$table->boolean('admin')->default(false);
 

On a donc les deux rôles : user et admin et par défaut, c'est user qui est affecté.

On va aussi éviter d’avoir des noms identiques :

$table->string('name')->unique();

Pour nos besoins futurs, on va encore compléter ces informations. Pour la galerie de photos, on fera la distinction entre ce qui est accessible à tout le monde et ce qui est réservé aux adultes. D'autre part on va permettre à chaque utilisateur inscrit de préciser la pagination. Alors on ajoute ça maintenant :

$table->boolean('adult')->default(false);
$table->tinyInteger('pagination')->default(8);

Pour notre application, on va aussi créer 3 utilisateurs par défaut. Quand on regarde dans le fichier database/seeds/DatabaseSeeder.php on trouve ce code :

public function run(): void
{
    // User::factory(10)->create();

    User::factory()->create([
        'name' => 'Test User',
        'email' => 'test@example.com',
    ]);
}

On a par défaut la création d'un utilisateur et en version commentée l'utilisation d'un factory pour en créer 10.  On va supprimer tout ça et prévoir une classe spécifique pour les utilisateurs :

php artisan make:seeder UserSeeder
Avec ce code :
...
use App\Models\User;

class UserSeeder extends Seeder
{
    public function run(): void
    {

        $users = ['durand', 'dupont', 'martin'];

        foreach ($users as $user) {
            User::create([
                'name'     => ucfirst($user),
                'email'    => $user . '@chezlui.fr',
                'admin'    => $user === 'durand',
                'password' => bcrypt('password'),
            ]);
        }
    }
}

Donc un administrateur et deux utilisateurs de base.

Les catégories

On va avoir la possibilité de ranger les photos par catégories. Voyons ce dont nous aurons besoin pour la tables des catégories :
  • un nom
  • un slug

Le slug est une version transformée du nom pour être intégrée dans une url. Si par exemple le nom est Les Maisons il est évident qu’on ne peut pas intégrer ça directement dans une url. On va donc transformer le nom en les-maisons par exemple et là ça ira.

Pour être efficace, on va créer le modèle en même temps que la migration :
php artisan make:model Category --migration

Dans le code de la migration, changez ainsi la fonction up :

Schema::create('categories', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
    $table->string('slug')->unique();
    $table->timestamps();
});

On demande que les deux colonnes name et slug comportent des valeurs uniques, ce qui est logique.

Pour le modèle, on va ajouter les deux colonnes pour l'assignement de masse et aussi supprimer ce qui concerne les factories parce qu'on ne va pas s'en servir :

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    protected $fillable = [
        'name', 'slug',
    ];
}
On va aussi créer un seeder pour les catégories :
php artisan make:seeder CategorySeeder
Avec ce code :
...
use Illuminate\Support\Str;

class CategorySeeder extends Seeder
{
    public function run(): void
    {
        $cats = ['Paysages', 'Maisons', 'Personnages', 'Animaux', 'Végétation'];

        foreach ($cats as $cat) {
            Category::create([
                'name' => $cat,
                'slug' => Str::slug($cat),
            ]);
        }
    }
}

Les images

Il ne nous reste plus qu’à nous occuper des images, là aussi, nous avons besoin du modèle et de la migration :

php artisan make:model Image --migration
Pour les images on va avoir besoin de :
  • un nom (pas le nom de la photo, mais celui du fichier !)
  • une description optionnelle
  • un champ booléen pour savoir si le statut est « adulte »
  • une clé étrangère pour les utilisateurs
  • une clé étrangère pour les catégories
Ce qui donne cette migration :
Schema::create('images', function (Blueprint $table) {
    $table->id();
    $table->foreignId('category_id')->constrained()->onDelete('cascade');
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    $table->string('name');
    $table->string('description')->nullable();
    $table->boolean('adult')->default(false);
    $table->timestamps();
});

Remarquez que la colonne description est nullable puisqu’on la veut optionnelle.

La valeur par défaut pour le statut adulte est false.

D’autre part, on fait le choix de la suppression en cascade, donc en cas de suppression d’un utilisateur ou d’une catégorie, les images correspondantes seront aussi supprimées.

Pour le modèle, pour le moment, on ne va rien changer.

On migre !

Si on veut que nos seeders fonctionnent il faut renseigne DatabaseSeeder :

...

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            UserSeeder::class,
            CategorySeeder::class,
        ]);
    }
}
On est maintenant prêts pour faire nos migrations et la population :
php artisan migrate:fresh --seed

Vérifiez que vous avez bien les nouvelles tables categories et images dans la base de données et qu'il y a les données prévues dans les tables users et categories.

Les relations

On va établir ces relations :
  • User hasmany Image
  • Category hasMany Image
Et évidement les réciproques. Voici le schéma pour ces trois tables :

User

Un utilisateur a plusieurs images :
...

use Illuminate\Database\Eloquent\Relations\HasMany;

class User extends Authenticatable
{
    ...

    public function images(): HasMany
    {
        return $this->hasMany(Image::class);
    }
}

Category

Une catégorie a plusieurs images :
...

use Illuminate\Database\Eloquent\Relations\HasMany;

class Category extends Model
{
    ...

    public function images(): HasMany
    {
        return $this->hasMany(Image::class);
    }
}

Image

Une image appartient à un utilisateur et une catégorie :

... 

use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Image extends Model
{
    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

Conclusion

Dans ce chapitre, on a :
  • créé les migrations pour la galerie
  • créé les modèles avec leurs relations
  • créé 3 utilisateurs dont un administrateur
  • créé 5 catégories
Pour vous simplifier la vie, vous pouvez charger le projet dans son état à l’issue de ce chapitre.


Par bestmomo

Aucun commentaire