print_error('wrongcontextid', 'error');
}
$isfrontpage = $context->contextlevel == CONTEXT_COURSE && $context->instanceid == SITEID;
+ $PAGE->set_context($context);
$contextname = print_context_name($context);
$inmeta = 0;
print_error("unknowcategory");
}
- if (!$context = get_context_instance(CONTEXT_COURSECAT, $id)) {
- print_error("unknowcategory");
- }
+ $PAGE->set_category_by_id($id);
+ $context = $PAGE->context;
+ $category = $PAGE->category;
- if (!$category = $DB->get_record("course_categories", array("id"=>$id))) {
- print_error("unknowcategory");
- }
if (!$category->visible) {
require_capability('moodle/category:viewhiddencategories', $context);
}
* in order to keep redirects working properly. MDL-14495
*/
function require_login($courseorid=0, $autologinguest=true, $cm=null, $setwantsurltome=true) {
- global $CFG, $SESSION, $USER, $COURSE, $FULLME, $PAGE, $DB;
+ global $CFG, $SESSION, $USER, $COURSE, $FULLME, $PAGE, $SITE, $DB;
/// setup global $COURSE, themes, language and locale
if (!empty($courseorid)) {
protected $_context = null;
+ /**
+ * This holds any categories that $_course belongs to, starting with the
+ * particular category it belongs to, and working out through any parent
+ * categories to the top level. These are loaded progressively, if neaded.
+ * There are three states. $_categories = null initially when nothing is
+ * loaded; $_categories = array($id => $cat, $parentid => null) when we have
+ * loaded $_course->category, but not any parents; and a complete array once
+ * everything is loaded.
+ */
+ protected $_categories = null;
+
protected $_bodyclasses = array();
protected $_pagetype = null;
return $this->_course;
}
+ /**
+ * @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.
+ */
+ public function get_category() {
+ $this->ensure_category_loaded();
+ if (!empty($this->_categories)) {
+ return reset($this->_categories);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @return array an array of all the categories the page course belongs to,
+ * starting with the immediately containing category, and working out to
+ * the top-level category. This may be the empty array if we are in the
+ * front page course.
+ */
+ public function get_categories() {
+ $this->ensure_categories_loaded();
+ return $this->_categories;
+ }
+
/**
* @return object the main context to which this page belongs.
*/
* @param object the course to set as the global course.
*/
public function set_course($course) {
- global $COURSE, $SITE;
+ global $COURSE;
if (empty($course->id)) {
throw new coding_exception('$course passed to moodle_page::set_course does not look like a proper course object.');
$this->set_context(get_context_instance(CONTEXT_COURSE, $this->_course->id));
}
+ $this->_categories = null;
+
moodle_setlocale();
theme_setup();
}
}
}
+ /**
+ * Set the course category this page belongs to manually. This automatically
+ * sets $PAGE->course to be the site coures. You cannot use this method if
+ * you have already set $PAGE->course - in that case, the category must be
+ * the one that the course belongs to. This also automatically sets the
+ * page context to the category context.
+ * @param integer $categoryid The id of the category to set.
+ */
+ public function set_category_by_id($categoryid) {
+ global $SITE, $DB;
+ if (!is_null($this->_course)) {
+ throw new coding_exception('Attempt to manually set the course category when the course has been set. This is not allowed.');
+ }
+ if (is_array($this->_categories)) {
+ throw new coding_exception('Course category has already been set. You are not allowed to change it.');
+ }
+ $this->set_course($SITE);
+ $this->load_category($categoryid);
+ $this->set_context(get_context_instance(CONTEXT_COURSECAT, $categoryid));
+ }
+
/// Initialisation methods =====================================================
/// These set various things up in a default way.
}
}
+ protected function ensure_category_loaded() {
+ if (is_array($this->_categories)) {
+ return; // Already done.
+ }
+ if (is_null($this->_course)) {
+ throw new coding_exception('Attempt to get the course category for this page before the course was set.');
+ }
+ if ($this->_course->category == 0) {
+ $this->_categories = array();
+ } else {
+ $this->load_category($this->_course->category);
+ }
+ }
+
+ protected function load_category($categoryid) {
+ global $DB;
+ $category = $DB->get_record('course_categories', array('id' => $categoryid));
+ if (!$category) {
+ throw new moodle_exception('unknowncategory');
+ }
+ $this->_categories[$category->id] = $category;
+ $parentcategoryids = explode('/', trim($category->path, '/'));
+ array_pop($parentcategoryids);
+ foreach (array_reverse($parentcategoryids) as $catid) {
+ $this->_categories[$catid] = null;
+ }
+ }
+
+ protected function ensure_categories_loaded() {
+ global $DB;
+ $this->ensure_category_loaded();
+ if (!is_null(end($this->_categories))) {
+ return; // Already done.
+ }
+ $idstoload = array_keys($this->_categories);
+ array_shift($idstoload);
+ $categories = $DB->get_records_list('course_categories', 'id', $idstoload);
+ foreach ($idstoload as $catid) {
+ $this->_categories[$catid] = $categories[$catid];
+ }
+ }
+
protected function url_to_class_name($url) {
$bits = parse_url($url);
$class = str_replace('.', '-', $bits['host']);
$this->testpage->set_course($course);
}
+ public function test_cannot_set_category_once_output_started() {
+ // Setup fixture
+ $this->testpage->set_state(moodle_page::STATE_PRINTING_HEADER);
+ // Set expectation.
+ $this->expectException();
+ // Exercise SUT
+ $this->testpage->set_category_by_id(123);
+ }
+
+ public function test_cannot_set_category_once_course_set() {
+ // Setup fixture
+ $course = $this->create_a_course();
+ $this->testpage->set_context(new stdClass); // Avoid trying to set the context.
+ $this->testpage->set_course($course);
+ // Set expectation.
+ $this->expectException();
+ // Exercise SUT
+ $this->testpage->set_category_by_id(123);
+ }
+
public function test_set_state_normal_path() {
$this->assertEqual(moodle_page::STATE_BEFORE_HEADER, $this->testpage->state);
}
/**
- * Test functions that affect filter_active table with contextid = $syscontextid.
+ * Test functions that rely on the context table.
*/
-class moodle_page_with_db_test extends UnitTestCaseUsingDatabase {
+class moodle_page_with_context_table_test extends UnitTestCaseUsingDatabase {
protected $testpage;
protected $originalcourse;
public function setUp() {
global $COURSE;
+ parent::setUp();
$this->originalcourse = $COURSE;
$this->testpage = new moodle_page();
$this->create_test_table('context', 'lib');
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. */
$this->assert(new CheckSpecifiedFieldsExpectation($expectedcontext), $this->testpage->context);
}
}
+
+/**
+ * Test functions that rely on the context table.
+ */
+class moodle_page_categories_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_categories', 'context'), 'lib');
+ $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_category_with_context($parentid = 0) {
+ if ($parentid) {
+ $parent = $this->testdb->get_record('course_categories', array('id' => $parentid));
+ } else {
+ $parent = new stdClass;
+ $parent->depth = 0;
+ $parent->path = '';
+ }
+ $cat = new stdClass;
+ $cat->name = 'Anonymous test category';
+ $cat->description = '';
+ $cat->parent = $parentid;
+ $cat->depth = $parent->depth + 1;
+ $cat->id = $this->testdb->insert_record('course_categories', $cat);
+ $cat->path = $parent->path . '/' . $cat->id;
+ $this->testdb->set_field('course_categories', 'path', $cat->path, array('id' => $cat->id));
+
+ $context = new stdClass;
+ $context->contextlevel = CONTEXT_COURSECAT;
+ $context->instanceid = $cat->id;
+ $context->path = 'not initialised';
+ $context->depth = '-1';
+ $this->testdb->insert_record('context', $context);
+
+ return $cat;
+ }
+
+ public function test_set_category_top_level() {
+ // Setup fixture
+ $cat = $this->create_a_category_with_context();
+ // Exercise SUT
+ $this->testpage->set_category_by_id($cat->id);
+ // Validate
+ $this->assert(new CheckSpecifiedFieldsExpectation($cat), $this->testpage->category);
+ $expectedcontext = new stdClass; // Test it sets the context.
+ $expectedcontext->contextlevel = CONTEXT_COURSECAT;
+ $expectedcontext->instanceid = $cat->id;
+ $this->assert(new CheckSpecifiedFieldsExpectation($expectedcontext), $this->testpage->context);
+ }
+
+ public function test_set_nested_categories() {
+ // Setup fixture
+ $topcat = $this->create_a_category_with_context();
+ $subcat = $this->create_a_category_with_context($topcat->id);
+ // Exercise SUT
+ $this->testpage->set_category_by_id($subcat->id);
+ // Validate
+ $categories = $this->testpage->categories;
+ $this->assertEqual(2, count($categories));
+ $this->assert(new CheckSpecifiedFieldsExpectation($topcat), array_pop($categories));
+ $this->assert(new CheckSpecifiedFieldsExpectation($subcat), array_pop($categories));
+ }
+}
+
?>