Skip to Content

Terrain 15 — Module d’activité (mod)

⏱️ TL;DR — 30 mini-jeux ⭐⭐⭐⭐ pour construire mod_simplecheck (une checklist notée), le type de plugin le plus riche : lib.php + FEATURE_*, add/update/delete_instance, mod_form, view.php, intégration au carnet de notes, achèvement custom, events, backup/restore. C’est le projet Niveau 3 en mini-jeux — le sommet du dev Moodle « cœur ».

⚠️ Le module mod a beaucoup de contrats à honorer. On les prend un par un. Chaque FEATURE_* déclaré doit être réellement implémenté.


🕹️ Mini-jeu 1 — La structure d’un mod ⭐⭐⭐⭐ 💻

But : l’anatomie du plus gros type. Mission : crée mod/simplecheck/ avec version.php, lib.php, mod_form.php, view.php, index.php, lang/, db/.

✅ Solution

Un module a une structure stricte : lib.php (callbacks du cœur), mod_form.php (réglages d’instance), view.php (affichage), db/install.xml + access.php. Frankenstyle mod_simplecheck, dossier mod/simplecheck/. Le contrat le plus exigeant.


🕹️ Mini-jeu 2 — version.php ⭐⭐⭐ 💻

But : identité + maturité. Mission : crée version.php (component = 'mod_simplecheck', maturity).

✅ Solution

Comme les autres plugins, avec component = 'mod_simplecheck'. La maturity (ALPHA→STABLE) informe les admins. Bumpe à chaque changement de db/.


🕹️ Mini-jeu 3 — Les tables XMLDB ⭐⭐⭐⭐ 💻

But : persister l’activité et les données. Mission : crée db/install.xml : table simplecheck (instance) + simplecheck_items + simplecheck_checks.

✅ Solution

Convention : une table du même nom que le module (simplecheck) par instance (course, name, intro, grade…), plus des tables pour items et cochages. Via l’éditeur XMLDB (terrain 12). Bumpe + installe.


🕹️ Mini-jeu 4 — supports() et FEATURE_* ⭐⭐⭐⭐ 💻

But : déclarer les capacités. Mission : implémente simplecheck_supports() dans lib.php. Étapes :

function simplecheck_supports($feature) { switch ($feature) { case FEATURE_GRADE_HAS_GRADE: return true; case FEATURE_COMPLETION_HAS_RULES: return true; case FEATURE_BACKUP_MOODLE2: return true; case FEATURE_MOD_INTRO: return true; default: return null; } }

✅ Solution

supports() déclare ce que le module sait faire. ⚠️ Chaque true est un contrat : déclarer FEATURE_GRADE_HAS_GRADE oblige à implémenter le carnet (jeux 13–15). Ne mens jamais dans supports().


🕹️ Mini-jeu 5 — add_instance() ⭐⭐⭐⭐ 💻

But : créer une instance. Mission : implémente simplecheck_add_instance(). Étapes :

function simplecheck_add_instance($data, $mform = null) { global $DB; $data->timecreated = time(); $data->id = $DB->insert_record('simplecheck', $data); simplecheck_grade_item_update($data); return $data->id; }

✅ Solution

Appelé à la création : on insère et on renvoie l’id, et on initialise l’item de note (jeu 13). Pendant de mod_form (jeu 8).


🕹️ Mini-jeu 6 — update_instance() ⭐⭐⭐⭐ 💻

But : modifier une instance. Mission : implémente simplecheck_update_instance(). Étapes :

function simplecheck_update_instance($data, $mform = null) { global $DB; $data->id = $data->instance; $DB->update_record('simplecheck', $data); simplecheck_grade_item_update($data); return true; }

✅ Solution

Gère l’édition. Noter $data->id = $data->instance (le formulaire passe l’ID en instance). On remet l’item de note à jour (le max a pu changer).


🕹️ Mini-jeu 7 — delete_instance() ⭐⭐⭐⭐ 💻

But : supprimer proprement. Mission : implémente simplecheck_delete_instance(). Étapes :

function simplecheck_delete_instance($id) { global $DB; $DB->delete_records('simplecheck_checks', ['simplecheckid' => $id]); $DB->delete_records('simplecheck_items', ['simplecheckid' => $id]); $DB->delete_records('simplecheck', ['id' => $id]); return true; }

✅ Solution

Supprime l’instance et toutes ses données liées (items, cochages) et l’item de note. Pas de résidu. Symétrie create/update/delete = contrat de base du mod.


🕹️ Mini-jeu 8 — mod_form.php ⭐⭐⭐⭐ 💻

But : les réglages de l’activité. Mission : crée mod_form.php étendant moodleform_mod. Étapes :

<?php class mod_simplecheck_mod_form extends moodleform_mod { public function definition() { $mform = $this->_form; $mform->addElement('text', 'name', get_string('name')); $mform->setType('name', PARAM_TEXT); $this->standard_intro_elements(); $this->standard_grading_coursemodule_elements(); $this->standard_coursemodule_elements(); $this->add_action_buttons(); } }

✅ Solution

moodleform_mod fournit les blocs standards (intro, notation, réglages communs, restrictions, groupes) via standard_*_elements(). Tu ajoutes tes champs. Réutilise l’existant.


🕹️ Mini-jeu 9 — view.php sécurisé ⭐⭐⭐⭐ 💻

But : afficher l’activité. Mission : crée view.php avec le pattern module. Étapes :

<?php require('../../config.php'); $id = required_param('id', PARAM_INT); // course module id $cm = get_coursemodule_from_id('simplecheck', $id, 0, false, MUST_EXIST); $course = $DB->get_record('course', ['id' => $cm->course], '*', MUST_EXIST); require_login($course, true, $cm); $context = context_module::instance($cm->id); $PAGE->set_url('/mod/simplecheck/view.php', ['id' => $cm->id]); echo $OUTPUT->header(); echo $OUTPUT->footer();

✅ Solution

Le pattern module : id = course module idget_coursemodule_from_id → cours → require_login($course, true, $cm) (vérifie l’accès à l’activité) → contexte module. La base sécurisée de toute page d’activité.


🕹️ Mini-jeu 10 — Le contexte module ⭐⭐⭐⭐ 💻

But : le bon niveau de permission. Mission : vérifie une capability avec context_module. Étapes :

require_capability('mod/simplecheck:submit', $context);

✅ Solution

Le contexte module (context_module::instance($cm->id)) est le niveau où s’évaluent les capabilities d’une activité (terrain 11). Le bon contexte, toujours.


🕹️ Mini-jeu 11 — db/access.php ⭐⭐⭐⭐ 💻

But : les droits de l’activité. Mission : déclare mod/simplecheck:submit (étudiant) et :grade (enseignant).

✅ Solution

Deux capabilities typiques : submit (cocher, archetype student) et grade (noter, archetype teacher), plus addinstance. Elles calquent les rôles (terrain 02/11). Bumpe + purge.


🕹️ Mini-jeu 12 — Enregistrer un cochage ⭐⭐⭐⭐ 💻

But : la donnée étudiant. Mission : enregistre les items cochés (avec sesskey + capability).

✅ Solution

Sur soumission : require_sesskey(), require_capability('mod/simplecheck:submit', $context), puis upsert dans simplecheck_checks (par userid + itemid). On isole par utilisateur, on déclenche la note (jeu 15) et l’event (jeu 18).


🕹️ Mini-jeu 13 — L’item de note ⭐⭐⭐⭐⭐ 💻

But : créer la colonne au carnet. Mission : implémente simplecheck_grade_item_update(). Étapes :

function simplecheck_grade_item_update($instance, $grades = null) { global $CFG; require_once($CFG->libdir . '/gradelib.php'); $params = ['itemname' => $instance->name, 'gradetype' => GRADE_TYPE_VALUE, 'grademax' => 100]; return grade_update('mod/simplecheck', $instance->course, 'mod', 'simplecheck', $instance->id, 0, $grades, $params); }

✅ Solution

grade_update() (de gradelib.php) crée/maj l’item dans le carnet (terrain 07). Appelé à add/update_instance. Obligatoire dès qu’on déclare FEATURE_GRADE_HAS_GRADE.


🕹️ Mini-jeu 14 — Note en points ou échelle ⭐⭐⭐⭐ 💻

But : gérer les deux. Mission : adapte l’item selon note chiffrée vs échelle.

✅ Solution

Si grade > 0GRADE_TYPE_VALUE (points, grademax = grade) ; si grade < 0GRADE_TYPE_SCALE (échelle, ID = -grade) ; si 0 → pas de note. Branchement standard qui reflète le choix de mod_form (terrain 07, jeu 10).


🕹️ Mini-jeu 15 — Pousser les notes ⭐⭐⭐⭐⭐ 💻

But : noter les étudiants. Mission : implémente simplecheck_update_grades(). Étapes :

function simplecheck_update_grades($instance, $userid = 0) { $grades = simplecheck_get_user_grades($instance, $userid); simplecheck_grade_item_update($instance, $grades); }

✅ Solution

update_grades calcule la note (ex. % d’items cochés) par utilisateur et la pousse via grade_item_update. Appelée après chaque cochage (jeu 12). La note apparaît alors dans le carnet. Boucle de notation complète.


🕹️ Mini-jeu 16 — L’achèvement custom ⭐⭐⭐⭐⭐ 💻

But : « terminé si X % coché ». Mission : crée classes/completion/custom_completion.php.

✅ Solution

La classe custom_completion (moderne) déclare des règles d’achèvement propres (ex. completionpercent) : get_state() calcule si la règle est remplie, get_defined_custom_rules() les liste. Requiert FEATURE_COMPLETION_HAS_RULES (jeu 4). Alimente la progression (terrain 08).


🕹️ Mini-jeu 17 — Brancher la règle au form ⭐⭐⭐⭐ 💻

But : régler la règle dans l’UI. Mission : ajoute le champ « % requis » aux règles d’achèvement de mod_form.

✅ Solution

Dans mod_form, add_completion_rules() ajoute tes champs (ex. completionpercent), completion_rule_enabled() dit s’ils sont actifs, get_data() les récupère. L’enseignant configure alors « terminé à 80 % ». Le form et la classe custom_completion se répondent.


🕹️ Mini-jeu 18 — Déclencher un event ⭐⭐⭐⭐ 💻

But : tracer « activité consultée ». Mission : déclenche course_module_viewed dans view.php. Étapes :

$event = \mod_simplecheck\event\course_module_viewed::create([ 'objectid' => $instance->id, 'context' => $context, ]); $event->add_record_snapshot('course_modules', $cm); $event->trigger();

✅ Solution

L’Events API journalise les actions (logs, terrain 10) et permet à d’autres de réagir (observers). course_module_viewed est standard. La classe d’event vit dans classes/event/. Base de l’analytique et de l’extensibilité.


🕹️ Mini-jeu 19 — Un event custom ⭐⭐⭐⭐⭐ 💻

But : ton propre signal. Mission : crée un event checklist_completed déclenché au 100 %.

✅ Solution

Une classe dans classes/event/checklist_completed.php (étend \core\event\base) définit crud, edulevel, la description. Déclenché quand un étudiant coche tout. D’autres plugins peuvent l’observer. Rend ton module extensible (comme do_action côté WordPress).


🕹️ Mini-jeu 20 — Le backup ⭐⭐⭐⭐⭐ 💻

But : sauvegarder l’activité. Mission : crée backup/moodle2/backup_simplecheck_stepslib.php.

✅ Solution

Le Backup API décrit comment sérialiser l’instance et ses tables (items, checks) en XML. backup_simplecheck_activity_task.php + backup_..._stepslib.php définissent l’arbre d’éléments. C’est la partie la plus négligée et la plus testée en review (Partie 11).


🕹️ Mini-jeu 21 — Le restore ⭐⭐⭐⭐⭐ 💻

But : restaurer l’activité. Mission : crée backup/moodle2/restore_simplecheck_stepslib.php.

✅ Solution

Le Restore API (miroir du backup) recrée l’instance et ses données depuis le XML, en remappant les ID (cours, users). Gère les données utilisateur ou non selon l’option. Sans lui, une restauration perd les données de ton module.


🕹️ Mini-jeu 22 — Tester backup → restore ⭐⭐⭐⭐ 💻

But : LA vérif qui compte. Mission : sauvegarde un cours avec ton activité et restaure-le ailleurs.

✅ Solution

Fais un cycle complet (terrain 03, jeux 19–20) : l’activité et ses données doivent réapparaître intactes dans le cours restauré. Un module qui échoue ici perd les données des utilisateurs — à tester réellement avant de considérer le mod fini.


🕹️ Mini-jeu 23 — Le reset de cours ⭐⭐⭐⭐ 💻

But : vider pour une nouvelle promo. Mission : implémente simplecheck_reset_userdata().

✅ Solution

reset_userdata supprime les données étudiants (cochages) à la réinitialisation du cours (terrain 03, jeu 22), en gardant la structure. On déclare aussi les options de reset (_reset_course_form_definition). Contrat de rentrée d’un mod bien fait.


🕹️ Mini-jeu 24 — cm_info et l’affichage sur la page ⭐⭐⭐⭐ 💻

But : l’aspect dans le cours. Mission : personnalise l’icône/le libellé via simplecheck_cm_info_view (optionnel).

✅ Solution

Les callbacks *_cm_info_* personnalisent le rendu de l’activité sur la page de cours (badge « 3/5 coché », icône). Optionnel mais soigne l’UX. Une icône propre va dans pix/icon.svg.


🕹️ Mini-jeu 25 — index.php ⭐⭐⭐ 💻

But : lister les instances du cours. Mission : crée index.php (liste des simplecheck d’un cours).

✅ Solution

index.php liste toutes les instances du module dans un cours (lien depuis la page de cours). Pattern sécurisé (require_login au cours). Convention attendue de tout mod.


🕹️ Mini-jeu 26 — Valider le formulaire ⭐⭐⭐⭐ 💻

But : refuser les saisies invalides. Mission : ajoute validation() à mod_form. Étapes :

public function validation($data, $files) { $errors = parent::validation($data, $files); if (trim($data['name']) === '') { $errors['name'] = get_string('required'); } return $errors; }

✅ Solution

validation() renvoie un tableau d’erreurs par champ ; le formulaire ne se soumet pas tant qu’il n’est pas vide. Validation côté serveur (la seule fiable). Complète les PARAM_* (assainissement).


🕹️ Mini-jeu 27 — Réglages admin du module ⭐⭐⭐ 💻

But : des défauts globaux. Mission : ajoute settings.php (ex. couleur par défaut de la checklist).

✅ Solution

settings.php (comme au terrain 13, jeu 22) ajoute des réglages globaux au module (défauts appliqués aux nouvelles instances). Lus avec get_config('mod_simplecheck', ...). Standardise le comportement à l’échelle du site.


🕹️ Mini-jeu 28 — Un privacy provider ⭐⭐⭐⭐⭐ 💻

But : conformité RGPD. Mission : crée classes/privacy/provider.php déclarant les cochages.

✅ Solution

Le module stocke des données perso (cochages, notes) → Privacy API obligatoire (metadata + export + delete, terrain 13 jeu 26). Sans lui, non conforme → refus de publication (Partie 11). Cœur du respect des données étudiantes.


🕹️ Mini-jeu 29 — Tests et coding style ⭐⭐⭐⭐⭐ 💻

But : qualité de production. Mission : écris un test PHPUnit sur add_instance + passe moodle-cs.

✅ Solution

Un test dans tests/ (générateur de données tests/generator/) vérifie création/notation. Un scénario Behat dans tests/behat/ couvre le parcours étudiant. moodle-cs vert. C’est ce que la review moodle.org exige (Partie 11, terrain 16).


🕹️ Mini-jeu 30 — Récap mod_simplecheck ⭐⭐⭐⭐ 💻

But : capstone du terrain. Mission : un module complet : supports() honnête, add/update/delete_instance, mod_form validé, view sécurisée, carnet de notes (grade_update), achèvement custom, events, backup/restore testé, reset, privacy — coding style vert.

✅ Solution

Tu as construit le type de plugin le plus riche de Moodle — c’est mod_simplecheck du cours (Partie 6.5) et du projet Niveau 3. Si tu tiens tous ces contrats, tu es un vrai développeur Moodle. Restent la sécurité/qualité transverse (terrain 16), puis l’ouverture vers l’extérieur : web services (17) et LTI/headless (18).


Terrain suivant : 16 — Sécurité & qualité.