Moodle本地插件订阅Quiz模块「全部提交并完成」事件求助
问题描述
在Windows平台上为Moodle 2023042400(4.2.2+)开发本地插件local/adaptive_quiz/,需要订阅Quiz模块「全部提交并完成」事件,获取测试完成后的错误答案,仅需实现事件订阅与数据获取,使用PHP开发。插件已通过before_footer回调验证可正常运行,但此前的事件订阅方案均无效。
已尝试的无效方案
- 研究Moodle源码了解到
single_button类创建按钮,但未掌握事件订阅与数据获取方法 - 通过方法名订阅预设事件,无效果
- 通过
$handlers变量订阅事件,指定处理方法未被调用
正确的事件订阅与数据获取实现步骤
1. 确认目标事件的正确名称
Moodle 4.x中,「全部提交并完成」对应的标准事件是\mod_quiz\event\attempt_submitted,而非旧版格式的quiz_attempt_submitted,这是之前订阅失败的核心原因之一。
2. 采用事件观察者模式实现订阅
Moodle 4.x推荐使用**事件观察者(Event Observer)**机制处理事件订阅,替代旧的$handlers数组方式,以下是具体实现:
步骤2.1 创建观察者类文件
在插件目录下新建classes/observer.php,写入以下代码:
<?php defined('MOODLE_INTERNAL') || die(); class local_adaptive_quiz_observer { /** * 处理测验提交完成事件 * @param \mod_quiz\event\attempt_submitted $event */ public static function handle_quiz_submitted(\mod_quiz\event\attempt_submitted $event) { // 日志验证事件触发 error_log('local_adaptive_quiz: 测验提交事件已触发'); // 获取当前测验尝试ID $attemptid = $event->objectid; // 获取用户错误答案 $wrongAnswers = self::getUserWrongAnswers($attemptid); // 输出错误答案到日志(后续可替换为界面展示逻辑) error_log('local_adaptive_quiz: 用户错误详情:' . print_r($wrongAnswers, true)); } /** * 提取用户测验尝试中的错误答案 * @param int $attemptid 测验尝试ID * @return array 错误答案数组 */ private static function getUserWrongAnswers($attemptid) { global $DB; $wrongAnswers = []; // 获取当前测验尝试的基础信息 $attempt = $DB->get_record('quiz_attempts', ['id' => $attemptid], '*', MUST_EXIST); // 获取测验下的所有题目槽位 $slots = $DB->get_records('quiz_slots', ['quizid' => $attempt->quiz]); foreach ($slots as $slot) { // 获取用户该题的答题记录 $response = $DB->get_record('quiz_responses', [ 'attemptid' => $attemptid, 'slot' => $slot->slot ]); if (!$response) continue; // 加载题目实例,用于验证答案正确性 $question = question_load_questions([$slot->questionid])[$slot->questionid]; $questionEngine = question_engine::load_question($question); // 转换用户答案格式并验证是否错误 $userResponse = $questionEngine->get_response_summary($response->answer); if (!$questionEngine->is_correct_response($userResponse)) { $wrongAnswers[] = [ 'question_id' => $slot->questionid, 'question_name' => $question->name, 'user_answer' => $response->answer, 'correct_answer' => $questionEngine->get_correct_response() ]; } } return $wrongAnswers; } }
步骤2.2 注册事件观察者
在插件目录下新建db/events.php,注册观察者与事件的关联:
<?php defined('MOODLE_INTERNAL') || die(); $observers = [ [ 'eventname' => '\mod_quiz\event\attempt_submitted', 'callback' => 'local_adaptive_quiz_observer::handle_quiz_submitted', 'priority' => 10, 'internal' => false, ], ];
3. 更新插件并清除缓存
- 修改
version.php中的版本号(递增即可,触发Moodle插件更新机制):
<?php defined('MOODLE_INTERNAL') || die(); $plugin->version = 2023090901; // 版本号从原2023090900递增 $plugin->requires = 2023042400; $plugin->pluginname = 'Adaptive Quiz'; $plugin->component = 'local_adaptive_quiz'; ?>
- 登录Moodle后台,进入「站点管理」→「插件」→「插件检查」,执行插件更新。
- 清除Moodle缓存:「站点管理」→「开发」→「清除缓存」。
4. 验证事件触发
提交任意测验并点击「全部提交并完成」,查看Moodle错误日志(Windows下通常位于moodledata/logs/目录或PHP错误日志),若看到local_adaptive_quiz: 测验提交事件已触发及错误答案详情日志,说明事件订阅成功。
关键注意事项
- 事件名称必须准确:Moodle 4.x强制使用命名空间格式的事件名,旧格式
quiz_attempt_submitted已不再生效。 - 缓存必须清除:修改事件注册或观察者类后,必须清除Moodle缓存,否则新代码不会被加载。
- 题型兼容:示例仅适配选择题的错误答案判断,填空题、简答题等其他题型需根据题型调整答案验证逻辑。
内容的提问来源于stack exchange,提问作者Betrayal
相关产品推荐
相关产品推荐

