Tutoriel Laravel 9 #6 : Créer des modèles et configurer le panneau d’administration

Structure de la base de données

Pour un système de blog simple, nous avons besoin d’au moins 4 tables de base de données : UsersCategoriesTags et Posts. Si vous voulez d’autres fonctions pour votre blog, des commentaires, par exemple, vous pouvez ajouter d’autres tables vous-même. Pour que ce tutoriel soit court et facile à comprendre, ces quatre tableaux sont tout ce dont nous avons besoin.

Table des utilisateurs "Users"

idintegerauto increment
namestringnot null
emailstringunique, not null
passwordstring 

Table des catégories "Categories"

namestringnot null
slugstringunique, not null
descriptiontextnot null

Table des étiquettes "Tags"

namestringnot null
slugstringunique, not null
descriptiontextnot null

Table des articles "Posts"

titlestringnot null
slugstringunique, not null
featured imagestringnot null
contenttextnot null
publishedboolean 
featuredboolean 

Relations

Ici, j’aimerais présenter quelques relations de base. Je n’ai choisi que celles que nous devons utiliser pour construire un système de blog simple, car certaines relations, comme les relations polymorphes, peuvent être trop difficiles à comprendre pour les débutants.

Un à un (One to One)

Il s’agit de la relation la plus élémentaire. Par exemple, chaque User est associé à un Phone. Pour définir cette relation, nous devons créer une fonction phone sur l’objet User qui contiendra la relation vers Phone.
class User extends Model
{
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}
L’inverse de “hasOne” est “belongsTo”. Par exemple, chaque Phone appartiens à un User. Afin de définir l’inverse de la relation One to One. Nous plaçons un user sur l’objet Phone.
class Phone extends Model
{
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

De un à plusieurs ( One to Many )

Une relation de type “un à plusieurs” est utilisée pour définir des relations où un seul modèle possède un nombre quelconque d’autres modèles. Par exemple, un Category peut avoir plusieurs Posts. Tout comme la relation un à un, elle peut être définie en mettant une méthode posts dans l’objet Category.
class Category extends Model
{
    public function posts()
    {
        return $this->hasMany('App\Post');
    }
}
Cependant, il est parfois nécessaire de trouver la catégorie par le biais du poste. L’inverse de “One to Many” est “belongsTo” également.
class Post extends Model
{
    public function category()
    {
        return $this->belongsTo('App\Category');
    }
}

Plusieurs à plusieurs ( Many to Many )

Les relations « Plusieurs à plusieurs » sont légèrement plus compliquées que les relations entre plusieurs modèles. hasOne et hasMany. Un exemple d’une telle relation est qu’un article a plusieurs étiquettes et chaque étiquette appartient à plusieurs articles. Nous en parlerons plus tard.

Relations de conception

Pour notre projet de site web de blog. Il y a six relations dont nous devons nous occuper.

Créer des modèles

Maintenant, il est temps pour nous de mettre en œuvre cette conception. La première chose à faire est de générer les modèles et les fichiers de migration nécessaires à notre projet à l’aide des commandes artisanales.

php artisan make:model Category -m

php artisan make:model Post -m 

php artisan make:model Tag -m

Modèle des catégories

database/migrations/{date_de_creation}_create_categories_table.php

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

Ligne 6, unique() signifie que chaque enregistrement de la colonne slug est unique.

Ligne 7, nullable() signifie que l’enregistrement dans la colonne peut être vide.

Ligne 8, timestamps() crée deux colonnes qui stockent le moment où l’enregistrement est créé « created_at » et celui où il est mis à jour « updated_at ».

app/Models/Category.php

class Category extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'description',
        'slug',
    ];
}

Modèle des étiquettes

database/migrations/{date_de_creation}_create_tags_table.php

    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('slug')->unique();
            $table->text('description')->nullable();
            $table->timestamps();
        });
    }

app/Models/Tag.php

class Tag extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'description',
        'slug',
    ];
}

Modèle des articles

database/migrations/{date_de_creation}_create_posts_table.php

    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('category_id');
            $table->bigInteger('user_id');
            $table->string('title');
            $table->string('slug')->unique();
            $table->text('content');
            $table->string('featured_image')->nullable();
            $table->boolean('is_featured')->default(false);
            $table->boolean('is_published')->default(false);
            $table->timestamps();
        });
    }

app/Models/Post.php

class Post extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'category_id',
        'user_id',
        "title",
        'content',
        'slug',
        'featured_image',
        'is_featured',
        'is_published'
    ];
}

Relationship

Entre l’utilisateur et le poste (un à plusieurs)

Si vous avez suivi la section précédente, nous avons déjà ajouté une fonction user_id dans le fichier posts tableau.

database/migrations/create_posts_table.php

$table->bigInteger('user_id');

Cette colonne stocke l’identifiant de l’utilisateur à qui appartient l’article. Maintenant nous pouvons définir les relations dans les modèles. N’oubliez pas le nouveau répertoire indépendant pour les modèles !

app/Models/User.php

/**
 * Get the posts for the user.
 */
public function posts()
{
    return $this->hasMany('App\Models\Post');
}

app/Models/Post.php

/**
 * Get the user that owns the post.
 */
public function user()
{
    return $this->belongsTo('App\Models\User');
}

Entre la catégorie et l’article (un à plusieurs)

Encore une fois, nous devons avoir un category_id dans le fichier posts qui stocke l’identifiant de la catégorie dans laquelle se trouve ce message.

database/migrations/{date_de_creation}_create_posts_table.php

$table->bigInteger('category_id');

Définir les relations dans les modèles.

app/Models/Category.php

/**
 * Get the posts for the user.
 */
public function posts()
{
    return $this->hasMany('App\Models\Post');
}

app/Models/Post.php:

/**
 * Get the category that owns the post.
 */
public function category()
{
    return $this->belongsTo('App\Models\Category');
}

Entre les étiquettes et les articles (Many to Many)

Celle-ci est un peu plus compliquée, elle nécessite une fonction Relation de plusieurs à plusieurs et une table de base de données supplémentaire post_tag. Ce tableau est appelé tableau croisé dynamique.

Tout d’abord, créez un nouveau fichier de migration :

php artisan make:migration create_post_tag_table

database/migrations/create_post_tag_table.php

Schema::create('post_tag', function (Blueprint $table) {
    $table->bigInteger('tag_id');
    $table->bigInteger('post_id');
});

Maintenant nous pouvons définir les relations entre les tags et les posts.

app/Models/Tag.php

public function posts()
{
    return $this->belongsToMany('App\Models\Post');
}

app/Models/Post.php

public function tags()
{
    return $this->belongsToMany('App\Models\Tag');
}

Ici, Laravel suppose qu’il existe un post_tag et qu’il y a deux colonnes post_id et tag_id dans le tableau. Le nom de la table doit être dans l’ordre alphabétique. Si vous les avez nommés différemment, tag_post par exemple, vous devez les spécifier comme suit.

public function tags()
{
    return $this->belongsToMany('App\Models\Tag', 'tag_post');
}

N’oubliez pas d’appliquer les fichiers de migration en utilisant php artisan migrate.

Voyager

Pour configurer Voyager, nous n’avons pas besoin d’écrire de code. Tout ce que nous devons faire est d’ajouter BREAD (browse, read, edit, add and delete) pour chaque table de la base de données (à l’exclusion de post_tag).

Aller dans Tools->BREAD :

Modifier le BREAD pour categories

Tout d’abord, nous devons nous assurer que Voyager peut trouver le modèle correspondant. Dans la section “Categories BREAD info”, trouvez le “Model Name”, et changez-le en App\Models\Category soit le namespace de la classe du même nom Category.php.

Après cela, faites défiler vers le bas jusqu’à la section suivante, et changez le type de saisie pour “description” en “zone de texte”. Vous obtiendrez ainsi une zone de texte plus grande pour la description. N’oubliez pas d’enregistrer les modifications avant de poursuivre. 

Nous devons également ajouter la relation dans Voyager, comme nous l’avons conçu, chaque catégorie a beaucoup de postes :

Modifier le BREAD pour tags

Faites la même chose pour les tags.

Ajouter des relations :

Note : Vous allez devoir créer un override pour corriger un bug dans voyager public/resources/views/vendor/voyager/formfields/relationship.blade.php
en copiant-collant le code à partir du fichier
vendor/tcg/voyager/resources/views/formfields/relationship.blade.php
et remplacer la ligne 163

data-route="{{ route('voyager.'.\Illuminate\Support\Str::slug($options->table).'.store') }}"

par

data-route="{{ route('voyager.'.\Illuminate\Support\Str::slug($dataType->slug).'.store') }}"

Pourquoi ? Voyager utilise le nom de la table au lieu du slug pour rechercher une route, nous avons modifier le slug de la table Posts par blog-post pour éviter un conflit avec les routes par défaut de Voyager, hors si on créer une relations Belongs To Many vers Post avec « Allow Tagging » d’activer, Voyager essayera de trouver la route voyager.posts.store à la place voyager.blog-posts.store.

Si vous voulez voir la listes des routes possibles, vous pouvez taper la commande suivante :

php artisan route:list

Modifier le BREAD pour posts

Ajouter des relations :

Modifier le BREAD pour users

Nous devons seulement ajouter une relation supplémentaire pour les utilisateurs et les messages :

Maintenant, vous devriez pouvoir voir les éléments de menu “Categories”, “Tags” et “Posts”.

Erreur lors de la modification des messages

Cette erreur est due au fait que Voyager possède déjà un Post intégré, et le Post que nous avons créé est en conflit avec lui.

Pour résoudre ce problème, nous changeons l’URL Slug des articles en quelque chose d’autre que posts. Rendez-vous dans BREAD -> Posts -> Edit -> Url Slug

Ensuite, allez dans Menu Builder et éditer le menu admin -> posts pour indiquer le lien en static  :

Newsletter

Ne manquez jamais les nouveaux conseils, tutoriels et autres.

Pas de spam, jamais. Nous ne partagerons jamais votre adresse électronique et vous pouvez vous désabonner à tout moment.