224 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			No EOL
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
// This file is part of the Studyplan plugin for Moodle
 | 
						|
//
 | 
						|
// 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 <https://www.gnu.org/licenses/>.
 | 
						|
/**
 | 
						|
 *
 | 
						|
 * @package    local_treestudyplan
 | 
						|
 * @copyright  2023 P.M. Kuipers
 | 
						|
 * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
						|
 */
 | 
						|
 | 
						|
namespace local_treestudyplan;
 | 
						|
require_once($CFG->libdir.'/externallib.php');
 | 
						|
 | 
						|
use \local_treestudyplan\studyplan;
 | 
						|
 | 
						|
class cascadecohortsync {
 | 
						|
    private const METHOD = "cohort";
 | 
						|
    private $studyplan;
 | 
						|
    private $studyplanid;
 | 
						|
 | 
						|
    function __construct(studyplan $studyplan) {
 | 
						|
        $this->studyplan = $studyplan;
 | 
						|
        $this->studyplanid = $studyplan->id();
 | 
						|
    }
 | 
						|
 | 
						|
    static private function array_remove_value($array, $value) {
 | 
						|
        $a = [];
 | 
						|
        foreach ($array as $v) {
 | 
						|
            if ($v != $value) {
 | 
						|
                $a[] = $v;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $a;
 | 
						|
    }
 | 
						|
 | 
						|
    static function uploadenrolmentmethods_get_group($courseid, $groupname) {
 | 
						|
        // Function shamelessly copied from tool/uploadenrolmentmethods/locallib.php.
 | 
						|
        global $DB, $CFG;
 | 
						|
 | 
						|
        require_once($CFG->dirroot.'/group/lib.php');
 | 
						|
 | 
						|
        // Check to see if the group name already exists in this course.
 | 
						|
        if ($DB->record_exists('groups', array('name' => $groupname, 'courseid' => $courseid))) {
 | 
						|
            $group = $DB->get_record('groups', array('name' => $groupname, 'courseid' => $courseid));
 | 
						|
            return $group->id;
 | 
						|
        }
 | 
						|
        // The named group doesn't exist, so create a new one in the course.
 | 
						|
        $groupdata = new \stdClass();
 | 
						|
        $groupdata->courseid = $courseid;
 | 
						|
        $groupdata->name = $groupname;
 | 
						|
        $groupid = groups_create_group($groupdata);
 | 
						|
 | 
						|
        return $groupid;
 | 
						|
    }
 | 
						|
 | 
						|
    function sync() {
 | 
						|
        global $DB;
 | 
						|
 | 
						|
        /*  Explainer:
 | 
						|
            This script uses {enrol}.customtext4 to store a json array of all studyplans that need this cohort sync to exist.
 | 
						|
            Since the cohort-sync enrolment method uses only customint1 and customint2, this is a safe place to store the data.
 | 
						|
            (Should the cohortsync script at any future time be modified to use customtext fields, it is still extremely unlikely that
 | 
						|
            customtext4 will be used.)
 | 
						|
            Because of the overhead involved in keeping an extra table up to date and clean it up if cohort syncs are removed outside of this script,
 | 
						|
            it was determined to be the simplest and cleanest solution.
 | 
						|
        */
 | 
						|
 | 
						|
        $enrol = \enrol_get_plugin(self::METHOD);
 | 
						|
        // Find the courses that need to be synced to the associated cohorts.
 | 
						|
        $courseids = $this->studyplan->get_linked_course_ids();
 | 
						|
        // And find the cohorts that are linked to this studyplan.
 | 
						|
        $cohortids = $this->studyplan->get_linked_cohort_ids();
 | 
						|
 | 
						|
        // Next, for each course that is linked:.
 | 
						|
        foreach ($courseids as $courseid) {
 | 
						|
            $course = \get_course($courseid);
 | 
						|
            //\mtrace("Processing Course {$courseid} {$course->shortname}");.
 | 
						|
            // first create any nonexistent links.
 | 
						|
            foreach ($cohortids as $cohortid) {
 | 
						|
                $cohort = $DB->get_record('cohort', ['id'=>$cohortid]);
 | 
						|
                //\mtrace("Processing cohort {$cohortid} {$cohort->shortname}");.
 | 
						|
 | 
						|
                $instanceparams = [
 | 
						|
                    'courseid' => $courseid,
 | 
						|
                    'customint1' => $cohortid,
 | 
						|
                    'enrol' => self::METHOD,
 | 
						|
                    'roleid' => get_config("local_treestudyplan", "csync_roleid"),
 | 
						|
                ];
 | 
						|
 | 
						|
                $instancenewparams = [
 | 
						|
                    'customint1' => $cohortid,
 | 
						|
                    'enrol' => self::METHOD,
 | 
						|
                    'roleid' => get_config("local_treestudyplan", "csync_roleid"),
 | 
						|
                ];
 | 
						|
 | 
						|
                // Create group: .
 | 
						|
 | 
						|
                // 1:   check if a link exists.
 | 
						|
                //      If not, make it (maybe use some of the custom text to list the studyplans involved).
 | 
						|
                if ($instance = $DB->get_record('enrol', $instanceparams)) {
 | 
						|
                    //\mtrace("Instance exists");.
 | 
						|
                    // it already exists.
 | 
						|
                    // check if this studyplan is already referenced in customtext4 in json format.
 | 
						|
 | 
						|
                    //TODO: Check this code - Maybe add option to not remember manually added stuff .
 | 
						|
                    $plans = json_decode($instance->customtext4);
 | 
						|
                    if ($plans == false || !is_array(($plans))) {
 | 
						|
                        // If the data was not an array (null or garbled), count it as manually added.
 | 
						|
                        // This will prevent it's deletion upon.
 | 
						|
                        if (get_config("local_treestudyplan", "csync_remember_manual_csync")) {
 | 
						|
                            $plans = ["manual"];
 | 
						|
                        } else {
 | 
						|
                            $plans = [];
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    if (!in_array($this->studyplanid , $plans)) {
 | 
						|
                        // if not, add it to the reference.
 | 
						|
                        //\mtrace("Adding this plan to the list");.
 | 
						|
                        $plans[] = (int)($this->studyplanid);
 | 
						|
                        $enrol->update_instance($instance, (object)["customtext4"=>json_encode($plans)]);
 | 
						|
                    }
 | 
						|
 | 
						|
                } else {
 | 
						|
                    //\mtrace("New instance should be made");.
 | 
						|
                    // If method members should be added to a group, create it or get its ID.
 | 
						|
 | 
						|
                    if (get_config("local_treestudyplan", "csync_creategroup")) {
 | 
						|
                        // Make or get new new cohort group - but only on creating of instances.
 | 
						|
                        $groupname = $cohort->name." ".strtolower(\get_string('defaultgroupname', 'core_group'));
 | 
						|
                        //\mtrace("Adding group {$groupname} for this method");.
 | 
						|
                        // and make sure the .
 | 
						|
                        $instancenewparams['customint2'] = self::uploadenrolmentmethods_get_group($courseid, $groupname);
 | 
						|
                    }
 | 
						|
 | 
						|
                    if ($instanceid = $enrol->add_instance($course, $instancenewparams)) {
 | 
						|
                        // also record the (as of yet only) studyplans id requiring this association.
 | 
						|
                        // in the customtext4 field in json format.
 | 
						|
                        //\mtrace("Instance ({$instanceid} created. Updateing instance with studyplan id");.
 | 
						|
                        $instance = $DB->get_record('enrol', array('id' => $instanceid));
 | 
						|
                        $enrol->update_instance($instance, (object)["customtext4"=>json_encode([(int)($this->studyplanid)])]);
 | 
						|
 | 
						|
                        //\mtrace("Synchronize the enrolment");.
 | 
						|
                        // Successfully added a valid new instance, so now instantiate it.
 | 
						|
                        // First synchronise the enrolment.
 | 
						|
                        $cohorttrace = new \null_progress_trace();
 | 
						|
                        $result = enrol_cohort_sync($cohorttrace, $cohortid);
 | 
						|
                        if ($result > 0) {
 | 
						|
                            //\mtrace("Error during 'enrol_cohort_sync': code {$result}");.
 | 
						|
                        }
 | 
						|
                        $cohorttrace->finished();
 | 
						|
 | 
						|
                    } else {
 | 
						|
                        // Instance not added for some reason, so report an error somewhere.
 | 
						|
                        // (or not).
 | 
						|
                        //\mtrace("Error - instance not added for some reason");.
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
            // 2:   Check if there are cohort links for this studyplan in this course that should be removed.
 | 
						|
            //      A: Check if there are cohort links that are no longer related to this studyplan.
 | 
						|
            //      B: Check if these links are valid through another studyplan...
 | 
						|
            //      If no one uses the link anymore, deactivate it...
 | 
						|
            // INFO: This does not remove the sync from courses that are unlinked from a studplan. But maybe we do not want that anyway.
 | 
						|
            //       since it is generally a good idea to keep student access to courses available .
 | 
						|
 | 
						|
            if (get_config("local_treestudyplan", "csync_autoremove")) {
 | 
						|
                // Only try the autoremove if the option is enabled.
 | 
						|
                //\mtrace("Autoremove scan for course {$courseid} {$course->shortname}");.
 | 
						|
                // find all cohort syncs for this course.
 | 
						|
                $searchparams = [
 | 
						|
                    'courseid' => $courseid,
 | 
						|
                    'enrol' => self::METHOD,
 | 
						|
                    'roleid' => get_config("local_treestudyplan", "csync_roleid"),
 | 
						|
                ];
 | 
						|
 | 
						|
                $records = $DB->get_records("enrol", $searchparams);
 | 
						|
                foreach ($records as $instance) {
 | 
						|
                    if (!empty($instance->customtext4)) { // only check the records that have studyplan information in the customtext4 field.
 | 
						|
                        // first check if the cohort is not one of the cohort id's we have associated.
 | 
						|
                        if (!in_array($instance->customint1, $cohortids)) {
 | 
						|
                            //\mtrace("Found cohort sync instance that is not currently liked to the studyplan: {$instance->id}");.
 | 
						|
                            // So it may or may not need to be removed.
 | 
						|
                            $plans = json_decode($instance->customtext4);
 | 
						|
                            if ($plans !== null && is_array($plans)) {
 | 
						|
                                //if a valid array is not returned, better leave it be, we don't want to mess with it.
 | 
						|
                                // otherwise, check if we should remove it.
 | 
						|
                                if (in_array($this->studyplanid, $plans)) {
 | 
						|
                                    //\mtrace("Found this studyplan in the id list - removing from list");.
 | 
						|
                                    //if this plan was referenced before.
 | 
						|
                                    // first remove the link.
 | 
						|
                                    $fplans = self::array_remove_value($plans, $this->studyplanid);
 | 
						|
                                    if (count($fplans) == 0) {
 | 
						|
                                        // delete the sync if there are no studyplan references left.
 | 
						|
                                        //\mtrace("No references are left, removing instance");.
 | 
						|
                                        $enrol->delete_instance($instance);
 | 
						|
                                    } else {
 | 
						|
                                        // otherwise just update the references so this studyplan is no longer linked.
 | 
						|
                                        //\mtrace("Still references left in the list, updating list...");.
 | 
						|
                                        $enrol->update_instance($instance, (object)["customtext4"=>json_encode($fplans)]);
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        //\mtrace("Cascading complete");.
 | 
						|
    }
 | 
						|
} |