Commit 86b5ea0f authored by tjhunt's avatar tjhunt
Browse files

blocklib: MDL-19010 start of block_manager - get and set regions

parent c33db6e6
......@@ -167,6 +167,13 @@ $CFG->admin = 'admin';
// 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.
......
......@@ -45,6 +45,109 @@ define('BLOCKS_PINNED_BOTH',2);
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)) {
......@@ -329,7 +432,7 @@ function blocks_print_group(&$page, &$pageblocks, $position) {
$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'))) {
......@@ -639,7 +742,7 @@ function blocks_execute_action($page, &$pageblocks, $blockaction, $instanceorid,
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}
......@@ -835,7 +938,7 @@ function blocks_get_pinned($page) {
$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) {
......@@ -897,7 +1000,7 @@ function blocks_get_by_page($page) {
$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();
......@@ -986,7 +1089,7 @@ function blocks_repopulate_page($page) {
$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
......
......@@ -268,8 +268,14 @@ class moodle_page {
* @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;
}
......@@ -745,21 +751,21 @@ class moodle_page {
}
/**
* @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();
}
/**
......@@ -856,17 +862,6 @@ class moodle_page {
}
}
/** 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.
......
......@@ -275,7 +275,12 @@ global $SCRIPT;
}
/// 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) {
......
<?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');
}
}
?>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment