diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0768493 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,109 @@ +name: Moodle Plugin CI + +on: + push: + pull_request: + schedule: + - cron: '33 2 * * 1' # weekly, on Monday morning + +jobs: + test: + runs-on: ubuntu-latest + + services: + mariadb: + image: mariadb:10 + env: + MYSQL_USER: 'root' + MYSQL_ALLOW_EMPTY_PASSWORD: "true" + MYSQL_CHARACTER_SET_SERVER: "utf8mb4" + MYSQL_COLLATION_SERVER: "utf8mb4_unicode_ci" + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3 + + strategy: + fail-fast: false + matrix: + include: + - php: '8.2' + moodle-branch: 'main' + database: 'mariadb' + - php: '8.2' + moodle-branch: 'MOODLE_403_STABLE' + database: 'mariadb' + steps: + - name: Check out repository code + uses: actions/checkout@v3 + with: + path: plugin + + - name: Setup PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: ${{ matrix.extensions }} + ini-values: max_input_vars=5000 + # If you are not using code coverage, keep "none". Otherwise, use "pcov" (Moodle 3.10 and up) or "xdebug". + # If you try to use code coverage with "none", it will fallback to phpdbg (which has known problems). + coverage: none + + - name: Initialise moodle-plugin-ci + run: | + composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4 + echo $(cd ci/bin; pwd) >> $GITHUB_PATH + echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH + sudo locale-gen en_AU.UTF-8 + echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV + + - name: Install moodle-plugin-ci + run: | + moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 + env: + DB: ${{ matrix.database }} + MOODLE_BRANCH: ${{ matrix.moodle-branch }} + + - name: PHP Lint + if: ${{ !cancelled() }} + run: moodle-plugin-ci phplint + + - name: PHP Mess Detector + continue-on-error: true # This step will show errors but will not fail + if: ${{ !cancelled() }} + run: moodle-plugin-ci phpmd + + - name: Moodle Code Checker + if: ${{ !cancelled() }} + run: moodle-plugin-ci phpcs --max-warnings 0 + + - name: Moodle PHPDoc Checker + if: ${{ !cancelled() }} + run: moodle-plugin-ci phpdoc --max-warnings 0 + + - name: Validating + if: ${{ !cancelled() }} + run: moodle-plugin-ci validate + + - name: Check upgrade savepoints + if: ${{ !cancelled() }} + run: moodle-plugin-ci savepoints + + - name: Mustache Lint + if: ${{ !cancelled() }} + run: moodle-plugin-ci mustache + + - name: Grunt + if: ${{ !cancelled() }} + run: moodle-plugin-ci grunt --max-lint-warnings 0 + + - name: PHPUnit tests + if: ${{ !cancelled() }} + run: moodle-plugin-ci phpunit --fail-on-warning + + - name: Behat features + if: ${{ !cancelled() }} + run: moodle-plugin-ci behat --profile chrome + + - name: Mark cancelled jobs as failed. + if: ${{ cancelled() }} + run: exit 1 \ No newline at end of file diff --git a/.phpcs.xml b/.phpcs.xml new file mode 100644 index 0000000..a730760 --- /dev/null +++ b/.phpcs.xml @@ -0,0 +1,4 @@ + + + + diff --git a/ajax.php b/ajax.php index 600b875..8f874a5 100644 --- a/ajax.php +++ b/ajax.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * This file processes AJAX enrolment actions and returns JSON for the ilios plugin + * This file processes AJAX enrolment actions and returns JSON for the ilios plugin. * * The general idea behind this file is that any errors should throw exceptions * which will be returned and acted upon by the calling AJAX script. @@ -33,12 +33,12 @@ require_once($CFG->dirroot.'/group/lib.php'); // Must have the sesskey. -$id = required_param('id', PARAM_INT); // course id +$id = required_param('id', PARAM_INT); // Course ID. $action = required_param('action', PARAM_ALPHANUMEXT); -$PAGE->set_url(new moodle_url('/enrol/ilios/ajax.php', array('id'=>$id, 'action'=>$action))); +$PAGE->set_url(new moodle_url('/enrol/ilios/ajax.php', ['id' => $id, 'action' => $action])); -$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST); +$course = $DB->get_record('course', ['id' => $id], '*', MUST_EXIST); $context = context_course::instance($course->id, MUST_EXIST); if ($course->id == SITEID) { @@ -65,14 +65,14 @@ /** @var enrol_ilios_plugin $enrol */ $enrol = enrol_get_plugin('ilios'); -$api_client = $enrol->get_api_client(); -$access_token = $enrol->get_api_access_token(); +$apiclient = $enrol->get_api_client(); +$accesstoken = $enrol->get_api_access_token(); switch ($action) { case 'getselectschooloptions': require_capability('moodle/course:enrolconfig', $context); - $schools = $api_client->get($access_token, 'schools', '', array('title' => "ASC")); - $schoolarray = array(); + $schools = $apiclient->get($accesstoken, 'schools', '', ['title' => "ASC"]); + $schoolarray = []; foreach ($schools as $school) { $schoolarray["$school->id:$school->title"] = $school->title; } @@ -81,13 +81,13 @@ case 'getselectprogramoptions': require_capability('moodle/course:enrolconfig', $context); - $sid = required_param('filterid', PARAM_INT); // school id - $programs = array(); - $programs = $api_client->get($access_token, 'programs', array('school' => $sid), array('title' => "ASC")); - $programarray = array(); + $sid = required_param('filterid', PARAM_INT); // School ID. + $programs = []; + $programs = $apiclient->get($accesstoken, 'programs', ['school' => $sid], ['title' => "ASC"]); + $programarray = []; foreach ($programs as $program) { $key = $program->id; - foreach (array('shortTitle', 'title') as $attr) { + foreach (['shortTitle', 'title'] as $attr) { $key .= ':'; if (property_exists($program, $attr)) { $key .= $program->$attr; @@ -101,24 +101,24 @@ case 'getselectcohortoptions': require_capability('moodle/course:enrolconfig', $context); $pid = required_param('filterid', PARAM_INT); - $programyears = $api_client->get( - $access_token, + $programyears = $apiclient->get( + $accesstoken, 'programYears', - array("program" => $pid), - array("startYear" => "ASC") + ["program" => $pid], + ["startYear" => "ASC"] ); - $programyeararray = array(); - $cohortoptions = array(); + $programyeararray = []; + $cohortoptions = []; foreach ($programyears as $progyear) { $programyeararray[] = $progyear->id; } if (!empty($programyeararray)) { - $cohorts = $api_client->get( - $access_token, + $cohorts = $apiclient->get( + $accesstoken, 'cohorts', - array("programYear" => $programyeararray), - array("title" => "ASC") + ["programYear" => $programyeararray], + ["title" => "ASC"] ); foreach ($cohorts as $cohort) { $cohortoptions["$cohort->id:$cohort->title"] = $cohort->title @@ -131,15 +131,15 @@ case 'getselectlearnergroupoptions': require_capability('moodle/course:enrolconfig', $context); - $cid = required_param('filterid', PARAM_INT); // cohort id - $usertype = optional_param('usertype', 0, PARAM_INT); // learner or instructor - $learnergroups = $api_client->get( - $access_token, + $cid = required_param('filterid', PARAM_INT); // Cohort ID. + $usertype = optional_param('usertype', 0, PARAM_INT); // Learner or instructor. + $learnergroups = $apiclient->get( + $accesstoken, 'learnerGroups', - array('cohort' => $cid, 'parent' => 'null'), - array('title'=> "ASC") + ['cohort' => $cid, 'parent' => 'null'], + ['title' => "ASC"] ); - $grouparray = array(); + $grouparray = []; foreach ($learnergroups as $group) { $grouparray["$group->id:$group->title"] = $group->title. ' ('. count($group->children) .')'; @@ -150,14 +150,14 @@ case 'getselectsubgroupoptions': require_capability('moodle/course:enrolconfig', $context); - $gid = required_param('filterid', PARAM_INT); // group id - $usertype = optional_param('usertype', 0, PARAM_INT); // learner or instructor - $subgroupoptions = array(); - $subgroups = $api_client->get( - $access_token, + $gid = required_param('filterid', PARAM_INT); // Group ID. + $usertype = optional_param('usertype', 0, PARAM_INT); // Learner or instructor. + $subgroupoptions = []; + $subgroups = $apiclient->get( + $accesstoken, 'learnerGroups', - array("parent" => $gid), - array("title" => "ASC") + ["parent" => $gid], + ["title" => "ASC"] ); foreach ($subgroups as $subgroup) { $subgroupoptions["$subgroup->id:$subgroup->title"] = $subgroup->title. @@ -165,12 +165,12 @@ $subgroupoptions["$subgroup->id:$subgroup->title"] .= ' ('. count($subgroup->users) .')'; if (!empty($subgroup->children)) { - $processchildren = function ($parent) use (&$processchildren,&$subgroupoptions, $api_client, $access_token) { - $subgrps = $api_client->get( - $access_token, + $processchildren = function ($parent) use (&$processchildren, &$subgroupoptions, $apiclient, $accesstoken) { + $subgrps = $apiclient->get( + $accesstoken, 'learnerGroups', - array( 'parent' => $parent->id), - array( 'title' => "ASC") + [ 'parent' => $parent->id], + [ 'title' => "ASC"] ); foreach ($subgrps as $subgrp) { $subgroupoptions["$subgrp->id:$parent->title / $subgrp->title"] = $parent->title.' / '.$subgrp->title. @@ -190,16 +190,15 @@ case 'getselectinstructorgroupoptions': require_capability('moodle/course:enrolconfig', $context); - $gid = required_param('filterid', PARAM_INT); // group id - $instructorgroupoptions = array(); - $learnergroup = $api_client->get_by_id($access_token, 'learnerGroups', $gid); + $gid = required_param('filterid', PARAM_INT); // Group ID. + $instructorgroupoptions = []; + $learnergroup = $apiclient->get_by_id($accesstoken, 'learnerGroups', $gid); if (!empty($learnergroup->instructorGroups)) { - $instructorgroups = $api_client->get( - $access_token, + $instructorgroups = $apiclient->get( + $accesstoken, 'instructorGroups', - // array("id" => $learnergroup->instructorGroups), '', - array("title" => "ASC") + ["title" => "ASC"] ); foreach ($instructorgroups as $instructorgroup) { $instructorgroupoptions["$instructorgroup->id:$instructorgroup->title"] = $instructorgroup->title. diff --git a/classes/task/ilios_sync_task.php b/classes/task/ilios_sync_task.php index bbb652b..b223d52 100644 --- a/classes/task/ilios_sync_task.php +++ b/classes/task/ilios_sync_task.php @@ -24,27 +24,32 @@ namespace enrol_ilios\task; -defined('MOODLE_INTERNAL') || die; +use coding_exception; +use core\task\scheduled_task; /** * Simple task to run sync enrolments. * + * @package enrol_ilios * @copyright 2018 The Regents of the University of California * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class ilios_sync_task extends \core\task\scheduled_task { +class ilios_sync_task extends scheduled_task { /** - * @inheritdoc + * Gets the task name. + * + * @return string The task name. + * @throws coding_exception */ public function get_name() { return get_string('iliossync', 'enrol_ilios'); } /** - * @inheritdoc + * Executes the task. */ - public function execute() { + public function execute(): void { global $CFG; require_once($CFG->dirroot . '/enrol/ilios/lib.php'); @@ -54,8 +59,6 @@ public function execute() { } $plugin = enrol_get_plugin('ilios'); - $result = $plugin->sync(new \text_progress_trace()); - return $result; - + $plugin->sync(new \text_progress_trace()); } } diff --git a/db/access.php b/db/access.php index 144d36a..2cea578 100644 --- a/db/access.php +++ b/db/access.php @@ -25,26 +25,26 @@ defined('MOODLE_INTERNAL') || die(); -$capabilities = array( +$capabilities = [ - 'enrol/ilios:config' => array( + 'enrol/ilios:config' => [ 'captype' => 'write', 'contextlevel' => CONTEXT_COURSE, - 'archetypes' => array( + 'archetypes' => [ 'editingteacher' => CAP_ALLOW, 'manager' => CAP_ALLOW, - ) - ), + ], + ], /* This is used only when sync suspends users instead of full unenrolment. */ - 'enrol/ilios:unenrol' => array( + 'enrol/ilios:unenrol' => [ 'captype' => 'write', 'contextlevel' => CONTEXT_COURSE, - 'archetypes' => array( + 'archetypes' => [ 'manager' => CAP_ALLOW, - ) - ), + ], + ], -); +]; diff --git a/db/tasks.php b/db/tasks.php index 8bc171d..d464419 100644 --- a/db/tasks.php +++ b/db/tasks.php @@ -24,14 +24,14 @@ defined('MOODLE_INTERNAL') || die(); -$tasks = array( - array( +$tasks = [ + [ 'classname' => '\enrol_ilios\task\ilios_sync_task', 'blocking' => 0, 'minute' => '55', 'hour' => '*', 'day' => '*', 'dayofweek' => '*', - 'month' => '*' - ) -); + 'month' => '*', + ], +]; diff --git a/db/uninstall.php b/db/uninstall.php index 9c67469..4af99f8 100644 --- a/db/uninstall.php +++ b/db/uninstall.php @@ -23,19 +23,25 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -defined('MOODLE_INTERNAL') || die(); - +/** + * Callback to run during plugin uninstallation. + * Deletes all Ilios enrolments and removes any user role assignments for this plugin. + * + * @return bool Always TRUE. + * @throws coding_exception + * @throws dml_exception + */ function xmldb_enrol_ilios_uninstall() { global $CFG, $DB; $ilios = enrol_get_plugin('ilios'); - $rs = $DB->get_recordset('enrol', array('enrol'=>'ilios')); + $rs = $DB->get_recordset('enrol', ['enrol' => 'ilios']); foreach ($rs as $instance) { $ilios->delete_instance($instance); } $rs->close(); - role_unassign_all(array('component'=>'enrol_ilios')); + role_unassign_all(['component' => 'enrol_ilios']); return true; } diff --git a/edit.php b/edit.php index fb807ac..25b262f 100644 --- a/edit.php +++ b/edit.php @@ -30,17 +30,17 @@ $courseid = required_param('courseid', PARAM_INT); $instanceid = optional_param('id', 0, PARAM_INT); -$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST); +$course = $DB->get_record('course', ['id' => $courseid], '*', MUST_EXIST); $context = context_course::instance($course->id, MUST_EXIST); require_login($course); require_capability('moodle/course:enrolconfig', $context); require_capability('enrol/ilios:config', $context); -$PAGE->set_url('/enrol/ilios/edit.php', array('courseid'=>$course->id, 'id'=>$instanceid)); +$PAGE->set_url('/enrol/ilios/edit.php', ['courseid' => $course->id, 'id' => $instanceid]); $PAGE->set_pagelayout('admin'); -$returnurl = new moodle_url('/enrol/instances.php', array('id'=>$course->id)); +$returnurl = new moodle_url('/enrol/instances.php', ['id' => $course->id]); if (!enrol_is_enabled('ilios')) { redirect($returnurl); } @@ -49,23 +49,23 @@ $enrol = enrol_get_plugin('ilios'); if ($instanceid) { - $instance = $DB->get_record('enrol', array('courseid'=>$course->id, 'enrol'=>'ilios', 'id'=>$instanceid), '*', MUST_EXIST); + $instance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'ilios', 'id' => $instanceid], '*', MUST_EXIST); } else { // No instance yet, we have to add new instance. if (!$enrol->get_newinstance_link($course->id)) { redirect($returnurl); } - navigation_node::override_active_url(new moodle_url('/enrol/instances.php', array('id'=>$course->id))); + navigation_node::override_active_url(new moodle_url('/enrol/instances.php', ['id' => $course->id])); $instance = new stdClass(); $instance->id = null; $instance->courseid = $course->id; $instance->enrol = 'ilios'; - $instance->customchar1 = ''; // cohort / learnerGroup - $instance->customint1 = 0; // cohort / leaner group id. - $instance->customint2 = 0; // 0 - learner / 1 - instructor - $instance->customtext1 = ''; // json string of all useful values - $instance->customint6 = 0; // group id. + $instance->customchar1 = ''; // Cohort / learnerGroup. + $instance->customint1 = 0; // Cohort / leaner group id. + $instance->customint2 = 0; // Learner = 0, Instructor = 1. + $instance->customtext1 = ''; // JSON string of all useful values. + $instance->customint6 = 0; // Group ID. } // Try and make the manage instances node on the navigation active. @@ -74,7 +74,7 @@ $courseadmin->get('users')->get('manageinstances')->make_active(); } -$mform = new enrol_ilios_edit_form(null, array($instance, $enrol, $course)); +$mform = new enrol_ilios_edit_form(null, [$instance, $enrol, $course]); if ($mform->is_cancelled()) { redirect($returnurl); @@ -83,18 +83,18 @@ // We are here only because the form is submitted. $synctype = ''; $syncid = ''; - $syncinfo = array(); + $syncinfo = []; $selectvalue = isset($data->selectschool) ? $data->selectschool : ''; if (!empty($selectvalue)) { list($schoolid, $schooltitle) = explode( ":", $selectvalue, 2); - $syncinfo["school"] = array("id" => $schoolid, "title" => $schooltitle); + $syncinfo["school"] = ["id" => $schoolid, "title" => $schooltitle]; } $selectvalue = isset($data->selectprogram) ? $data->selectprogram : ''; if (!empty($selectvalue)) { list($programid, $programshorttitle, $programtitle) = explode( ":", $selectvalue, 3); - $syncinfo["program"] = array("id" => $programid, "shorttitle" => $programshorttitle, "title" => $programtitle); + $syncinfo["program"] = ["id" => $programid, "shorttitle" => $programshorttitle, "title" => $programtitle]; } $selectvalue = isset($data->selectcohort) ? $data->selectcohort : ''; @@ -102,7 +102,7 @@ list($cohortid, $cohorttitle) = explode( ":", $selectvalue, 2); $synctype = 'cohort'; $syncid = $cohortid; - $syncinfo["cohort"] = array("id" => $cohortid, "title" => $cohorttitle); + $syncinfo["cohort"] = ["id" => $cohortid, "title" => $cohorttitle]; } $selectvalue = isset($data->selectlearnergroup) ? $data->selectlearnergroup : ''; @@ -110,7 +110,7 @@ list($learnergroupid, $learnergrouptitle) = explode( ":", $selectvalue, 2); $synctype = 'learnerGroup'; $syncid = $learnergroupid; - $syncinfo["learnerGroup"] = array( "id" => $learnergroupid, "title" => $learnergrouptitle ); + $syncinfo["learnerGroup"] = [ "id" => $learnergroupid, "title" => $learnergrouptitle ]; } $selectvalue = isset($data->selectsubgroup) ? $data->selectsubgroup : ''; @@ -118,14 +118,21 @@ list($subgroupid, $subgrouptitle) = explode( ":", $selectvalue, 2); $synctype = 'learnerGroup'; $syncid = $subgroupid; - $syncinfo["subGroup"] = array( "id" => $subgroupid, "title" => $subgrouptitle ); + $syncinfo["subGroup"] = [ "id" => $subgroupid, "title" => $subgrouptitle ]; } if ($data->id) { // NOTE: no cohort or learner group changes here!!! if ($data->roleid != $instance->roleid) { // The sync script can only add roles, for perf reasons it does not modify them. - role_unassign_all(array('contextid'=>$context->id, 'roleid'=>$instance->roleid, 'component'=>'enrol_ilios', 'itemid'=>$instance->id)); + role_unassign_all( + [ + 'contextid' => $context->id, + 'roleid' => $instance->roleid, + 'component' => 'enrol_ilios', + 'itemid' => $instance->id, + ] + ); } $instance->name = $data->name; @@ -140,13 +147,19 @@ $DB->update_record('enrol', $instance); } else { - $enrol->add_instance($course, array('name'=>$data->name, 'status'=>$data->status, - 'customchar1'=>$synctype, - 'customint1'=>$syncid, - 'customtext1'=>json_encode($syncinfo), - 'roleid'=>$data->roleid, - 'customint2'=>$data->selectusertype, - 'customint6'=>$data->customint6)); + $enrol->add_instance( + $course, + [ + 'name' => $data->name, + 'status' => $data->status, + 'customchar1' => $synctype, + 'customint1' => $syncid, + 'customtext1' => json_encode($syncinfo), + 'roleid' => $data->roleid, + 'customint2' => $data->selectusertype, + 'customint6' => $data->customint6, + ], + ); } $trace = new null_progress_trace(); diff --git a/edit_form.php b/edit_form.php index 9fe2a87..7aede27 100644 --- a/edit_form.php +++ b/edit_form.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Adds instance form + * Edit instance form. * * @package enrol_ilios * @author Carson Tam @@ -28,41 +28,66 @@ require_once("$CFG->libdir/formslib.php"); require_once("lib.php"); +/** + * Edit instance form class. + * + * @package enrol_ilios + * @author Carson Tam + * @copyright 2017 The Regents of the University of California + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ class enrol_ilios_edit_form extends moodleform { - - function definition() { + /** + * Form definition. + * + * @return void + * @throws coding_exception + * @throws dml_exception + * @throws moodle_exception + */ + protected function definition(): void { global $CFG, $DB, $PAGE; $mform = $this->_form; - /** @var enrol_ilios_plugin $plugin */ + /* @var enrol_ilios_plugin $plugin This enrolment plugin. */ list($instance, $plugin, $course) = $this->_customdata; $coursecontext = context_course::instance($course->id); - $PAGE->requires->yui_module('moodle-enrol_ilios-groupchoosers', 'M.enrol_ilios.init_groupchoosers', - array(array('formid' => $mform->getAttribute('id'), 'courseid' => $course->id))); + $PAGE->requires->yui_module( + 'moodle-enrol_ilios-groupchoosers', + 'M.enrol_ilios.init_groupchoosers', + [ + [ + 'formid' => $mform->getAttribute('id'), + 'courseid' => $course->id, + ], + ] + ); $enrol = $plugin; - $api_client = $plugin->get_api_client(); - $access_token = $plugin->get_api_access_token(); + $apiclient = $plugin->get_api_client(); + $accesstoken = $plugin->get_api_access_token(); - $mform->addElement('header','general', get_string('pluginname', 'enrol_ilios')); + $mform->addElement('header', 'general', get_string('pluginname', 'enrol_ilios')); $mform->addElement('text', 'name', get_string('custominstancename', 'enrol')); $mform->setType('name', PARAM_TEXT); - $options = array(ENROL_INSTANCE_ENABLED => get_string('yes'), - ENROL_INSTANCE_DISABLED => get_string('no')); + $options = [ENROL_INSTANCE_ENABLED => get_string('yes'), + ENROL_INSTANCE_DISABLED => get_string('no')]; $mform->addElement('select', 'status', get_string('status', 'enrol_ilios'), $options); - - $usertypes = array(get_string('learner', 'enrol_ilios'), get_string('instructor', 'enrol_ilios')); - $schooloptions = array('' => get_string('choosedots')); - $programoptions = array('' => get_string('choosedots')); - $cohortoptions = array('' => get_string('choosedots')); - $learnergroupoptions = array('' => get_string('none')); - $hasOrphanedLearnerGroup = false; - $subgroupoptions = array('' => get_string('none')); - $instructorgroupoptions = array('' => get_string('none')); + $usertypes = [ + get_string('learner', 'enrol_ilios'), + get_string('instructor', 'enrol_ilios'), + ]; + $schooloptions = ['' => get_string('choosedots')]; + $programoptions = ['' => get_string('choosedots')]; + $cohortoptions = ['' => get_string('choosedots')]; + $learnergroupoptions = ['' => get_string('none')]; + $hasorphanedlearnergroup = false; + $subgroupoptions = ['' => get_string('none')]; + $instructorgroupoptions = ['' => get_string('none')]; if ($instance->id) { $synctype = $instance->customchar1; @@ -71,29 +96,29 @@ function definition() { $syncinfo = json_decode($instance->customtext1); $instance->schoolid = $syncinfo->school->id; - $school = $api_client->get_by_id($access_token, 'schools', $instance->schoolid); + $school = $apiclient->get_by_id($accesstoken, 'schools', $instance->schoolid); $instance->selectschoolindex = "$instance->schoolid:$school->title"; - $schooloptions = array( $instance->selectschoolindex => $school->title ); + $schooloptions = [ $instance->selectschoolindex => $school->title ]; $instance->programid = $syncinfo->program->id; - $program = $api_client->get_by_id($access_token, 'programs', $instance->programid); + $program = $apiclient->get_by_id($accesstoken, 'programs', $instance->programid); $instance->selectprogramindex = $instance->programid; - foreach (array('shortTitle', 'title') as $attr) { + foreach (['shortTitle', 'title'] as $attr) { $instance->selectprogramindex .= ':'; if (property_exists($program, $attr)) { $instance->selectprogramindex .= $program->$attr; } } - $programoptions = array( $instance->selectprogramindex => $program->title ); + $programoptions = [ $instance->selectprogramindex => $program->title ]; $instance->cohortid = $syncinfo->cohort->id; - $cohort = $api_client->get_by_id($access_token, 'cohorts', $instance->cohortid); + $cohort = $apiclient->get_by_id($accesstoken, 'cohorts', $instance->cohortid); $instance->selectcohortindex = "$instance->cohortid:$cohort->title"; - $cohortoptions = array( $instance->selectcohortindex => + $cohortoptions = [ $instance->selectcohortindex => $cohort->title .' ('.count($cohort->learnerGroups).')' - .' ('.count($cohort->users).')'); + .' ('.count($cohort->users).')']; $instance->learnergroupid = ''; $instance->selectlearnergroupindex = ''; @@ -103,9 +128,9 @@ function definition() { if ($synctype == 'learnerGroup') { $instance->learnergroupid = $syncid; if (!empty($instance->customint2)) { - $group = $enrol->getGroupData('learnerGroup', $instance->learnergroupid); + $group = $enrol->get_group_data('learnerGroup', $instance->learnergroupid); } else { - $group = $api_client->get_by_id($access_token, 'learnerGroups', $instance->learnergroupid); + $group = $apiclient->get_by_id($accesstoken, 'learnerGroups', $instance->learnergroupid); } if ($group) { @@ -113,22 +138,23 @@ function definition() { $grouptitle = $group->title. ' ('. count($group->children) .')'; $grouptitle .= ' ('. count($group->users) .')'; - // $grouptitle .= (empty($instance->customint2)) ? ' ('. count($group->users) .')' : ' ('. count($group->instructors) .')'; - $learnergroupoptions = array($instance->selectlearnergroupindex => $grouptitle); + $learnergroupoptions = [$instance->selectlearnergroupindex => $grouptitle]; if (!empty($group->parent)) { $processparents = function ($child) use (&$processparents, &$learnergroupoptions, &$grouptitle, &$instance, - $api_client, - $access_token + $apiclient, + $accesstoken ) { - $parentgroup = $api_client->get_by_id($access_token, 'learnerGroups', $child->parent); + $parentgroup = $apiclient->get_by_id($accesstoken, 'learnerGroups', $child->parent); $instance->learnergroupid = $parentgroup->id; $instance->selectlearnergroupindex = "$instance->learnergroupid:$parentgroup->title"; - $learnergroupoptions = array( "$instance->learnergroupid:$parentgroup->title" => $parentgroup->title); - if (!empty($parentgroup->parent)){ + $learnergroupoptions = [ + "$instance->learnergroupid:$parentgroup->title" => $parentgroup->title, + ]; + if (!empty($parentgroup->parent)) { $grouptitle = $parentgroup->title . ' / '. $grouptitle; $processparents($parentgroup); } @@ -136,10 +162,10 @@ function definition() { $processparents($group); $instance->subgroupid = $group->id; $instance->selectsubgroupindex = "$group->id:$group->title"; - $subgroupoptions = array($instance->selectsubgroupindex => $grouptitle); + $subgroupoptions = [$instance->selectsubgroupindex => $grouptitle]; } } else { - $hasOrphanedLearnerGroup = true; + $hasorphanedlearnergroup = true; } } } @@ -150,14 +176,13 @@ function definition() { $mform->hardFreeze('selectusertype', $instance->customint2); } else { $mform->addElement('select', 'selectusertype', get_string('selectusertype', 'enrol_ilios'), $usertypes); - // $mform->addRule('selectusertype', get_string('required'), 'required', null, 'client'); $mform->addHelpButton('selectusertype', 'selectusertype', 'enrol_ilios'); } if ($instance->id) { $mform->addElement('select', 'selectschool', get_string('school', 'enrol_ilios'), $schooloptions); $mform->setConstant('selectschool', $instance->selectschoolindex); - $mform->hardFreeze('selectschool', $instance->selectschoolindex); + $mform->hardFreeze('selectschool'); } else { $mform->addElement('select', 'selectschool', get_string('school', 'enrol_ilios'), $schooloptions); $mform->addRule('selectschool', get_string('required'), 'required', null, 'client'); @@ -169,7 +194,7 @@ function definition() { if ($instance->id) { $mform->addElement('select', 'selectprogram', get_string('program', 'enrol_ilios'), $programoptions); $mform->setConstant('selectprogram', $instance->selectprogramindex); - $mform->hardFreeze('selectprogram', $instance->selectprogramindex); + $mform->hardFreeze('selectprogram'); } else { $mform->addElement('select', 'selectprogram', get_string('program', 'enrol_ilios'), $programoptions); @@ -183,7 +208,7 @@ function definition() { if ($instance->id) { $mform->addElement('select', 'selectcohort', get_string('cohort', 'enrol_ilios'), $cohortoptions); $mform->setConstant('selectcohort', $instance->selectcohortindex); - $mform->hardFreeze('selectcohort', $instance->selectcohortindex); + $mform->hardFreeze('selectcohort'); } else { $mform->addElement('select', 'selectcohort', get_string('cohort', 'enrol_ilios'), $cohortoptions); @@ -197,18 +222,17 @@ function definition() { if ($instance->id) { $mform->addElement('select', 'selectlearnergroup', get_string('learnergroup', 'enrol_ilios'), $learnergroupoptions); $mform->setConstant('selectlearnergroup', $instance->selectlearnergroupindex); - $mform->hardFreeze('selectlearnergroup', $instance->selectlearnergroupindex); + $mform->hardFreeze('selectlearnergroup'); } else { $mform->addElement('select', 'selectlearnergroup', get_string('learnergroup', 'enrol_ilios'), $learnergroupoptions); - // $mform->addRule('selectlearnergroup', get_string('required'), 'required', null, 'client'); $mform->addHelpButton('selectlearnergroup', 'learnergroup', 'enrol_ilios'); $mform->disabledIf('selectlearnergroup', 'selectcohort', 'eq', ''); $mform->registerNoSubmitButton('updatelearnergroupoptions'); $mform->addElement('submit', 'updatelearnergroupoptions', get_string('learnergroupoptionsupdate', 'enrol_ilios')); } - if ($hasOrphanedLearnerGroup) { + if ($hasorphanedlearnergroup) { $mform->addElement( 'static', 'orphaned_learnergroup', @@ -219,26 +243,25 @@ function definition() { if ($instance->id) { $mform->addElement('select', 'selectsubgroup', get_string('subgroup', 'enrol_ilios'), $subgroupoptions); $mform->setConstant('selectsubgroup', $instance->selectsubgroupindex); - $mform->hardFreeze('selectsubgroup', $instance->selectsubgroupindex); + $mform->hardFreeze('selectsubgroup'); } else { $mform->addElement('select', 'selectsubgroup', get_string('subgroup', 'enrol_ilios'), $subgroupoptions); $mform->addHelpButton('selectsubgroup', 'subgroup', 'enrol_ilios'); $mform->disabledIf('selectsubgroup', 'selectlearnergroup', 'eq', ''); $mform->registerNoSubmitButton('updatesubgroupoptions'); - // $mform->addElement('submit', 'updatesubgroupoptions', get_string('subgroupoptionsupdate', 'enrol_ilios')); $mform->addElement('submit', 'updatesubgroupoptions', 'Update subgroup option'); } - // Role assignment - $mform->addElement('header','roleassignments', get_string('roleassignments', 'role')); + // Role assignment. + $mform->addElement('header', 'roleassignments', get_string('roleassignments', 'role')); $roles = get_assignable_roles($coursecontext); $roles[0] = get_string('none'); $roles = array_reverse($roles, true); // Descending default sortorder. if ($instance->id) { if (!isset($roles[$instance->roleid])) { - if ($role = $DB->get_record('role', array('id'=>$instance->roleid))) { + if ($role = $DB->get_record('role', ['id' => $instance->roleid])) { $roles = role_fix_names($roles, $coursecontext, ROLENAME_ALIAS, true); $roles[$instance->roleid] = role_get_name($role, $coursecontext); } else { @@ -250,12 +273,9 @@ function definition() { $mform->addElement('select', 'roleid', get_string('assignrole', 'enrol_ilios'), $roles); $mform->setDefault('roleid', $enrol->get_config('roleid')); - // Group assignment - // $mform->addElement('header','groupassignment', 'Group assignment'); - - $groups = array(0 => get_string('none')); + $groups = [0 => get_string('none')]; foreach (groups_get_all_groups($course->id) as $group) { - $groups[$group->id] = format_string($group->name, true, array('context'=>$coursecontext)); + $groups[$group->id] = format_string($group->name, true, ['context' => $coursecontext]); } $mform->addElement('select', 'customint6', get_string('addgroup', 'enrol_ilios'), $groups); @@ -273,29 +293,39 @@ function definition() { } $this->set_data($instance); - $prog_el =& $mform->getElement('selectschool'); + $progel =& $mform->getElement('selectschool'); } - function definition_after_data() { + /** + * Set up the form depending on current values. + * This method is called after definition(), data submission and set_data(). + * All form setup that is dependent on form values should go in here. + * + * @return void + * @throws coding_exception + * @throws moodle_exception + */ + public function definition_after_data(): void { global $DB; $mform = $this->_form; - $prog_el = $mform->getElement('selectschool'); - if ($prog_el->isFrozen()) { + $progel = $mform->getElement('selectschool'); + if ($progel->isFrozen()) { return; } - /** @var enrol_ilios_plugin $enrol */ + /* @var enrol_ilios_plugin $enrol This enrolment plugin. */ $enrol = enrol_get_plugin('ilios'); - $api_client = $enrol->get_api_client(); - $access_token = $enrol->get_api_access_token(); + $apiclient = $enrol->get_api_client(); + $accesstoken = $enrol->get_api_access_token(); $selectvalues = $mform->getElementValue('selectschool'); if (is_array($selectvalues)) { - if (strstr($selectvalues[0],':')) + if (strstr($selectvalues[0], ':')) { list($schoolid, $schooltitle) = explode(':', $selectvalues[0], 2); - else - list($schoolid, $schooltitle) = array($selectvalues[0],'',''); + } else { + list($schoolid, $schooltitle) = [$selectvalues[0], '', '']; + } } else { $schoolid = ''; $schooltitle = ''; @@ -303,22 +333,23 @@ function definition_after_data() { $selectvalues = $mform->getElementValue('selectprogram'); if (is_array($selectvalues)) { - if (strstr($selectvalues[0],':')) + if (strstr($selectvalues[0], ':')) { list($programid, $programshorttitle, $programtitle) = explode(':', $selectvalues[0], 3); - else + } else { list($programid, $programshorttitle, $programtitle) - = array( $selectvalues[0], '', ''); + = [ $selectvalues[0], '', '']; + } } else { - list($programid, $programshorttitle, $programtitle) - = array( '', '', ''); + list($programid, $programshorttitle, $programtitle) = [ '', '', '']; } $selectvalues = $mform->getElementValue('selectcohort'); if (is_array($selectvalues)) { - if (strstr($selectvalues[0],':')) + if (strstr($selectvalues[0], ':')) { list($cohortid, $cohorttitle) = explode(':', $selectvalues[0], 2); - else - list($cohortid, $cohorttitle) = array($selectvalues[0],'',''); + } else { + list($cohortid, $cohorttitle) = [$selectvalues[0], '', '']; + } } else { $cohortid = ''; $cohorttitle = ''; @@ -326,44 +357,45 @@ function definition_after_data() { $selectvalues = $mform->getElementValue('selectlearnergroup'); if (is_array($selectvalues)) { - if (strstr($selectvalues[0],':')) + if (strstr($selectvalues[0], ':')) { list($learnergroupid, $learnergrouptitle) = explode(':', $selectvalues[0], 2); - else - list($learnergroupid, $learnergrouptitle) = array($selectvalues[0],'',''); + } else { + list($learnergroupid, $learnergrouptitle) = [$selectvalues[0], '', '']; + } } else { $learnergroupid = ''; $learnergrouptitle = ''; } - $schools = $api_client->get($access_token, 'schools', '', array('title' => "ASC")); + $schools = $apiclient->get($accesstoken, 'schools', '', ['title' => "ASC"]); - $prog_el =& $mform->getElement('selectschool'); - if ($schools === null) { // no connection to the server - // @TODO: get from cache if possible - $schooloptions = array('' => get_string('error')); - $prog_el->load($schooloptions); + $progel =& $mform->getElement('selectschool'); + if ($schools === null) { // No connection to the server. + // Todo: get from cache if possible. + $schooloptions = ['' => get_string('error')]; + $progel->load($schooloptions); } else { foreach ($schools as $school) { - $prog_el->addOption( $school->title, "$school->id:$school->title" ); + $progel->addOption( $school->title, "$school->id:$school->title" ); } } if (!empty($schoolid)) { $sid = $schoolid; - $prog_el =& $mform->getElement('selectprogram'); - $programoptions = array(); - $programs = array(); - $programs = $api_client->get( - $access_token, + $progel =& $mform->getElement('selectprogram'); + $programoptions = []; + $programs = []; + $programs = $apiclient->get( + $accesstoken, 'programs', - array('school' => $sid), - array('title' => "ASC") + ['school' => $sid], + ['title' => "ASC"] ); if (!empty($programs)) { foreach ($programs as $program) { $key = $program->id; - foreach (array('shortTitle', 'title') as $attr) { + foreach (['shortTitle', 'title'] as $attr) { $key .= ':'; if (property_exists($program, $attr)) { $key .= $program->$attr; @@ -371,31 +403,32 @@ function definition_after_data() { } $programoptions[$key] = $program->title; } - $prog_el->load($programoptions); + $progel->load($programoptions); } } if (!empty($programid)) { $pid = $programid; - $prog_el =& $mform->getElement('selectcohort'); - $cohortoptions = array(); + $progel =& $mform->getElement('selectcohort'); + $cohortoptions = []; - $programyears = $api_client->get( - $access_token, + $programyears = $apiclient->get( + $accesstoken, 'programYears', - array("program" => $pid), - array("startYear" => "ASC")); - $programyeararray = array(); + ["program" => $pid], + ["startYear" => "ASC"] + ); + $programyeararray = []; foreach ($programyears as $progyear) { $programyeararray[] = $progyear->id; } if (!empty($programyeararray)) { - $cohorts = $api_client->get( - $access_token, + $cohorts = $apiclient->get( + $accesstoken, 'cohorts', - array("programYear" => $programyeararray), - array("title" => "ASC") + ["programYear" => $programyeararray], + ["title" => "ASC"] ); foreach ($cohorts as $cohort) { @@ -403,20 +436,20 @@ function definition_after_data() { .' ('.count($cohort->learnerGroups).')' .' ('.count($cohort->users).')'; } - $prog_el->load($cohortoptions); + $progel->load($cohortoptions); } } if (!empty($cohortid)) { $cid = $cohortid; - $prog_el =& $mform->getElement('selectlearnergroup'); - $learnergroupoptions = array(); + $progel =& $mform->getElement('selectlearnergroup'); + $learnergroupoptions = []; - $learnergroups = $api_client->get( - $access_token, + $learnergroups = $apiclient->get( + $accesstoken, 'learnerGroups', - array('cohort' => $cid, 'parent' => 'null'), - array('title' => "ASC") + ['cohort' => $cid, 'parent' => 'null'], + ['title' => "ASC"] ); if (!empty($learnergroups)) { foreach ($learnergroups as $group) { @@ -424,32 +457,32 @@ function definition_after_data() { ' ('. count($group->children) .')'. ' ('. count($group->users) .')'; } - $prog_el->load($learnergroupoptions); + $progel->load($learnergroupoptions); } } if (!empty($learnergroupid)) { $gid = $learnergroupid; - $prog_el =& $mform->getElement('selectsubgroup'); - $subgroupoptions = array(); + $progel =& $mform->getElement('selectsubgroup'); + $subgroupoptions = []; - $subgroups = $api_client->get( - $access_token, + $subgroups = $apiclient->get( + $accesstoken, 'learnerGroups', - array("parent" => $gid), - array("title" => "ASC") + ["parent" => $gid], + ["title" => "ASC"] ); foreach ($subgroups as $subgroup) { $subgroupoptions["$subgroup->id:$subgroup->title"] = $subgroup->title. ' ('. count($subgroup->children) .')'. ' ('. count($subgroup->users) .')'; if (!empty($subgroup->children)) { - $processchildren = function ($parent) use (&$processchildren, &$subgroupoptions, $api_client, $access_token) { - $subgrps = $api_client->get( - $access_token, + $processchildren = function ($parent) use (&$processchildren, &$subgroupoptions, $apiclient, $accesstoken) { + $subgrps = $apiclient->get( + $accesstoken, 'learnerGroups', - array( 'parent' => $parent->id), - array( 'title' => "ASC") + [ 'parent' => $parent->id], + [ 'title' => "ASC"] ); foreach ($subgrps as $subgrp) { $subgroupoptions["$subgrp->id:$parent->title / $subgrp->title"] = $parent->title.' / '.$subgrp->title. @@ -463,39 +496,67 @@ function definition_after_data() { $processchildren($subgroup); } } - $prog_el->load($subgroupoptions); + $progel->load($subgroupoptions); } } - function validation($data, $files) { + /** + * Perform some extra validation. + * + * @param array $data array of ("fieldname"=>value) of submitted data + * @param array $files array of uploaded files "element_name"=>tmp_file_path + * @return array of "element_name"=>"error_description" if there are errors, or an empty array if everything is OK. + * @throws coding_exception + * @throws dml_exception + */ + public function validation($data, $files) { global $DB; $errors = parent::validation($data, $files); - // Make sure a learner group is selected if customint2 = 1 (instructor) + // Make sure a learner group is selected if customint2 = 1 (instructor). if (!empty($data['selectusertype'])) { if (empty($data['selectlearnergroup'])) { $errors['selectlearnergroup'] = get_string('requiredforinstructor', 'enrol_ilios'); } } - // Check for existing role + // Check for existing role. $selectgrouptype = 'cohort'; - list($selectgroupid,$selecttitle) = explode(':',$data['selectcohort'], 2); - if (!empty($data['selectlearnergroup'])){ + list($selectgroupid, $selecttitle) = explode(':', $data['selectcohort'], 2); + if (!empty($data['selectlearnergroup'])) { $selectgrouptype = 'learnerGroup'; - list($selectgroupid,$selecttitle) = explode(':',$data['selectlearnergroup'], 2); + list($selectgroupid, $selecttitle) = explode(':', $data['selectlearnergroup'], 2); if (!empty($data['selectsubgroup'])) { - list($selectgroupid,$selecttitle) = explode(':',$data['selectsubgroup'], 2); + list($selectgroupid, $selecttitle) = explode(':', $data['selectsubgroup'], 2); } } - $params = array('roleid'=>$data['roleid'], 'customchar1'=>$selectgrouptype,'customint1'=>$selectgroupid,'customint2'=>$data['selectusertype'],'courseid'=>$data['courseid'], 'id'=>$data['id']); - // customint2 could be NULL or 0 on the database - if (empty($data['selectusertype']) && $DB->record_exists_select('enrol', "roleid = :roleid AND customchar1 = :customchar1 AND customint1 = :customint1 AND customint2 IS NULL AND courseid = :courseid AND enrol = 'ilios' AND id <> :id", $params)) { - $errors['roleid'] = get_string('instanceexists', 'enrol_ilios'); + $params = [ + 'roleid' => $data['roleid'], + 'customchar1' => $selectgrouptype, + 'customint1' => $selectgroupid, + 'customint2' => $data['selectusertype'], + 'courseid' => $data['courseid'], + 'id' => $data['id'], + ]; + // Customint2 could be NULL or 0 on the database. + if (empty($data['selectusertype']) + && $DB->record_exists_select( + 'enrol', + "roleid = :roleid AND customchar1 = :customchar1 AND customint1 = :customint1 " + . " AND customint2 IS NULL AND courseid = :courseid AND enrol = 'ilios' AND id <> :id", + $params + ) + ) { + $errors['roleid'] = get_string('instanceexists', 'enrol_ilios'); } else { - if ($DB->record_exists_select('enrol', "roleid = :roleid AND customchar1 = :customchar1 AND customint1 = :customint1 AND customint2 = :customint2 AND courseid = :courseid AND enrol = 'ilios' AND id <> :id", $params)) { + if ($DB->record_exists_select( + 'enrol', + "roleid = :roleid AND customchar1 = :customchar1 AND customint1 = :customint1 " . + " AND customint2 = :customint2 AND courseid = :courseid AND enrol = 'ilios' AND id <> :id", + $params + )) { $errors['roleid'] = get_string('instanceexists', 'enrol_ilios'); } } diff --git a/lib.php b/lib.php index ccdd218..23f35c6 100644 --- a/lib.php +++ b/lib.php @@ -27,7 +27,7 @@ defined('MOODLE_INTERNAL') || die(); -require_once $CFG->libdir.'/filelib.php'; +require_once($CFG->libdir.'/filelib.php'); /** * Ilios enrolment plugin implementation. @@ -35,46 +35,60 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class enrol_ilios_plugin extends enrol_plugin { + /** + * @var ilios_client The Ilios API client. + */ + protected ilios_client $apiclient; - protected ilios_client $api_client; - + /** + * @var string the plugin settings key for the API access token. + */ public const SETTINGS_API_ACCESS_TOKEN = 'apikey'; /** - * Constructor + * Constructor. */ public function __construct() { - $this->api_client = new ilios_client($this->get_config('host_url', ''), new curl()); + $this->apiclient = new ilios_client($this->get_config('host_url', ''), new curl()); } /** - * @inheritdoc + * Is it possible to delete enrol instance via standard UI? + * + * @param stdClass $instance + * @return bool + * @throws coding_exception */ - public function can_delete_instance($instance) { + public function can_delete_instance($instance): bool { $context = context_course::instance($instance->courseid); return has_capability('enrol/ilios:config', $context); } /** - * @inheritdoc + * Is it possible to hide/show enrol instance via standard UI? + * + * @param stdClass $instance + * @return bool + * @throws coding_exception */ - public function can_hide_show_instance($instance) { + public function can_hide_show_instance($instance): bool { $context = context_course::instance($instance->courseid); return has_capability('enrol/ilios:config', $context); } /** - * Returns the Ilios Client for API access + * Returns the Ilios Client for API access. * - * @return ilios_client + * @return ilios_client The Ilios API client. */ public function get_api_client(): ilios_client { - return $this->api_client; + return $this->apiclient; } /** * Retrieves the Ilios API access token from the plugin configuration. - * @return string + * + * @return string The API access token. */ public function get_api_access_token(): string { return $this->get_config(self::SETTINGS_API_ACCESS_TOKEN, ''); @@ -83,9 +97,9 @@ public function get_api_access_token(): string { /** * Returns localised name of enrol instance. * - * @param stdClass $instance (null is accepted too) - * @return string - * @throws \Exception + * @param stdClass $instance An enrol instance (or NULL for *this* instance). + * @return string The name of this enrol instance. + * @throws Exception */ public function get_instance_name($instance) { global $DB; @@ -96,36 +110,25 @@ public function get_instance_name($instance) { } else if (empty($instance->name)) { $enrol = $this->get_name(); - - $syncfield = $instance->customchar1; - $syncid = $instance->customint1; - - // $groups = $this->iliosclient->get_by_ids($this->get_api_access_token(), $syncfield.'s', $syncid); - - // if (!empty($groups)) { - // $group = $groups[0]; - // $groupname = format_string($group->title, true, array('context'=>context::instance_by_id($instance->courseid))); - // } else - { - $groupname = get_string('pluginshortname', 'enrol_'.$enrol); - $syncinfo = json_decode($instance->customtext1); - if (!empty($syncinfo)) { - $schooltitle = $syncinfo->school->title; - $programtitle = $syncinfo->program->shorttitle; - $cohorttitle = $syncinfo->cohort->title; - $groupname .= ": ". $schooltitle ."/".$programtitle."/".$cohorttitle; - if (isset($syncinfo->learnerGroup)) { - $grouptitle = $syncinfo->learnerGroup->title; - $groupname .= '/'.$grouptitle; - } - if (isset($syncinfo->subGroup)) { - $grouptitle = $syncinfo->subGroup->title; - $groupname .= '/'.$grouptitle; - } + $groupname = get_string('pluginshortname', 'enrol_'.$enrol); + $syncinfo = json_decode($instance->customtext1); + + if (!empty($syncinfo)) { + $schooltitle = $syncinfo->school->title; + $programtitle = $syncinfo->program->shorttitle; + $cohorttitle = $syncinfo->cohort->title; + $groupname .= ": ". $schooltitle ."/".$programtitle."/".$cohorttitle; + if (isset($syncinfo->learnerGroup)) { + $grouptitle = $syncinfo->learnerGroup->title; + $groupname .= '/'.$grouptitle; + } + if (isset($syncinfo->subGroup)) { + $grouptitle = $syncinfo->subGroup->title; + $groupname .= '/'.$grouptitle; } } - if ($role = $DB->get_record('role', array('id'=>$instance->roleid))) { + if ($role = $DB->get_record('role', ['id' => $instance->roleid])) { $role = role_get_name($role, context_course::instance($instance->courseid, IGNORE_MISSING)); if (empty($instance->customint2)) { $groupname .= ' (Learner => '.$role; @@ -150,37 +153,38 @@ public function get_instance_name($instance) { return $groupname; } else { - return format_string($instance->name, true, array('context'=>context_course::instance($instance->courseid))); + return format_string($instance->name, true, ['context' => context_course::instance($instance->courseid)]); } } /** * Returns link to page which may be used to add new instance of enrolment plugin in course. - * @param int $courseid - * @return moodle_url page url - * @throws \Exception + * + * @param int $courseid The course ID. + * @return moodle_url|null The page URL to the new instance form, or NULL if not allowed. + * @throws Exception */ public function get_newinstance_link($courseid) { if (!$this->can_add_new_instances($courseid)) { - return NULL; + return null; } // Multiple instances supported - multiple parent courses linked. - return new moodle_url('/enrol/ilios/edit.php', array('courseid'=>$courseid)); + return new moodle_url('/enrol/ilios/edit.php', ['courseid' => $courseid]); } /** * Given a courseid this function returns true if the user is able to enrol or configure cohorts. * AND there are cohorts that the user can view. * - * @param int $courseid - * @return bool - * @throws \Exception + * @param int $courseid The course ID. + * @return bool TRUE if the current user can add new enrolment instances in the given course, FALSE otherwise. + * @throws Exception */ - protected function can_add_new_instances($courseid) { + protected function can_add_new_instances($courseid): bool { global $DB; $coursecontext = context_course::instance($courseid); - if (!has_capability('moodle/course:enrolconfig', $coursecontext) or !has_capability('enrol/ilios:config', $coursecontext)) { + if (!has_capability('moodle/course:enrolconfig', $coursecontext) || !has_capability('enrol/ilios:config', $coursecontext)) { return false; } return true; @@ -188,11 +192,12 @@ protected function can_add_new_instances($courseid) { /** * Returns edit icons for the page with list of instances. - * @param stdClass $instance - * @return array - * @throws \Exception + * + * @param stdClass $instance The enrol instance. + * @return array The list of edit icons und URLs. + * @throws Exception */ - public function get_action_icons(stdClass $instance) { + public function get_action_icons(stdClass $instance): array { global $OUTPUT; if ($instance->enrol !== 'ilios') { @@ -200,36 +205,36 @@ public function get_action_icons(stdClass $instance) { } $context = context_course::instance($instance->courseid); - $icons = array(); + $icons = []; if (has_capability('enrol/ilios:config', $context)) { - $editlink = new moodle_url("/enrol/ilios/edit.php", array('courseid'=>$instance->courseid, 'id'=>$instance->id)); + $editlink = new moodle_url("/enrol/ilios/edit.php", ['courseid' => $instance->courseid, 'id' => $instance->id]); $icons[] = $OUTPUT->action_icon($editlink, new pix_icon('t/edit', get_string('edit'), 'core', - array('class' => 'iconsmall'))); + ['class' => 'iconsmall'])); } return $icons; } - /** - * Execute synchronisation. - * @param progress_trace $trace - * @param int|NULL $courseid one course, empty mean all + * Execute all sync jobs, or all sync jobs for a given course. + * + * @param progress_trace $trace The progress tracer for this task run. + * @param int|NULL $courseid The course ID, or NULL if all sync jobs should be executed. * @return int exit code, 0 means ok, 2 means plugin disabled. - * @throws \Exception + * @throws Exception */ - public function sync($trace, $courseid = NULL) { + public function sync($trace, $courseid = null): int { global $CFG, $DB; - require_once $CFG->dirroot . '/group/lib.php'; + require_once($CFG->dirroot . '/group/lib.php'); - $api_client = $this->get_api_client(); - $access_token = $this->get_api_access_token(); + $apiclient = $this->get_api_client(); + $accesstoken = $this->get_api_access_token(); if (!enrol_is_enabled('ilios')) { // Purge all roles if ilios sync disabled, those can be recreated later here by cron or CLI. $trace->output('Ilios enrolment sync plugin is disabled, unassigning all plugin roles and stopping.'); - role_unassign_all(array('component'=>'enrol_ilios')); + role_unassign_all(['component' => 'enrol_ilios']); return 2; } @@ -240,7 +245,7 @@ public function sync($trace, $courseid = NULL) { $trace->output('Starting user enrolment synchronisation...'); $allroles = get_all_roles(); - $iliosusers = array(); // cache user data + $iliosusers = []; // Cache user data. $unenrolaction = $this->get_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL); @@ -250,7 +255,7 @@ public function sync($trace, $courseid = NULL) { FROM {enrol} e WHERE e.enrol = 'ilios' $onecourse"; - $params = array(); + $params = []; $params['courseid'] = $courseid; $params['suspended'] = ENROL_USER_SUSPENDED; $instances = $DB->get_recordset_sql($sql, $params); @@ -261,10 +266,10 @@ public function sync($trace, $courseid = NULL) { if (!empty($instance->customint2)) { // Need to get instructor ids. This function takes longer to run. - $group = $this->getGroupData($synctype, $syncid); + $group = $this->get_group_data($synctype, $syncid); } else { // No need to get instructor ids. - $group = $api_client->get_by_id($access_token, $synctype.'s', $syncid); + $group = $apiclient->get_by_id($accesstoken, $synctype.'s', $syncid); } if (empty($group)) { @@ -272,87 +277,138 @@ public function sync($trace, $courseid = NULL) { continue; } - if (!empty($group)) { - - $enrolleduserids = array(); // keep a list of enrolled user's Moodle userid (both learners and instructors). - $users = []; // ilios users in that group - $suspendEnrolments = []; // list of user enrollments to suspend - - $users = []; - - if (!empty($instance->customint2) && !empty($group->instructors)) { - $trace->output("Enrolling instructors to Course ID ".$instance->courseid." with Role ID ".$instance->roleid." through Ilios Sync ID ".$instance->id."."); - $users = $api_client->get_by_ids($access_token, 'users', $group->instructors); - } elseif (!empty($group->users)) { - $trace->output("Enrolling students to Course ID ".$instance->courseid." with Role ID ".$instance->roleid." through Ilios Sync ID ".$instance->id."."); - $users = $api_client->get_by_ids($access_token, 'users', $group->users); - } - $trace->output(count($users) . " Ilios users found."); - - foreach ($users as $user) { - // Fetch user info if not cached in $iliosusers - if (!isset($iliosusers[$user->id])) { - $iliosusers[$user->id] = null; - if (!empty($user->campusId)) { - $urec = $DB->get_record('user', array("idnumber" => $user->campusId)); - if (!empty($urec)) { - $iliosusers[$user->id] = array( 'id' => $urec->id, - 'syncfield' => $urec->idnumber ); - } + $enrolleduserids = []; // Keep a list of enrolled user's Moodle userid (both learners and instructors). + $users = []; // Ilios users in that group. + $suspendenrolments = []; // List of user enrollments to suspend. + + $users = []; + + if (!empty($instance->customint2) && !empty($group->instructors)) { + $trace->output( + "Enrolling instructors to Course ID " + . $instance->courseid + . " with Role ID " + . $instance->roleid + . " through Ilios Sync ID " + . $instance->id + . "." + ); + $users = $apiclient->get_by_ids($accesstoken, 'users', $group->instructors); + } else if (!empty($group->users)) { + $trace->output( + "Enrolling students to Course ID " + . $instance->courseid + . " with Role ID " + . $instance->roleid + . " through Ilios Sync ID " . + $instance->id + . "." + ); + $users = $apiclient->get_by_ids($accesstoken, 'users', $group->users); + } + $trace->output(count($users) . " Ilios users found."); + + foreach ($users as $user) { + // Fetch user info if not cached in $iliosusers. + if (!isset($iliosusers[$user->id])) { + $iliosusers[$user->id] = null; + if (!empty($user->campusId)) { + $urec = $DB->get_record('user', ["idnumber" => $user->campusId]); + if (!empty($urec)) { + $iliosusers[$user->id] = [ 'id' => $urec->id, 'syncfield' => $urec->idnumber ]; } } + } - if ($iliosusers[$user->id] === null) { - if (!empty($user->campusId)) { - $trace->output("skipping: Cannot find campusId ".$user->campusId." that matches Moodle user field 'idnumber'.", 1); - } else { - $trace->output("skipping: Ilios user ".$user->id." does not have a 'campusId' field.", 1); - } + if ($iliosusers[$user->id] === null) { + if (!empty($user->campusId)) { + $trace->output( + "skipping: Cannot find campusId " + . $user->campusId + . " that matches Moodle user field 'idnumber'." + , 1); } else { - $enrolleduserids[] = $userid = $iliosusers[$user->id]['id']; + $trace->output( + "skipping: Ilios user " + . $user->id + . " does not have a 'campusId' field." + , 1 + ); + } + } else { + $enrolleduserids[] = $userid = $iliosusers[$user->id]['id']; - $ue = $DB->get_record('user_enrolments', array('enrolid' => $instance->id, 'userid' => $userid)); + $ue = $DB->get_record('user_enrolments', ['enrolid' => $instance->id, 'userid' => $userid]); - // don't enroll disabled ilios users that are currently not enrolled. - if (empty($ue) && !$user->enabled) { - continue; - } + // Don't enroll disabled Ilios users that are currently not enrolled. + if (empty($ue) && !$user->enabled) { + continue; + } - // don't re-enroll suspended enrollments for disabled ilios users - if (!empty($ue) && ENROL_USER_SUSPENDED === (int) $ue->status && !$user->enabled) { - continue; - } + // Don't re-enroll suspended enrollments for disabled Ilios users. + if (!empty($ue) && ENROL_USER_SUSPENDED === (int) $ue->status && !$user->enabled) { + continue; + } - // flag actively enrolled users that are disabled in ilios - // for enrollment suspension further downstream - if (!empty($ue) && ENROL_USER_ACTIVE === (int) $ue->status && !$user->enabled) { - $suspendEnrolments[] = $ue; - continue; - } + // Flag actively enrolled users that are disabled in Ilios + // for enrollment suspension further downstream. + if (!empty($ue) && ENROL_USER_ACTIVE === (int) $ue->status && !$user->enabled) { + $suspendenrolments[] = $ue; + continue; + } - // Continue if already enrolled with active status - if (!empty($ue) && ENROL_USER_ACTIVE === (int) $ue->status) { - continue; - } + // Continue if already enrolled with active status. + if (!empty($ue) && ENROL_USER_ACTIVE === (int) $ue->status) { + continue; + } - // Enroll user - $this->enrol_user($instance, $userid, $instance->roleid, 0, 0, ENROL_USER_ACTIVE); - if (!empty($ue) && ENROL_USER_ACTIVE !== (int) $ue->status) { - $trace->output("changing enrollment status to '" . ENROL_USER_ACTIVE . "' from '{$ue->status}': userid $userid ==> courseid ".$instance->courseid, 1); - } else { - $trace->output("enrolling with " . ENROL_USER_ACTIVE . " status: userid $userid ==> courseid ".$instance->courseid, 1); - } + // Enroll user. + $this->enrol_user( + $instance, + $userid, + $instance->roleid, + 0, + 0, + ENROL_USER_ACTIVE + ); + if (!empty($ue) && ENROL_USER_ACTIVE !== (int) $ue->status) { + $trace->output( + "changing enrollment status to '" + . ENROL_USER_ACTIVE + . "' from '{$ue->status}': userid $userid ==> courseid " + . $instance->courseid + , 1 + ); + } else { + $trace->output( + "enrolling with " + . ENROL_USER_ACTIVE + . " status: userid $userid ==> courseid " + . $instance->courseid + , 1 + ); } } - // suspend active enrollments for users that are disabled in ilios - foreach ($suspendEnrolments as $ue) { - $trace->output("Suspending enrollment for disabled Ilios user: userid {$ue->userid} ==> courseid {$instance->courseid}.", 1); + // Suspend active enrollments for users that are disabled in Ilios. + foreach ($suspendenrolments as $ue) { + $trace->output( + "Suspending enrollment for disabled Ilios user: userid " + . " {$ue->userid} ==> courseid {$instance->courseid}." + , 1 + ); $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED); } // Unenrol as necessary. - $trace->output("Unenrolling users from Course ID ".$instance->courseid." with Role ID ".$instance->roleid." that no longer associate with Ilios Sync ID ".$instance->id."."); + $trace->output( + "Unenrolling users from Course ID " + . $instance->courseid." with Role ID " + . $instance->roleid + . " that no longer associate with Ilios Sync ID " + . $instance->id + . "." + ); $sql = "SELECT ue.* FROM {user_enrolments} ue @@ -363,18 +419,34 @@ public function sync($trace, $courseid = NULL) { } $rs = $DB->get_recordset_sql($sql); - foreach($rs as $ue) { + foreach ($rs as $ue) { if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) { // Remove enrolment together with group membership, grades, preferences, etc. $this->unenrol_user($instance, $ue->userid); - $trace->output("unenrolling: $ue->userid ==> ".$instance->courseid." via Ilios $synctype $syncid", 1); - } else { // ENROL_EXT_REMOVED_SUSPENDNOROLES + $trace->output( + "unenrolling: $ue->userid ==> " + . $instance->courseid + . " via Ilios $synctype $syncid" + , 1 + ); + } else { // Would be ENROL_EXT_REMOVED_SUSPENDNOROLES. // Just disable and ignore any changes. if ($ue->status != ENROL_USER_SUSPENDED) { $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED); $context = context_course::instance($instance->courseid); - role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$context->id, 'component'=>'enrol_ilios', 'itemid'=>$instance->id)); - $trace->output("suspending and unsassigning all roles: userid ".$ue->userid." ==> courseid ".$instance->courseid, 1); + role_unassign_all([ + 'userid' => $ue->userid, + 'contextid' => $context->id, + 'component' => 'enrol_ilios', + 'itemid' => $instance->id, + ]); + $trace->output( + "suspending and unsassigning all roles: userid " + . $ue->userid + . " ==> courseid " + . $instance->courseid + , 1 + ); } } } @@ -392,16 +464,22 @@ public function sync($trace, $courseid = NULL) { JOIN {role} r ON (r.id = e.roleid) JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :coursecontext) JOIN {user} u ON (u.id = ue.userid AND u.deleted = 0) - LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = ue.userid AND ra.itemid = e.id AND ra.component = 'enrol_ilios' AND e.roleid = ra.roleid) - WHERE ue.status = :useractive AND ra.id IS NULL"; - $params = array(); + LEFT JOIN {role_assignments} ra ON ( + ra.contextid = c.id + AND ra.userid = ue.userid + AND ra.itemid = e.id + AND ra.component = 'enrol_ilios' + AND e.roleid = ra.roleid + ) + WHERE ue.status = :useractive AND ra.id IS NULL"; + $params = []; $params['statusenabled'] = ENROL_INSTANCE_ENABLED; $params['useractive'] = ENROL_USER_ACTIVE; $params['coursecontext'] = CONTEXT_COURSE; $params['courseid'] = $courseid; $rs = $DB->get_recordset_sql($sql, $params); - foreach($rs as $ra) { + foreach ($rs as $ra) { role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_ilios', $ra->itemid); $trace->output("assigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname, 1); } @@ -415,14 +493,14 @@ public function sync($trace, $courseid = NULL) { JOIN {enrol} e ON (e.id = ra.itemid AND e.enrol = 'ilios' $onecourse) LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid AND ue.status = :useractive) WHERE ra.component = 'enrol_ilios' AND (ue.id IS NULL OR e.status <> :statusenabled)"; - $params = array(); + $params = []; $params['statusenabled'] = ENROL_INSTANCE_ENABLED; $params['useractive'] = ENROL_USER_ACTIVE; $params['coursecontext'] = CONTEXT_COURSE; $params['courseid'] = $courseid; $rs = $DB->get_recordset_sql($sql, $params); - foreach($rs as $ra) { + foreach ($rs as $ra) { role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_ilios', $ra->itemid); $trace->output("unassigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname, 1); } @@ -438,11 +516,11 @@ public function sync($trace, $courseid = NULL) { JOIN {enrol} e ON (e.enrol = 'ilios' AND e.courseid = g.courseid $onecourse) JOIN {user_enrolments} ue ON (ue.userid = gm.userid AND ue.enrolid = e.id) WHERE gm.component='enrol_ilios' AND gm.itemid = e.id AND g.id <> e.customint6"; - $params = array(); + $params = []; $params['courseid'] = $courseid; $rs = $DB->get_recordset_sql($sql, $params); - foreach($rs as $gm) { + foreach ($rs as $gm) { groups_remove_member($gm->groupid, $gm->userid); $trace->output("removing user from group: $gm->userid ==> $gm->courseid - $gm->groupname", 1); } @@ -456,11 +534,11 @@ public function sync($trace, $courseid = NULL) { JOIN {user} u ON (u.id = ue.userid AND u.deleted = 0) LEFT JOIN {groups_members} gm ON (gm.groupid = g.id AND gm.userid = ue.userid) WHERE gm.id IS NULL"; - $params = array(); + $params = []; $params['courseid'] = $courseid; $rs = $DB->get_recordset_sql($sql, $params); - foreach($rs as $ue) { + foreach ($rs as $ue) { groups_add_member($ue->groupid, $ue->userid, 'enrol_ilios', $ue->enrolid); $trace->output("adding user to group: $ue->userid ==> $ue->courseid - $ue->groupname", 1); } @@ -471,25 +549,13 @@ public function sync($trace, $courseid = NULL) { return 0; } - // /** - // * Called after updating/inserting course. - // * - // * @param bool $inserted true if course just inserted - // * @param stdClass $course - // * @param stdClass $data form data - // * @return void - // */ - // public function course_updated($inserted, $course, $data) { - // // It turns out there is no need for cohorts to deal with this hook, see MDL-34870. - // } - /** - * Update instance status + * Update instance status. * * @param stdClass $instance * @param int $newstatus ENROL_INSTANCE_ENABLED, ENROL_INSTANCE_DISABLED * @return void - * @throws \Exception + * @throws Exception */ public function update_status($instance, $newstatus) { parent::update_status($instance, $newstatus); @@ -501,14 +567,14 @@ public function update_status($instance, $newstatus) { /** * Does this plugin allow manual unenrolment of a specific user? - * Yes, but only if user suspended... + * Yes, but only if user suspended. * - * @param stdClass $instance course enrol instance - * @param stdClass $ue record from user_enrolments table + * @param stdClass $instance The course enrol instance. + * @param stdClass $ue A user enrolment record. * - * @return bool - true means user with 'enrol/xxx:unenrol' may unenrol this user, false means nobody may touch this user enrolment + * @return bool TRUE means that the current user may unenrol this user, FALSE otherwise. */ - public function allow_unenrol_user(stdClass $instance, stdClass $ue) { + public function allow_unenrol_user(stdClass $instance, stdClass $ue): bool { if ($ue->status == ENROL_USER_SUSPENDED) { return true; } @@ -519,53 +585,39 @@ public function allow_unenrol_user(stdClass $instance, stdClass $ue) { /** * Gets an array of the user enrolment actions. * - * @param course_enrolment_manager $manager - * @param stdClass $ue A user enrolment object - * @return array An array of user_enrolment_actions - * @throws \Exception + * @param course_enrolment_manager $manager The course enrolment manager. + * @param stdClass $ue A user enrolment object. + * @return array An array of user_enrolment_actions. + * @throws Exception */ - public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) { - $actions = array(); + public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue): array { + $actions = []; $context = $manager->get_context(); $instance = $ue->enrolmentinstance; $params = $manager->get_moodlepage()->url->params(); $params['ue'] = $ue->id; if ($this->allow_unenrol_user($instance, $ue) && has_capability('enrol/ilios:unenrol', $context)) { $url = new moodle_url('/enrol/unenroluser.php', $params); - $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id)); + $actions[] = new user_enrolment_action( + new pix_icon('t/delete', ''), + get_string('unenrol', 'enrol'), + $url, + ['class' => 'unenrollink', 'rel' => $ue->id] + ); } return $actions; } - /** - * Returns a button to enrol a ilios or its users through the manual enrolment plugin. - * - * @param course_enrolment_manager $manager - * @return enrol_user_button - * @throws \Exception - */ - // public function get_manual_enrol_button(course_enrolment_manager $manager) { - // $course = $manager->get_course(); - // if (!$this->can_add_new_instances($course->id)) { - // return false; - // } - - // $iliosurl = new moodle_url('/enrol/ilios/edit.php', array('courseid' => $course->id)); - // $button = new enrol_user_button($iliosurl, get_string('enrol', 'enrol_ilios'), 'get'); - - // return $button; - // } - /** * Restore instance and map settings. * - * @param restore_enrolments_structure_step $step - * @param stdClass $data - * @param stdClass $course - * @param int $oldid - * @throws \Exception + * @param restore_enrolments_structure_step $step The restore enrolments structure step. + * @param stdClass $data The data object. + * @param stdClass $course The course object. + * @param int $oldid The old enrolment instance ID. + * @throws Exception */ - public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid) { + public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid): void { global $DB; if (!$step->get_task()->is_samesite()) { @@ -578,9 +630,17 @@ public function restore_instance(restore_enrolments_structure_step $step, stdCla $data->customint6 = $step->get_mappingid('group', $data->customint6); } - // if ($data->roleid and $DB->record_exists('cohort', array('id'=>$data->customint1))) { if ($data->roleid) { - $instance = $DB->get_record('enrol', array('roleid'=>$data->roleid, 'customint1'=>$data->customint1, 'customchar1'=>$data->customchar1, 'courseid'=>$course->id, 'enrol'=>$this->get_name())); + $instance = $DB->get_record( + 'enrol', + [ + 'roleid' => $data->roleid, + 'customint1' => $data->customint1, + 'customchar1' => $data->customchar1, + 'courseid' => $course->id, + 'enrol' => $this->get_name(), + ], + ); if ($instance) { $instanceid = $instance->id; } else { @@ -593,7 +653,16 @@ public function restore_instance(restore_enrolments_structure_step $step, stdCla $trace->finished(); } else if ($this->get_config('unenrolaction') == ENROL_EXT_REMOVED_SUSPENDNOROLES) { - $instance = $DB->get_record('enrol', array('roleid'=>$data->roleid, 'customint1'=>$data->customint1, 'customerchar1'=>$data->customchar1, 'courseid'=>$course->id, 'enrol'=>$this->get_name())); + $instance = $DB->get_record( + 'enrol', + [ + 'roleid' => $data->roleid, + 'customint1' => $data->customint1, + 'customerchar1' => $data->customchar1, + 'courseid' => $course->id, + 'enrol' => $this->get_name(), + ], + ); if ($instance) { $instanceid = $instance->id; } else { @@ -614,14 +683,20 @@ public function restore_instance(restore_enrolments_structure_step $step, stdCla /** * Restore user enrolment. * - * @param restore_enrolments_structure_step $step - * @param stdClass $data - * @param stdClass $instance - * @param int $oldinstancestatus - * @param int $userid - * @throws \Exception + * @param restore_enrolments_structure_step $step The restore enrolment structure step. + * @param stdClass $data The data object. + * @param stdClass $instance The enrolment instance. + * @param int $userid The user ID. + * @param int $oldinstancestatus The old enrolment instance status. + * @throws Exception */ - public function restore_user_enrolment(restore_enrolments_structure_step $step, $data, $instance, $userid, $oldinstancestatus) { + public function restore_user_enrolment( + restore_enrolments_structure_step $step, + $data, + $instance, + $userid, + $oldinstancestatus + ): void { global $DB; if ($this->get_config('unenrolaction') != ENROL_EXT_REMOVED_SUSPENDNOROLES) { @@ -632,44 +707,33 @@ public function restore_user_enrolment(restore_enrolments_structure_step $step, // ENROL_EXT_REMOVED_SUSPENDNOROLES means all previous enrolments are restored // but without roles and suspended. - if (!$DB->record_exists('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) { + if (!$DB->record_exists('user_enrolments', ['enrolid' => $instance->id, 'userid' => $userid])) { $this->enrol_user($instance, $userid, null, $data->timestart, $data->timeend, ENROL_USER_SUSPENDED); } } /** - * Restore user group membership. - * @param stdClass $instance - * @param int $groupid - * @param int $userid - */ - public function restore_group_member($instance, $groupid, $userid) { - // Nothing to do here, the group members are added in $this->restore_group_restored() - return; - } - - /** - * Recursive get for learner group data with instructors info, to compensate + * Recursive get for learner group data with instructors info, to compensate for * something that the ILIOS API fails to do! * - * @param string $grouptype singular noun of the group type, e.g. cohort, learnerGroup - * @param string $groupid the id for the corresponding group type, e.g. cohort id, learner group id. + * @param string $grouptype Singular noun of the group type, e.g. cohort, learnerGroup. + * @param string $groupid The ID for the corresponding group type, e.g. cohort id, learner group id. * - * @return mixed returned by the ILIOS api in addition of populating + * @return mixed Returned by the ILIOS api in addition of populating * the instructor array with correct ids, which is to * iterate into offerings and ilmSessions and fetch the * associated instructors and instructor groups. Should * also iterate into subgroups. - * @throws \Exception + * @throws Exception */ - public function getGroupData($grouptype, $groupid) { - $api_client = $this->get_api_client(); - $access_token = $this->get_api_access_token(); + public function get_group_data($grouptype, $groupid) { + $apiclient = $this->get_api_client(); + $accesstoken = $this->get_api_access_token(); // Ilios API uses a plural noun, append an 's'. - $group = $api_client->get_by_id($access_token, $grouptype.'s', $groupid ); + $group = $apiclient->get_by_id($accesstoken, $grouptype.'s', $groupid ); if ($group && $grouptype === 'learnerGroup') { - $group->instructors = $this->getInstructorIdsFromGroup($grouptype, $groupid); + $group->instructors = $this->get_instructor_ids_from_group($grouptype, $groupid); asort($group->instructors); } @@ -677,95 +741,98 @@ public function getGroupData($grouptype, $groupid) { } /** - * @param $grouptype - * @param $groupid - * - * @return array + * Retrieves a list instructors for a given type of group (learner group or instructor group) and given group ID. + + * @param string $grouptype The group type (either 'instructorgroup' or 'learnergroup'). + * @param string $groupid The group ID. + * @return array A list of user IDs. * @throws moodle_exception */ - private function getInstructorIdsFromGroup($grouptype, $groupid) { - - $api_client = $this->get_api_client(); - $access_token = $this->get_api_access_token(); + private function get_instructor_ids_from_group($grouptype, $groupid): array { + $apiclient = $this->get_api_client(); + $accesstoken = $this->get_api_access_token(); // Ilios API uses a plural noun, append an 's'. - $group = $api_client->get_by_id($access_token, $grouptype.'s', $groupid); + $group = $apiclient->get_by_id($accesstoken, $grouptype.'s', $groupid); - $instructorGroupIds = array(); - $instructorIds = array(); + $instructorgroupids = []; + $instructorids = []; - // get instructors/instructor-groups from the offerings that this learner group is being taught in. + // Get instructors/instructor-groups from the offerings that this learner group is being taught in. if (!empty($group->offerings)) { - $offerings = $api_client->get_by_ids($access_token, 'offerings', $group->offerings); + $offerings = $apiclient->get_by_ids($accesstoken, 'offerings', $group->offerings); foreach ($offerings as $offering) { if (empty($offering->instructors)) { - // no instructor AND no instructor groups have been set for this offering. - // fall back to the default instructors/instructor-groups defined for the learner group. - $instructorIds = array_merge($instructorIds, $group->instructors); - $instructorGroupIds = array_merge($instructorGroupIds, $group->instructorGroups); + // No instructor AND no instructor groups have been set for this offering. + // Fall back to the default instructors/instructor-groups defined for the learner group. + $instructorids = array_merge($instructorids, $group->instructors); + $instructorgroupids = array_merge($instructorgroupids, $group->instructorGroups); } else { - // if there are instructors and/or instructor-groups set on the offering, - // then use these. - $instructorIds = array_merge($instructorIds, $offering->instructors); - $instructorGroupIds = array_merge($instructorGroupIds, $offering->instructorGroups); + // If there are instructors and/or instructor-groups set on the offering, then use these. + $instructorids = array_merge($instructorids, $offering->instructors); + $instructorgroupids = array_merge($instructorgroupids, $offering->instructorGroups); } } - } - // get instructors/instructor-groups from the ilm sessions that this learner group is being taught in. - // (this is a rinse/repeat from offerings-related code above) + // Get instructors/instructor-groups from the ilm sessions that this learner group is being taught in. + // This is a rinse/repeat from offerings-related code above. if (!empty($group->ilmSessions)) { - $ilms = $api_client->get_by_ids($access_token, 'ilmSessions', $group->ilmSessions); + $ilms = $apiclient->get_by_ids($accesstoken, 'ilmSessions', $group->ilmSessions); foreach ($ilms as $ilm) { if (empty($ilm->instructors) && empty($ilm->instructorGroups)) { - // no instructor AND no instructor groups have been set for this offering. - // fall back to the default instructors/instructor-groups defined for the learner group. - $instructorIds = array_merge($instructorIds, $group->instructors); - $instructorGroupIds = array_merge($instructorGroupIds, $group->instructorGroups); + // No instructor AND no instructor groups have been set for this offering. + // Fall back to the default instructors/instructor-groups defined for the learner group. + $instructorids = array_merge($instructorids, $group->instructors); + $instructorgroupids = array_merge($instructorgroupids, $group->instructorGroups); } else { - // if there are instructors and/or instructor-groups set on the offering, - // then use these. - $instructorIds = array_merge($instructorIds, $ilm->instructors); - $instructorGroupIds = array_merge($instructorGroupIds, $ilm->instructorGroups); + // If there are instructors and/or instructor-groups set on the offering, then use these. + $instructorids = array_merge($instructorids, $ilm->instructors); + $instructorgroupids = array_merge($instructorgroupids, $ilm->instructorGroups); } } } - // get instructors from sub-learnerGroups + // Get instructors from sub-learner-groups. if (!empty($group->children)) { - foreach($group->children as $subgroupid) { - $instructorIds = array_merge($instructorIds, $this->getInstructorIdsFromGroup('learnerGroup', $subgroupid)); - // We don't care about instructor groups here, we will merge instructor groups into the $instructorIds array later. + foreach ($group->children as $subgroupid) { + $instructorids = array_merge( + $instructorids, + $this->get_instructor_ids_from_group('learnerGroup', $subgroupid) + ); + // We don't care about instructor groups here, + // we will merge instructor groups into the $instructorIds array later. } } - // next, get the ids of all instructors from the instructor-groups that we determined as relevant earlier. - // but first.. let's de-dupe them. - $instructorGroupIds = array_unique($instructorGroupIds); - if (!empty($instructorGroupIds)) { - $instructorGroups = $api_client->get_by_ids($access_token, 'instructorGroups', $instructorGroupIds); - foreach ($instructorGroups as $instructorGroup) { - $instructorIds = array_merge($instructorIds, $instructorGroup->users); + // Next, get the ids of all instructors from the instructor-groups that we determined as relevant earlier. + // But first let's de-dupe them. + $instructorgroupids = array_unique($instructorgroupids); + if (!empty($instructorgroupids)) { + $instructorgroups = $apiclient->get_by_ids($accesstoken, 'instructorGroups', $instructorgroupids); + foreach ($instructorgroups as $instructorgroup) { + $instructorids = array_merge($instructorids, $instructorgroup->users); } } - // finally, we retrieve all the users that were identified as relevant instructors earlier. - $instructorIds = array_unique($instructorIds); + // Finally, we retrieve all the users that were identified as relevant instructors earlier. + $instructorids = array_unique($instructorids); - return $instructorIds; + return $instructorids; } } /** - * Prevent removal of enrol roles. - * @param int $itemid - * @param int $groupid - * @param int $userid - * @return bool + * Prevents the removal of enrol roles. + * Implements the allow_group_member_remove callback from the Group API. + * + * @param int $itemid The item ID. + * @param int $groupid The group ID. + * @param int $userid The user ID. + * @return bool Always FALSE. */ -function enrol_ilios_allow_group_member_remove($itemid, $groupid, $userid) { +function enrol_ilios_allow_group_member_remove($itemid, $groupid, $userid): bool { return false; } diff --git a/settings.php b/settings.php index 10cd44e..fbb6e55 100644 --- a/settings.php +++ b/settings.php @@ -27,26 +27,55 @@ if ($ADMIN->fulltree) { - //--- general settings ----------------------------------------------------------------------------------- + // General settings. $settings->add(new admin_setting_heading('enrol_ilios_settings', '', get_string('pluginname_desc', 'enrol_ilios'))); - //--- enrol instance defaults ---------------------------------------------------------------------------- + // Enrol instance defaults. if (!during_initial_install()) { - // FIX: Change host to host_url (more descriptive) - $settings->add(new admin_setting_configtext('enrol_ilios/host_url', get_string('host_url', 'enrol_ilios'), get_string('host_url_desc', 'enrol_ilios'), 'localhost')); - $settings->add(new admin_setting_configtext('enrol_ilios/apikey', get_string('apikey', 'enrol_ilios'), get_string('apikey_desc', 'enrol_ilios'), '')); + // FIX: Change host to host_url (more descriptive). + $settings->add( + new admin_setting_configtext( + 'enrol_ilios/host_url', + get_string('host_url', 'enrol_ilios'), + get_string('host_url_desc', 'enrol_ilios'), + 'localhost' + ) + ); + $settings->add( + new admin_setting_configtext( + 'enrol_ilios/apikey', + get_string('apikey', 'enrol_ilios'), + get_string('apikey_desc', 'enrol_ilios'), + '' + ) + ); $options = get_default_enrol_roles(context_system::instance()); $student = get_archetype_roles('student'); $student = reset($student); - $settings->add(new admin_setting_configselect('enrol_ilios/roleid', - get_string('defaultlearnerrole', 'enrol_ilios'), - '', $student->id, $options)); - - $options = array( - ENROL_EXT_REMOVED_UNENROL => get_string('extremovedunenrol', 'enrol'), - ENROL_EXT_REMOVED_SUSPENDNOROLES => get_string('extremovedsuspendnoroles', 'enrol')); - $settings->add(new admin_setting_configselect('enrol_ilios/unenrolaction', get_string('extremovedaction', 'enrol'), get_string('extremovedaction_help', 'enrol'), ENROL_EXT_REMOVED_UNENROL, $options)); + $settings->add( + new admin_setting_configselect( + 'enrol_ilios/roleid', + get_string('defaultlearnerrole', 'enrol_ilios'), + '', + $student->id, + $options + ) + ); + + $options = [ + ENROL_EXT_REMOVED_UNENROL => get_string('extremovedunenrol', 'enrol'), + ENROL_EXT_REMOVED_SUSPENDNOROLES => get_string('extremovedsuspendnoroles', 'enrol'), + ]; + $settings->add( + new admin_setting_configselect( + 'enrol_ilios/unenrolaction', + get_string('extremovedaction', 'enrol'), + get_string('extremovedaction_help', 'enrol'), + ENROL_EXT_REMOVED_UNENROL, + $options + ) + ); } } diff --git a/version.php b/version.php index 6f9bdc9..724e615 100644 --- a/version.php +++ b/version.php @@ -25,12 +25,12 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024053100; // The current plugin version (Date: YYYYMMDDXX) -$plugin->requires = 2023100400; // Requires this Moodle version -$plugin->component = 'enrol_ilios'; // Full name of the plugin (used for diagnostics) +$plugin->version = 2024053100; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2023100400; // Requires this Moodle version. +$plugin->component = 'enrol_ilios'; // Full name of the plugin (used for diagnostics). $plugin->release = 'v4.3'; $plugin->supported = [403, 403]; $plugin->maturity = MATURITY_STABLE; -$plugin->dependencies = array( +$plugin->dependencies = [ 'local_iliosapiclient' => 2024032200, -); +];