Laravel

Un framework qui rend heureux

Voir cette catégorie
Vers le bas
Voir cette série
Mon CMS - Les données
Mardi 20 août 2024 13:19

Vous avez sans doute remarqué que mon blog a récemment changé d'apparence et de fonctionnalités. Ce changement est dû au passage de WordPress à Laravel, une migration qui a nécessité du temps et des efforts d'adaptation, mais qui est maintenant réussie. Ce projet étant intéressant du point de vue de l'apprentissage, j'ai décidé de consacrer une série d'articles à l'explication pas à pas de la création de ce type d'application. Ce format progressif est particulièrement apprécié de mes lecteurs.

Nous allons commencer doucement en installant Laravel et en analysant les besoins de notre CMS en termes de données. Cette étape est essentielle, car tout retour en arrière à ce niveau pourrait s'avérer fastidieux et complexe. Par conséquent, nous allons évaluer précisément nos besoins pour éviter toute régression laborieuse. Avancer en toute confiance est nettement plus gratifiant !

Au fil de cette série d'articles, vous aurez l'occasion de découvrir les différentes étapes de la création d'un CMS avec Laravel, de la planification à la mise en œuvre effective. Vous pourrez suivre la progression, de l'installation initiale jusqu'à la mise en place de fonctionnalités avancées. Mon  objectif est de vous fournir un guide pratique et concis, qui couvrira tous les aspects importants de ce projet de développement.

N'hésitez pas à me faire part de vos suggestions ou de vos questions au fur et à mesure de notre exploration de Laravel. Je souhaite que cette série d'articles soit non seulement instructive, mais aussi interactive, afin que vous puissiez apprendre au maximum et partager vos expériences avec d'autres membres de la communauté.

Je suis impatient de vous guider tout au long de cette série d'articles passionnants et j'espère que vous apprécierez autant que moi cette plongée dans la création d'un CMS avec Laravel.

Pour vous simplifier la vie en cas de problème, vous pouvez télécharger le code final de cet article ici.

Les indications qui apparaissent sous forme de bloc de citation sont à l'intention des débutants, elle détaillent les actions et développent certains points. Le lecteur averti peut les sauter et ainsi avoir une lecture plus fluide.

Installation

On commence par installer un Laravel tout neuf et tout propre :

Ouvrez votre terminal (ou invite de commande) : C'est une interface où vous pouvez taper des commandes pour interagir avec votre ordinateur.

composer  create-project laravel/laravel moncms --prefer-dist

composer est un outil de gestion de dépendances pour PHP.

create-project est une commande qui crée un nouveau projet.

laravel/laravel spécifie que vous voulez créer un projet Laravel.

moncms est le nom du dossier où le projet sera créé.

--prefer-dist indique que vous préférez télécharger les versions distribuées des dépendances.

 

Une fois l'installation terminée, vous devez configurer certains paramètres dans le fichier .env situé à la racine de votre projet. Ce fichier contient des variables d'environnement qui sont utilisées pour configurer votre application.

Ouvrez le fichier .env avec un éditeur de texte : Vous pouvez utiliser des éditeurs comme VSCode, Sublime Text, ou même un simple éditeur de texte comme Notepad.

On va ajuster les réglages (.env) :

APP_NAME="Mon CMS"
...
APP_URL=http://moncms.oo (là ajustez selon votre serveur local)
...
APP_LOCALE=fr
...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=moncms
DB_USERNAME=root
DB_PASSWORD=
...

APP_NAME : Le nom de votre application.
APP_URL : L'URL de votre application. Ajustez-la selon votre serveur local.
APP_LOCALE : La langue par défaut de votre application. Ici, elle est définie en français (fr).
DB_CONNECTION : Le type de base de données que vous utilisez. Ici, c'est MySQL.
DB_HOST : L'adresse de l'hôte de la base de données. 127.0.0.1 est l'adresse locale.
DB_PORT : Le port de la base de données. 3306 est le port par défaut pour MySQL.
DB_DATABASE : Le nom de votre base de données.
DB_USERNAME : Le nom d'utilisateur de la base de données.
DB_PASSWORD : Le mot de passe de la base de données. Si vous n'avez pas de mot de passe, laissez ce champ vide.

Pour le moment, on va se contenter de ça, on y reviendra pour des réglages ultérieurs.

Pour que votre CMS soit en français, même si vous prévoyez de le rendre multilingue, vous devez installer un package de langue.

composer require --dev laravel-lang/common
php artisan lang:update

composer require --dev laravel-lang/common : Cette commande installe le package de langue.
php artisan lang:update : Cette commande met à jour les fichiers de langue de votre application.

On se retrouve donc avec l'anglais et le français :

Les données

On va maintenant s'intéresser aux données qui nous seront nécessaires.

Les utilisateurs

Lorsque vous créez un nouveau projet Laravel, certaines fonctionnalités sont déjà configurées par défaut pour vous faciliter la vie. L'une de ces fonctionnalités est la migration pour les utilisateurs.

Qu'est-ce qu'une migration ?

Une migration est un fichier qui contient des instructions pour créer ou modifier des tables dans votre base de données. Laravel utilise des migrations pour gérer les changements de structure de la base de données de manière organisée et réversible.

La table users

Par défaut, Laravel inclut une migration pour créer une table users. Cette table est utilisée pour stocker les informations des utilisateurs de votre application. Voici ce que vous devez savoir :

    Fichier de Migration : Vous pouvez trouver le fichier de migration pour les utilisateurs dans le dossier database/migrations. Le fichier est généralement nommé quelque chose comme create_users_table.php.

    Structure de la Table : La table users contient des colonnes comme id, name, email, password, remember_token, et des timestamps (created_at et updated_at). Ces colonnes sont essentielles pour gérer les informations de base des utilisateurs.

Comment ça marche ?

Ouvrez le Fichier de Migration : Vous pouvez ouvrir le fichier de migration avec un éditeur de texte pour voir comment la table users est définie.
Exécuter les Migrations : Pour appliquer les migrations et créer la table users dans votre base de données, vous devez exécuter la commande suivante dans votre terminal :

    php artisan migrate

        php artisan est la commande de base pour interagir avec Laravel via la ligne de commande.
        migrate est la commande qui exécute toutes les migrations en attente.

Pourquoi C'est Utile ?

    Gestion des Utilisateurs : Avoir une table users par défaut vous permet de gérer facilement les utilisateurs de votre application. Vous pouvez ajouter, modifier, ou supprimer des utilisateurs sans avoir à créer manuellement la structure de la table.
    Authentification : Laravel inclut également des fonctionnalités d'authentification par défaut, qui utilisent la table users. Cela vous permet de mettre en place rapidement des fonctionnalités comme la connexion, l'inscription, et la gestion des sessions utilisateur.

On a par défaut une migration pour les utilisateurs avec la table users. Mais on va devoir la compléter. Voici la fonction up complétée :

public function up(): void
{
	Schema::create('users', function (Blueprint $table) {
		$table->id();
		$table->string('name')->unique();
		$table->string('email')->unique();
		$table->string('password');
		$table->enum('role', ['user', 'redac', 'admin'])->default('user');
		$table->boolean('valid')->default(false);
		$table->rememberToken();
		$table->timestamps();
	});

	Schema::create('password_reset_tokens', function (Blueprint $table) {
		$table->string('email')->primary();
		$table->string('token');
		$table->timestamp('created_at')->nullable();
	});

	Schema::create('sessions', function (Blueprint $table) {
		$table->string('id')->primary();
		$table->foreignId('user_id')->nullable()->index();
		$table->string('ip_address', 45)->nullable();
		$table->text('user_agent')->nullable();
		$table->longText('payload');
		$table->integer('last_activity')->index();
	});
}

Le code que vous voyez est une méthode up dans une migration Laravel. Cette méthode est utilisée pour définir la structure des tables de votre base de données.

Méthode up

La méthode up est appelée lorsque vous exécutez la commande php artisan migrate. Elle contient les instructions pour créer ou modifier les tables de votre base de données.

Création de la table users :

    Schema::create('users', function (Blueprint $table) { ... }) : Cette ligne crée une nouvelle table nommée users.
    $table->id() : Ajoute une colonne id de type entier auto-incrémenté, qui servira de clé primaire.
    $table->string('name')->unique() : Ajoute une colonne name de type chaîne de caractères, avec une contrainte d'unicité.
    $table->string('email')->unique() : Ajoute une colonne email de type chaîne de caractères, avec une contrainte d'unicité.
    $table->string('password') : Ajoute une colonne password de type chaîne de caractères.
    $table->enum('role', ['user', 'redac', 'admin'])->default('user') : Ajoute une colonne role de type énumération, avec les valeurs possibles user, redac, et admin. La valeur par défaut est user.
    $table->boolean('valid')->default(false) : Ajoute une colonne valid de type booléen, avec une valeur par défaut de false.
    $table->rememberToken() : Ajoute une colonne remember_token de type chaîne de caractères, utilisée pour les fonctionnalités de "se souvenir de moi".
    $table->timestamps() : Ajoute deux colonnes created_at et updated_at de type timestamp, pour suivre les dates de création et de mise à jour des enregistrements.

Création de la Table password_reset_tokens :

    Schema::create('password_reset_tokens', function (Blueprint $table) { ... }) : Cette ligne crée une nouvelle table nommée password_reset_tokens.
    $table->string('email')->primary() : Ajoute une colonne email de type chaîne de caractères, qui servira de clé primaire.
    $table->string('token') : Ajoute une colonne token de type chaîne de caractères.
    $table->timestamp('created_at')->nullable() : Ajoute une colonne created_at de type timestamp, qui peut être nulle.

Création de la Table sessions :

    Schema::create('sessions', function (Blueprint $table) { ... }) : Cette ligne crée une nouvelle table nommée sessions.
    $table->string('id')->primary() : Ajoute une colonne id de type chaîne de caractères, qui servira de clé primaire.
    $table->foreignId('user_id')->nullable()->index() : Ajoute une colonne user_id de type entier, qui peut être nulle et qui est indexée.
    $table->string('ip_address', 45)->nullable() : Ajoute une colonne ip_address de type chaîne de caractères, avec une longueur maximale de 45 caractères, qui peut être nulle.
    $table->text('user_agent')->nullable() : Ajoute une colonne user_agent de type texte, qui peut être nulle.
    $table->longText('payload') : Ajoute une colonne payload de type long texte.
    $table->integer('last_activity')->index() : Ajoute une colonne last_activity de type entier, qui est indexée.

Pourquoi C'est Utile ?

    Structure de la Base de Données : Ces migrations définissent la structure de votre base de données, ce qui est essentiel pour le bon fonctionnement de votre application.
    Gestion des Utilisateurs : La table users permet de gérer les informations des utilisateurs, y compris leurs rôles et leur statut de validation.
    Réinitialisation des Mots de Passe : La table password_reset_tokens est utilisée pour gérer les jetons de réinitialisation de mot de passe.
    Gestion des Sessions : La table sessions est utilisée pour gérer les sessions utilisateur, y compris les informations sur l'adresse IP, l'agent utilisateur, et la dernière activité.

Aux colonnes de base déjà créées par Laravel, on ajoute deux informations :

  • role : pour savoir quelles sont les permissions de l'utilisateur : administrateur, rédacteur ou simple utilisateur. Ce n'est pas la peine d'utiliser un package pour ce genre de chose.
  • valid : pour valider un utilisateur au niveau des commentaires, le premier commentaire d'un utilisateur n'apparaîtra pas tout de suite, il faut que ce soit validé par l'administrateur ou l'auteur de l'article, les commentaires suivants, par contre, apparaitront immédiatement, c'est une façon d'éviter les trolls.

D'autre part, j'ai supprimé le champ email_verified_at qui sert à la vérification éventuelle de l'email fourni par l'utilisateur. Cette vérification n'est pas très pertinente parce qu'il est très facile d'utiliser une adresse provisoire et de la confirmer, on n'a donc aucune assurance qu'il s'agit vraiment d'une adresse légitime.

Je n'ai rien changé aux deux blocs qui concernent le renouvellement du mot de passe et les sessions.

On dispose déjà d'une factory pour cette table (database/factories/UserFactory.php). On la complète pour mettre la colonne valid à true pour que notre population génère des utilisateurs déjà validés. Et on supprime email_verified_at :

return [
    'name'           => fake()->lastname(),
    'email'          => fake()->unique()->safeEmail(),
    'password'       => static::$password ??= Hash::make('password'),
    'remember_token' => Str::random(10),
    'valid'          => true,
];

On pourra évidemment en dévalider pour tester le code correspondant. Pour les rôles, on les renseignera avec le seeder.

Lorsque vous développez une application web, il est souvent utile de pouvoir générer rapidement des données de test pour vérifier que votre application fonctionne correctement. Laravel facilite cette tâche grâce aux factories, qui sont des classes permettant de générer des instances de modèles avec des données fictives.

Qu'est-ce qu'une factory ?

Une factory est une classe qui définit comment générer des instances d'un modèle avec des données fictives. Les factories sont particulièrement utiles pour les tests unitaires et les tests d'intégration, car elles permettent de créer rapidement des données de test réalistes.

Pourquoi utiliser des factories ?

    Rapidité : Les factories permettent de générer rapidement des données de test sans avoir à écrire manuellement chaque enregistrement.
    Consistance : Elles garantissent que les données de test sont cohérentes et réalistes.
    Facilité de Test : Elles facilitent les tests en fournissant des données de test fiables et reproductibles.

Dans le modèle User, on complète la propriété $fillable :

protected $fillable = ['name', 'email', 'password', 'role', 'valid'];

Lorsque vous travaillez avec Laravel, vous utilisez souvent des modèles pour interagir avec votre base de données. Le modèle User est l'un des modèles les plus couramment utilisés, car il gère les informations des utilisateurs de votre application.

Qu'est-ce que la propriété $fillable ?

La propriété $fillable est une liste de colonnes de la table de la base de données qui peuvent être remplies en masse. Cela signifie que vous pouvez passer un tableau de données à une instance du modèle, et Laravel remplira automatiquement les colonnes spécifiées dans $fillable.

Pourquoi Utiliser $fillable ?

Utiliser $fillable est une bonne pratique pour plusieurs raisons :

    Sécurité : Cela empêche les attaques de type "mass assignment" en limitant les colonnes qui peuvent être remplies en masse.
    Clarté : Cela rend votre code plus clair en spécifiant explicitement quelles colonnes peuvent être remplies.

Les catégories

Les articles vont être organisés en catégories, on a donc une table pour mémoriser celles-ci. On va avoir besoin de deux informations :

  • title : le titre
  • slug : c'est le texte qui va apparaître dans l'URL et qui ne doit comporter que des caractères autorisés

Qu'est-ce qu'un slug ?

Un slug est une version simplifiée et lisible par les machines d'un titre ou d'un nom. Il est utilisé dans les URL pour identifier de manière unique une page ou une ressource. Par exemple, si le titre de la catégorie est "Technologie", le slug pourrait être "technologie". Les slugs ne doivent contenir que des caractères alphanumériques, des tirets (-), et des underscores (_).

Pourquoi utiliser des slugs ?

    Lisibilité : Les slugs rendent les URL plus lisibles et compréhensibles pour les utilisateurs.
    SEO : Les URL avec des slugs sont plus faciles à indexer par les moteurs de recherche, ce qui peut améliorer le référencement de votre site.
    Unicité : Les slugs permettent d'identifier de manière unique chaque catégorie ou article, ce qui facilite la gestion du contenu.

D'autre part, on ne va pas utiliser les timestamps, quel intérêt de savoir quand une catégorie a été créée ou modifiée ?

On crée la migration et le modèle avec la même commande :

php artisan make:model Category --migration

Pour la migration, on prévoit ce code :

public function up(): void
{
    Schema::create('categories', function (Blueprint $table) {
        $table->id();
        $table->string('title')->unique();
        $table->string('slug')->unique();
    });
}

Et dans le modèle Category on signale l'absence du timestamp, d'autre part, on n'utilisera pas de repository , enfin, on prévoit la propriété $fillable :

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    public $timestamps = false;

	protected $fillable = [	'title', 'slug', ];
}

Les articles (posts)

Là, c'est le gros morceau bien sûr ! On a besoin de pas mal d'informations :

  • title : le titre
  • slug
  • body : le corps de l'article
  • active : pour savoir si l'article est publié
  • image : pour le lien de l'image en exergue sur la page d'accueil
  • seo_title : le titre de la page (SEO)
  • meta_description : description de la page (SEO)
  • meta_keywords : mots clefs de la page (SEO)
  • pinned : pour savoir si l'article est épinglé

Qu'est-ce que le SEO ?

Le SEO (Search Engine Optimization) est un ensemble de techniques visant à améliorer la position d'un site web dans les résultats des moteurs de recherche. Cela inclut l'optimisation du contenu, des balises HTML, et d'autres éléments pour rendre le site plus attrayant pour les moteurs de recherche.

Pourquoi utiliser des informations SEO ?

    Visibilité : Les informations SEO aident les moteurs de recherche à comprendre le contenu de votre page et à l'afficher dans les résultats de recherche pertinents.
    Clics : Un bon titre et une bonne description peuvent inciter les utilisateurs à cliquer sur votre lien dans les résultats de recherche.
    Classement : Les mots-clés aident les moteurs de recherche à classer votre page pour des requêtes spécifiques.

D'autre part, il faut commencer à penser aux relations. Un article appartient à un utilisateur et une catégorie. On doit donc prévoir deux clés étrangères pour gérer cette situation.

Lorsque vous concevez une application web, il est crucial de penser aux relations entre les différentes entités de votre base de données. Ces relations permettent de structurer les données de manière logique et de faciliter les interactions entre les différentes parties de votre application.
Relations entre les Articles, les Utilisateurs et les Catégories

Dans notre cas, un article appartient à un utilisateur et à une catégorie. Cela signifie que chaque article doit être associé à un utilisateur spécifique et à une catégorie spécifique. Pour gérer cette situation, nous devons prévoir des clés étrangères dans la table des articles.

Qu'est-ce qu'une clé étrangère ?

Une clé étrangère est une colonne dans une table qui crée un lien entre cette table et une autre table. Elle permet de maintenir l'intégrité référentielle, c'est-à-dire de s'assurer que les relations entre les tables sont cohérentes.

Pourquoi utiliser des clés étrangères ?

    Intégrité des Données : Les clés étrangères garantissent que les relations entre les tables sont correctes et cohérentes.
    Facilité de Gestion : Elles permettent de gérer facilement les relations entre les différentes entités de votre application.
    Efficacité des Requêtes : Elles facilitent les requêtes complexes en permettant de joindre facilement les tables.

On commence par créer la migration et le modèle :

php artisan make:model Post --migration

Pour la migration, ça va donner ce code :

public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
        $table->string('title');
        $table->string('slug')->unique();
        $table->mediumText('body');
        $table->boolean('active')->default(false);
        $table->string('image')->nullable();
        $table->string('seo_title');
        $table->text('meta_description');
        $table->text('meta_keywords');
        $table->boolean('pinned')->default(false);

        $table->foreignId('user_id')
            ->constrained()
            ->onDelete('cascade')
            ->onUpdate('cascade');

        $table->foreignId('category_id')
            ->constrained()
            ->onDelete('cascade')
            ->onUpdate('cascade');
    });
}

On va terminer en créant une factory :

php artisan make:factory PostFactory

Avec ce code :

public function definition(): array
{
	return [
		'body'             => fake()->paragraphs($nb = 8, $asText = true),
		'meta_description' => fake()->sentence($nbWords = 6, $variableNbWords = true),
		'meta_keywords'    => implode(',', fake()->words($nb = 3, $asText = false)),
		'active'           => true,
	];
}

Pour terminer avec les articles, on ajoute la propriété $fillable dans le modèle Post :

protected $fillable = ['title', 'slug', 'body', 'active', 'image', 'user_id', 'category_id', 'seo_title', 'meta_description', 'meta_keywords', 'pinned'];

Les relations

Maintenant que nous avons créé les migrations pour les tables users, posts et categories, qui sont les principales de notre projet, nous allons nous intéresser aux relations entre ces tables. Nous avons d'ailleurs déjà commencé puisque des clés étrangères ont été prévues dans la table posts. Comme je l'ai dit plus haut, un article appartient à la fois à une catégorie et un utilisateur. Les réciproques sont qu'un utilisateur possède plusieurs articles, de même pour les catégories. Il nous faut à présent formaliser ces relations dans les modèles correspondants.

Les relations dans le modèle Post

  • Un Post appartient à un User.
  • Un Post appartient à une Category.
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Post extends Model
{
	...

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

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

...

La relation dans le modèle User

Un User peut avoir plusieurs Post.

use Illuminate\Database\Eloquent\Relations\HasMany;

class User extends Authenticatable
{
    ...

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

La relation dans le modèle Category

Une Category peut avoir plusieurs Post.

use Illuminate\Database\Eloquent\Relations\HasMany;

class Category extends Model
{
    ...

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

En définissant ces relations dans les modèles, Laravel sait comment lier les différentes tables entre elles. Par exemple, si vous avez un objet Post, vous pouvez facilement accéder à l'utilisateur qui l'a créé en utilisant $post->user, et à la catégorie à laquelle il appartient en utilisant $post->category. De même, si vous avez un objet User, vous pouvez accéder à tous les posts qu'il a créés en utilisant $user->posts.

Ces relations sont essentielles pour structurer votre application de manière cohérente et pour faciliter les opérations de base de données complexes.

La migration

Le moment de vérité est arrivé et on va lancer les migrations pour voir si tout fonctionne et que les tables se créent correctement.

php artisan migrate

On se retrouve avec 11 tables créées :

Parmi ces tables, il y a les 3 qui nous intéressent, les autres étant dévolues à l'intendance de Laravel et nous n'avons pas à nous en inquiéter. 

Voici un diagramme pour illustrer nos trois tables avec leurs relations visualisées :

Nous voyons dans ce diagramme les trois tables avec leurs colonnes (nom et type), leurs contraintes et leurs index, ainsi que les deux relations générées par les clés étrangères que nous avons prévues.

La population

Nous allons maintenant créer les factories pour remplir nos trois tables avec des données qui nous seront utiles pour que notre CMS soit tout de suite fonctionnel.

Les users

php artisan make:seeder UserSeeder

On va prévoir trois utilisateurs (un administrateur, un rédacteur et un utilisateur de base) : 

<?php

namespace Database\Seeders;

use App\Models\User;
use Carbon\Carbon;
use Illuminate\Database\Seeder;

class UserSeeder extends Seeder
{
	public function run()
	{
		$users = [
			[
				'name'       => 'Admin',
				'email'      => 'admin@example.com',
				'role'       => 'admin',
				'created_at' => Carbon::now()->subYears(3),
				'updated_at' => Carbon::now()->subYears(3),
			],
			[
				'name'       => 'Redac',
				'email'      => 'redac@example.com',
				'role'       => 'redac',
				'created_at' => Carbon::now()->subYears(3),
				'updated_at' => Carbon::now()->subYears(3),
			],
			[
				'name'       => 'User',
				'email'      => 'user@example.com',
				'role'       => 'user',
				'created_at' => Carbon::now()->subYears(2),
				'updated_at' => Carbon::now()->subYears(2),
			],
		];

        foreach ($users as $userData) {
			User::factory()->create($userData);
		}

	}
}

$users est un tableau contenant des tableaux associatifs, chacun représentant un utilisateur à insérer dans la base de données.
Chaque utilisateur a des attributs comme name, email, role, created_at, et updated_at.
Carbon::now()->subYears(3) et Carbon::now()->subYears(2) sont utilisés pour définir les dates de création et de mise à jour des utilisateurs. Carbon::now() renvoie la date et l'heure actuelles, et subYears(3) soustrait 3 ans à cette date.
Ensuite dans une boucle on fait appel à la factory qui complète les données et on crée effectivement les utilisateurs dans la base.

On verra plus loin comment on appelle ce seeder.

Les categories

php artisan make:seeder CategorySeeder

Pour le code, on va adopter la même stratégie que pour les utilisateurs :

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\Category;

class CategorySeeder extends Seeder
{
	public function run()
	{
        $categories = [
			[
				'title' => 'Categorie 1',
				'slug'  => 'category-1',
			],
			[
				'title' => 'Categorie 2',
				'slug'  => 'category-2',
			],
			[
				'title' => 'Categorie 3',
				'slug'  => 'category-3',
			],
		];

        foreach ($categories as $categoryData) {
			Category::create($categoryData);
		}
	}
}

La différence, c'est que nous n'avons pas besoin ici de factory.

Les posts

Les helpers

Avant de créer le code pour les articles, on va faire une petite digression pour créer un helper. 

Les helpers sont des fonctions utilitaires fournies par Laravel ou que l'on peut créer soi-même qui facilitent l'écriture de code propre et concis. Ils sont conçus pour accomplir des tâches courantes et répétitives, ce qui permet aux développeurs de se concentrer sur la logique métier de leur application. Laravel propose une variété de helpers pour diverses tâches, allant de la manipulation de chaînes de caractères à la gestion des chemins de fichiers.

Pourquoi utiliser les helpers ?

    Simplicité : Les helpers permettent d'écrire du code plus lisible et plus facile à comprendre. Par exemple, au lieu d'écrire une longue série de conditions pour vérifier si une variable est définie et non nulle, vous pouvez utiliser la fonction blank().

    Réutilisabilité : Les helpers sont des fonctions globales qui peuvent être utilisées n'importe où dans votre application. Cela signifie que vous n'avez pas besoin de réécrire le même code plusieurs fois.

    Productivité : En utilisant les helpers, vous pouvez réduire le temps de développement en utilisant des fonctions prêtes à l'emploi pour des tâches courantes.

Exemples de helpers in clus dans Laravel et couramment utilisés :

str_contains($haystack, $needles) : Vérifie si une chaîne contient une sous-chaîne.
str_slug($title, $separator = '-') : Génère une chaîne de caractères compatible avec les URL à partir d'un titre.

On commence par créer un fichier de helpers :

On veut une fonction qui génère une date aléatoire entre deux dates données, voici le code :

<?php

if (!function_exists('generateRandomDateInRange')) {
	function generateRandomDateInRange($startDate, $endDate)
	{
		$start = Carbon\Carbon::parse($startDate);
		$end   = Carbon\Carbon::parse($endDate);

		$difference = $end->timestamp - $start->timestamp;

		$randomSeconds = rand(0, $difference);

		return $start->copy()->addSeconds($randomSeconds);
	}
}

Carbon\Carbon::parse($startDate) : Convertit la chaîne de caractères $startDate en un objet Carbon représentant la date de début.
Carbon\Carbon::parse($endDate) : Convertit la chaîne de caractères $endDate en un objet Carbon représentant la date de fin.
$end->timestamp : Renvoie le timestamp (nombre de secondes depuis l'époque Unix) de la date de fin.
$start->timestamp : Renvoie le timestamp de la date de début.
$difference : Calcule la différence en secondes entre les deux dates.
rand(0, $difference) : Génère un nombre aléatoire entre 0 et $difference. Ce nombre représente un nombre aléatoire de secondes à ajouter à la date de début.
$start->copy() : Crée une copie de l'objet Carbon représentant la date de début. Cela permet de ne pas modifier l'objet original.
addSeconds($randomSeconds) : Ajoute le nombre aléatoire de secondes à la date de début.
La fonction retourne l'objet Carbon résultant, qui représente une date aléatoire entre $startDate et $endDate.

Pour que Laravel charge automatiquement votre fichier helper, vous devez l'inclure dans le fichier de configuration composer.json.

Ouvrez le fichier composer.json situé à la racine de votre projet et ajoutez votre fichier de helper dans la section autoload sous files :

"autoload": {
    "files": [
        "app/helpers.php"
    ],
    ...
},

Vous aurez sans doute besoin de régénérer l'autoload :

composer dumpautoload

Maintenant que nous avons notre helper, on va créer le seeder :

php artisan make:seeder PostSeeder

<?php

namespace Database\Seeders;

use App\Models\Post;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;

class PostSeeder extends Seeder
{
	public static $nbrPosts;

	public function run()
	{
		$nbrCategories = 3;

		$this->createPost(1, 1);
		$this->createPost(2, rand(1, $nbrCategories));
		$this->createPost(3, 1);
		$this->createPost(4, 1);
		$this->createPost(5, rand(1, $nbrCategories));
		$this->createPost(6, 1);
		$this->createPost(7, 1);
		$this->createPost(8, rand(1, $nbrCategories));
		$this->createPost(9, rand(1, $nbrCategories));
	}

	protected function createPost($id, $category_id)
	{
		$months = ['03', '03', '03', '04', '04', '06', '06', '06', '06'];

		$date = generateRandomDateInRange('2022-01-01', '2024-07-01');

		$postId = "Post {$id}";

		return Post::factory()->create([
			'title'       => $postId,
			'seo_title'   => $postId,
			'slug'        => Str::of($postId)->slug('-'),
			'user_id'     => rand(1, 2),
			'image'       => '2024/' . $months[$id - 1] . '/img0' . $id . '.jpg',
			'category_id' => $category_id,
			'created_at'  => $date,
			'updated_at'  => $date,
			'pinned'      => 5 == $id,
		]);
	}
}

On crée ainsi neuf articles nommés de "Post 1" à "Post 9", avec leur slug. On affecte de façon aléatoire l'utilisateur et les dates, plus ou moins aléatoire la catégorie. Je reparlerai plus tard de la donnée "image".

Le DatabaseSeeder

Pour que ces seeders soient lancés, nous devons intervenir dans le fichier DatabaseSeeder :

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->call([
            UserSeeder::class,
            CategorySeeder::class,
            PostSeeder::class,            
        ]);
    }
}

Remarquez l'ordre des seeders qui est important pour ne pas générer d'erreurs (on a d'autres possibilités pour s'en prémunir, mais c'est plus clair ainsi).

On peut à présent lancer notre population :

php artisan db:seed

Vérifiez les données dans la base :

Si ce n'est pas le cas, c'est que vous avez dû rater du code quelque part...

Les pages

Comme nous sommes bien lancés dans les données, nous allons ajouter les pages. Ce sont en gros des articles qui ne dépendent pas d'une catégorie ou d'un utilisateur et qui contiennent des données plutôt fixes pour le CMS comme les mentions légales. On va donc avoir presque les mêmes éléments que pour un article, mais en plus simple.

php artisan make:model Page --migration

Pour la migration, voici le code :

public function up(): void
{
    Schema::create('pages', function (Blueprint $table) {
        $table->id();
        $table->string('slug');
        $table->string('title');
        $table->mediumText('body');
        $table->boolean('active')->default(false);
        $table->string('seo_title');
        $table->text('meta_description');
        $table->text('meta_keywords');
    });
}

Dans le modèle Page, on va prévoir la propriété $fillable et aussi le fait qu'on a supprimé le timestamp :

<?php

/**
 * (ɔ) LARAVEL.Sillo.org - 2012-2024
 */

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Page extends Model
{
	use HasFactory;

	public $timestamps  = false;
	protected $fillable = [
		'title',
		'slug',
		'body',
		'active',
		'seo_title',
		'meta_description',
		'meta_keywords',
	];
}

On ajoute une factory :

php artisan make:factory PageFactory

public function definition(): array
{
    return [
        'body'             => fake()->paragraph(10),
        'meta_description' => fake()->sentence($nbWords = 6, $variableNbWords = true),
        'meta_keywords'    => implode(',', fake()->words($nb = 3, $asText = false)),
    ];
}

Et évidemment aussi un seeder :

php artisan make:seeder PageSeeder
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\Page;

class PageSeeder extends Seeder
{
	public function run()
	{
		$items = [
			['slug' => 'terms', 'title' => 'Terms'],
			['slug' => 'privacy-policy', 'title' => 'Privacy Policy'],
		];

		foreach ($items as $item) {
			Page::factory()->create([
				'title'     => $item['title'],
				'seo_title' => 'Page ' . $item['title'],
				'slug'      => $item['slug'],
				'active'    => true,
			]);
		}
	}
}

On prévoit ainsi deux pages.

Et enfin dans DatabaseSeeder on ajoute l'appel à notre nouveau seeder :

public function run(): void
{
    $this->call([
        UserSeeder::class,
        CategorySeeder::class,
        PostSeeder::class,
        PageSeeder::class,   
    ]);
}

Il ne reste plus qu'à rafraîchir la base :

php artisan migrate:fresh --seed

On a ainsi ajouté et rempli la table pages :

Conclusion

Au terme de cet article un peu long, on se retrouve avec les données essentielles de notre CMS : les utilisateurs, les catégories, les articles et les pages. On n'en a pas pour autant terminé avec les données et on complètera plus tard avec la gestion des commentaires et autres fantaisies. Nous allons dans un prochain article pouvoir aborder le frontend en commençant par l'authentification.



Par bestmomo

Nombre de commentaires : 2

Article suivant : Mon CMS - L'authentification