Chapitre 4.4 — L’outillage du développeur Moodle
Vous avez maintenant un Moodle 5.2 qui tourne sous moodle-docker dans WSL2, le code source dans ~/moodle, et VS Code connecté en Remote-WSL. Techniquement, vous pourriez commencer à écrire du code dès maintenant. En pratique, vous iriez droit dans le mur — et pas pour des raisons de compétence.
Moodle est un logiciel conçu pour servir des dizaines de milliers d’utilisateurs sur des serveurs mutualisés parfois modestes. Pour y arriver, il met en cache absolument tout : les chaînes de langue, le JavaScript minifié, le CSS compilé, les templates Mustache, les définitions de plugins, les configurations… Par défaut, il masque aussi les erreurs PHP et se comporte comme un serveur de production discret et opaque. C’est exactement l’inverse de ce dont un développeur a besoin.
Ce chapitre transforme votre installation « prête pour la production » en véritable environnement de développement : mode debug maximal, caches désactivés ou purgés à la demande, débogueur pas à pas avec XDebug, CLI d’administration, générateurs de données de test, et deux outils tiers qui vont vous faire gagner des heures : moosh et MDK.
💡 Pour un dev React : ce chapitre est l’équivalent de la mise en place de votre DX sur un projet Next.js —
next devavec Fast Refresh, ESLint, le debugger Node attaché à VS Code, et vos scriptspackage.json. Moodle n’a pas de commande magique unique qui active tout ça : il faut le configurer soi-même, une fois pour toutes. C’est l’objet de ce chapitre.
Mini-sommaire
- Philosophie : le cache est votre ennemi n°1 en développement
- Le mode debug : configurer config.php pour le développement
- Purger les caches : quand, pourquoi, comment
- moosh : le couteau suisse en ligne de commande
- MDK : le Moodle Development Kit
- XDebug 3 + VS Code : le débogage pas à pas
- VS Code : extensions et réglages pour Moodle
- Les scripts admin/cli incontournables
- Générer des données de test avec tool_generator
- Le workflow quotidien : table symptôme → outil
4.4.1 — Philosophie : le cache est votre ennemi n°1 en développement
Commençons par le piège dans lequel tombe chaque développeur Moodle débutant, sans exception. Vous modifiez un fichier — une chaîne de langue, un template Mustache, un fichier JavaScript — vous rechargez la page… et rien ne change. Vous vérifiez votre code : il est correct. Vous rechargez encore. Rien. Vous videz le cache du navigateur. Toujours rien. Vous commencez à douter de votre installation, de Docker, de vous-même.
Le coupable, dans 95 % des cas : un cache côté serveur de Moodle.
Moodle maintient plusieurs couches de cache indépendantes :
| Couche de cache | Ce qu’elle stocke | Symptôme quand elle est périmée |
|---|---|---|
| MUC (Moodle Universal Cache) | Données applicatives : configs, infos de cours, résultats de requêtes coûteuses | Données obsolètes affichées, comportements incohérents |
| Cache de langue | Les chaînes de tous les fichiers lang/ fusionnées et sérialisées | Votre nouvelle chaîne get_string() affiche [[monidentifiant]] ou l’ancienne valeur |
| Cache JavaScript | Les modules AMD minifiés et concaténés | Votre JS modifié n’est jamais exécuté (Moodle sert amd/build/*.min.js, pas amd/src/) |
| Cache des templates | Les templates Mustache compilés en closures PHP | Votre modification de .mustache est invisible |
| Cache du thème | Le SCSS compilé en CSS, avec un numéro de révision dans l’URL | Votre CSS ne s’applique pas |
| Cache des plugins | La liste des plugins installés et leurs versions | Votre nouveau plugin n’apparaît pas, vos changements de version.php sont ignorés |
Chacune de ces couches existe pour une excellente raison en production : compiler un thème SCSS prend plusieurs secondes, parser tous les fichiers de langue de 400 plugins aussi. Mais en développement, ces caches transforment chaque itération en séance de spiritisme.
💡 Pour un dev React : purger les caches Moodle, c’est exactement votre réflexe
rm -rf .next && npm run devquand Next.js sert un build fantôme, ourm -rf node_modules/.vite. La différence : avec Moodle, ce réflexe doit devenir quotidien, et il existe des réglages pour désactiver certains caches en amont — l’équivalent d’un « mode dev » permanent.
La stratégie que nous allons mettre en place tient en trois volets :
- Désactiver les caches qui peuvent l’être sans rendre le site inutilisable (langue, JS, templates) via
config.php; - Purger à la demande ceux qui ne peuvent pas être désactivés (MUC, plugins) via un alias shell d’une seule commande ;
- Activer ponctuellement le « theme designer mode » quand on travaille sur du SCSS, et le désactiver sitôt fini (il est très lent).
Gardez ce principe en tête pour toute la suite de la documentation : quand votre code ne semble pas pris en compte, suspectez d’abord un cache, jamais votre code. Vous économiserez des heures.
⚠️ Piège : le cache du navigateur peut se superposer aux caches Moodle. Pendant le développement, gardez les DevTools ouverts avec « Disable cache » coché, comme vous le faites déjà en front. Mais retenez que vider uniquement le cache navigateur ne suffit presque jamais : le problème est côté serveur.
4.4.2 — Le mode debug : configurer config.php pour le développement
Le bloc à coller dans config.php
Ouvrez le config.php à la racine de votre projet (~/moodle/config.php — rappel du chapitre précédent : depuis Moodle 5.1, le code web vit dans public/, mais config.php reste à la racine du dépôt). Ajoutez ce bloc avant la ligne require_once(__DIR__ . '/public/lib/setup.php'); :
//=========================================================================
// RÉGLAGES DE DÉVELOPPEMENT — NE JAMAIS DÉPLOYER EN PRODUCTION
//=========================================================================
// PHP lui-même : afficher toutes les erreurs, y compris avant que Moodle
// n'ait fini de démarrer (fatales dans setup.php, etc.).
@error_reporting(E_ALL);
@ini_set('display_errors', '1');
// Niveau de débogage Moodle : DEBUG_DEVELOPER, le maximum.
$CFG->debug = (E_ALL | E_STRICT); // = 32767 = DEBUG_DEVELOPER
$CFG->debugdisplay = 1; // afficher les messages dans la page (pas seulement les logs)
// Footer de performance : requêtes SQL, mémoire, temps de génération.
$CFG->perfdebug = 15;
// Informations de contexte de page dans le footer (nom de la page, layout, etc.).
$CFG->debugpageinfo = 1;
// Permettre l'affichage des identifiants de chaînes de langue avec ?strings=1.
$CFG->debugstringids = 1;
// Désactiver les caches "désactivables".
$CFG->langstringcache = 0; // chaînes de langue relues à chaque requête
$CFG->cachejs = false; // servir amd/src/ non minifié au lieu de amd/build/
$CFG->cachetemplates = false; // recompiler les templates Mustache à chaque requête
// Afficher la sortie détaillée du cron quand on le lance à la main.
$CFG->showcrondebugging = true;
// Theme designer mode : SCSS recompilé à CHAQUE requête. Très lent.
// À activer uniquement pendant une session de travail sur un thème.
// $CFG->themedesignermode = true;
//=========================================================================Sauvegardez, rechargez n’importe quelle page de votre Moodle : vous devez voir apparaître en bas de page un footer bourré d’informations techniques (temps de génération, nombre de requêtes SQL, RAM consommée). Si c’est le cas, votre mode développeur est actif.
⚠️ Piège : tout réglage écrit « en dur » dans
config.phpest verrouillé : la page d’administration correspondante affichera la valeur grisée avec la mention « Défini dans config.php » et vous ne pourrez plus la modifier via l’interface ni via la tablemdl_config. C’est voulu — et c’est pour ça qu’on préfèreconfig.phpà l’UI en développement : la valeur survit aux réinstallations de la base et personne ne peut la changer par accident. Mais si un jour un réglage semble « impossible à modifier », vérifiez d’abord votreconfig.php.
Comprendre $CFG->debug et ses paliers
$CFG->debug est un masque de bits calqué sur les niveaux d’erreur PHP (E_ALL, E_WARNING, etc.). Moodle définit cinq constantes de commodité :
| Constante | Valeur | Ce qui est remonté | Usage typique |
|---|---|---|---|
DEBUG_NONE | 0 | Rien | Production paranoïaque |
DEBUG_MINIMAL | 5 | Erreurs fatales et avertissements critiques (E_ERROR | E_PARSE) | Production |
DEBUG_NORMAL | 15 | + warnings et notices importantes (E_ERROR | E_PARSE | E_WARNING | E_NOTICE) | Préproduction |
DEBUG_ALL | E_ALL | Toutes les erreurs PHP | Débogage ponctuel |
DEBUG_DEVELOPER | E_ALL | E_STRICT = 32767 | Tout, plus les messages internes que Moodle réserve aux développeurs | Développement |
Le point important : DEBUG_DEVELOPER ne se contente pas d’afficher les erreurs PHP. Quand ce niveau est actif, Moodle lui-même devient bavard : les appels à des fonctions dépréciées déclenchent des avertissements explicites avec stack trace, les erreurs d’utilisation des API (paramètre manquant dans get_string(), appel à $OUTPUT avant l’en-tête de page, requête SQL mal formée…) produisent des messages debugging() détaillés qui n’existent tout simplement pas aux niveaux inférieurs. Dans tout le code de Moodle, vous trouverez des centaines d’appels du type :
debugging('Ce paramètre est déprécié, utilisez X à la place.', DEBUG_DEVELOPER);Ces messages ne s’affichent que si votre niveau de debug les couvre. Développer sans DEBUG_DEVELOPER, c’est coder les yeux bandés.
💡 Pour un dev React :
DEBUG_DEVELOPER, c’est le mode dev de Next.js — l’overlay d’erreur rouge, les warnings React sur leskeymanquantes, les avertissements de dépréciation dans la console. En prod (next build && next start), tout ça disparaît et React se tait. Même logique ici : les mêmes erreurs existent en prod, elles sont juste silencieuses. Note au passage :E_STRICTne sert plus à rien depuis PHP 8 (il est fusionné dansE_ALL, et la constante est dépréciée en PHP 8.4) — l’écriture(E_ALL | E_STRICT)est une convention historique de la documentation Moodle ;$CFG->debug = E_ALL;donne exactement le même résultat, 32767.
$CFG->debugdisplay = 1 est le complément indispensable : sans lui, les erreurs partent dans les logs du serveur web mais ne s’affichent pas dans la page. Avec moodle-docker, vous pourriez les lire via bin/moodle-docker-compose logs -f webserver, mais autant les avoir sous les yeux directement.
Les réglages de confort au quotidien
$CFG->perfdebug = 15 ajoute en pied de chaque page un panneau de métriques : temps de génération de la page, nombre de requêtes SQL en lecture/écriture, RAM au pic, nombre d’appels au MUC avec taux de hit/miss, temps passé dans le cache de session… C’est votre onglet « Network + Performance » des DevTools, version serveur. Quand vous développerez un plugin qui déclenche 300 requêtes SQL sur une page de cours, c’est ce footer qui vous le dira — avant vos utilisateurs.
$CFG->debugpageinfo = 1 affiche dans le footer l’identité technique de la page : son pagetype (ex. course-view-topics), le layout de thème utilisé, le contexte. Indispensable quand vous écrirez du CSS ciblé ou des callbacks conditionnés au type de page.
$CFG->debugstringids = 1 active un mode de traque des chaînes de langue : ajoutez ?strings=1 à n’importe quelle URL et chaque texte de la page s’affichera suivi de son identifiant et de son composant, par exemple Enregistrer {save/core}. Quand vous chercherez « d’où sort ce libellé que je dois modifier ? », c’est l’outil. Essayez tout de suite :
http://localhost:8000/?strings=1$CFG->langstringcache = 0, $CFG->cachejs = false, $CFG->cachetemplates = false : le trio anti-cache. Respectivement : les fichiers lang/*.php sont relus à chaque requête (fini la purge après chaque nouvelle chaîne), Moodle sert vos fichiers amd/src/*.js bruts au lieu des amd/build/*.min.js (fini le grunt obligatoire à chaque itération JS — on en reparlera au chapitre sur le JavaScript), et les templates Mustache sont recompilés à chaque affichage. Le site est un peu plus lent, mais chaque modification est visible au rechargement suivant. C’est le plus proche d’un « hot reload » que Moodle sache faire.
$CFG->showcrondebugging = true : quand vous lancerez le cron à la main en CLI (section 4.4.8), affiche le détail de chaque tâche exécutée au lieu d’un silence poli.
Le cas particulier : themedesignermode
$CFG->themedesignermode = true mérite un traitement à part, parce que c’est à la fois l’outil le plus utile pour travailler sur un thème et le meilleur moyen de rendre votre site inutilisable si vous l’oubliez.
Ce qu’il fait réellement :
- le SCSS du thème est recompilé à chaque requête HTTP (au lieu d’être compilé une fois puis servi avec un numéro de révision) ;
- les fichiers CSS et images du thème sont servis sans en-têtes de cache navigateur ;
- diverses optimisations de pipeline de thème sont contournées.
Résultat : vous modifiez un fichier .scss, vous rechargez, c’est là. Mais chaque page met 3 à 10 secondes à se générer, car Boost et ses dépendances représentent des dizaines de milliers de lignes de SCSS à recompiler. C’est pourquoi la règle est : on l’active au début d’une session de travail sur le thème, on le coupe à la fin. Ne le laissez jamais dans le bloc permanent de votre config.php autrement qu’en commentaire.
Plutôt que d’éditer config.php à chaque fois, basculez-le en CLI (le réglage vit alors en base de données, modifiable à volonté) :
# Activer (depuis ~/moodle-docker, comme toujours)
bin/moodle-docker-compose exec webserver php public/admin/cli/cfg.php --name=themedesignermode --set=1
# Désactiver
bin/moodle-docker-compose exec webserver php public/admin/cli/cfg.php --name=themedesignermode --set=0Ou via l’interface : Administration du site → Présentation → Thèmes → Réglages thème → Mode concepteur de thèmes.
⚠️ Piège : si vous ne travaillez PAS sur un thème mais seulement sur du CSS ponctuel, ne l’activez pas — une simple purge du cache thème après chaque modification (
purge_caches.php --theme, section suivante) est bien plus rapide au global. Et surtout : themedesignermode actif + oublié = « pourquoi mon Moodle est devenu si lent ?? » trois jours plus tard. C’est un classique.
Les équivalents via l’interface et via CLI
Tout ce que nous venons de mettre dans config.php existe aussi comme réglage en base de données, modifiable de deux autres façons.
Via l’interface : Administration du site → Développement → Débogage (/admin/settings.php?section=debugging). Vous y retrouvez le menu déroulant des niveaux (Aucun / Minimal / Normal / Tous / Développeur), la case « Afficher les messages de débogage » (debugdisplay), perfdebug, debugpageinfo, debugstringids. Les réglages de cache JS/templates sont dans Administration du site → Développement et Présentation → Réglages HTTP selon les cas. Si une valeur est grisée, c’est qu’elle est verrouillée par votre config.php — comportement attendu.
Via CLI avec cfg.php, le script qui lit/écrit n’importe quel réglage :
# Lire la valeur actuelle
bin/moodle-docker-compose exec webserver php public/admin/cli/cfg.php --name=debug
# Passer en DEBUG_DEVELOPER (32767) si vous ne l'avez pas mis dans config.php
bin/moodle-docker-compose exec webserver php public/admin/cli/cfg.php --name=debug --set=32767
bin/moodle-docker-compose exec webserver php public/admin/cli/cfg.php --name=debugdisplay --set=1Quelle méthode choisir ? En développement local : config.php, sans hésiter. C’est versionnable (dans un gist ou un template personnel, pas dans le dépôt Moodle !), ça survit à un install_database.php qui réinitialise la base, et c’est copiable d’un projet à l’autre. L’UI et cfg.php servent pour les bascules ponctuelles (themedesignermode) et pour les environnements que vous ne contrôlez pas.
⚠️ Piège : il va sans dire, mais disons-le — aucun de ces réglages ne doit jamais atteindre une production.
debugdisplay = 1affiche des chemins de fichiers, des requêtes SQL et des stack traces à n’importe quel visiteur : c’est une fuite d’informations exploitable.cachejs = falseetcachetemplates = falsemultiplient la charge serveur. Les rapports de sécurité Moodle mentionnent régulièrement des sites compromis dont la reconnaissance a commencé par undebugdisplayoublié. Si vous gérez plusieurs environnements, faites de ce bloc un marqueur : sa présence = machine de dev, point.
4.4.3 — Purger les caches : quand, pourquoi, comment
Même avec les réglages ci-dessus, certains caches restent actifs — notamment le MUC (données applicatives) et le cache des définitions de plugins. Et si vous n’avez pas désactivé les caches de langue/JS/templates (sur un environnement partagé, par exemple), la purge devient votre geste réflexe.
Quand purger ?
Les situations classiques qui exigent une purge :
- vous avez ajouté ou modifié une chaîne de langue (
lang/en/monplugin.php) etlangstringcachen’est pas à 0 ; - vous avez créé ou modifié un template Mustache et
cachetemplatesn’est pas àfalse; - vous avez modifié le SCSS/CSS d’un thème sans themedesignermode ;
- vous avez modifié
version.phpd’un plugin, ajouté une capability dansdb/access.php, un service web dansdb/services.php, une tâche dansdb/tasks.php— bref, touché au répertoiredb/(là il faudra en plus passer par la page de mise à niveau, on le verra au chapitre plugins) ; - vous avez ajouté un nouveau fichier de classe dans
classes/et l’autoloader ne le trouve pas (la carte des classes est en cache) ; - comportement inexplicable, données visiblement périmées, ou simple doute : purger ne coûte presque rien en dev.
Via l’interface
Administration du site → Développement → Purger les caches (/admin/purgecaches.php). Le gros bouton violet « Purger tous les caches » fait table rase. Juste en dessous, la même page propose des purges sélectives par case à cocher : thème, langue, JavaScript, templates, filtres, MUC, autres — utile pour ne pas payer le coût d’une purge totale (qui force la recompilation du thème, notamment) quand seule la langue vous intéresse.
Via CLI : purge_caches.php
C’est la méthode que vous utiliserez 50 fois par jour :
# Tout purger (l'équivalent du gros bouton violet)
bin/moodle-docker-compose exec webserver php public/admin/cli/purge_caches.phpSortie attendue :
Purging caches...
Success.Le script accepte des options de purge sélective — si vous en passez une ou plusieurs, seuls ces caches sont purgés :
php public/admin/cli/purge_caches.php --help| Option | Cache purgé | Cas d’usage typique |
|---|---|---|
--muc | Moodle Universal Cache (données applicatives) | Données obsolètes, après manipulation directe de la base |
--theme | CSS compilé des thèmes | Modification SCSS sans themedesignermode |
--lang | Chaînes de langue | Nouvelle chaîne dans lang/ |
--js | JavaScript minifié | Nouveau build AMD |
--template | Templates Mustache compilés | Modification d’un .mustache |
--filter | Caches des filtres de contenu | Développement d’un filtre |
--other | Le reste (dont divers caches de fichiers) | Complément des précédents |
Exemple d’une purge ciblée après avoir ajouté une chaîne de langue :
bin/moodle-docker-compose exec webserver php public/admin/cli/purge_caches.php --langL’alias shell qui change la vie
Taper bin/moodle-docker-compose exec webserver php public/admin/cli/purge_caches.php cinquante fois par jour n’est pas un projet de vie. Ajoutez ceci à votre ~/.bashrc (ou ~/.zshrc) côté WSL2 :
# --- Aliases Moodle dev (à adapter : chemin de votre clone moodle-docker) ---
export MOODLE_DOCKER_DIR="$HOME/moodle-docker"
# Raccourci générique : mdc <commande docker compose>
alias mdc="$MOODLE_DOCKER_DIR/bin/moodle-docker-compose"
# Lancer n'importe quel PHP dans le conteneur : mphp public/admin/cli/xxx.php
mphp() {
"$MOODLE_DOCKER_DIR/bin/moodle-docker-compose" exec webserver php "$@"
}
# La purge, enfin humaine
alias mpurge="mphp public/admin/cli/purge_caches.php"
# Le cron à la demande
alias mcron="mphp public/admin/cli/cron.php --force"Rechargez votre shell (source ~/.bashrc), et désormais :
mpurge # purge tout
mpurge --theme # purge le thème seulement
mcron # lance le cron
mphp public/admin/cli/cfg.php --name=debug # n'importe quel script CLI💡 Pour un dev React :
mpurge, c’est votrerm -rf .nextdevenu un réflexe moteur. La bonne heuristique à intérioriser : « code modifié + page rechargée + rien ne change » →mpurgeavant d’ouvrir le débogueur. Neuf fois sur dix, c’était ça.
La purge automatique au bump de version
Détail d’architecture utile à connaître dès maintenant : quand vous incrémentez le numéro dans le version.php d’un plugin (ou du core) et que vous passez par le processus de mise à niveau (page d’admin ou php public/admin/cli/upgrade.php), Moodle purge lui-même tous ses caches à la fin de l’upgrade. C’est pour cela que la procédure canonique de déploiement d’une modification de plugin est « bump de version + upgrade » et non « copier les fichiers + purger à la main » : le bump garantit que les définitions en base (db/), les caches et la carte des classes sont resynchronisés atomiquement. En développement, pour une simple modif de template ou de chaîne, la purge manuelle suffit ; dès que vous touchez à db/ ou version.php, faites un vrai upgrade.
4.4.4 — moosh : le couteau suisse en ligne de commande
Ce que c’est
moosh (« MOOdle SHell », github.com/tmuras/moosh ) est un outil CLI communautaire, développé par Tomasz Muras, qui expose en une commande des dizaines d’opérations Moodle qui demanderaient sinon dix clics dans l’interface ou vingt lignes de PHP : créer des cours, des utilisateurs, des inscriptions, installer des plugins, exécuter du SQL, lire/écrire la config, générer des squelettes de code…
moosh fonctionne en bootstrappant Moodle lui-même : lancé depuis un répertoire contenant (ou situé sous) un config.php Moodle, il charge le framework complet puis exécute sa commande avec les vraies API internes. Ce n’est donc pas un outil qui bricole la base de données à l’aveugle : un moosh user-create passe par les mêmes fonctions que le formulaire d’admin.
💡 Pour un dev React : moosh est à Moodle ce qu’
artisanest à Laravel ounxà un monorepo : un CLI générique qui pilote le framework de l’extérieur. Vous l’utiliserez pour tout ce qui est répétitif — créer 50 utilisateurs de test, réinstaller un plugin, vider un cache précis — et pour scaffolder du code, comme unnx generate.
Installation sous WSL2 / moodle-docker
Deux stratégies possibles avec moodle-docker. La plus simple et la plus robuste : installer moosh dans le conteneur webserver, puisque c’est là que PHP, la base et config.php se rencontrent déjà.
Clonez moosh sur l’hôte WSL2, dans le répertoire de votre code Moodle ou à côté, puis installez ses dépendances depuis le conteneur (pour que les versions PHP correspondent) :
# Sur l'hôte WSL2 : cloner moosh à côté de votre code
cd ~
git clone https://github.com/tmuras/moosh.git
# Le rendre visible dans le conteneur : moodle-docker monte ~/moodle sur
# /var/www/html ; le plus simple est de déclarer un montage supplémentaire
# via un fichier local.yml (voir ci-dessous), ou — solution zéro-config —
# de cloner moosh DANS le dossier moodle (il sera ignoré par git via .git/info/exclude) :
cd ~/moodle
git clone https://github.com/tmuras/moosh.git .moosh
echo ".moosh/" >> .git/info/exclude
# Installer les dépendances Composer depuis le conteneur
cd ~/moodle-docker
bin/moodle-docker-compose exec webserver bash -c "cd /var/www/html/.moosh && composer install --no-dev"Puis ajoutez un alias dans votre ~/.bashrc — moosh doit être lancé depuis un répertoire Moodle, donc on fixe le répertoire de travail du exec :
moosh() {
"$MOODLE_DOCKER_DIR/bin/moodle-docker-compose" exec -w /var/www/html webserver \
php /var/www/html/.moosh/moosh.php "$@"
}Vérification :
moosh -h | head -20
moosh infoL’alternative « sur l’hôte WSL2 » (installer PHP 8.3 + composer dans WSL, cloner moosh dans ~/opt/moosh, ln -s ~/opt/moosh/moosh.php ~/.local/bin/moosh) fonctionne aussi, mais moosh devrait alors se connecter à la base de données depuis l’hôte : il faudrait exposer le port de la base et dupliquer un config.php avec les bons hôtes. Avec moodle-docker, restez dans le conteneur, c’est le chemin de moindre douleur.
⚠️ Piège : moosh suit de près les versions de Moodle, mais le passage au répertoire
public/(Moodle 5.1+) a demandé des adaptations dans beaucoup d’outils de l’écosystème. Utilisez toujours lemasterfrais de moosh (ou la dernière release) avec Moodle 5.2, et si une commande échoue avec une erreur de chemin ou de bootstrap, vérifiez les issues GitHub du projet avant d’incriminer votre installation.moosh infoest le smoke test : s’il affiche la version de votre Moodle, le bootstrap fonctionne.
Le top des commandes, avec exemples
moosh compte plus de 150 commandes (moosh -h pour la liste complète, documentation exhaustive sur moosh-online.com/commands ). Voici celles qui constituent 90 % de l’usage réel d’un développeur.
Explorer et créer des cours :
# Lister les cours (id, nom court, nom complet)
moosh course-list"id","category","shortname","fullname","idnumber","visible"
"1","0","monsite","Mon site Moodle","","1"
"2","1","TEST101","Cours de test 101","","1"# Créer un cours (retourne l'id créé)
moosh course-create --fullname "Sandbox plugin forum" --shortname SANDBOX1 --category 1
# En créer cinq d'un coup
moosh course-create --category 1 sandbox{1..5}Créer des utilisateurs — le batch qui remplace dix minutes de formulaires :
# Un utilisateur
moosh user-create --password 'Test1234!' --email etudiant1@example.com \
--firstname "Étudiant" --lastname "Un" etudiant1
# Vingt d'un coup, grâce à l'expansion d'accolades bash
moosh user-create --password 'Test1234!' --email etu%@example.com \
--firstname Étudiant --lastname "N°%" etu{1..20}Le caractère % est remplacé par le nom d’utilisateur dans les champs email/prénom/nom — moosh crée donc etu1@example.com, etu2@example.com, etc. Sortie : la liste des ids créés, un par ligne.
# Modifier un utilisateur existant (mot de passe, email, champs de profil)
moosh user-mod --password 'NouveauPass1!' etudiant1
# Donner les droits admin à un compte
moosh user-mod --admin etudiant1Inscrire dans un cours :
# Inscrire etu1..etu20 comme étudiants (rôle 5 = student par défaut) dans le cours id 2
moosh course-enrol --id 2 etu{1..20}
# Inscrire un enseignant (rôle par nom court)
moosh course-enrol --id 2 --role editingteacher prof1Gérer les plugins :
# Chercher un plugin dans le répertoire officiel
moosh plugin-list | grep -i attendance
# Télécharger + installer un plugin depuis moodle.org (déclenche l'upgrade)
moosh plugin-install mod_attendance
# Juste télécharger l'archive sans installer
moosh plugin-download mod_attendanceplugin-install télécharge la version compatible avec votre Moodle, la décompresse au bon endroit de l’arborescence et lance la mise à niveau. Pour un plugin que vous développez, vous n’en aurez pas besoin (votre code est déjà en place), mais pour installer des plugins tiers de référence à étudier, c’est imbattable.
Caches et maintenance :
# Équivalent de purge_caches.php
moosh cache-clear
# Reconstruire le cache d'un cours précis (après manipulation directe en base)
moosh cache-course-rebuild 2Base de données et configuration :
# Exécuter du SQL directement (avec le préfixe géré : {user} devient mdl_user)
moosh sql-run "SELECT id, username, email FROM {user} WHERE deleted = 0 LIMIT 5"
# Lire une config (globale ou de plugin)
moosh config-get core debug
moosh config-get mod_forum
# Écrire une config
moosh config-set maxbytes 20971520
moosh config-set displaymode 2 mod_forumsql-run est précieux pour l’exploration rapide sans ouvrir un client SQL — la syntaxe {table} applique automatiquement le préfixe mdl_, exactement comme dans l’API $DB de Moodle que vous découvrirez bientôt.
Scaffolding de code — les commandes generate- :*
C’est la famille la plus intéressante pour la suite de cette documentation : moosh sait générer des squelettes de plugins et de composants conformes aux conventions Moodle.
# Générer un squelette de module d'activité complet (structure, version.php, lang, db/…)
moosh generate-module montest
# Générer un squelette de bloc
moosh generate-block monbloc
# Générer une classe de formulaire (moodleform) prête à remplir
moosh generate-form edit_form
# Autres : generate-filter, generate-theme, generate-qtype, generate-cfg…
moosh -h | grep generate-Le code généré est un point de départ à adapter, pas un produit fini — mais il vous évite de recopier la structure obligatoire (dont nous détaillerons chaque fichier au chapitre sur l’anatomie d’un plugin).
Le bump de version en une commande :
# Incrémente automatiquement le numéro de version dans version.php du plugin
# situé dans le répertoire courant
cd /var/www/html/public/mod/montest
moosh dev-versionbumpCouplé à un upgrade.php, c’est le cycle de déploiement local d’une modification structurelle : dev-versionbump → php public/admin/cli/upgrade.php --non-interactive.
📚 Aller plus loin : la documentation de chaque commande, avec tous les flags, est sur moosh-online.com (générée depuis le dépôt). Le code source des commandes (github.com/tmuras/moosh/tree/master/Moosh/Command ) est lui-même une excellente lecture pédagogique : chaque commande est un exemple court et réel d’utilisation des API internes de Moodle.
4.4.5 — MDK : le Moodle Development Kit
MDK (Moodle Development Kit) est l’outil maintenu par Moodle HQ pour les développeurs du core Moodle. Là où moosh agit sur une instance Moodle, MDK gère des instances : il en crée, les met à jour, exécute les suites de tests, et automatise le workflow de contribution au projet officiel (branches liées au tracker MDL, backports entre versions stables, push vers votre fork pour la revue par peer review).
Installation — c’est un outil Python, distribué sur PyPI sous le nom moodle-sdk, et pipx est la méthode propre sous WSL2 :
sudo apt install -y pipx
pipx ensurepath
pipx install moodle-sdk
# Initialiser la configuration (chemins des instances, credentials git, etc.)
mdk initLes commandes emblématiques :
# Créer une instance Moodle complète (clone, base, install) — ici la branche de dev
mdk create --install --run mindev --version main
# Créer une instance stable 5.2 sur PostgreSQL
mdk create --install --engine pgsql --version 502
# Lancer un script utilitaire sur une instance (mdk embarque ses propres scripts)
mdk run mindev dev # applique des réglages "développeur" à l'instance
# Démarrer un travail sur une issue du tracker : crée la branche MDL-xxxxx-main
mdk fix MDL-12345
# Backporter votre branche de correctif vers les branches stables supportées
mdk backport --branch MDL-12345-main --versions 501,502
# Lancer PHPUnit / Behat sur une instance
mdk phpunit
mdk behat --runFaut-il l’installer aujourd’hui ? Honnêtement : probablement pas encore. MDK brille quand on contribue au core Moodle et qu’on jongle entre main, MOODLE_501_STABLE et MOODLE_502_STABLE avec des correctifs à répliquer partout. Il suppose aussi historiquement une pile LAMP locale (il sait dialoguer avec Docker, mais c’est un usage moins balisé que moodle-docker seul). Pour le parcours de cette documentation — développer des plugins sur une instance moodle-docker — moosh et les scripts admin/cli/ couvrent l’essentiel, avec moins de machinerie. Retenez que MDK existe, à quoi il sert, et revenez-y le jour où vous soumettrez votre premier patch au tracker Moodle : le chapitre sur la contribution au core y reviendra.
📚 Aller plus loin : la page officielle moodledev.io/general/development/tools/mdk documente toutes les commandes, et le README du dépôt github.com/moodlehq/mdk détaille l’installation avancée (config
~/.moodle-sdk/config.json, intégration Docker).
4.4.6 — XDebug 3 + VS Code : le débogage pas à pas
Jusqu’ici, votre débogage PHP se résume probablement à des var_dump() et au mode DEBUG_DEVELOPER. Il est temps de passer au vrai débogueur : points d’arrêt, inspection des variables, pile d’appels, exécution pas à pas — dans VS Code, à travers Docker et WSL2. C’est la section la plus « plomberie » du chapitre, mais une fois en place, ça ne bouge plus.
Comment ça marche (deux minutes de théorie)
XDebug est une extension PHP qui s’exécute dans le conteneur webserver. Quand une requête arrive avec un déclencheur (cookie, variable GET, variable d’environnement), XDebug ouvre une connexion TCP sortante vers votre IDE — protocole DBGp, port 9003 par défaut. VS Code, lui, écoute passivement sur ce port. Le sens de connexion est contre-intuitif : c’est le serveur PHP qui appelle l’IDE, pas l’inverse. D’où les deux difficultés classiques : dire au conteneur quelle adresse IP est « votre machine » (client_host), et s’assurer qu’aucun pare-feu ne bloque la connexion entrante côté Windows.
💡 Pour un dev React : c’est l’équivalent de
node --inspect+ l’attachement du débogueur VS Code sur le port 9229 — même expérience finale (breakpoints, step over/into, watch), mais avec la topologie inversée : Node expose un port que l’IDE contacte ; XDebug contacte un port que l’IDE expose.
Étape 1 — Installer XDebug dans le conteneur
Les images moodlehq/moodle-php-apache utilisées par moodle-docker n’embarquent pas XDebug par défaut (il pénalise les perfs). On l’installe via PECL, dans le conteneur en cours d’exécution :
cd ~/moodle-docker
# Compiler et installer l'extension
bin/moodle-docker-compose exec webserver pecl install xdebug
# Créer la configuration XDebug
read -r -d '' XDEBUG_INI <<'EOF'
xdebug.mode = debug
xdebug.client_host = host.docker.internal
xdebug.client_port = 9003
xdebug.start_with_request = trigger
EOF
bin/moodle-docker-compose exec webserver \
bash -c "echo '$XDEBUG_INI' > /usr/local/etc/php/conf.d/99-xdebug.ini"
# Activer l'extension (ajoute zend_extension=xdebug.so au bon endroit)
bin/moodle-docker-compose exec webserver docker-php-ext-enable xdebug
# Redémarrer le serveur web pour charger l'extension
bin/moodle-docker-compose restart webserverVérification :
bin/moodle-docker-compose exec webserver php -vPHP 8.3.x (cli) ...
with Xdebug v3.x.x, Copyright (c) 2002-2025, by Derick RethansLes trois réglages qui comptent :
xdebug.mode = debug: active le débogage pas à pas (les autres modes —profile,trace,coverage— servent au profiling et à la couverture de tests) ;xdebug.client_host = host.docker.internal: l’adresse à laquelle joindre votre IDE depuis l’intérieur du conteneur ;xdebug.start_with_request = trigger: XDebug ne tente la connexion que si la requête porte un déclencheur explicite. L’alternative= yes(connexion à chaque requête) rend chaque page lente même quand vous ne déboguez pas — évitez.
Étape 2 — Rendre l’installation persistante
Le pecl install ci-dessus vit dans le conteneur… et meurt avec lui. Un bin/moodle-docker-compose down (qui détruit les conteneurs) vous ramène à la case départ. Deux solutions.
Solution pragmatique : un script à rejouer. Créez ~/moodle-docker/install-xdebug.sh avec les commandes de l’étape 1, et relancez-le après chaque down/up. Simple, transparent, suffisant si vous ne détruisez pas vos conteneurs tous les jours (stop/start préservent le conteneur, XDebug survit).
Solution durable : une image dérivée, déclarée via le mécanisme d’override local.yml de moodle-docker. Créez d’abord le Dockerfile :
# ~/moodle-docker/Dockerfile.xdebug
FROM moodlehq/moodle-php-apache:8.3
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug \
&& { \
echo 'xdebug.mode = debug'; \
echo 'xdebug.client_host = host.docker.internal'; \
echo 'xdebug.client_port = 9003'; \
echo 'xdebug.start_with_request = trigger'; \
} >> /usr/local/etc/php/conf.d/99-xdebug.iniPuis le fichier d’override, que moodle-docker fusionne automatiquement s’il existe :
# ~/moodle-docker/local.yml
services:
webserver:
build:
context: .
dockerfile: Dockerfile.xdebug
extra_hosts:
- "host.docker.internal:host-gateway"Et reconstruisez :
cd ~/moodle-docker
bin/moodle-docker-compose build webserver
bin/moodle-docker-compose up -dLa ligne extra_hosts mérite une explication : avec Docker Desktop (le setup Windows + WSL2 du chapitre précédent), host.docker.internal est résolu nativement dans les conteneurs. Mais si vous utilisez docker-ce installé directement dans WSL2 (sans Docker Desktop), ce nom n’existe pas par défaut — host-gateway demande à Docker de le faire pointer vers la passerelle de l’hôte. La ligne est inoffensive dans les deux cas : mettez-la.
⚠️ Piège : adaptez le tag
FROMà la version PHP de votre setup (8.3ou8.4selon votre variableMOODLE_DOCKER_PHP_VERSION). Une image dérivée sur un mauvais tag et vous déboguerez un PHP différent de celui qui sert votre site — le genre d’incohérence qui coûte une soirée.
Étape 3 — VS Code : extension et launch.json
Installez l’extension PHP Debug de Xdebug (identifiant : xdebug.php-debug) — dans la fenêtre Remote-WSL, vérifiez qu’elle est bien installée « dans WSL: Ubuntu » et pas seulement côté Windows.
Créez ensuite .vscode/launch.json à la racine de votre workspace (~/moodle/.vscode/launch.json) :
{
"version": "0.2.0",
"configurations": [
{
"name": "Écouter XDebug (moodle-docker)",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
"log": false
},
{
"name": "Écouter XDebug (log verbeux, pour diagnostiquer)",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
"log": true
}
]
}Le réglage critique est pathMappings : il traduit les chemins dans le conteneur (clé) vers les chemins de votre workspace (valeur). moodle-docker monte votre ~/moodle complet sur /var/www/html ; votre workspace VS Code étant ~/moodle, le mapping racine-à-racine suffit — le fichier exécuté /var/www/html/public/index.php se résout naturellement en ${workspaceFolder}/public/index.php.
⚠️ Piège : c’est ici que la nouvelle arborescence
public/de Moodle 5.1+ peut vous jouer des tours. Deux erreurs classiques : (1) ouvrir~/moodle/publiccomme workspace VS Code tout en gardant le mapping"/var/www/html": "${workspaceFolder}"— il faudrait alors"/var/www/html/public": "${workspaceFolder}", mais vous perdriezconfig.phpet les fichiers racine, donc ouvrez plutôt~/moodle; (2) recopier un vieux tutoriel où le volume Docker monte directement le docroot. La règle d’or : la clé doit être le chemin tel que PHP le voit dans le conteneur (vérifiable avecmphp -r 'echo __DIR__;'ou dans le footer debugpageinfo), la valeur le même fichier vu par VS Code. Si vos breakpoints s’affichent gris/creux (« unverified »), c’est presque toujours un pathMapping faux.
Étape 4 — Premier breakpoint
- Dans VS Code, ouvrez
public/index.phpet cliquez dans la marge à gauche d’une des premières lignes exécutables (par exemple lerequire_oncedeconfig.php) : un point rouge apparaît. - Onglet « Exécuter et déboguer » (Ctrl+Maj+D) → sélectionnez « Écouter XDebug (moodle-docker) » → F5. La barre d’état passe en orange : VS Code écoute sur le port 9003.
- Déclenchez le débogage depuis le navigateur. Deux méthodes :
- L’extension navigateur Xdebug Helper (Chrome/Firefox/Edge) : un clic sur l’icône « bug » → « Debug » pose le cookie
XDEBUG_SESSIONsur toutes vos requêtes. C’est la méthode confortable au quotidien. - À la main : ajoutez
?XDEBUG_TRIGGER=1à l’URL —http://localhost:8000/?XDEBUG_TRIGGER=1.
- L’extension navigateur Xdebug Helper (Chrome/Firefox/Edge) : un clic sur l’icône « bug » → « Debug » pose le cookie
- Rechargez la page : VS Code prend le focus, l’exécution est suspendue sur votre ligne, les panneaux Variables / Watch / Call Stack se remplissent. Explorez
$CFGdans le panneau Variables : vous venez de voir l’objet de configuration global de Moodle en pleine construction. F10 (step over), F11 (step into), F5 (continue).
Prenez dix minutes pour « step-into » le démarrage de Moodle depuis public/index.php : config.php → setup.php → chargement de $CFG, $DB, $SESSION, $OUTPUT, $PAGE. C’est la meilleure introduction possible à l’architecture interne que nous détaillerons dans la partie suivante de cette documentation.
Déboguer un script CLI
Les scripts CLI ne passent pas par le navigateur, donc pas de cookie : le déclencheur est une variable d’environnement. VS Code écoutant toujours (F5), lancez :
bin/moodle-docker-compose exec -e XDEBUG_TRIGGER=1 webserver \
php public/admin/cli/purge_caches.phpLe breakpoint que vous aurez posé (par exemple dans public/admin/cli/purge_caches.php lui-même) est atteint immédiatement. Si client_host posait problème en CLI (rare avec la conf ci-dessus), on peut forcer les réglages au cas par cas :
bin/moodle-docker-compose exec -e XDEBUG_TRIGGER=1 webserver \
php -d xdebug.start_with_request=yes public/admin/cli/cron.php --forceDéboguer un test PHPUnit
Même principe — nous verrons l’initialisation de PHPUnit au chapitre consacré aux tests, mais notez la recette dès maintenant :
bin/moodle-docker-compose exec -e XDEBUG_TRIGGER=1 webserver \
vendor/bin/phpunit --filter test_get_string public/lib/tests/moodlelib_test.phpBreakpoint dans le test ou dans le code testé, F5 côté VS Code, et vous avancez pas à pas dans un test rouge au lieu de deviner. C’est l’une des plus grosses montées en productivité de tout ce chapitre.
Pièges spécifiques WSL2
host.docker.internalne résout pas (log XDebug : « Could not connect to debugging client ») : vous êtes probablement en docker-ce natif WSL2 → ajoutez l’extra_hosts: host-gatewaydu local.yml ci-dessus. Pour diagnostiquer :bin/moodle-docker-compose exec webserver getent hosts host.docker.internal.- Le pare-feu Windows bloque le port 9003 : avec VS Code en Remote-WSL, le serveur d’écoute tourne dans WSL2, et le trafic conteneur → WSL2 ne traverse normalement pas le pare-feu Windows. Mais si vous utilisez VS Code « natif Windows » sans Remote-WSL, ou PHPStorm côté Windows, la connexion entrante depuis le sous-réseau Docker peut être bloquée : autorisez l’application dans le pare-feu, ou créez une règle entrante TCP 9003. Test rapide depuis le conteneur :
bash -c 'echo > /dev/tcp/host.docker.internal/9003' && echo OK(pendant que l’IDE écoute). - VS Code écoute dans la mauvaise « moitié » : l’extension PHP Debug doit être installée dans WSL (bandeau vert « WSL: Ubuntu » en bas à gauche, puis vérifier l’extension dans la section « WSL » du panneau Extensions). Une extension installée uniquement côté Windows écoute sur un localhost que le conteneur ne peut pas joindre de la même manière.
- Rien ne se passe, aucun message : activez la config « log verbeux » du launch.json et ajoutez
xdebug.log=/tmp/xdebug.logdans le99-xdebug.inidu conteneur, puis lisezbin/moodle-docker-compose exec webserver cat /tmp/xdebug.log— XDebug y consigne chaque tentative de connexion et la raison de l’échec.
Et sous PHPStorm ?
Si vous préférez PHPStorm, la configuration équivalente tient en cinq lignes : Settings → PHP → Debug (vérifier le port 9003), Settings → PHP → Servers → créer un serveur localhost:8000 avec « Use path mappings » et le mapping ~/moodle → /var/www/html, puis activer l’écoute (icône téléphone). PHPStorm valide automatiquement la configuration à la première connexion entrante. Signalons aussi le plugin Moodle pour PHPStorm qui apporte complétion et navigation spécifiques (chaînes de langue, templates). Cette documentation reste sur VS Code, mais tout ce qui suit s’y transpose.
4.4.7 — VS Code : extensions et réglages pour Moodle
Moodle, c’est plus de 10 000 fichiers PHP et plusieurs centaines de Mo de code. Sans réglages, VS Code et son analyse PHP vont ramer — et vous polluer avec des résultats de recherche venus de bibliothèques tierces embarquées.
Les extensions recommandées
Installez-les dans WSL (fenêtre Remote-WSL) :
| Extension | Identifiant | Rôle |
|---|---|---|
| PHP Intelephense | bmewburn.vscode-intelephense-client | Language server PHP : complétion, go-to-definition, signatures, refactoring. L’équivalent du service TypeScript pour PHP. |
| PHP Debug | xdebug.php-debug | Client XDebug (section précédente). |
| EditorConfig | EditorConfig.EditorConfig | Moodle fournit un .editorconfig (indentation 4 espaces, fins de ligne LF…) : l’extension l’applique automatiquement. |
| ESLint | dbaeumer.vscode-eslint | Lint des modules JavaScript AMD selon le .eslintrc de Moodle. |
| Stylelint | stylelint.vscode-stylelint | Lint du SCSS des thèmes selon la config Moodle. |
| Mustache syntax | dawhite.mustache (coloration) | Coloration des templates .mustache. |
Il existe quelques extensions « Moodle snippets » sur le Marketplace ; elles sont d’un apport marginal et parfois datées — testez si vous voulez, mais rien d’indispensable. Le vrai levier de productivité, c’est Intelephense bien configuré + XDebug.
La version gratuite d’Intelephense suffit largement pour démarrer (la licence payante, unique et bon marché, débloque le renommage global et quelques finesses — investissement rentable si vous restez sur PHP).
settings.json : dompter la taille du projet
Créez ~/moodle/.vscode/settings.json :
{
// --- PHP ---
// Désactiver l'analyseur PHP basique de VS Code (redondant avec Intelephense)
"php.suggest.basic": false,
"php.validate.enable": false,
// --- Intelephense ---
// Aligner l'analyse sur la version PHP du conteneur
"intelephense.environment.phpVersion": "8.3.0",
// Moodle contient quelques très gros fichiers générés ; relever la limite
// d'indexation évite des trous dans la complétion
"intelephense.files.maxSize": 3000000,
// Ne pas indexer les répertoires de build et de données
"intelephense.files.exclude": [
"**/.git/**",
"**/node_modules/**",
"**/amd/build/**",
"**/yui/build/**",
"**/vendor/**/{Tests,tests}/**"
],
// --- Recherche : exclure le bruit, garder le core ---
// NE PAS exclure public/lib entier : c'est là que vivent les API Moodle
// que vous chercherez en permanence. On n'exclut que les builds,
// les bibliothèques tierces volumineuses et les fixtures de test.
"search.exclude": {
"**/node_modules": true,
"**/amd/build": true,
"**/yui/build": true,
"public/lib/aws-sdk": true,
"public/lib/google": true,
"public/lib/zipstream": true,
"public/lib/phpspreadsheet": true,
"public/lib/tcpdf": true,
"public/lib/pear": true,
"public/lib/yui": true,
"public/lib/editor/tiny/js": true,
"**/tests/behat": true,
"**/tests/fixtures": true
},
// --- Watcher : alléger la charge fichier ---
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/node_modules/**": true,
"**/amd/build/**": true,
"**/yui/build/**": true
},
// --- Confort Moodle ---
"files.associations": {
"*.mustache": "handlebars"
},
"editor.rulers": [132],
"files.trimTrailingWhitespace": true
}Quelques commentaires :
- N’excluez pas
public/lib/en bloc. Réflexe tentant (« c’est du vendor »), mais faux :public/lib/moodlelib.php,public/lib/weblib.php,public/lib/classes/sont le cœur de Moodle, et vous passerez votre vie à y faire des recherches. On n’exclut que les sous-répertoires de bibliothèques tierces réellement importées (SDK AWS, TCPDF…). editor.rulers: [132]matérialise la limite de longueur de ligne des conventions de code Moodle (nous y reviendrons au chapitre sur les standards).- La première indexation Intelephense d’un Moodle complet prend quelques minutes et un pic de CPU : laissez-le finir une bonne fois, ensuite c’est fluide.
💡 Pour un dev React : ce settings.json joue le rôle de vos
tsconfig.exclude+.eslintignore+ l’exclusion denode_modules: réduire le graphe que l’outillage doit comprendre. La différence culturelle : Moodle versionne ses dépendances tierces dans le dépôt (pas decomposer installpour faire tourner le site — le répertoirevendor/que vous verrez apparaître ne sert qu’aux outils de dev comme PHPUnit), d’où la nécessité de tracer soi-même la frontière « mon code / leur code ».
4.4.8 — Les scripts admin/cli incontournables
Moodle embarque toute une boîte à outils d’administration en CLI dans public/admin/cli/ (et quelques-uns dans les cli/ d’outils d’admin comme public/admin/tool/*/cli/). Vous en avez déjà croisé plusieurs ; voici la carte d’ensemble. Rappel du schéma d’exécution systématique sous moodle-docker :
bin/moodle-docker-compose exec webserver php public/admin/cli/<script>.php [options]
# ou, avec l'alias de la section 4.4.3 :
mphp public/admin/cli/<script>.php [options]Tous acceptent --help. Le tour d’horizon :
| Script | Rôle | Exemple type |
|---|---|---|
cfg.php | Lire/écrire n’importe quel $CFG (core ou plugin) | cfg.php --name=debug --set=32767 |
purge_caches.php | Purger les caches (voir 4.4.3) | purge_caches.php --theme |
maintenance.php | Activer/désactiver le mode maintenance | maintenance.php --enable |
cron.php | Exécuter le cron (toutes les tâches dues) | cron.php --force |
scheduled_task.php | Lister/exécuter UNE tâche planifiée | scheduled_task.php --list |
adhoc_task.php | Exécuter les tâches ad hoc en attente | adhoc_task.php --execute |
reset_password.php | Réinitialiser un mot de passe | reset_password.php (interactif) |
install_database.php | (Ré)installer la base sur un code en place | voir chapitre précédent |
upgrade.php | Exécuter les mises à niveau en attente | upgrade.php --non-interactive |
uninstall_plugins.php | Désinstaller proprement des plugins | uninstall_plugins.php --plugins=mod_x --run |
checks.php | Exécuter les vérifications d’état du site | checks.php |
mysql_collation.php / mysql_engine.php | Vérifs/conversions spécifiques MySQL (collation, moteur) | mysql_collation.php --list |
Détaillons ceux que vous utiliserez le plus.
cfg.php — la config en ligne de commande
# Lister TOUS les réglages core
mphp public/admin/cli/cfg.php
# Lire un réglage
mphp public/admin/cli/cfg.php --name=debug
# → 32767
# Lire la config d'un plugin (--component)
mphp public/admin/cli/cfg.php --component=mod_forum --name=displaymode
# Écrire
mphp public/admin/cli/cfg.php --name=debug --set=32767
# Supprimer un réglage (retour à la valeur par défaut)
mphp public/admin/cli/cfg.php --name=themedesignermode --unsetÀ noter : cfg.php refuse de modifier un réglage verrouillé dans config.php — cohérent avec ce qu’on a vu en 4.4.2.
cron.php, scheduled_task.php, adhoc_task.php — le système de tâches
Moodle exécute son travail de fond via deux familles de tâches : planifiées (récurrentes, type cron applicatif : envoyer les notifications, nettoyer les sessions…) et ad hoc (ponctuelles, mises en file : suppression différée d’un cours, envoi d’un gros lot d’emails…). Le conteneur moodle-docker ne fait pas tourner de cron automatique : en dev, c’est vous le cron.
# Lancer tout ce qui est dû, maintenant, en ignorant les verrous d'horaire
mcron # alias de : mphp public/admin/cli/cron.php --forceAvec $CFG->showcrondebugging = true (section 4.4.2), la sortie détaille chaque tâche :
Execute scheduled task: Nettoyage des fichiers temporaires (core\task\file_temp_cleanup_task)
... started 14:02:11. Current memory use 42.1 Mo.
... used 3 dbqueries
... used 0.081 seconds
Scheduled task complete: ...Pour ne lancer qu’une tâche — le cas permanent quand vous développerez vos propres tâches planifiées :
# Lister toutes les tâches planifiées avec leur prochaine exécution
mphp public/admin/cli/scheduled_task.php --list
# Exécuter UNE tâche précise, tout de suite (nom de classe complet, quoté !)
mphp public/admin/cli/scheduled_task.php --execute='\core\task\send_new_user_passwords_task'
# Idem en forçant même si la tâche est désactivée
mphp public/admin/cli/scheduled_task.php --execute='\mod_forum\task\cron_task' --force⚠️ Piège : les antislashs du nom de classe doivent survivre au shell — utilisez toujours des quotes simples autour de
'\core\task\...'. Sans quotes, bash mange les\et vous obtenez une erreur « task not found » incompréhensible.
# Exécuter les tâches ad hoc en attente
mphp public/admin/cli/adhoc_task.php --execute
# Cibler une classe de tâche ad hoc précise
mphp public/admin/cli/adhoc_task.php --execute --classname='\core_course\task\course_delete_modules'maintenance.php, upgrade.php, uninstall_plugins.php — le cycle de vie
# Mode maintenance (bloque les non-admins pendant une opération sensible)
mphp public/admin/cli/maintenance.php --enable
mphp public/admin/cli/maintenance.php --disable
# Lancer les upgrades en attente sans confirmation interactive
# (après un bump de version.php, un nouveau plugin déposé, un git pull…)
mphp public/admin/cli/upgrade.php --non-interactive
# Désinstaller un plugin proprement (tables, configs, fichiers de données)
mphp public/admin/cli/uninstall_plugins.php --show-all # lister l'installé
mphp public/admin/cli/uninstall_plugins.php --plugins=mod_montest --runLe duo upgrade.php --non-interactive + purge_caches.php constitue, avec le bump de version, la boucle de déploiement local d’un plugin en développement. Retenez-le, il reviendra sans cesse dans les chapitres suivants.
reset_password.php et checks.php — le dépannage
# Réinitialiser un mot de passe (mode interactif : demande username puis mot de passe)
mphp public/admin/cli/reset_password.php
# Version non interactive
mphp public/admin/cli/reset_password.php --username=admin --password='NouveauPass1!' --ignore-password-policyLe grand classique du lundi matin : « c’était quoi déjà le mot de passe admin de cette instance ? ». Trente secondes, réglé.
# Bilan de santé du site (les mêmes "checks" que la page Administration → Rapports → Bilans)
mphp public/admin/cli/checks.phpchecks.php remonte l’état des vérifications de sécurité, de performance et d’environnement — pratique en sortie de CI ou après une grosse manipulation.
📚 Aller plus loin : la liste complète et à jour des scripts CLI est documentée sur docs.moodle.org — Administration via command line . Et rien ne vous empêche de lire les scripts eux-mêmes : ils sont courts, et leur préambule (
define('CLI_SCRIPT', true);+require config.php+cli_get_params()) est exactement le squelette que vous réutiliserez pour écrire vos scripts CLI de plugin.
4.4.9 — Générer des données de test avec tool_generator
Un Moodle fraîchement installé est désespérément vide : un site, un admin, zéro cours. Or vous allez avoir besoin de matière — des cours avec des sections, des activités, des fichiers, des étudiants inscrits, des messages de forum — pour développer quoi que ce soit de réaliste. Les créer à la main est exclu ; moosh aide (section 4.4.4), mais Moodle embarque encore mieux : tool_generator, le générateur de données de test officiel.
💡 Pour un dev React : tool_generator, c’est votre script de seed —
prisma db seed+ faker. Même philosophie : des données synthétiques mais structurellement réalistes, reproductibles, en une commande.
maketestcourse.php — générer UN cours de test
mphp public/admin/tool/generator/cli/maketestcourse.php --shortname=PERF_S --size=SLe script crée un cours complet : sections, activités variées (forums, pages, devoirs, gros fichiers…), utilisateurs de test créés et inscrits, messages postés dans les forums. La taille est contrôlée par --size, de XS à XXL :
| Taille | Ordre de grandeur | Génération | Usage |
|---|---|---|---|
XS | ~1 étudiant, quelques activités | secondes | fumée, démo d’API |
S | ~dizaines d’étudiants et d’activités | < 1 min | développement quotidien |
M | ~centaines d’étudiants, beaucoup de contenu | minutes | tests d’UI réalistes, pagination |
L | ~1 000 étudiants | longues minutes | premiers tests de perfs |
XL / XXL | ~10 000+ étudiants, contenu massif | très long, plusieurs Go | perfs sérieuses uniquement |
(Les volumes exacts par taille sont définis dans les backends de tool_generator et évoluent d’une version à l’autre — fiez-vous à l’ordre de grandeur, pas au chiffre.)
Options utiles :
# Nom complet personnalisé + sortie silencieuse
mphp public/admin/tool/generator/cli/maketestcourse.php \
--shortname=BIGCOURSE --fullname="Cours de test perfs" --size=M --quiet
# Ne générer QUE certains types de données (voir --help pour la liste)
mphp public/admin/tool/generator/cli/maketestcourse.php --shortname=FORUMS1 --size=SPourquoi c’est précieux : la moitié des bugs de plugins n’apparaissent que sur de gros volumes — la requête SQL qui explose à 1 000 inscrits, la page qui ne pagine pas, le sélecteur d’utilisateurs qui charge tout le monde en mémoire. Un cours L vous donne en dix minutes le terrain de test qu’un vrai client mettrait un an à constituer. Testez sur S au quotidien, validez sur L avant de livrer.
maketestsite.php — générer un site entier (DANGER)
mphp public/admin/tool/generator/cli/maketestsite.php --size=S --bypasscheckCelui-ci ne crée pas un cours mais peuple tout le site : de nombreux cours de tailles variées, des cohortes d’utilisateurs globales, etc. Deux garde-fous à connaître :
- il refuse de s’exécuter sans
--bypasschecken CLI, précisément parce qu’il transforme irréversiblement le site — ne le lancez jamais sur une instance qui contient quoi que ce soit d’important ; - l’option
--fixeddatasetfige l’aléatoire (noms, contenus) pour obtenir un site reproductible d’une génération à l’autre — indispensable si vous comparez des mesures de performance avant/après une modification.
# Site de test reproductible, taille M
mphp public/admin/tool/generator/cli/maketestsite.php --size=M --fixeddataset --bypasscheckAux grandes tailles (L et au-delà), comptez des heures de génération et des dizaines de Go : c’est un outil de bancs d’essai, pas de dev quotidien.
⚠️ Piège : il n’existe pas de « makeuntestsite » — la génération ne se annule pas. Sur moodle-docker, la parade est structurelle : vos données vivent dans des volumes Docker jetables. Un
bin/moodle-docker-compose down -v(attention : détruit tout, base comprise) suivi d’une réinstallation vous rend un site propre. C’est l’équivalent dudocker compose down -v && prisma migrate resetd’un projet Node.
Et pour les tests automatisés : les data generators
Sachez enfin que cette machinerie de génération a un troisième visage, que vous rencontrerez au chapitre sur les tests : dans PHPUnit, chaque test Moodle peut invoquer des data generators programmatiques :
$course = $this->getDataGenerator()->create_course();
$user = $this->getDataGenerator()->create_user(['email' => 'etu@example.com']);
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
$forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]);Mêmes fabriques sous-jacentes que tool_generator, mais à l’échelle d’un test : chaque plugin peut fournir son propre generator pour ses objets. Nous y consacrerons une section entière dans la partie tests — retenez simplement que « créer des données de test réalistes » est un problème résolu chez Moodle, à tous les étages.
4.4.10 — Le workflow quotidien : table symptôme → outil
Pour clore ce chapitre, la synthèse à épingler au mur. La colonne de gauche, c’est vous dans trois semaines ; la colonne de droite, ce chapitre.
| Symptôme | Réflexe | Commande / action |
|---|---|---|
| « Mon SCSS ne s’applique pas » | Purge thème, ou themedesignermode si session thème longue | mpurge --theme / cfg.php --name=themedesignermode --set=1 |
« Ma chaîne de langue affiche [[monid]] ou l’ancienne valeur » | Purge langue (ou langstringcache=0 en amont) | mpurge --lang |
| « Mon template Mustache modifié est invisible » | Purge templates (ou cachetemplates=false) | mpurge --template |
| « Mon JS modifié ne s’exécute pas » | cachejs=false + vérifier qu’on sert bien amd/src (sinon build grunt) | config.php + mpurge --js |
| « Mon nouveau plugin / ma nouvelle capability n’apparaît pas » | Bump version.php + upgrade | mphp public/admin/cli/upgrade.php --non-interactive |
« Ma classe dans classes/ n’est pas trouvée par l’autoloader » | Purge totale (carte de classes en cache) | mpurge |
| « Ma tâche planifiée ne part pas » | L’exécuter directement pour voir l’erreur | scheduled_task.php --execute='\mon_plugin\task\ma_tache' |
| « Les mails / notifications ne partent pas » | Le cron ne tourne pas en dev : le lancer | mcron (et lire MailHog, cf. chapitre précédent) |
| « Page blanche / erreur 500 muette » | Vérifier que le bloc debug de config.php est en place | section 4.4.2, puis logs mdc logs -f webserver |
| « D’où sort ce libellé dans l’interface ? » | Mode identifiants de chaînes | ?strings=1 (avec debugstringids=1) |
| « Cette page est lente, pourquoi ? » | Footer de perfs : requêtes SQL, RAM, hits MUC | perfdebug=15, lire le footer |
| « Je veux comprendre ce que fait ce code » | Breakpoint + pas à pas plutôt que var_dump | XDebug, section 4.4.6 |
| « Il me faut 50 étudiants inscrits pour tester » | moosh en batch, ou un cours généré | moosh user-create ... etu{1..50} + course-enrol / maketestcourse.php |
| « Il me faut un GROS cours pour tester les perfs » | tool_generator taille L | maketestcourse.php --shortname=BIG --size=L |
| « C’était quoi le mot de passe admin déjà ? » | Reset CLI | reset_password.php --username=admin --password=... |
| « Quelle est la valeur de tel réglage ? » | cfg.php en lecture | cfg.php --name=<réglage> |
Et le rituel de démarrage d’une journée de dev Moodle, en quatre lignes :
cd ~/moodle-docker
bin/moodle-docker-compose start # réveiller les conteneurs
mpurge # partir d'un état de cache propre
code ~/moodle # VS Code Remote-WSL, F5 si session de debugRécapitulatif
- Le piège n°1 de Moodle en développement, ce sont ses caches : MUC, langues, JS, templates, thème, plugins. Quand « ça ne marche pas », purgez avant de douter de votre code. Alias à demeure :
mpurge→php public/admin/cli/purge_caches.php(avec options sélectives--muc,--js,--theme,--lang,--template,--filter,--other). - Le bloc de dev dans
config.phpest la fondation :$CFG->debug = 32767(DEBUG_DEVELOPER = tout PHP + les messages internes Moodle),debugdisplay,perfdebug=15(footer SQL/RAM/temps),debugpageinfo,debugstringids(+?strings=1), et le trio anti-cachelangstringcache=0/cachejs=false/cachetemplates=false.themedesignermodes’active ponctuellement (SCSS recompilé à chaque requête : puissant mais très lent). Rien de tout cela ne va jamais en production. - moosh est le CLI communautaire à tout faire (type artisan/nx) : cours, utilisateurs en batch, inscriptions, plugins, SQL, config, purges, et scaffolding de plugins via
generate-*+dev-versionbump. Installé dans le conteneur webserver, piloté par un alias shell. - MDK est l’outil des contributeurs core (multi-instances, backports, tracker) : sachez qu’il existe, installez-le le jour où vous contribuerez au core.
- XDebug 3 + VS Code fonctionne très bien à travers moodle-docker/WSL2 :
pecl install xdebug+ confclient_host=host.docker.internal/start_with_request=trigger, persisté vialocal.yml+ Dockerfile dérivé ;launch.jsonavecpathMappings {"/var/www/html": "${workspaceFolder}"}; déclenchement par extension navigateur ou?XDEBUG_TRIGGER=1, et par-e XDEBUG_TRIGGER=1pour le CLI et PHPUnit. - Les scripts
public/admin/cli/couvrent l’administration quotidienne :cfg.php,purge_caches.php,cron.php --force,scheduled_task.php --list/--execute,adhoc_task.php,upgrade.php --non-interactive,maintenance.php,reset_password.php,uninstall_plugins.php,checks.php. - tool_generator fabrique des données de test réalistes en une commande :
maketestcourse.php --size=XS..XXLpour un cours,maketestsite.php --fixeddataset --bypasscheckpour un site entier (irréversible !), et les data generators PHPUnit reprennent la même mécanique dans les tests.
Votre environnement n’est plus seulement « un Moodle qui tourne » : c’est un poste de travail de développeur Moodle complet — verbeux quand il y a une erreur, purgeable en une commande, débogable pas à pas, et capable de se peupler de données de test à la demande.
Dans le prochain chapitre
Outillage en place, il est temps d’ouvrir le capot. Le prochain chapitre entame la visite guidée de l’architecture de Moodle : l’anatomie du répertoire public/, le cycle de vie d’une requête (de config.php à $OUTPUT->footer()), les objets globaux $CFG, $DB, $USER, $PAGE et $OUTPUT que vous avez entrevus dans le débogueur, et surtout le concept central autour duquel tout Moodle s’organise : le système de plugins et ses conventions. C’est là que votre breakpoint dans public/index.php va prendre tout son sens.