From: tjhunt Date: Wed, 6 May 2009 09:03:33 +0000 (+0000) Subject: moodle_page: MDL-12212 ->cm and ->activityrecord fields X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=5ec434a9c24900588b019d3a3df48f89ba9f787f;p=moodle.git moodle_page: MDL-12212 ->cm and ->activityrecord fields --- diff --git a/lib/adminlib.php b/lib/adminlib.php index b0a325883e..d086ce5c38 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -3908,7 +3908,7 @@ function admin_externalpage_setup($section, $extrabutton = '', page_map_class(PAGE_ADMIN, 'page_admin'); $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); - $PAGE->set_extra_button($extrabutton); + // $PAGE->set_extra_button($extrabutton); TODO $adminroot = admin_get_root(false, false); // settings not required for external pages $extpage = $adminroot->locate($section); @@ -3916,6 +3916,7 @@ function admin_externalpage_setup($section, $extrabutton = '', if (!$actualurl) { $actualurl = $extpage->url; } + $PAGE->set_pagetype(null); $PAGE->set_url(str_replace($CFG->wwwroot . '/', '', $actualurl), array_merge($extraurlparams, array('section' => $section))); diff --git a/lib/pagelib.php b/lib/pagelib.php index fdc9a21bfc..2b744d8a1b 100644 --- a/lib/pagelib.php +++ b/lib/pagelib.php @@ -54,6 +54,23 @@ class moodle_page { protected $_course = null; + /** + * If this page belongs to a module, this is the row from the course_modules + * table, as fetched by get_coursemodule_from_id or get_coursemodule_from_instance, + * so the extra modname and name fields are present. + */ + protected $_cm = null; + + /** + * If $_cm is not null, then this will hold the corresponding row from the + * modname table. For example, if $_cm->modname is 'quiz', this will be a + * row from the quiz table. + */ + protected $_module = null; + + /** + * The context that this page belongs to. + */ protected $_context = null; /** @@ -127,6 +144,42 @@ class moodle_page { return $this->_course; } + /** + * @return object the course_module that this page belongs to. Will be null + * if this page is not within a module. This is a full cm object, as loaded + * by get_coursemodule_from_id or get_coursemodule_from_instance, + * so the extra modname and name fields are present. + */ + public function get_cm() { + return $this->_cm; + } + + /** + * @return object the course_module that this page belongs to. Will be null + * if this page is not within a module. This is a full cm object, as loaded + * by get_coursemodule_from_id or get_coursemodule_from_instance, + * so the extra modname and name fields are present. + */ + public function get_activityrecord() { + if (is_null($this->_module) && !is_null($this->_cm)) { + $this->load_activity_record(); + } + return $this->_module; + } + + /** + * @return object the course_module that this page belongs to. Will be null + * if this page is not within a module. This is a full cm object, as loaded + * by get_coursemodule_from_id or get_coursemodule_from_instance, + * so the extra modname and name fields are present. + */ + public function get_activityname() { + if (is_null($this->_cm)) { + return null; + } + return $this->_cm->modname; + } + /** * @return mixed the category that the page course belongs to. If there isn't one * (that is, if this is the front page course) returns null. @@ -317,6 +370,50 @@ class moodle_page { $this->_context = $context; } + /** + * The course module that this page belongs to (if it does belong to one). + * + * @param objcet $cm a full cm objcet obtained from get_coursemodule_from_id or get_coursemodule_from_instance. + */ + public function set_cm($cm, $course = null, $module = null) { + if (!isset($cm->name) || !isset($cm->modname)) { + throw new coding_exception('The $cm you set on $PAGE must have been obtained with get_coursemodule_from_id or get_coursemodule_from_instance. That is, the ->name and -> modname fields must be present and correct.'); + } + $this->_cm = $cm; + if (!$this->_context) { + $this->set_context(get_context_instance(CONTEXT_MODULE, $cm->id)); + } + if (!$this->_course || $this->_course->id != $cm->course) { + if (!$course) { + global $DB; + $course = $DB->get_record('course', array('id' => $cm->course)); + } + if ($course->id != $cm->course) { + throw new coding_exception('The course you passed to $PAGE->set_cm does not seem to correspond to the $cm.'); + } + $this->set_course($course); + } + if ($module) { + $this->set_activity_record($module); + } + } + + /** + * @param $module a row from the main database table for the module that this + * page belongs to. For example, if ->cm is a forum, then you can pass the + * corresponding row from the forum table here if you have it (saves a database + * query sometimes). + */ + public function set_activity_record($module) { + if (is_null($this->_cm)) { + throw new coding_exception('You cannot call $PAGE->set_activity_record until after $PAGE->cm has been set.'); + } + if ($module->id != $this->_cm->instance || $module->course != $this->_course->id) { + throw new coding_exception('The activity record your are trying to set does not seem to correspond to the cm that has been set.'); + } + $this->_module = $module; + } + /** * @param string $pagetype e.g. 'my-index' or 'mod-quiz-attempt'. Normally * you do not need to set this manually, it is automatically created from the @@ -396,6 +493,9 @@ class moodle_page { if (is_null($this->_pagetype)) { $this->initialise_default_pagetype($url); } + if (!is_null($this->_legacypageobject)) { + $this->_legacypageobject->set_url($url, $params); + } } /** @@ -514,6 +614,14 @@ class moodle_page { } } + protected function load_activity_record() { + global $DB; + if (is_null($this->_cm)) { + return; + } + $this->_module = $DB->get_record($this->_cm->modname, array('id' => $this->_cm->instance)); + } + protected function ensure_category_loaded() { if (is_array($this->_categories)) { return; // Already done. @@ -707,6 +815,14 @@ class moodle_page { } return 0; } + + /** + * @deprecated since Moodle 2.0 - user $PAGE->cm instead. + * @return $this->cm; + */ + function get_modulerecord() { + return $this->cm; + } } /** Stub implementation of the blocks_manager, to stop things from breaking too badly. */ @@ -748,12 +864,12 @@ function page_create_instance($instance) { * If you need custom behaviour, you should just set properties of that object. */ function page_create_object($type, $id = NULL) { - global $CFG, $PAGE, $SITE; + global $CFG, $PAGE, $SITE, $ME; debugging('Call to deprecated function page_create_object.', DEBUG_DEVELOPER); $data = new stdClass; $data->pagetype = $type; - $data->pageid = $id; + $data->pageid = $id; $classname = page_map_class($type); $legacypage = new $classname; @@ -776,7 +892,9 @@ function page_create_object($type, $id = NULL) { } } $legacypage->set_pagetype($type); - $legacypage->set_url(str_replace($CFG->wwwroot . '/', '', $legacypage->url_get_full())); + + $legacypage->set_url($ME); + $PAGE->set_url(str_replace($CFG->wwwroot . '/', '', $legacypage->url_get_full())); $PAGE->set_pagetype($type); $PAGE->set_legacy_page_object($legacypage); @@ -817,37 +935,18 @@ function page_map_class($type, $classname = NULL) { * @package pages */ class page_base extends moodle_page { - /** - * The string identifier for the type of page being described. - * @var string $type - */ - var $type = NULL; - /** * The numeric identifier of the page being described. * @var int $id */ var $id = NULL; - /** - * Class bool to determine if the instance's full initialization has been completed. - * @var boolean $full_init_done - */ - var $full_init_done = false; - /// Class Functions // HTML OUTPUT SECTION - // We have absolutely no idea what derived pages are all about - function print_header($title, $morenavlinks=NULL) { - trigger_error('Page class does not implement method print_header()', E_USER_WARNING); - return; - } - // SELF-REPORTING SECTION - // Simple stuff, do not override this. function get_id() { return $this->id; @@ -855,12 +954,10 @@ class page_base extends moodle_page { // Initialize the data members of the parent class function init_quick($data) { - $this->type = $data->pagetype; $this->id = $data->pageid; } function init_full() { - $this->full_init_done = true; } } @@ -871,39 +968,6 @@ class page_base extends moodle_page { * @package pages */ class page_course extends page_base { - // Do any validation of the officially recognized bits of the data and forward to parent. - // Do NOT load up "expensive" resouces (e.g. SQL data) here! - function init_quick($data) { - if(empty($data->pageid) && !defined('ADMIN_STICKYBLOCKS')) { - print_error('cannotinitpage', 'debug', '', (object)array('name'=>'course', 'id'=>'?')); - } - parent::init_quick($data); - } - - // Here you should load up all heavy-duty data for your page. Basically everything that - // does not NEED to be loaded for the class to make basic decisions should NOT be loaded - // in init_quick() and instead deferred here. Of course this function had better recognize - // $this->full_init_done to prevent wasteful multiple-time data retrieval. - function init_full() { - global $COURSE, $DB; - - if($this->full_init_done) { - return; - } - if (empty($this->id)) { - $this->id = 0; // avoid db errors - } - - $this->context = get_context_instance(CONTEXT_COURSE, $this->id); - - // Preload - ensures that the context cache is populated - // in one DB query... - $this->childcontexts = get_child_contexts($this->context); - - // Mark we're done - $this->full_init_done = true; - } - // HTML OUTPUT SECTION // This function prints out the common part of the page's header. @@ -999,29 +1063,6 @@ class page_course extends page_base { * @package pages */ class page_generic_activity extends page_base { - var $activityname = NULL; - var $modulerecord = NULL; - var $activityrecord = NULL; - - function init_full() { - global $DB; - - if($this->full_init_done) { - return; - } - if(empty($this->activityname)) { - print_error('noactivityname', 'debug'); - } - if (!$this->modulerecord = get_coursemodule_from_instance($this->activityname, $this->id)) { - print_error('cannotinitpager', 'debug', '', (object)array('name'=>$this->activityname, 'id'=>$this->id)); - } - $this->activityrecord = $DB->get_record($this->activityname, array('id'=>$this->id)); - if(empty($this->activityrecord)) { - print_error('cannotinitpager', 'debug', '', (object)array('name'=>$this->activityname, 'id'=>$this->id)); - } - $this->full_init_done = true; - } - function print_header($title, $morenavlinks = NULL, $bodytags = '', $meta = '') { global $USER, $CFG; diff --git a/lib/simpletest/testpagelib_moodlepage.php b/lib/simpletest/testpagelib_moodlepage.php index 60f42cc371..e6abd33ba0 100644 --- a/lib/simpletest/testpagelib_moodlepage.php +++ b/lib/simpletest/testpagelib_moodlepage.php @@ -456,6 +456,207 @@ class moodle_page_categories_test extends UnitTestCaseUsingDatabase { } } +/** + * Test functions that rely on the context table. + */ +class moodle_page_cm_test extends UnitTestCaseUsingDatabase { + protected $testpage; + protected $originalcourse; + + public function setUp() { + global $COURSE, $SITE; + parent::setUp(); + $this->originalcourse = $COURSE; + $this->testpage = new moodle_page(); + $this->create_test_tables(array('course', 'context'), 'lib'); + $this->create_test_table('forum', 'mod/forum'); + $this->switch_to_test_db(); + + $context = new stdClass; + $context->contextlevel = CONTEXT_COURSE; + $context->instanceid = $SITE->id; + $context->path = 'not initialised'; + $context->depth = '-1'; + $this->testdb->insert_record('context', $context); + } + + public function tearDown() { + global $COURSE; + $this->testpage = NULL; + $COURSE = $this->originalcourse; + parent::tearDown(); + } + + /** Creates an object with all the fields you would expect a $course object to have. */ + protected function create_a_forum_with_context() { + $course = new stdClass; + $course->category = 2; + $course->fullname = 'Anonymous test course'; + $course->shortname = 'ANON'; + $course->summary = ''; + $course->id = $this->testdb->insert_record('course', $course); + + $forum = new stdClass; + $forum->course = $course->id; + $forum->name = 'Anonymouse test forum'; + $forum->intro = ''; + $forum->id = $this->testdb->insert_record('forum', $forum); + + $cm = new stdClass; + $cm->id = -1; + $cm->course = $course->id; + $cm->instance = $forum->id; + $cm->modname = 'forum'; + $cm->name = $forum->name; + + $context = new stdClass; + $context->contextlevel = CONTEXT_MODULE; + $context->instanceid = $cm->id; + $context->path = 'not initialised'; + $context->depth = '-1'; + $this->testdb->insert_record('context', $context); + + return array($cm, $course, $forum); + } + + public function test_cm_null_initially() { + // Validate + $this->assertNull($this->testpage->cm); + } + + public function test_set_cm() { + // Setup fixture + list($cm) = $this->create_a_forum_with_context(); + // Exercise SUT + $this->testpage->set_cm($cm); + // Validate + $this->assert(new CheckSpecifiedFieldsExpectation($cm), $this->testpage->cm); + } + + public function test_cannot_set_cm_without_name() { + // Setup fixture + list($cm) = $this->create_a_forum_with_context(); + // Set expectation + $this->expectException(); + // Exercise SUT + unset($cm->name); + $this->testpage->set_cm($cm); + } + + public function test_cannot_set_cm_without_modname() { + // Setup fixture + list($cm) = $this->create_a_forum_with_context(); + // Set expectation + $this->expectException(); + // Exercise SUT + unset($cm->modname); + $this->testpage->set_cm($cm); + } + + public function test_cannot_set_activity_record_before_cm() { + // Setup fixture + list($cm, $course, $forum) = $this->create_a_forum_with_context(); + // Set expectation + $this->expectException(); + // Exercise SUT + $this->testpage->set_activity_record($forum); + } + + public function test_setting_cm_sets_context() { + // Setup fixture + list($cm) = $this->create_a_forum_with_context(); + // Exercise SUT + $this->testpage->set_cm($cm); + // Validate + $expectedcontext = new stdClass; + $expectedcontext->contextlevel = CONTEXT_MODULE; + $expectedcontext->instanceid = $cm->id; + $this->assert(new CheckSpecifiedFieldsExpectation($expectedcontext), $this->testpage->context); + } + + public function test_activity_record_loaded_if_not_set() { + // Setup fixture + list($cm, $course, $forum) = $this->create_a_forum_with_context(); + // Exercise SUT + $this->testpage->set_cm($cm); + // Validate + $this->assert(new CheckSpecifiedFieldsExpectation($forum), $this->testpage->activityrecord); + } + + public function test_set_activity_record() { + // Setup fixture + list($cm, $course, $forum) = $this->create_a_forum_with_context(); + $this->testpage->set_cm($cm); + // Exercise SUT + $this->testpage->set_activity_record($forum); + // Validate + $this->assert(new CheckSpecifiedFieldsExpectation($forum), $this->testpage->activityrecord); + } + + public function test_cannot_set_inconsistent_activity_record_course() { + // Setup fixture + list($cm, $course, $forum) = $this->create_a_forum_with_context(); + $this->testpage->set_cm($cm); + // Set expectation + $this->expectException(); + // Exercise SUT + $forum->course = -1; + $this->testpage->set_activity_record($forum); + } + + public function test_cannot_set_inconsistent_activity_record_instance() { + // Setup fixture + list($cm, $course, $forum) = $this->create_a_forum_with_context(); + $this->testpage->set_cm($cm); + // Set expectation + $this->expectException(); + // Exercise SUT + $forum->id = -1; + $this->testpage->set_activity_record($forum); + } + + public function test_settin_cm_sets_course() { + // Setup fixture + list($cm, $course) = $this->create_a_forum_with_context(); + // Exercise SUT + $this->testpage->set_cm($cm); + // Validate + $this->assert(new CheckSpecifiedFieldsExpectation($course), $this->testpage->course); + } + + public function test_set_cm_with_course_and_activity_no_db() { + // Setup fixture + list($cm, $course, $forum) = $this->create_a_forum_with_context(); + $this->drop_test_table('forum'); + $this->drop_test_table('course'); + // Exercise SUT + $this->testpage->set_cm($cm, $course, $forum); + // Validate + $this->assert(new CheckSpecifiedFieldsExpectation($cm), $this->testpage->cm); + $this->assert(new CheckSpecifiedFieldsExpectation($course), $this->testpage->course); + $this->assert(new CheckSpecifiedFieldsExpectation($forum), $this->testpage->activityrecord); + } + + public function test_cannot_set_cm_with_inconsistent_course() { + // Setup fixture + list($cm, $course, $forum) = $this->create_a_forum_with_context(); + // Set expectation + $this->expectException(); + // Exercise SUT + $cm->course = -1; + $this->testpage->set_cm($cm, $course); + } + + public function test_get_activity_name() { + // Setup fixture + list($cm, $course, $forum) = $this->create_a_forum_with_context(); + // Exercise SUT + $this->testpage->set_cm($cm, $course, $forum); + // Validate + $this->assertEqual('forum', $this->testpage->activityname); + } +} + /** * Test functions that affect filter_active table with contextid = $syscontextid. */