// These blocks are used when no other default setting is found.
// $CFG->defaultblocks = 'participants,activity_modules,search_forums,admin,course_list:news_items,calendar_upcoming,recent_activity';
//
+// You can specify a different class to be created for the $PAGE global, and to
+// compute which blocks appear on each page. However, I cannot think of any good
+// reason why you would need to change that. It just felt wrong to hard-code the
+// the class name. You are stronly advised not to use these to settings unless
+// you are absolutely sure you know what you are doing.
+// $CFG->moodlepageclass = 'moodle_page';
+// $CFG->blockmanagerclass = 'block_manager';
//
// Seconds for files to remain in caches. Decrease this if you are worried
// about students being served outdated versions of uploaded files.
require_once($CFG->libdir.'/pagelib.php');
+/**
+ * This class keeps track of the block that should appear on a moodle_page.
+ * The page to work with as passed to the constructor.
+ * The only fields of moodle_page that is uses are ->context, ->pagetype and
+ * ->subpage, so instead of passing a full moodle_page object, you may also
+ * pass a stdClass object with those three fields. These field values are read
+ * only at the point that the load_blocks() method is called. It is the caller's
+ * responsibility to ensure that those fields do not subsequently change.
+ */
+class block_manager {
+ /**#@+ Tracks the where we are in the generation of the page. */
+ const STATE_BLOCKS_NOT_LOADED = 0;
+ const STATE_BLOCKS_LOADED = 1;
+ /**#@-*/
+
+/// Field declarations =========================================================
+
+ protected $loaded = self::STATE_BLOCKS_NOT_LOADED;
+
+ protected $page;
+
+ protected $regions = array();
+
+ protected $defaultregion;
+
+/// Constructor ================================================================
+
+ /**
+ * Constructor.
+ * @param object $page the moodle_page object object we are managing the blocks for,
+ * or a reasonable faxilimily. (See the comment at the top of this classe
+ * and http://en.wikipedia.org/wiki/Duck_typing)
+ */
+ public function __construct($page) {
+ $this->page = $page;
+ }
+
+/// Getter methods =============================================================
+
+ /**
+ * @return array the internal names of the regions on this page where block may appear.
+ */
+ public function get_regions() {
+ return array_keys($this->regions);
+ }
+
+ /**
+ * @return string the internal names of the region where new blocks are added
+ * by default, and where any blocks from an unrecognised region are shown.
+ * (Imagine that blocks were added with one theme selected, then you switched
+ * to a theme with different block positions.)
+ */
+ public function get_default_region() {
+ return $this->defaultregion;
+ }
+
+/// Setter methods =============================================================
+
+ /**
+ * @param string $region add a named region where blocks may appear on the
+ * current page. This is an internal name, like 'side-pre', not a string to
+ * display in the UI.
+ */
+ public function add_region($region) {
+ $this->check_not_yet_loaded();
+ $this->regions[$region] = 1;
+ }
+
+ /**
+ * @param array $regions this utility method calls add_region for each array element.
+ */
+ public function add_regions($regions) {
+ foreach ($regions as $region) {
+ $this->add_region($region);
+ }
+ }
+
+ /**
+ * @param string $defaultregion the internal names of the region where new
+ * blocks should be added by default, and where any blocks from an
+ * unrecognised region are shown.
+ */
+ public function set_default_region($defaultregion) {
+ $this->check_not_yet_loaded();
+ if (!array_key_exists($defaultregion, $this->regions)) {
+ throw new coding_exception('Trying to set an unknown block region as the default.');
+ }
+ $this->defaultregion = $defaultregion;
+ }
+
+/// Inner workings =============================================================
+
+ protected function check_not_yet_loaded() {
+ if ($this->loaded) {
+ throw new coding_exception('block_manager has already loaded the blocks, to it is too late to change things that might affect which blocks are visible.');
+ }
+ }
+
+ protected function mark_loaded() {
+ $this->loaded = self::STATE_BLOCKS_LOADED;
+ }
+}
+
//This function retrieves a method-defined property of a class WITHOUT instantiating an object
function block_method_result($blockname, $method, $param = NULL) {
if(!block_load_class($blockname)) {
$managecourseblocks = has_capability('moodle/site:manageblocks', $coursecontext);
$editmymoodle = $page->pagetype == PAGE_MY_MOODLE && has_capability('moodle/my:manageblocks', $coursecontext);
- if ($page->blocks->get_default_position() == $position &&
+ if ($page->blocks->get_default_region() == $position &&
$page->user_is_editing() &&
($managecourseblocks || $editmymoodle || $myownblogpage || defined('ADMIN_STICKYBLOCKS'))) {
break;
}
- $newpos = $page->blocks->get_default_position();
+ $newpos = $page->blocks->get_default_region();
if (!empty($pinned)) {
$sql = "SELECT 1, MAX(weight) + 1 AS nextfree
FROM {block_pinned_old}
$blocks = $DB->get_records_select('block_pinned_old', $select, $params, 'position, weight');
- $positions = $page->blocks->get_positions();
+ $positions = $page->blocks->get_regions();
$arr = array();
foreach($positions as $key => $position) {
$blocks = $DB->get_records_select('block_instance_old', "pageid = ? AND ? LIKE (" . $DB->sql_concat('pagetype', "'%'") . ")",
array($page->get_id(), $page->pagetype), 'position, weight');
- $positions = $page->blocks->get_positions();
+ $positions = $page->blocks->get_regions();
$arr = array();
foreach($positions as $key => $position) {
$arr[$position] = array();
$blocknames = $page->blocks_get_default();
}
- $positions = $page->blocks->get_positions();
+ $positions = $page->blocks->get_regions();
$posblocks = explode(':', $blocknames);
// Now one array holds the names of the positions, and the other one holds the blocks
* @return blocks_manager the blocks manager object for this page.
*/
public function get_blocks() {
+ global $CFG;
if (is_null($this->_blocks)) {
- $this->_blocks = new blocks_manager();
+ if (!empty($CFG->blockmanagerclass)) {
+ $classname = $CFG->blockmanagerclass;
+ } else {
+ $classname = 'block_manager';
+ }
+ $this->_blocks = new $classname($this);
}
return $this->_blocks;
}
}
/**
- * @deprecated since Moodle 2.0 - use $PAGE->blocks->get_positions() instead
+ * @deprecated since Moodle 2.0 - use $PAGE->blocks->get_regions() instead
* @return string the places on this page where blocks can go.
*/
function blocks_get_positions() {
- debugging('Call to deprecated method moodle_page::blocks_get_positions. Use $PAGE->blocks->get_positions() instead.');
- return $this->blocks->get_positions();
+ debugging('Call to deprecated method moodle_page::blocks_get_positions. Use $PAGE->blocks->get_regions() instead.');
+ return $this->blocks->get_regions();
}
/**
- * @deprecated since Moodle 2.0 - use $PAGE->blocks->get_default_position() instead
+ * @deprecated since Moodle 2.0 - use $PAGE->blocks->get_default_region() instead
* @return string the default place for blocks on this page.
*/
function blocks_default_position() {
- debugging('Call to deprecated method moodle_page::blocks_default_position. Use $PAGE->blocks->get_default_position() instead.');
- return $this->blocks->get_default_position();
+ debugging('Call to deprecated method moodle_page::blocks_default_position. Use $PAGE->blocks->get_default_region() instead.');
+ return $this->blocks->get_default_region();
}
/**
}
}
-/** Stub implementation of the blocks_manager, to stop things from breaking too badly. */
-class blocks_manager {
- public function get_positions() {
- return array(BLOCK_POS_LEFT, BLOCK_POS_RIGHT);
- }
-
- public function get_default_position() {
- return BLOCK_POS_RIGHT;
- }
-}
-
/**
* @deprecated since Moodle 2.0
* Not needed any more.
}
/// Create the $PAGE global.
- $PAGE = new moodle_page();
+ if (!empty($CFG->moodlepageclass)) {
+ $classname = $CFG->moodlepageclass;
+ } else {
+ $classname = 'moodle_page';
+ }
+ $PAGE = new $classname();
/// Set error reporting back to normal
if ($originaldatabasedebug == -1) {
--- /dev/null
+<?php // $Id$
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// NOTICE OF COPYRIGHT //
+// //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment //
+// http://moodle.org //
+// //
+// Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details: //
+// //
+// http://www.gnu.org/copyleft/gpl.html //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ * Tests for the block_manager class in ../blocklib.php.
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package moodlecore
+ */
+
+if (!defined('MOODLE_INTERNAL')) {
+ die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
+}
+
+require_once($CFG->libdir . '/pagelib.php');
+require_once($CFG->libdir . '/blocklib.php');
+
+/** Test-specific subclass to make some protected things public. */
+class testable_block_manager extends block_manager {
+ public function mark_loaded() {
+ parent::mark_loaded();
+ }
+}
+
+/**
+ * Test functions that don't need to touch the database.
+ */
+class moodle_page_test extends UnitTestCase {
+ protected $testpage;
+ protected $blockmanager;
+
+ public function setUp() {
+ $this->testpage = new moodle_page();
+ $this->blockmanager = new testable_block_manager($this->testpage);
+ }
+
+ public function tearDown() {
+ $this->testpage = NULL;
+ $this->blockmanager = NULL;
+ }
+
+ public function test_no_regions_initially() {
+ // Exercise SUT & Validate
+ $this->assertEqual(array(), $this->blockmanager->get_regions());
+ }
+
+ public function test_add_region() {
+ // Exercise SUT.
+ $this->blockmanager->add_region('a-region-name');
+ // Validate
+ $this->assertEqual(array('a-region-name'), $this->blockmanager->get_regions());
+ }
+
+ public function test_add_regions() {
+ // Set up fixture.
+ $regions = array('a-region', 'another-region');
+ // Exercise SUT.
+ $this->blockmanager->add_regions($regions);
+ // Validate
+ $this->assert(new ArraysHaveSameValuesExpectation($regions), $this->blockmanager->get_regions());
+ }
+
+ public function test_add_region_twice() {
+ // Exercise SUT.
+ $this->blockmanager->add_region('a-region-name');
+ $this->blockmanager->add_region('another-region');
+ // Validate
+ $this->assert(new ArraysHaveSameValuesExpectation(array('a-region-name', 'another-region')),
+ $this->blockmanager->get_regions());
+ }
+
+ public function test_cannot_add_region_after_loaded() {
+ // Set up fixture.
+ $this->blockmanager->mark_loaded();
+ // Set expectation
+ $this->expectException();
+ // Exercise SUT.
+ $this->blockmanager->add_region('too-late');
+ }
+
+ public function test_set_default_region() {
+ // Set up fixture.
+ $this->blockmanager->add_region('a-region-name');
+ // Exercise SUT.
+ $this->blockmanager->set_default_region('a-region-name');
+ // Validate
+ $this->assertEqual('a-region-name', $this->blockmanager->get_default_region());
+ }
+
+ public function test_cannot_set_unknown_region_as_default() {
+ // Set expectation
+ $this->expectException();
+ // Exercise SUT.
+ $this->blockmanager->set_default_region('a-region-name');
+ }
+
+ public function test_cannot_change_default_region_after_loaded() {
+ // Set up fixture.
+ $this->blockmanager->mark_loaded();
+ // Set expectation
+ $this->expectException();
+ // Exercise SUT.
+ $this->blockmanager->set_default_region('too-late');
+ }
+
+}
+
+?>