Structure d'un projet Laravel
Bloc Laravel · séance 1 · ~40 min
Le projet premier-test-laravel, créé au chapitre Installation et complété au chapitre MVC, compte vingt-huit éléments à sa racine, dossiers cachés compris. Vous modifierez surtout le code de app/, les routes de routes/ et les vues de resources/views/.
D'autres dossiers contiennent la configuration ou des fichiers créés pendant l'installation et le fonctionnement de l'application. Le modèle, le contrôleur et la vue créés à l'exercice 3 du chapitre MVC doivent être présents dans votre projet.
À la fin de ce chapitre, vous serez capables de :
- dire à quoi sert chaque dossier de la racine d'un projet Laravel 13,
- retrouver où ranger un contrôleur, un modèle, une vue ou une modification de la base, et avec quelle commande les créer,
- expliquer le trajet d'une requête fichier par fichier, de
public/index.phpjusqu'à la vue, - distinguer les fichiers que vous modifiez de ceux que vous ne touchez jamais,
- reconnaître
$fillable, la liste des colonnes que Laravel peut remplir, sous ses deux écritures.
1. La racine
La racine d'un projet est le dossier qui contient tous ses fichiers et ses sous-dossiers. La commande laravel new a créé celle de premier-test-laravel en septembre 2026. Elle a utilisé Pest, le lanceur de tests, et npm, l'outil qui installe les paquets JavaScript.
premier-test-laravel/
├── .editorconfig réglages de l'éditeur
├── .git/ historique git
├── .env vos réglages, hors git
├── .env.example modèle de .env, versionné
├── .gitattributes réglages git
├── .gitignore ce que git ignore
├── .npmrc réglages npm
├── AGENTS.md consignes pour agents IA
├── CLAUDE.md même texte
├── README.md présentation
├── app/ votre code PHP
├── artisan console de Laravel
├── bootstrap/ démarrage
├── composer.json dépendances PHP
├── composer.lock versions exactes
├── config/ configuration
├── database/ la base de données
├── node_modules/ paquets npm
├── package-lock.json versions exactes npm
├── package.json dépendances JavaScript
├── phpunit.xml configuration des tests
├── public/ ce que voit le navigateur
├── resources/ vues, CSS, JavaScript
├── routes/ les routes
├── storage/ fichiers générés
├── tests/ les tests Pest
├── vendor/ paquets Composer
└── vite.config.js configuration de Vite

2. Les fichiers de la racine
.env et .env.example
Une variable d'environnement contient un réglage propre à la machine sur laquelle l'application fonctionne. Votre ordinateur peut utiliser SQLite tandis que le serveur utilise MySQL. Au démarrage, Laravel lit ces valeurs dans .env. Vous pouvez ainsi changer la base, l'adresse du site ou un mot de passe sans modifier les classes de l'application.
Le fichier .env.example contient les noms des variables nécessaires au projet et des valeurs utilisables sans secret.
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000
…
DB_CONNECTION=sqlite
…
SESSION_DRIVER=database
QUEUE_CONNECTION=database
CACHE_STORE=database
…
MAIL_MAILER=log
Dans cet exemple, APP_KEY est donc vide. Pendant l'installation, la commande a copié .env.example vers .env, puis elle a créé une clé propre au projet. Sur un serveur de production, .env contient les mots de passe de la base et des services. Le fichier .gitignore empêche Git d'enregistrer trois fichiers qui pourraient contenir ces secrets.
.env
.env.backup
.env.production
N'enregistrez jamais .env dans Git. Quand votre application a besoin d'une nouvelle variable, ajoutez son nom dans .env.example sans y placer de valeur secrète.
artisan
artisan est le fichier qui lance Artisan, l'outil en ligne de commande vu au chapitre Installation. Ses commandes peuvent créer un fichier, lancer un test ou afficher des informations sur le projet. La commande php artisan about affiche notamment les versions installées et les principaux réglages actifs.
Environment ................................................................
Application Name ................................................... Laravel
Laravel Version .................................................... 13.33.0
PHP Version ......................................................... 8.4.21
Composer Version ..................................................... 2.8.6
Environment .......................................................... local
Debug Mode ......................................................... ENABLED
URL ......................................................... localhost:8000
…
Chez vous, la ligne Application Name affiche Premier test, le nom choisi à l'exercice 2 du chapitre Installation. Sous Herd ou Laragon, la ligne URL affiche premier-test-laravel.test.
composer.json
Le fichier composer.json indique les paquets PHP nécessaires au projet et la manière de charger vos classes. Dans premier-test-laravel, ses parties require et autoload contiennent ces lignes.
"require": {
"php": "^8.3",
"laravel/framework": "^13.17",
"laravel/tinker": "^3.0"
},
…
"autoload": {
"psr-4": {
"App\\": "app/",
…
}
},
Une dépendance est un paquet dont le projet a besoin pour fonctionner. Laravel apparaît donc dans la partie require de composer.json.
Un espace de noms est le début du nom complet d'une classe, comme App\Models dans App\Models\User. La règle PSR-4 relie cet espace de noms au dossier qui contient le fichier de la classe. La ligne "App\\": "app/" permet ainsi de retrouver App\Models\User dans app/Models/User.php.
La partie scripts de composer.json associe des noms courts à des commandes. Vous lancez directement composer run setup pour préparer un projet copié depuis un dépôt Git. composer run dev démarre le serveur et composer run test lance les tests. D'autres noms commencent par pre- ou post-. Composer exécute ces scripts avant ou après une opération précise. Par exemple, post-install-cmd est exécuté après composer install.
package.json et vite.config.js
Le fichier package.json liste les paquets JavaScript du projet, dont Vite, l'outil qui prépare les fichiers chargés par le navigateur. La version installée est Vite 8. Le fichier vite.config.js lui indique de partir de resources/css/app.css et de resources/js/app.js. Vite lit aussi les fichiers auxquels ces deux sources font référence. La commande npm run build écrit le CSS et le JavaScript obtenus dans public/build/.
Le même fichier liste Tailwind CSS 4 et ses extensions.
Les autres fichiers
Le fichier phpunit.xml contient les réglages utilisés pendant les tests. AGENTS.md et CLAUDE.md contiennent le même texte pour les agents IA de programmation. Ce texte leur demande d'installer Laravel Boost, un paquet qui fournit à ces agents des informations sur le projet et les conventions de Laravel.
3. Les dossiers
app/ : votre code
Dans un projet neuf, app/ contient trois fichiers : Http/Controllers/Controller.php, Models/User.php et Providers/AppServiceProvider.php. Votre projet premier-test-laravel contient aussi PostController.php et Post.php, créés au chapitre MVC.
Controller.php contient la classe abstraite vide vue au chapitre Framework et librairie. Votre PostController, créé au chapitre MVC, en hérite. Le dossier Models/ contient une classe par table, comme Post pour la table posts.
Le dossier Providers/ contient les fournisseurs de services. Laravel exécute ces classes pendant son démarrage pour enregistrer ou configurer une classe utilisée ailleurs. Un fournisseur peut, par exemple, indiquer quelle classe doit envoyer les courriels de l'application.
Un projet neuf ne contient pas tous les sous-dossiers possibles de app/. Lorsqu'une commande Artisan crée un premier fichier d'un certain type, elle crée aussi le dossier prévu pour ce type s'il n'existe pas.
php artisan make:event DemoEvent
INFO Event [app/Events/DemoEvent.php] created successfully.
Avant cette commande, app/ contient Http, Models et Providers. make:event crée le dossier app/Events/ et le fichier DemoEvent.php. Supprimez ensuite app/Events/, puisque ce fichier sert uniquement à cet essai. Les commandes make:job, make:mail et make:policy créent de la même manière les dossiers prévus pour leurs fichiers.
Vous pouvez aussi créer app/Services/ vous-même. Le chargement automatique permet à Composer de trouver une classe à partir de son nom complet. Composer trouvera App\Services\Mailer si la classe se trouve dans app/Services/Mailer.php et déclare l'espace de noms App\Services.
routes/
Dans un projet neuf, le dossier routes/ contient seulement web.php et console.php. Dans web.php, chaque route associe une adresse et une méthode HTTP au code qui doit traiter la requête.
Route::get('/', function () {
return view('welcome');
});
Le fichier console.php permet de définir de courtes commandes Artisan, comme inspire. Le fichier api.php n'existe pas dans un projet neuf. La commande php artisan install:api le crée si l'application en a besoin.
La commande php artisan route:list affiche l'adresse, la méthode HTTP et le code associé à chaque route.
GET|HEAD / ............................................... routes/web.php:6
GET|HEAD posts ....................................... PostController@index
GET|HEAD storage/{path} storage.local › vendor/laravel/framework/src/Illum…
PUT storage/{path} storage.local.upload › vendor/laravel/framework/sr…
GET|HEAD up vendor/laravel/framework/src/Illuminate/Foundation/Configurati…
Showing [5] routes
La route posts a été ajoutée au chapitre MVC. Laravel enregistre lui-même les deux routes storage/{path} : elles servent les fichiers du disque local, le dossier storage/app/private, à condition que l'adresse porte une signature que Laravel a fabriquée. Vous n'avez pas besoin de les modifier, et vous ne les utiliserez pas dans ce cours.
resources/
Le dossier views/ contient les vues Blade dont le nom se termine par .blade.php. Les dossiers css/ et js/ contiennent les fichiers que Vite lit avant de produire ceux de public/build/.
Le nom passé à view() part de resources/views/ et omet l'extension .blade.php. Dans view('posts.index'), posts désigne le sous-dossier et index désigne le fichier. Laravel ouvre donc resources/views/posts/index.blade.php, la vue créée au chapitre MVC.
Les fichiers de traduction ne se trouvent pas dans resources/. La commande php artisan lang:publish crée le dossier lang/ à la racine pour les recevoir.
database/
Une migration est un fichier PHP qui décrit une modification de la structure de la base. Le dossier migrations/ contient les trois fichiers exécutés par l'installeur pour créer users, cache et jobs. Il contient aussi la migration de posts, ajoutée au chapitre MVC.
Une fabrique crée des objets remplis de données fictives pour les tests. Celle des utilisateurs se trouve dans factories/UserFactory.php. Un seeder ajoute des données de départ dans la base. Le fichier principal est seeders/DatabaseSeeder.php.
Le fichier database.sqlite contient la base SQLite elle-même. La règle inscrite dans database/.gitignore empêche Git de l'enregistrer.
config/
Dix fichiers, un par sujet, de app.php à session.php. Extrait de config/app.php :
'name' => env('APP_NAME', 'Laravel'),
…
'env' => env('APP_ENV', 'production'),
Les fichiers de config/ lisent .env avec env(). Dans env('APP_NAME', 'Laravel'), la seconde valeur est utilisée lorsque APP_NAME n'en contient aucune. Les contrôleurs et les autres classes lisent ensuite ce réglage avec config('app.name').
Un cache de configuration est un fichier qui contient des réglages déjà rassemblés. Sur un serveur de production, la commande php artisan config:cache écrit ces valeurs dans bootstrap/cache/config.php pour accélérer le démarrage. Au démarrage suivant, Laravel charge ce fichier au lieu de relire .env et les fichiers de config/. Un appel direct à env('APP_NAME') dans un contrôleur renvoie alors null, tandis que config('app.name') lit la valeur préparée. Utilisez env() dans config/ et config() dans les autres classes.
public/ : la racine web
La racine web est le dossier dans lequel le serveur cherche les fichiers demandés par le navigateur. Pour ce projet, Herd et Laragon utilisent premier-test-laravel/public à l'adresse premier-test-laravel.test. Le navigateur peut donc recevoir favicon.ico, robots.txt et les fichiers de build/. Il ne peut pas demander directement .env ni les classes de app/, qui se trouvent en dehors de public/.
Le fichier public/index.php reçoit les requêtes qui ne visent pas un fichier présent dans public/. Le fichier .htaccess donne cette règle au serveur Apache.
bootstrap/
Le fichier app.php prépare Laravel et lui indique notamment où trouver les routes. Le fichier providers.php donne la liste des fournisseurs de services à exécuter pendant ce démarrage.
return [
AppServiceProvider::class,
];
La commande php artisan config:cache, par exemple, écrit dans bootstrap/cache/ le fichier que Laravel relira au prochain démarrage.
storage/, tests/, vendor/
Le dossier storage/ reçoit les fichiers que Laravel produit pendant le fonctionnement. Les fichiers conservés par l'application vont dans storage/app/.
Laravel place ses fichiers de travail dans storage/framework/. Vous y trouvez les caches, les données conservées entre deux requêtes d'un même navigateur et les vues déjà transformées en PHP.
Un journal est un fichier dans lequel Laravel écrit ses erreurs et ses messages. Le journal principal se trouve dans storage/logs/laravel.log. La commande composer run dev lance Pail, l'outil qui lit ce journal et affiche les nouvelles lignes dans le terminal. Pail crée aussi storage/pail/.
Le dossier tests/ contient Feature/, Unit/, TestCase.php et Pest.php. Un test unitaire vérifie une classe seule et se place dans Unit/. Un test de fonctionnalité vérifie plusieurs parties de l'application ensemble, par exemple en envoyant une requête HTTP. La commande make:test crée ce second type de test dans Feature/ par défaut.
Le dossier vendor/ contient les paquets PHP installés par Composer. La commande composer install peut le recréer à partir de composer.lock.
Où ranger quoi
| Je veux ajouter… | php artisan … |
Fichier créé |
|---|---|---|
| un contrôleur | make:controller CommentController |
app/Http/Controllers/CommentController.php |
| un modèle | make:model Comment |
app/Models/Comment.php |
| une migration | make:migration create_comments_table |
database/migrations/2026_09_26_140158_create_comments_table.php |
| une vue | make:view comments.index |
resources/views/comments/index.blade.php |
| un test | make:test CommentTest |
tests/Feature/CommentTest.php |
| une commande Artisan | make:command PublishPosts |
app/Console/Commands/PublishPosts.php |
Artisan place au début du nom de la migration la date et l'heure auxquelles vous lancez la commande.
4. Le trajet d'une requête, fichier par fichier
Quand le navigateur demande http://premier-test-laravel.test/, le serveur cherche d'abord un fichier correspondant dans la racine web. Comme cette adresse ne désigne aucun fichier public, le serveur exécute public/index.php.
…
// Register the Composer autoloader...
require __DIR__.'/../vendor/autoload.php';
// Bootstrap Laravel and handle the request...
/** @var Application $app */
$app = require_once __DIR__.'/../bootstrap/app.php';
$app->handleRequest(Request::capture());
La première instruction charge vendor/autoload.php. Quand PHP rencontre un nom de classe, le chargeur de Composer utilise la règle PSR-4 pour trouver et ouvrir son fichier. La deuxième instruction ouvre bootstrap/app.php, qui crée l'objet représentant l'application.
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
…
L'appel à withRouting donne à Laravel le chemin de routes/web.php et celui de routes/console.php. La ligne health: '/up' enregistre aussi la route /up affichée par php artisan route:list.
Dans public/index.php, Request::capture() rassemble l'adresse, la méthode HTTP et les données reçues. La méthode handleRequest() reçoit cet objet et compare ensuite l'adresse / aux routes de routes/web.php. La route correspondante exécute view('welcome'). Laravel ouvre alors resources/views/welcome.blade.php et utilise son contenu pour produire la réponse HTML.
Pour afficher /posts, le serveur commence aussi par public/index.php. Ce fichier active le chargement automatique, puis ouvre bootstrap/app.php. Laravel lit alors routes/web.php et trouve PostController::index().
La méthode index() demande les articles à la classe Post, puis choisit la vue avec view('posts.index'). Laravel ouvre donc resources/views/posts/index.blade.php. Blade parcourt les articles reçus dans $posts et produit le HTML envoyé au navigateur.
Le fichier artisan ouvre lui aussi bootstrap/app.php. Il transmet toutefois une commande à handleCommand au lieu de transmettre une requête HTTP à handleRequest.

5. Ce qu'on modifie, ce qu'on ne touche jamais
| Vous écrivez dans | Vous ne touchez jamais à |
|---|---|
app/, routes/, resources/, database/, tests/ |
vendor/, recréé par composer install |
config/ |
node_modules/, recréé par npm install |
.env et .env.example |
bootstrap/cache/, généré par Laravel |
composer.json via composer require |
storage/framework/, généré par Laravel |
public/build/, produit par npm run build |
composer install recrée vendor/, tandis que npm install recrée node_modules/. Laravel recrée bootstrap/cache/ et storage/framework/ quand il en a besoin. La commande npm run build remplace le contenu de public/build/. Une modification manuelle dans l'un de ces dossiers disparaît donc à la génération suivante.
6. Deux écritures de $fillable
Le modèle Post lu au chapitre 0 de la POO déclarait protected $fillable = ['title', 'body'];. Celui que vous avez créé au chapitre MVC ne déclare encore rien. Dans Laravel 13, le fichier User.php utilise une autre écriture.
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable
#[Fillable(...)] est un attribut PHP, une information attachée à une classe que Laravel peut lire. Ici, cet attribut remplace la propriété protected $fillable = [...]. Les deux écritures indiquent les colonnes que Laravel peut remplir à partir d'un ensemble de données, comme celles d'un formulaire validé.
Le modèle Post créé au chapitre MVC ne contient encore ni cette propriété ni cet attribut. L'exercice utilise donc forceCreate(). Cette méthode remplit le nouvel article et l'enregistre sans consulter la liste des colonnes autorisées.
À retenir
- Vous placez le code PHP dans
app/, les routes dansroutes/et les vues dansresources/views/. - Le fichier
.envcontient les réglages de votre machine et ne doit jamais être enregistré dans Git. - Le dossier
public/est la racine web, etpublic/index.phpreçoit les requêtes qui ne visent aucun fichier public. - Une commande
make:crée le fichier demandé et son dossier si celui-ci n'existe pas encore. - Les outils recréent
vendor/,node_modules/,bootstrap/cache/,storage/framework/etpublic/build/. Vous ne modifiez donc pas leur contenu.
Exercices
1. Chasse au trésor
Dans premier-test-laravel, trouvez chaque fichier. Affichez ensuite la réponse de la carte pour vérifier son chemin.
2. Les générateurs
Dans premier-test-laravel, lancez php artisan list make, puis comptez les commandes dont le nom commence par make:. Lancez ensuite php artisan make:job SendNewsletter et php artisan make:enum Status. Regardez dans app/ quel fichier chaque commande a créé et si un nouveau dossier est apparu. Supprimez enfin ces deux fichiers et le dossier devenu vide.
3. Sur papier : où ranger ces fichiers ?
Écrivez le chemin complet de chaque fichier dans premier-test-laravel. Les étiquettes, ou tags, servent à classer les articles.
TagController.php- le modèle
Tag.php 2026_10_05_120000_create_tags_table.php- la vue appelée par
view('tags.index') TagTest.php, un test de fonctionnalitéTagSeeder.php