Skip to Content

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 dev avec Fast Refresh, ESLint, le debugger Node attaché à VS Code, et vos scripts package.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

  1. Philosophie : le cache est votre ennemi n°1 en développement
  2. Le mode debug : configurer config.php pour le développement
  3. Purger les caches : quand, pourquoi, comment
  4. moosh : le couteau suisse en ligne de commande
  5. MDK : le Moodle Development Kit
  6. XDebug 3 + VS Code : le débogage pas à pas
  7. VS Code : extensions et réglages pour Moodle
  8. Les scripts admin/cli incontournables
  9. Générer des données de test avec tool_generator
  10. 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 cacheCe qu’elle stockeSymptôme quand elle est périmée
MUC (Moodle Universal Cache)Données applicatives : configs, infos de cours, résultats de requêtes coûteusesDonnées obsolètes affichées, comportements incohérents
Cache de langueLes chaînes de tous les fichiers lang/ fusionnées et sérialiséesVotre nouvelle chaîne get_string() affiche [[monidentifiant]] ou l’ancienne valeur
Cache JavaScriptLes modules AMD minifiés et concaténésVotre JS modifié n’est jamais exécuté (Moodle sert amd/build/*.min.js, pas amd/src/)
Cache des templatesLes templates Mustache compilés en closures PHPVotre modification de .mustache est invisible
Cache du thèmeLe SCSS compilé en CSS, avec un numéro de révision dans l’URLVotre CSS ne s’applique pas
Cache des pluginsLa liste des plugins installés et leurs versionsVotre 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 dev quand Next.js sert un build fantôme, ou rm -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 :

  1. Désactiver les caches qui peuvent l’être sans rendre le site inutilisable (langue, JS, templates) via config.php ;
  2. Purger à la demande ceux qui ne peuvent pas être désactivés (MUC, plugins) via un alias shell d’une seule commande ;
  3. 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.php est 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 table mdl_config. C’est voulu — et c’est pour ça qu’on préfère config.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 votre config.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é :

ConstanteValeurCe qui est remontéUsage typique
DEBUG_NONE0RienProduction paranoïaque
DEBUG_MINIMAL5Erreurs fatales et avertissements critiques (E_ERROR | E_PARSE)Production
DEBUG_NORMAL15+ warnings et notices importantes (E_ERROR | E_PARSE | E_WARNING | E_NOTICE)Préproduction
DEBUG_ALLE_ALLToutes les erreurs PHPDébogage ponctuel
DEBUG_DEVELOPERE_ALL | E_STRICT = 32767Tout, plus les messages internes que Moodle réserve aux développeursDé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 les key manquantes, 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_STRICT ne sert plus à rien depuis PHP 8 (il est fusionné dans E_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=0

Ou 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=1

Quelle 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 = 1 affiche des chemins de fichiers, des requêtes SQL et des stack traces à n’importe quel visiteur : c’est une fuite d’informations exploitable. cachejs = false et cachetemplates = false multiplient la charge serveur. Les rapports de sécurité Moodle mentionnent régulièrement des sites compromis dont la reconnaissance a commencé par un debugdisplay oublié. 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) et langstringcache n’est pas à 0 ;
  • vous avez créé ou modifié un template Mustache et cachetemplates n’est pas à false ;
  • vous avez modifié le SCSS/CSS d’un thème sans themedesignermode ;
  • vous avez modifié version.php d’un plugin, ajouté une capability dans db/access.php, un service web dans db/services.php, une tâche dans db/tasks.php — bref, touché au répertoire db/ (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.php

Sortie 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
OptionCache purgéCas d’usage typique
--mucMoodle Universal Cache (données applicatives)Données obsolètes, après manipulation directe de la base
--themeCSS compilé des thèmesModification SCSS sans themedesignermode
--langChaînes de langueNouvelle chaîne dans lang/
--jsJavaScript minifiéNouveau build AMD
--templateTemplates Mustache compilésModification d’un .mustache
--filterCaches des filtres de contenuDéveloppement d’un filtre
--otherLe 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 --lang

L’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 votre rm -rf .next devenu un réflexe moteur. La bonne heuristique à intérioriser : « code modifié + page rechargée + rien ne change »mpurge avant 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’artisan est à Laravel ou nx à 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 un nx 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 info

L’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 le master frais 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 info est 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 etudiant1

Inscrire 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 prof1

Gé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_attendance

plugin-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 2

Base 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_forum

sql-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-versionbump

Couplé à un upgrade.php, c’est le cycle de déploiement local d’une modification structurelle : dev-versionbumpphp 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 init

Les 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 --run

Faut-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 webserver

Vérification :

bin/moodle-docker-compose exec webserver php -v
PHP 8.3.x (cli) ... with Xdebug v3.x.x, Copyright (c) 2002-2025, by Derick Rethans

Les 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.ini

Puis 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 -d

La 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.3 ou 8.4 selon votre variable MOODLE_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/public comme workspace VS Code tout en gardant le mapping "/var/www/html": "${workspaceFolder}" — il faudrait alors "/var/www/html/public": "${workspaceFolder}", mais vous perdriez config.php et 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 avec mphp -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

  1. Dans VS Code, ouvrez public/index.php et cliquez dans la marge à gauche d’une des premières lignes exécutables (par exemple le require_once de config.php) : un point rouge apparaît.
  2. 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.
  3. 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_SESSION sur 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.
  4. 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 $CFG dans 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.phpsetup.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.php

Le 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 --force

Dé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.php

Breakpoint 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.internal ne résout pas (log XDebug : « Could not connect to debugging client ») : vous êtes probablement en docker-ce natif WSL2 → ajoutez l’extra_hosts: host-gateway du 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.log dans le 99-xdebug.ini du conteneur, puis lisez bin/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) :

ExtensionIdentifiantRôle
PHP Intelephensebmewburn.vscode-intelephense-clientLanguage server PHP : complétion, go-to-definition, signatures, refactoring. L’équivalent du service TypeScript pour PHP.
PHP Debugxdebug.php-debugClient XDebug (section précédente).
EditorConfigEditorConfig.EditorConfigMoodle fournit un .editorconfig (indentation 4 espaces, fins de ligne LF…) : l’extension l’applique automatiquement.
ESLintdbaeumer.vscode-eslintLint des modules JavaScript AMD selon le .eslintrc de Moodle.
Stylelintstylelint.vscode-stylelintLint du SCSS des thèmes selon la config Moodle.
Mustache syntaxdawhite.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 de node_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 de composer install pour faire tourner le site — le répertoire vendor/ 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 :

ScriptRôleExemple type
cfg.phpLire/écrire n’importe quel $CFG (core ou plugin)cfg.php --name=debug --set=32767
purge_caches.phpPurger les caches (voir 4.4.3)purge_caches.php --theme
maintenance.phpActiver/désactiver le mode maintenancemaintenance.php --enable
cron.phpExécuter le cron (toutes les tâches dues)cron.php --force
scheduled_task.phpLister/exécuter UNE tâche planifiéescheduled_task.php --list
adhoc_task.phpExécuter les tâches ad hoc en attenteadhoc_task.php --execute
reset_password.phpRéinitialiser un mot de passereset_password.php (interactif)
install_database.php(Ré)installer la base sur un code en placevoir chapitre précédent
upgrade.phpExécuter les mises à niveau en attenteupgrade.php --non-interactive
uninstall_plugins.phpDésinstaller proprement des pluginsuninstall_plugins.php --plugins=mod_x --run
checks.phpExécuter les vérifications d’état du sitechecks.php
mysql_collation.php / mysql_engine.phpVé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 --force

Avec $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 --run

Le 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-policy

Le 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.php

checks.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=S

Le 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 :

TailleOrdre de grandeurGénérationUsage
XS~1 étudiant, quelques activitéssecondesfumée, démo d’API
S~dizaines d’étudiants et d’activités< 1 mindéveloppement quotidien
M~centaines d’étudiants, beaucoup de contenuminutestests d’UI réalistes, pagination
L~1 000 étudiantslongues minutespremiers tests de perfs
XL / XXL~10 000+ étudiants, contenu massiftrès long, plusieurs Goperfs 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=S

Pourquoi 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 --bypasscheck

Celui-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 --bypasscheck en 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 --fixeddataset fige 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 --bypasscheck

Aux 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 du docker compose down -v && prisma migrate reset d’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ômeRéflexeCommande / action
« Mon SCSS ne s’applique pas »Purge thème, ou themedesignermode si session thème longuempurge --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 + upgrademphp 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’erreurscheduled_task.php --execute='\mon_plugin\task\ma_tache'
« Les mails / notifications ne partent pas »Le cron ne tourne pas en dev : le lancermcron (et lire MailHog, cf. chapitre précédent)
« Page blanche / erreur 500 muette »Vérifier que le bloc debug de config.php est en placesection 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 MUCperfdebug=15, lire le footer
« Je veux comprendre ce que fait ce code »Breakpoint + pas à pas plutôt que var_dumpXDebug, 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 Lmaketestcourse.php --shortname=BIG --size=L
« C’était quoi le mot de passe admin déjà ? »Reset CLIreset_password.php --username=admin --password=...
« Quelle est la valeur de tel réglage ? »cfg.php en lecturecfg.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 debug

Ré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 : mpurgephp public/admin/cli/purge_caches.php (avec options sélectives --muc, --js, --theme, --lang, --template, --filter, --other).
  • Le bloc de dev dans config.php est 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-cache langstringcache=0 / cachejs=false / cachetemplates=false. themedesignermode s’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 + conf client_host=host.docker.internal / start_with_request=trigger, persisté via local.yml + Dockerfile dérivé ; launch.json avec pathMappings {"/var/www/html": "${workspaceFolder}"} ; déclenchement par extension navigateur ou ?XDEBUG_TRIGGER=1, et par -e XDEBUG_TRIGGER=1 pour 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..XXL pour un cours, maketestsite.php --fixeddataset --bypasscheck pour 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.