Introduction
Lors d'un changement de configuration — renommage d'un projet et modification des paramètres de base de données dans un fichier .env — il est courant de rencontrer des erreurs inattendues, même sur une application Laravel parfaitement stable en temps normal.
Dans cet article, nous allons explorer un cas réel rencontré sur une stack composée de :
- Une application Laravel 11
- Exécutée via Docker Compose
- Utilisant Filament pour l'administration
- Et Spatie Laravel Permission pour la gestion des rôles et permissions
Nous verrons pourquoi une erreur 500 est apparue, pourquoi vider le cache ne suffisait pas, comment identifier précisément le problème, comment corriger la base de données, et comment attribuer correctement permissions et rôles.
1. Contexte initial
Le projet s'appelait initialement mon-projet-v1 et a été renommé en mon-projet-v2. Les actions suivantes ont été effectuées :
- Renommage du dossier du projet
- Modification du nom de la base de données dans le fichier
.env - Redémarrage des containers Docker
Tout semblait correct... jusqu'à l'accès à l'interface admin Filament.
2. L'erreur rencontrée
En accédant à /admin, Laravel retournait :
Internal Server Error
SQLSTATE[42S02]: Base table or view not found: 1146
Table 'mabaseprod.permissions' doesn't exist
Ce que cela signifie
Laravel essaie d'accéder à une table appelée permissions qui n'existe pas dans la nouvelle base de données. Or, cette table est fournie par le package Spatie Laravel Permission.
3. Pourquoi le problème est apparu
La cause principale est un changement de base de données sans synchronisation du schéma. En clair :
- La nouvelle base contient déjà certaines tables (ex :
users) - Mais pas toutes les tables nécessaires
- Notamment celles utilisées pour les permissions et rôles
Filament, lors de l'accès au panel admin, appelle la méthode suivante dans le modèle User :
public function canAccessPanel(Panel $panel): bool
{
return $this->hasPermissionTo('view_dashboard');
}
Cette méthode déclenche une requête SQL vers la table permissions. Comme elle n'existe pas, Laravel plante immédiatement avec une erreur 500.
Point clé : Filament vérifie les permissions avant même d'afficher quoi que ce soit. Si la table permissions n'existe pas, l'ensemble du panel est inaccessible.
4. Pourquoi un simple php artisan migrate a échoué
En tentant un classique :
php artisan migrate
Laravel a retourné :
SQLSTATE[42S01]: Base table or view already exists: 1050
Table 'users' already exists
Pourquoi ? Parce que :
- La base n'est pas vide
- Certaines migrations ont déjà été exécutées dans le passé
- Mais Laravel n'a aucune trace de ces migrations dans la table
migrations
Résultat : conflit entre l'état réel de la base et l'état attendu par Laravel.
5. Diagnostic : migrations Spatie manquantes
En listant les migrations disponibles dans le projet :
ls database/migrations | grep permission
On découvre :
create_permission_tables.phpest bien présente dans le dossier des migrations- Mais elle n'a jamais été exécutée dans cette nouvelle base
Le problème est donc ciblé : seules les tables de permissions sont absentes.
6. La bonne solution : migration ciblée
Plutôt que de tout migrer (et casser l'existant), on exécute uniquement la migration Spatie :
# Exécuter UNIQUEMENT la migration Spatie
php artisan migrate --path=database/migrations/2025_01_15_000000_create_permission_tables.php
Résultat : création des tables suivantes :
permissionsrolesmodel_has_permissionsmodel_has_rolesrole_has_permissions
Sans toucher aux autres tables existantes.
Astuce : L'option--pathdephp artisan migratepermet d'exécuter une migration spécifique sans affecter le reste du schéma. C'est extrêmement utile dans ce type de situation.
7. Nettoyage des caches (étape cruciale)
Après toute modification liée au .env, à la base de données ou aux permissions, il est impératif de vider les caches :
# Réinitialiser le cache des permissions Spatie
php artisan permission:cache-reset
# Vider tous les caches Laravel
php artisan optimize:clear
Pourquoi ?
- Laravel met en cache la configuration (fichier
.env, config) - Spatie met en cache les permissions pour éviter des requêtes SQL répétitives
- Filament met en cache certains éléments du panel admin
Si vous ne videz pas ces caches, Laravel pourrait continuer à utiliser d'anciennes valeurs même après la correction en base de données.
8. Création de la permission requise
Même avec les tables créées, elles sont vides. Or le code attend explicitement la permission view_dashboard. Création via Tinker :
php artisan tinker
>>> use Spatie\Permission\Models\Permission;
>>> Permission::create(['name' => 'view_dashboard']);
=> Spatie\Permission\Models\Permission {
name: "view_dashboard",
guard_name: "web",
id: 1,
}
9. Attribution de la permission à l'utilisateur
L'utilisateur administrateur doit avoir cette permission pour accéder au panel Filament :
# Toujours dans Tinker
>>> $user = App\Models\User::find(1);
>>> $user->givePermissionTo('view_dashboard');
# Vérification
>>> $user->hasPermissionTo('view_dashboard');
=> true
À partir de ce moment :
- La méthode
hasPermissionTo()retournetrue - Filament autorise l'accès au panel admin
- L'erreur 500 disparaît
10. Bonus : utiliser les rôles (bonne pratique)
Au lieu d'assigner des permissions directement à chaque utilisateur, la bonne pratique est de passer par des rôles. C'est plus maintenable et plus scalable :
php artisan tinker
>>> use Spatie\Permission\Models\Role;
>>> use Spatie\Permission\Models\Permission;
# Créer le rôle admin
>>> $role = Role::create(['name' => 'admin']);
# Lui attribuer la permission
>>> $role->givePermissionTo('view_dashboard');
# Assigner le rôle à l'utilisateur
>>> $user = App\Models\User::find(1);
>>> $user->assignRole('admin');
# Vérification
>>> $user->hasRole('admin');
=> true
>>> $user->hasPermissionTo('view_dashboard');
=> true
Avantages des rôles
- Plus lisible : un utilisateur a un rôle, pas 20 permissions individuelles
- Plus scalable : ajoutez une permission au rôle et tous les utilisateurs en bénéficient
- Plus sécurisé : gestion centralisée, moins de risques d'oubli
Récapitulatif : les commandes clés
Voici un résumé des commandes essentielles utilisées pour résoudre ce problème, dans l'ordre :
# 1. Migration ciblée (Spatie uniquement)
php artisan migrate --path=database/migrations/2025_01_15_000000_create_permission_tables.php
# 2. Vider les caches
php artisan permission:cache-reset
php artisan optimize:clear
# 3. Créer la permission et l'attribuer (via Tinker)
php artisan tinker
>>> Permission::create(['name' => 'view_dashboard']);
>>> $user = App\Models\User::find(1);
>>> $user->givePermissionTo('view_dashboard');
Leçons à retenir
Ce qui a causé le problème
- Changement de base de données sans re-migration complète
- Migrations incomplètes (tables partiellement présentes)
- Dépendance forte de Filament aux permissions Spatie
Ce qui ne suffisait pas
- Vider le cache uniquement (
optimize:clear) - Redémarrer Docker sans migrer
- Lancer un
php artisan migrateglobal (conflit avec les tables existantes)
Ce qui a réellement résolu le problème
- Identifier précisément la table manquante via le message d'erreur
- Exécuter la migration ciblée avec
--path - Recréer les permissions et rôles nécessaires
- Vider tous les caches (Laravel + Spatie)
Conclusion
Ce type de problème est plus fréquent qu'on ne le pense, surtout dans les environnements Docker où l'on peut facilement switcher de base de données. La clé est de ne pas paniquer face à l'erreur 500, de lire attentivement le message d'erreur, et de procéder méthodiquement : identifier ce qui manque, corriger de manière ciblée, et ne pas oublier de vider les caches.
Avec Spatie Permission et Filament, les permissions sont au cœur du fonctionnement de l'admin. Une simple table absente peut bloquer tout le panel. Gardez toujours vos migrations à jour et pensez à documenter les étapes de setup pour vos collègues (ou votre futur vous) !
Conseil : Après tout changement majeur de configuration (renommage de projet, switch de BDD, mise à jour de packages), prenez l'habitude de lancer php artisan migrate --status pour vérifier que toutes les migrations sont bien exécutées.