Moodle 3.10自定义测验提交事件插件触发失败修复请求
Moodle 3.10自定义测验提交JSON生成插件修复方案
问题概述
在Moodle 3.10开发本地自定义插件,目标是用户提交测验时生成包含用户、测验及成绩信息的JSON文件。已注册\mod_quiz\event\attempt_submitted事件观察者,事件可在管理员日志中看到,但插件的事件处理逻辑未触发,无法生成指定路径的JSON文件。
原代码问题分析
- 事件观察者缓存未更新:Moodle会缓存事件注册信息,新注册的观察者可能未生效
- Quiz实例获取错误:直接使用
contextinstanceid作为Quiz ID不够严谨,需通过上下文对象验证后获取 - 文件路径与权限问题:Windows路径未转义,且未确保目标目录存在;Web服务器用户可能无读写权限
- 无错误捕获机制:处理过程中出现错误时无法排查,也无日志记录
- 文件覆盖风险:固定文件名会被后续提交覆盖
修复步骤与修改后代码
1. 清除Moodle缓存
登录站点管理员后台,进入站点管理 -> 开发 -> 清除缓存,确保事件观察者注册生效。
2. 修改事件处理类 (classes/event_handler.php)
添加错误捕获、日志记录,修正Quiz实例获取方式,优化文件路径处理:
<?php namespace local_attempt_submission_plugin\classes; defined('MOODLE_INTERNAL') || die(); class event_handler { public static function handle_attempt_submitted(\mod_quiz\event\attempt_submitted $event) { try { // 验证上下文并获取Quiz ID $context = $event->get_context(); if ($context->contextlevel !== CONTEXT_MODULE) { debugging('事件上下文无效,非模块上下文', DEBUG_DEVELOPER); return; } $quizid = $context->instanceid; // 获取用户与Quiz快照记录 $user = $event->get_record_snapshot('user', $event->userid); $quiz = $event->get_record_snapshot('quiz', $quizid); if (!$user || !$quiz) { debugging('无法获取用户或测验记录', DEBUG_DEVELOPER); return; } // 准备JSON数据 $data = [ 'user_id' => $user->id, 'username' => $user->username, 'quiz_id' => $quiz->id, 'quiz_name' => $quiz->name, 'score' => $event->grade, 'submitted_timestamp' => $event->timecreated, 'submitted_at' => date('Y-m-d H:i:s', $event->timecreated) ]; // JSON编码并检查错误 $json_data = json_encode($data, JSON_PRETTY_PRINT); if ($json_data === false) { debugging('JSON编码失败: ' . json_last_error_msg(), DEBUG_DEVELOPER); return; } // 处理目标目录与文件路径 $target_dir = 'C:\\sample\\'; // 确保目录存在,不存在则创建 if (!file_exists($target_dir)) { mkdir($target_dir, 0777, true); } // 使用测验尝试ID作为文件名后缀,避免覆盖 $json_file_path = $target_dir . 'quiz_submission_' . $event->objectid . '.json'; // 写入文件并检查结果 $write_result = file_put_contents($json_file_path, $json_data); if ($write_result === false) { $error_msg = '无法写入JSON文件: ' . $json_file_path; debugging($error_msg, DEBUG_DEVELOPER); add_to_log(SITEID, 'local_attempt_submission_plugin', 'error', '', $error_msg); } else { add_to_log(SITEID, 'local_attempt_submission_plugin', 'success', '', 'JSON文件已生成: ' . $json_file_path); } } catch (\Exception $e) { $error_msg = '事件处理函数异常: ' . $e->getMessage(); debugging($error_msg, DEBUG_DEVELOPER); add_to_log(SITEID, 'local_attempt_submission_plugin', 'exception', '', $error_msg); } } }
3. 优化事件注册文件 (db/events.php)
显式设置internal参数,确保事件被正确捕获:
<?php defined('MOODLE_INTERNAL') || die(); $observers = [ [ 'eventname' => '\mod_quiz\event\attempt_submitted', 'callback' => '\local_attempt_submission_plugin\classes\event_handler::handle_attempt_submitted', 'internal' => false, ], ];
4. 其他必要设置
- 权限检查:确保Moodle运行的Web服务器用户(如Windows下的IUSR、Linux下的www-data)对
C:\sample\目录拥有读写权限 - 启用调试:在
config.php中添加$CFG->debug = DEBUG_DEVELOPER;,便于查看处理过程中的错误提示 - 验证触发:可在事件处理函数开头添加
add_to_log(SITEID, 'local_attempt_submission_plugin', 'trigger', '', '事件处理函数已触发');,确认函数是否被调用
内容的提问来源于stack exchange,提问作者Tamil Selvan s
相关产品推荐
相关产品推荐

