Merge branch 'MDL-83904-master' of https://github.com/ngtrdai/moodle

This commit is contained in:
Sara Arjona
2025-06-18 17:19:05 +02:00
5 changed files with 341 additions and 281 deletions
@@ -0,0 +1,10 @@
issueNumber: MDL-83904
notes:
core_badges:
- message: >-
The class core_badges_observer in badges/classes/observer.php has been moved to
core_badges\event\observer in badges/classes/event/observer.php. A compatibility
layer has been added to maintain backward compatibility, but direct use of the old
class name is now deprecated. If you've extended or directly used the old class,
you should update your code to use the new namespaced class.
type: improved
+268
View File
@@ -0,0 +1,268 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_badges\event;
use core\event\badge_awarded;
use core\event\cohort_member_added;
use core\event\competency_evidence_created;
use core\event\course_completed;
use core\event\course_module_completion_updated;
use core\event\user_updated;
use core_badges\badge;
/**
* Event observer for badges.
*
* @package core_badges
* @copyright 2013 Rajesh Taneja <[email protected]>
* @author Rajesh Taneja <[email protected]>
* @author Dai Nguyen Trong <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class observer {
/**
* Determines if badge processing is enabled.
*
* @return bool True if badges are enabled, false otherwise.
*/
private static function badges_enabled(): bool {
global $CFG;
return !empty($CFG->enablebadges);
}
/**
* Common method to process badge issue after criteria is met.
*
* @param badge $badge The badge instance
* @param int $criteriatype The type of criteria being checked
* @param int $userid The user ID to check criteria against
*/
private static function process_criteria_completion(badge $badge, int $criteriatype, int $userid): void {
if (!$badge->is_active() || $badge->is_issued($userid)) {
return;
}
if ($badge->criteria[$criteriatype]->review($userid)) {
$badge->criteria[$criteriatype]->mark_complete($userid);
if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
$badge->issue($userid);
}
}
}
/**
* Triggered when 'course_module_completion_updated' event is triggered.
*
* @param course_module_completion_updated $event
*/
public static function course_module_criteria_review(course_module_completion_updated $event): void {
global $DB, $CFG;
if (!self::badges_enabled()) {
return;
}
require_once($CFG->dirroot.'/lib/badgeslib.php');
$eventdata = $event->get_record_snapshot('course_modules_completion', $event->objectid);
$userid = $event->relateduserid;
$mod = $event->contextinstanceid;
// Only process completion states that indicate the module has been completed.
if (!in_array($eventdata->completionstate, [
COMPLETION_COMPLETE,
COMPLETION_COMPLETE_PASS,
COMPLETION_COMPLETE_FAIL,
])) {
return;
}
// Find all badges that have this module in their criteria.
$params = [
'name' => 'module_' . $mod,
'value' => $mod,
];
if ($rs = $DB->get_records('badge_criteria_param', $params)) {
foreach ($rs as $r) {
$bid = $DB->get_field('badge_criteria', 'badgeid', ['id' => $r->critid], MUST_EXIST);
$badge = new badge($bid);
self::process_criteria_completion($badge, BADGE_CRITERIA_TYPE_ACTIVITY, $userid);
}
}
}
/**
* Triggered when '\core\event\competency_evidence_created' event is triggered.
*
* @param competency_evidence_created $event
*/
public static function competency_criteria_review(competency_evidence_created $event): void {
global $DB, $CFG;
if (!self::badges_enabled()) {
return;
}
require_once($CFG->dirroot.'/lib/badgeslib.php');
if (!get_config('core_competency', 'enabled')) {
return;
}
$cid = $event->other['competencyid'];
$userid = $event->relateduserid;
$params = [
'name' => 'competency_' . $cid,
'value' => $cid,
];
if ($rs = $DB->get_records('badge_criteria_param', $params)) {
foreach ($rs as $r) {
$crit = $DB->get_record('badge_criteria', ['id' => $r->critid], 'badgeid, criteriatype', MUST_EXIST);
$badge = new badge($crit->badgeid);
self::process_criteria_completion($badge, $crit->criteriatype, $userid);
}
}
}
/**
* Triggered when 'course_completed' event is triggered.
*
* @param course_completed $event
*/
public static function course_criteria_review(course_completed $event): void {
global $DB, $CFG;
if (!self::badges_enabled()) {
return;
}
require_once($CFG->dirroot.'/lib/badgeslib.php');
$userid = $event->relateduserid;
$courseid = $event->courseid;
$params = [
'name' => 'course_' . $courseid,
'value' => $courseid,
];
if ($rs = $DB->get_records('badge_criteria_param', $params)) {
foreach ($rs as $r) {
$crit = $DB->get_record(
'badge_criteria',
['id' => $r->critid],
'badgeid, criteriatype',
MUST_EXIST
);
$badge = new badge($crit->badgeid);
self::process_criteria_completion($badge, $crit->criteriatype, $userid);
}
}
}
/**
* Triggered when 'badge_awarded' event happens.
*
* @param badge_awarded $event event generated when a badge is awarded.
*/
public static function badge_criteria_review(badge_awarded $event): void {
global $DB, $CFG;
if (!self::badges_enabled()) {
return;
}
require_once($CFG->dirroot.'/lib/badgeslib.php');
$userid = $event->relateduserid;
if ($rs = $DB->get_records('badge_criteria', ['criteriatype' => BADGE_CRITERIA_TYPE_BADGE])) {
foreach ($rs as $r) {
$badge = new badge($r->badgeid);
self::process_criteria_completion($badge, BADGE_CRITERIA_TYPE_BADGE, $userid);
}
}
}
/**
* Triggered when 'user_updated' event happens.
*
* @param user_updated $event event generated when user profile is updated.
*/
public static function profile_criteria_review(user_updated $event): void {
global $DB, $CFG;
if (!self::badges_enabled()) {
return;
}
require_once($CFG->dirroot . '/lib/badgeslib.php');
$userid = $event->objectid;
if ($rs = $DB->get_records('badge_criteria', ['criteriatype' => BADGE_CRITERIA_TYPE_PROFILE])) {
foreach ($rs as $r) {
$badge = new badge($r->badgeid);
self::process_criteria_completion($badge, BADGE_CRITERIA_TYPE_PROFILE, $userid);
}
}
}
/**
* Triggered when the 'cohort_member_added' event happens.
*
* @param cohort_member_added $event generated when a user is added to a cohort
*/
public static function cohort_criteria_review(cohort_member_added $event): void {
global $DB, $CFG;
if (!self::badges_enabled()) {
return;
}
require_once($CFG->dirroot . '/lib/badgeslib.php');
$cohortid = $event->objectid;
$userid = $event->relateduserid;
// Get relevant badges.
$badgesql = "SELECT badgeid
FROM {badge_criteria_param} cp
JOIN {badge_criteria} c ON cp.critid = c.id
WHERE c.criteriatype = ?
AND cp.name = ?";
$badges = $DB->get_records_sql(
$badgesql,
[BADGE_CRITERIA_TYPE_COHORT, "cohort_{$cohortid}"],
);
if (empty($badges)) {
return;
}
foreach ($badges as $b) {
$badge = new badge($b->badgeid);
self::process_criteria_completion($badge, BADGE_CRITERIA_TYPE_COHORT, $userid);
}
}
}
-254
View File
@@ -1,254 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
defined('MOODLE_INTERNAL') || die();
use \core_badges\badge;
/**
* Event observer for badges.
*
* @package core_badges
* @copyright 2013 Rajesh Taneja <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_badges_observer {
/**
* Triggered when 'course_module_completion_updated' event is triggered.
*
* @param \core\event\course_module_completion_updated $event
*/
public static function course_module_criteria_review(\core\event\course_module_completion_updated $event) {
global $DB, $CFG;
if (!empty($CFG->enablebadges)) {
require_once($CFG->dirroot.'/lib/badgeslib.php');
$eventdata = $event->get_record_snapshot('course_modules_completion', $event->objectid);
$userid = $event->relateduserid;
$mod = $event->contextinstanceid;
if ($eventdata->completionstate == COMPLETION_COMPLETE
|| $eventdata->completionstate == COMPLETION_COMPLETE_PASS
|| $eventdata->completionstate == COMPLETION_COMPLETE_FAIL) {
// Need to take into account that there can be more than one badge with the same activity in its criteria.
if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'module_' . $mod, 'value' => $mod))) {
foreach ($rs as $r) {
$bid = $DB->get_field('badge_criteria', 'badgeid', array('id' => $r->critid), MUST_EXIST);
$badge = new badge($bid);
if (!$badge->is_active() || $badge->is_issued($userid)) {
continue;
}
if ($badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->mark_complete($userid);
if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
$badge->issue($userid);
}
}
}
}
}
}
}
/**
* Triggered when '\core\event\competency_evidence_created' event is triggered.
*
* @param \core\event\competency_evidence_created $event
*/
public static function competency_criteria_review(\core\event\competency_evidence_created $event) {
global $DB, $CFG;
if (!empty($CFG->enablebadges)) {
require_once($CFG->dirroot.'/lib/badgeslib.php');
if (!get_config('core_competency', 'enabled')) {
return;
}
$ucid = $event->other['usercompetencyid'];
$cid = $event->other['competencyid'];
$userid = $event->relateduserid;
if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'competency_' . $cid, 'value' => $cid))) {
foreach ($rs as $r) {
$crit = $DB->get_record('badge_criteria', array('id' => $r->critid), 'badgeid, criteriatype', MUST_EXIST);
$badge = new badge($crit->badgeid);
// Only site badges are updated from site competencies.
if (!$badge->is_active() || $badge->is_issued($userid)) {
continue;
}
if ($badge->criteria[$crit->criteriatype]->review($userid)) {
$badge->criteria[$crit->criteriatype]->mark_complete($userid);
if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
$badge->issue($userid);
}
}
}
}
}
}
/**
* Triggered when 'course_completed' event is triggered.
*
* @param \core\event\course_completed $event
*/
public static function course_criteria_review(\core\event\course_completed $event) {
global $DB, $CFG;
if (!empty($CFG->enablebadges)) {
require_once($CFG->dirroot.'/lib/badgeslib.php');
$userid = $event->relateduserid;
$courseid = $event->courseid;
// Need to take into account that course can be a part of course_completion and courseset_completion criteria.
if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'course_' . $courseid, 'value' => $courseid))) {
foreach ($rs as $r) {
$crit = $DB->get_record('badge_criteria', array('id' => $r->critid), 'badgeid, criteriatype', MUST_EXIST);
$badge = new badge($crit->badgeid);
if (!$badge->is_active() || $badge->is_issued($userid)) {
continue;
}
if ($badge->criteria[$crit->criteriatype]->review($userid)) {
$badge->criteria[$crit->criteriatype]->mark_complete($userid);
if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
$badge->issue($userid);
}
}
}
}
}
}
/**
* Triggered when 'badge_awarded' event happens.
*
* @param \core\event\badge_awarded $event event generated when a badge is awarded.
*/
public static function badge_criteria_review(\core\event\badge_awarded $event) {
global $DB, $CFG;
if (!empty($CFG->enablebadges)) {
require_once($CFG->dirroot.'/lib/badgeslib.php');
$userid = $event->relateduserid;
if ($rs = $DB->get_records('badge_criteria', array('criteriatype' => BADGE_CRITERIA_TYPE_BADGE))) {
foreach ($rs as $r) {
$badge = new badge($r->badgeid);
if (!$badge->is_active() || $badge->is_issued($userid)) {
continue;
}
if ($badge->criteria[BADGE_CRITERIA_TYPE_BADGE]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_BADGE]->mark_complete($userid);
if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
$badge->issue($userid);
}
}
}
}
}
}
/**
* Triggered when 'user_updated' event happens.
*
* @param \core\event\user_updated $event event generated when user profile is updated.
*/
public static function profile_criteria_review(\core\event\user_updated $event) {
global $DB, $CFG;
if (!empty($CFG->enablebadges)) {
require_once($CFG->dirroot.'/lib/badgeslib.php');
$userid = $event->objectid;
if ($rs = $DB->get_records('badge_criteria', array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE))) {
foreach ($rs as $r) {
$badge = new badge($r->badgeid);
if (!$badge->is_active() || $badge->is_issued($userid)) {
continue;
}
if ($badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->mark_complete($userid);
if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
$badge->issue($userid);
}
}
}
}
}
}
/**
* Triggered when the 'cohort_member_added' event happens.
*
* @param \core\event\cohort_member_added $event generated when a user is added to a cohort
*/
public static function cohort_criteria_review(\core\event\cohort_member_added $event) {
global $DB, $CFG;
if (!empty($CFG->enablebadges)) {
require_once($CFG->dirroot.'/lib/badgeslib.php');
$cohortid = $event->objectid;
$userid = $event->relateduserid;
// Get relevant badges.
$badgesql = "SELECT badgeid
FROM {badge_criteria_param} cp
JOIN {badge_criteria} c ON cp.critid = c.id
WHERE c.criteriatype = ?
AND cp.name = ?";
$badges = $DB->get_records_sql($badgesql, array(BADGE_CRITERIA_TYPE_COHORT, "cohort_{$cohortid}"));
if (empty($badges)) {
return;
}
foreach ($badges as $b) {
$badge = new badge($b->badgeid);
if (!$badge->is_active()) {
continue;
}
if ($badge->is_issued($userid)) {
continue;
}
if ($badge->criteria[BADGE_CRITERIA_TYPE_COHORT]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_COHORT]->mark_complete($userid);
if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
$badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
$badge->issue($userid);
}
}
}
}
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains mappings for classes that have been renamed so that they meet the requirements of the autoloader.
*
* Renaming isn't always the recommended approach, but can provide benefit in situations where we've already got a
* close structure, OR where lots of classes get included and not necessarily used, or checked for often.
*
* When renaming a class delete the original class and add an entry to the db/renamedclasses.php directory for that
* component.
* This way we don't need to keep around old classes, instead creating aliases only when required.
* One big advantage to this method is that we provide consistent debugging for renamed classes when they are used.
*
* @package core_badges
* @copyright Dai Nguyen Trong <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$renamedclasses = [
'core_badges_observer' => 'core_badges\\event\\observer',
];
+26 -27
View File
@@ -34,47 +34,46 @@ defined('MOODLE_INTERNAL') || die();
// List of legacy event handlers.
$handlers = array(
$handlers = [
// No more old events!
);
];
// List of events_2 observers.
$observers = array(
array(
$observers = [
[
'eventname' => '\core\event\course_module_completion_updated',
'callback' => 'core_badges_observer::course_module_criteria_review',
),
array(
'callback' => '\core_badges\event\observer::course_module_criteria_review',
],
[
'eventname' => '\core\event\badge_awarded',
'callback' => 'core_badges_observer::badge_criteria_review',
),
array(
'callback' => '\core_badges\event\observer::badge_criteria_review',
],
[
'eventname' => '\core\event\course_completed',
'callback' => 'core_badges_observer::course_criteria_review',
),
array(
'callback' => '\core_badges\event\observer::course_criteria_review',
],
[
'eventname' => '\core\event\user_updated',
'callback' => 'core_badges_observer::profile_criteria_review',
),
array(
'callback' => '\core_badges\event\observer::profile_criteria_review',
],
[
'eventname' => '\core\event\cohort_member_added',
'callback' => 'core_badges_observer::cohort_criteria_review',
),
array(
'callback' => '\core_badges\event\observer::cohort_criteria_review',
],
[
'eventname' => '\core\event\competency_evidence_created',
'callback' => 'core_badges_observer::competency_criteria_review',
),
'callback' => '\core_badges\event\observer::competency_criteria_review',
],
// Competencies.
array(
[
'eventname' => '\core\event\course_completed',
'callback' => 'core_competency\api::observe_course_completed',
),
array(
],
[
'eventname' => '\core\event\course_module_completion_updated',
'callback' => 'core_competency\api::observe_course_module_completion_updated',
),
);
],
];
// List of all events triggered by Moodle can be found using Events list report.