]> git.mjollnir.org Git - moodle.git/commitdiff
blocklib: MDL-19010 start of block_manager - get and set regions
authortjhunt <tjhunt>
Wed, 6 May 2009 09:14:01 +0000 (09:14 +0000)
committertjhunt <tjhunt>
Wed, 6 May 2009 09:14:01 +0000 (09:14 +0000)
config-dist.php
lib/blocklib.php
lib/pagelib.php
lib/setup.php
lib/simpletest/testblocklib_blockmanager.php [new file with mode: 0644]

index 6f2c092cc31a3d28e0f8b5e5dbf1eaff4dff1afb..8e66e42b3d6152db9a752d81ee07cec130afe3a1 100644 (file)
@@ -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.
index cf8120b0131504ee7e9406cb4ade930e428ab6b2..13e01ad593bd2d0d0f8c3d40990ecdd77d11dd60 100644 (file)
@@ -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
index 0fdb40dd5ed11154d184084fabd55d2d886e8d04..c2551e9f29efb5030f903a13abaccee150db2cb7 100644 (file)
@@ -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.
index 63790b75c945e269b9dde6192d49adc04f7c3857..26dd952115d78e0a9b985ceb8fabae793a5457e3 100644 (file)
@@ -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) {
diff --git a/lib/simpletest/testblocklib_blockmanager.php b/lib/simpletest/testblocklib_blockmanager.php
new file mode 100644 (file)
index 0000000..5cb08c5
--- /dev/null
@@ -0,0 +1,130 @@
+<?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');
+    }
+
+}
+
+?>