mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
Merge branch 'MDL-46706-master' of https://github.com/sammarshallou/moodle
Conflicts: lib/tests/modinfolib_test.php
This commit is contained in:
commit
52ed065131
@ -1747,6 +1747,31 @@ class cm_info implements IteratorAggregate {
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cm_info object from a database record (also accepts cm_info
|
||||
* in which case it is just returned unchanged).
|
||||
*
|
||||
* @param stdClass|cm_info|null $cm Stdclass or cm_info (or null)
|
||||
* @param int $userid Optional userid (default to current)
|
||||
* @return cm_info|null Object as cm_info, or null if input was null
|
||||
*/
|
||||
public static function create($cm, $userid = 0) {
|
||||
// Nulls get passed through.
|
||||
if (is_null($cm)) {
|
||||
return null;
|
||||
}
|
||||
// If it is already a cm_info object, just return it.
|
||||
if ($cm instanceof cm_info) {
|
||||
return $cm;
|
||||
}
|
||||
// Otherwise load modinfo.
|
||||
if (empty($cm->id) || empty($cm->course)) {
|
||||
throw new coding_exception('$cm must contain ->id and ->course');
|
||||
}
|
||||
$modinfo = get_fast_modinfo($cm->course, $userid);
|
||||
return $modinfo->get_cm($cm->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* If dynamic data for this course-module is not yet available, gets it.
|
||||
*
|
||||
@ -2062,6 +2087,165 @@ function get_fast_modinfo($courseorid, $userid = 0, $resetonly = false) {
|
||||
return course_modinfo::instance($courseorid, $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently retrieves the $course (stdclass) and $cm (cm_info) objects, given
|
||||
* a cmid. If module name is also provided, it will ensure the cm is of that type.
|
||||
*
|
||||
* Usage:
|
||||
* list($course, $cm) = get_course_and_cm_from_cmid($cmid, 'forum');
|
||||
*
|
||||
* Using this method has a performance advantage because it works by loading
|
||||
* modinfo for the course - which will then be cached and it is needed later
|
||||
* in most requests. It also guarantees that the $cm object is a cm_info and
|
||||
* not a stdclass.
|
||||
*
|
||||
* The $course object can be supplied if already known and will speed
|
||||
* up this function - although it is more efficient to use this function to
|
||||
* get the course if you are starting from a cmid.
|
||||
*
|
||||
* To avoid security problems and obscure bugs, you should always specify
|
||||
* $modulename if the cmid value came from user input.
|
||||
*
|
||||
* By default this obtains information (for example, whether user can access
|
||||
* the activity) for current user, but you can specify a userid if required.
|
||||
*
|
||||
* @param stdClass|int $cmorid Id of course-module, or database object
|
||||
* @param string $modulename Optional modulename (improves security)
|
||||
* @param stdClass|int $courseorid Optional course object if already loaded
|
||||
* @param int $userid Optional userid (default = current)
|
||||
* @return array Array with 2 elements $course and $cm
|
||||
* @throws moodle_exception If the item doesn't exist or is of wrong module name
|
||||
*/
|
||||
function get_course_and_cm_from_cmid($cmorid, $modulename = '', $courseorid = 0, $userid = 0) {
|
||||
global $DB;
|
||||
if (is_object($cmorid)) {
|
||||
$cmid = $cmorid->id;
|
||||
if (isset($cmorid->course)) {
|
||||
$courseid = (int)$cmorid->course;
|
||||
} else {
|
||||
$courseid = 0;
|
||||
}
|
||||
} else {
|
||||
$cmid = (int)$cmorid;
|
||||
$courseid = 0;
|
||||
}
|
||||
|
||||
// Validate module name if supplied.
|
||||
if ($modulename && !core_component::is_valid_plugin_name('mod', $modulename)) {
|
||||
throw new coding_exception('Invalid modulename parameter');
|
||||
}
|
||||
|
||||
// Get course from last parameter if supplied.
|
||||
$course = null;
|
||||
if (is_object($courseorid)) {
|
||||
$course = $courseorid;
|
||||
} else if ($courseorid) {
|
||||
$courseid = (int)$courseorid;
|
||||
}
|
||||
|
||||
if (!$course) {
|
||||
if ($courseid) {
|
||||
// If course ID is known, get it using normal function.
|
||||
$course = get_course($courseid);
|
||||
} else {
|
||||
// Get course record in a single query based on cmid.
|
||||
$course = $DB->get_record_sql("
|
||||
SELECT c.*
|
||||
FROM {course_modules} cm
|
||||
JOIN {course} c ON c.id = cm.course
|
||||
WHERE cm.id = ?", array($cmid), MUST_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
// Get cm from get_fast_modinfo.
|
||||
$modinfo = get_fast_modinfo($course, $userid);
|
||||
$cm = $modinfo->get_cm($cmid);
|
||||
if ($modulename && $cm->modname !== $modulename) {
|
||||
throw new moodle_exception('invalidcoursemodule', 'error');
|
||||
}
|
||||
return array($course, $cm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently retrieves the $course (stdclass) and $cm (cm_info) objects, given
|
||||
* an instance id or record and module name.
|
||||
*
|
||||
* Usage:
|
||||
* list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum');
|
||||
*
|
||||
* Using this method has a performance advantage because it works by loading
|
||||
* modinfo for the course - which will then be cached and it is needed later
|
||||
* in most requests. It also guarantees that the $cm object is a cm_info and
|
||||
* not a stdclass.
|
||||
*
|
||||
* The $course object can be supplied if already known and will speed
|
||||
* up this function - although it is more efficient to use this function to
|
||||
* get the course if you are starting from an instance id.
|
||||
*
|
||||
* By default this obtains information (for example, whether user can access
|
||||
* the activity) for current user, but you can specify a userid if required.
|
||||
*
|
||||
* @param stdclass|int $instanceorid Id of module instance, or database object
|
||||
* @param string $modulename Modulename (required)
|
||||
* @param stdClass|int $courseorid Optional course object if already loaded
|
||||
* @param int $userid Optional userid (default = current)
|
||||
* @return array Array with 2 elements $course and $cm
|
||||
* @throws moodle_exception If the item doesn't exist or is of wrong module name
|
||||
*/
|
||||
function get_course_and_cm_from_instance($instanceorid, $modulename, $courseorid = 0, $userid = 0) {
|
||||
global $DB;
|
||||
|
||||
// Get data from parameter.
|
||||
if (is_object($instanceorid)) {
|
||||
$instanceid = $instanceorid->id;
|
||||
if (isset($instanceorid->course)) {
|
||||
$courseid = (int)$instanceorid->course;
|
||||
} else {
|
||||
$courseid = 0;
|
||||
}
|
||||
} else {
|
||||
$instanceid = (int)$instanceorid;
|
||||
$courseid = 0;
|
||||
}
|
||||
|
||||
// Get course from last parameter if supplied.
|
||||
$course = null;
|
||||
if (is_object($courseorid)) {
|
||||
$course = $courseorid;
|
||||
} else if ($courseorid) {
|
||||
$courseid = (int)$courseorid;
|
||||
}
|
||||
|
||||
// Validate module name if supplied.
|
||||
if (!core_component::is_valid_plugin_name('mod', $modulename)) {
|
||||
throw new coding_exception('Invalid modulename parameter');
|
||||
}
|
||||
|
||||
if (!$course) {
|
||||
if ($courseid) {
|
||||
// If course ID is known, get it using normal function.
|
||||
$course = get_course($courseid);
|
||||
} else {
|
||||
// Get course record in a single query based on instance id.
|
||||
$pagetable = '{' . $modulename . '}';
|
||||
$course = $DB->get_record_sql("
|
||||
SELECT c.*
|
||||
FROM $pagetable instance
|
||||
JOIN {course} c ON c.id = instance.course
|
||||
WHERE instance.id = ?", array($instanceid), MUST_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
// Get cm from get_fast_modinfo.
|
||||
$modinfo = get_fast_modinfo($course, $userid);
|
||||
$instances = $modinfo->get_instances_of($modulename);
|
||||
if (!array_key_exists($instanceid, $instances)) {
|
||||
throw new moodle_exception('invalidmoduleid', 'error', $instanceid);
|
||||
}
|
||||
return array($course, $instances[$instanceid]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rebuilds or resets the cached list of course activities stored in MUC.
|
||||
*
|
||||
|
@ -965,4 +965,236 @@ class core_modinfolib_testcase extends advanced_testcase {
|
||||
$this->assertCount(0, $groups);
|
||||
$this->assertArrayNotHasKey($group1->id, $groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the function for constructing a cm_info from mixed data.
|
||||
*/
|
||||
public function test_create() {
|
||||
global $CFG, $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create a course and an activity.
|
||||
$generator = $this->getDataGenerator();
|
||||
$course = $generator->create_course();
|
||||
$page = $generator->create_module('page', array('course' => $course->id,
|
||||
'name' => 'Annie'));
|
||||
|
||||
// Null is passed through.
|
||||
$this->assertNull(cm_info::create(null));
|
||||
|
||||
// Stdclass object turns into cm_info.
|
||||
$cm = cm_info::create(
|
||||
(object)array('id' => $page->cmid, 'course' => $course->id));
|
||||
$this->assertInstanceOf('cm_info', $cm);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// A cm_info object stays as cm_info.
|
||||
$this->assertSame($cm, cm_info::create($cm));
|
||||
|
||||
// Invalid object (missing fields) causes error.
|
||||
try {
|
||||
cm_info::create((object)array('id' => $page->cmid));
|
||||
$this->fail();
|
||||
} catch (Exception $e) {
|
||||
$this->assertInstanceOf('coding_exception', $e);
|
||||
}
|
||||
|
||||
// Create a second hidden activity.
|
||||
$hiddenpage = $generator->create_module('page', array('course' => $course->id,
|
||||
'name' => 'Annie', 'visible' => 0));
|
||||
|
||||
// Create 2 user accounts, one is a manager who can see everything.
|
||||
$user = $generator->create_user();
|
||||
$generator->enrol_user($user->id, $course->id);
|
||||
$manager = $generator->create_user();
|
||||
$generator->enrol_user($manager->id, $course->id,
|
||||
$DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
|
||||
|
||||
// User can see the normal page but not the hidden one.
|
||||
$cm = cm_info::create((object)array('id' => $page->cmid, 'course' => $course->id),
|
||||
$user->id);
|
||||
$this->assertTrue($cm->uservisible);
|
||||
$cm = cm_info::create((object)array('id' => $hiddenpage->cmid, 'course' => $course->id),
|
||||
$user->id);
|
||||
$this->assertFalse($cm->uservisible);
|
||||
|
||||
// Manager can see the hidden one too.
|
||||
$cm = cm_info::create((object)array('id' => $hiddenpage->cmid, 'course' => $course->id),
|
||||
$manager->id);
|
||||
$this->assertTrue($cm->uservisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests function for getting $course and $cm at once quickly from modinfo
|
||||
* based on cmid or cm record.
|
||||
*/
|
||||
public function test_get_course_and_cm_from_cmid() {
|
||||
global $CFG, $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create a course and an activity.
|
||||
$generator = $this->getDataGenerator();
|
||||
$course = $generator->create_course(array('shortname' => 'Halls'));
|
||||
$page = $generator->create_module('page', array('course' => $course->id,
|
||||
'name' => 'Annie'));
|
||||
|
||||
// Successful usage.
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($page->cmid);
|
||||
$this->assertEquals('Halls', $course->shortname);
|
||||
$this->assertInstanceOf('cm_info', $cm);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// Specified module type.
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page');
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// With id in object.
|
||||
$fakecm = (object)array('id' => $page->cmid);
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($fakecm);
|
||||
$this->assertEquals('Halls', $course->shortname);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// With both id and course in object.
|
||||
$fakecm->course = $course->id;
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($fakecm);
|
||||
$this->assertEquals('Halls', $course->shortname);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// With supplied course id.
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', $course->id);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// With supplied course object (modified just so we can check it is
|
||||
// indeed reusing the supplied object).
|
||||
$course->silly = true;
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', $course);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
$this->assertTrue($course->silly);
|
||||
|
||||
// Incorrect module type.
|
||||
try {
|
||||
get_course_and_cm_from_cmid($page->cmid, 'forum');
|
||||
$this->fail();
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals('invalidcoursemodule', $e->errorcode);
|
||||
}
|
||||
|
||||
// Invalid module name.
|
||||
try {
|
||||
get_course_and_cm_from_cmid($page->cmid, 'pigs can fly');
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertContains('Invalid modulename parameter', $e->getMessage());
|
||||
}
|
||||
|
||||
// Doesn't exist.
|
||||
try {
|
||||
get_course_and_cm_from_cmid($page->cmid + 1);
|
||||
$this->fail();
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertInstanceOf('dml_exception', $e);
|
||||
}
|
||||
|
||||
// Create a second hidden activity.
|
||||
$hiddenpage = $generator->create_module('page', array('course' => $course->id,
|
||||
'name' => 'Annie', 'visible' => 0));
|
||||
|
||||
// Create 2 user accounts, one is a manager who can see everything.
|
||||
$user = $generator->create_user();
|
||||
$generator->enrol_user($user->id, $course->id);
|
||||
$manager = $generator->create_user();
|
||||
$generator->enrol_user($manager->id, $course->id,
|
||||
$DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
|
||||
|
||||
// User can see the normal page but not the hidden one.
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', 0, $user->id);
|
||||
$this->assertTrue($cm->uservisible);
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $user->id);
|
||||
$this->assertFalse($cm->uservisible);
|
||||
|
||||
// Manager can see the hidden one too.
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $manager->id);
|
||||
$this->assertTrue($cm->uservisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests function for getting $course and $cm at once quickly from modinfo
|
||||
* based on instance id or record.
|
||||
*/
|
||||
public function test_get_course_and_cm_from_instance() {
|
||||
global $CFG, $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create a course and an activity.
|
||||
$generator = $this->getDataGenerator();
|
||||
$course = $generator->create_course(array('shortname' => 'Halls'));
|
||||
$page = $generator->create_module('page', array('course' => $course->id,
|
||||
'name' => 'Annie'));
|
||||
|
||||
// Successful usage.
|
||||
list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page');
|
||||
$this->assertEquals('Halls', $course->shortname);
|
||||
$this->assertInstanceOf('cm_info', $cm);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// With id in object.
|
||||
$fakeinstance = (object)array('id' => $page->id);
|
||||
list($course, $cm) = get_course_and_cm_from_instance($fakeinstance, 'page');
|
||||
$this->assertEquals('Halls', $course->shortname);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// With both id and course in object.
|
||||
$fakeinstance->course = $course->id;
|
||||
list($course, $cm) = get_course_and_cm_from_instance($fakeinstance, 'page');
|
||||
$this->assertEquals('Halls', $course->shortname);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// With supplied course id.
|
||||
list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page', $course->id);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
|
||||
// With supplied course object (modified just so we can check it is
|
||||
// indeed reusing the supplied object).
|
||||
$course->silly = true;
|
||||
list($course, $cm) = get_course_and_cm_from_instance($page->id, 'page', $course);
|
||||
$this->assertEquals('Annie', $cm->name);
|
||||
$this->assertTrue($course->silly);
|
||||
|
||||
// Doesn't exist (or is wrong type).
|
||||
try {
|
||||
get_course_and_cm_from_instance($page->id, 'forum');
|
||||
$this->fail();
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertInstanceOf('dml_exception', $e);
|
||||
}
|
||||
|
||||
// Invalid module name.
|
||||
try {
|
||||
get_course_and_cm_from_cmid($page->cmid, '1337 h4x0ring');
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertContains('Invalid modulename parameter', $e->getMessage());
|
||||
}
|
||||
|
||||
// Create a second hidden activity.
|
||||
$hiddenpage = $generator->create_module('page', array('course' => $course->id,
|
||||
'name' => 'Annie', 'visible' => 0));
|
||||
|
||||
// Create 2 user accounts, one is a manager who can see everything.
|
||||
$user = $generator->create_user();
|
||||
$generator->enrol_user($user->id, $course->id);
|
||||
$manager = $generator->create_user();
|
||||
$generator->enrol_user($manager->id, $course->id,
|
||||
$DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST));
|
||||
|
||||
// User can see the normal page but not the hidden one.
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($page->cmid, 'page', 0, $user->id);
|
||||
$this->assertTrue($cm->uservisible);
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $user->id);
|
||||
$this->assertFalse($cm->uservisible);
|
||||
|
||||
// Manager can see the hidden one too.
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($hiddenpage->cmid, 'page', 0, $manager->id);
|
||||
$this->assertTrue($cm->uservisible);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,11 @@ information provided here is intended especially for developers.
|
||||
* renderers: We now remove the suffix _renderable when looking for a render method for a renderable.
|
||||
If you have a renderable class named like "blah_renderable" and have a method on a renderer named "render_blah_renderable"
|
||||
you will need to change the name of your render method to "render_blah" instead, as renderable at the end is no longer accepted.
|
||||
* New functions get_course_and_cm_from_cmid($cmorid, $modulename) and
|
||||
get_course_and_cm_from_instance($instanceorid, $modulename) can be used to
|
||||
more efficiently load these basic data objects at the start of a script.
|
||||
* New function cm_info::create($cm) can be used when you need a cm_info
|
||||
object, but have a $cm which might only be a standard database record.
|
||||
|
||||
DEPRECATIONS:
|
||||
* completion_info->get_incomplete_criteria() is deprecated and will be removed in Moodle 3.0.
|
||||
|
Loading…
x
Reference in New Issue
Block a user