Ok, maintenant la base de votre application est installée.
Nous pouvons nous plonger dans quelque chose de plus concret.
Ce dont nous avons besoin pour gérer nos liens.
Rappelez-vous ce que j'ai dit dans la première partie :
- un utilisateur peut s'identifier, se connecter, se déconnecter et gérer son compte
- un utilisateur peut voir la liste des liens qui lui sont associés
- un utilisateur peut ajouter, modifier ou supprimer un lien
- un utilisateur peut avoir un lien partageable pour partager ses liens avec le monde entier
- un lien a un nom, un statut (publié ou non) et évidemment une url. Nous ajouterons peut-être d'autres options plus tard.
Cela est fait nativement avec Filament. En fait, pas complètement, on peut se connecter, se déconnecter mais pas s'enregistrer ni même gérer son propre compte.
Mais vous verrez qu'il est très facile d'ajouter une page d'inscription et une page de profil pour les utilisateurs.
Dans app/Providers/Filament/AdminPanelProvider.php
il suffit d'ajouter 2 lignes sous l'appel à la fonction login() pour implémenter les deux fonctionnalités :
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('admin')
->login()
// Lesson 2 : here we add registration and profile page
->registration() // registration
->profile() // profile management
->colors([
'primary' => Color::Amber,
])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->pages([
Pages\Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
]);
}
}
Retournez sur la page de login : http://linkeeper.com/admin/login
et vous verrez
que le lien pour l'inscription a été ajouté.
Si vous vous connectez, vous verrez sous votre menu le nouveau sous-menu 'Profil'
Il vous permet de modifier votre pseudo, votre adresse e-mail et de changer votre mot de passe.
Donc, après cette étape très rapide, nous pouvons vérifier la première fonctionnalité :
✅ un utilisateur peut s'identifier, se connecter, se déconnecter et gérer son compte
- un utilisateur peut voir la liste des liens qui lui sont associés
- un utilisateur peut ajouter, modifier ou supprimer un lien
- un utilisateur peut avoir un lien partageable pour partager ses liens avec le monde entier
- un lien a un nom, un statut (publié ou non) et évidemment un lien. Nous ajouterons peut-être d'autres options plus tard.
Je sais que ce n'est pas dans l'ordre de la liste, mais d'abord c'est moi qui écris, ensuite j'ai besoin de définir la table links
et ses champs avant qu'un utilisateur puisse ajouter un lien, n'est-ce pas ?
Alors laissez-moi faire ! 🤣
Ok, quels seront les champs de notre table links
?
Bien sûr un id
, une url
, une courte description
, un statut published
(publié ou non), une clé étrangère user_id
et enfin les classiques created_at
et updated_at
.
Le user_id
sert à définir la relation entre un utilisateur et un lien.
En fait, nous pouvons résumer cette relation par :
id
) appartient à un et un seul utilisateurC'est pourquoi nous utilisons une relation one-to-many.
Qu'en pensez-vous, y a-t-il quelque chose qui manque ? Dites-moi dans les commentaires si vous pensez que j'ai oublié quelque chose.
Ok, maintenant nous devons créer la migration pour la table links
.
php artisan make:migration create_links_table
À présent nous devons éditer cette migration pour ajouter les champs à la table. Donc, éditons cette migration :
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('links', function (Blueprint $table) {
$table->id();
$table->string('url');
$table->string('description', 255)->nullable();
$table->boolean('published')->default(false);
$table->foreignId('user_id')->constrained('users')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('links');
}
};
Ok, il est temps de migrer. Pour cela, nous allons utiliser (encore) Artisan.
php artisan migrate
Rappelez vous que si vous faites une erreur ou que vous voulez modifier votre le schéma de votre table, vous pouvez rollback votre migration avec :
php artisan migrate:rollback
Et si vous voulez voir le statis de vos migrations, vous pouvez utiliser :
php artisan migrate:status
Regardez ce screenshot capturé avant de lancer la dernière migration.
On peut y voir deux choses :
links
n'a pas encore été exécutéeL'étape suivante consiste à définir le modèle Link
et à adapter le modèle User
.
Nous utiliserons à nouveau Artisan :
php artisan make:model Link
Nous devons maintenant indiquer au modèle qu'un lien appartient à un utilisateur.
Ajoutez cette fonction à la classe de modèle Link
:
public function user()
{
return $this->belongsTo(User::class);
}
Pour terminer avec le modèle, nous devons mettre à jour le modèle User
en lui ajoutant une fonction links
public function links()
{
return $this->hasMany(Link::class);
}
Après avoir défini notre schéma de base de données, faisons quelque chose de très important.
Créons de fausses données pour jouer avec notre application. De grâce, n'utilisez pas les données de production de votre base de données pendant le développement, pour de nombreuses raisons telles que l'éthique, la confidentialité et la sécurité.
Nous sommes des professionnels, alors agissons en conséquence.
Par défaut, Laravel est livré avec la factory User
, nous avons donc juste besoin de créer une factory Link
.
php artisan make:factory Link
Dans la fonction definition
générée, on ajoute ce code :
public function definition(): array
{
return [
'url' => fake()->url(),
'description' => fake()->sentence(5),
'published' => fake()->boolean(80),
];
}
Les factories utilisent Faker pour générer des données fausses mais très proches de données réelles.
Dans ce code, nous générons :
sentence
par défaut (true), sentence va générer des phrases d'environ 5 mots. Cela peut être quatre, cinq, six ou même sept mots.published
avec un pourcentage minimum de true de 80%.Laravel est livré avec database/seeders/DatabaseSeeder.php
Nous devons l'éditer pour utiliser notre usine.
Voici le code :
/**
* Seed the application's database.
*/
public function run(): void
{
User::factory()->create([
'name' => 'Happytodev',
'email' => 'happytodev@gmail.com',
'email_verified_at' => now(),
'password' => Hash::make('Password*'),
'remember_token' => Str::random(10),
]);
User::factory()
->count(10)
->create()
->each(function ($user) {
Link::factory()
->count(rand(2, 10))
->create(['user_id' => $user->id]);
});
}
Quelques explications :
user_id
doivent être remplis avec le user->id
qui vient d'être crée par la boucle each
.Et maintenant, la magie peut commencer.
Revenons dans votre terminal, et lançons simplement cette commande :
php artisan db:seed
Allez dans votre visualateur de base de données préféré, et vérifiez le contenu des tables users
et links
.
Vous devriez voir quelque chose comme ceci :
table users
table links
Si vous voulez vérifier que tout fonctionne bien, allons faire une ballade dans Tinker.
php artisan tinker
Tinker nous permet de jouer avec nos données et de vérifier que la relation fonctionne correctement.
User::find(6)->links()->get(['id', 'url', 'published', 'user_id']);
Ici, nous demandons de trouver tous les liens pour l'utilisateur avec id = 6. Nous demandons également de ne récupérer que les champs intéressants.
En voyant ces résultats, nous pouvons immédiatement améliorer quelque chose.
Et si nous ne voulions que les liens publiés ?
On peut alors procéder comme suit :
> User::find(6)->links()->where('published', 1)->get(['id', 'url', 'published', 'user_id']) ;
Mais il y a une meilleure façon de faire cela et de ne pas se répéter plus tard. Nous pouvons utiliser des scopes.
Un scope peut ajouter une série de requêtes à votre requête. Les scopes peuvent être globaux ou locaux. Je vous laisse consulter [la documentation] (https://laravel.com/docs/11.x/eloquent#query-scopes) pour en savoir plus.
Ici, nous allons utiliser un scope local.
Allez dans votre modèle link
et ajoutez cette fonction :
/**
* Scope a query to only include published links.
*/
public function scopePublished(Builder $query): void
{
$query->where('published', 1);
}
Maintenant, si on utilise la requête suivante dans Tinker :
User::find(6)->links()->published()->get(['id', 'url', 'published', 'user_id']);
on obtiendra uniquement les liens publiés pour l'utilisateur avec l'id = 6.
Et voilà, on peut valider un autre point sur notre liste :
✅ un utilisateur peut s'identifier, se connecter, se déconnecter et gérer son compte
- un utilisateur peut voir la liste des liens qui lui sont associés
- un utilisateur peut ajouter, modifier ou supprimer un lien
- un utilisateur peut avoir un lien partageable pour partager ses liens avec le monde entier
✅ un lien a un nom, un statut (publié ou non) et évidemment un lien. Nous ajouterons peut-être d'autres options plus tard.
Nous allons nous arrêter là pour aujourd'hui.
Dans ce chapitre plus long, nous avons fait les premiers pas pour découvrir :
Comme d'habitude, j'attends vos commentaires ci-dessous.
A bientôt.
This article also exists in English version 🇬🇧