]> git.mjollnir.org Git - moodle.git/commitdiff
blocklib: MDL-19010 add block and get_blocks methods
authortjhunt <tjhunt>
Wed, 6 May 2009 09:14:42 +0000 (09:14 +0000)
committertjhunt <tjhunt>
Wed, 6 May 2009 09:14:42 +0000 (09:14 +0000)
blog/header.php
lib/blocklib.php
lib/pagelib.php
lib/simpletest/testblocklib_blockmanager.php
lib/weblib.php
theme/standard/config.php

index 6674a016de08831e3e1b484106c51e93e429d6db..03a0be6f1cc6978f819c29c8fd8b48e8105aed49 100755 (executable)
@@ -91,7 +91,6 @@ if ($editing) {
         // but I'm not sure if it's worth the complexity increase...
         $pageblocks = blocks_get_by_page($PAGE);
     }
-    $missingblocks = blocks_get_missing($PAGE, $pageblocks);
 }
 
 if (!empty($tagid)) {
index 13e01ad593bd2d0d0f8c3d40990ecdd77d11dd60..f3a54a2652bb80d7381c06649f22cf398914794d 100644 (file)
@@ -55,21 +55,21 @@ require_once($CFG->libdir.'/pagelib.php');
  * 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;
 
+    protected $allblocks = null; // Will be get_records('blocks');
+
+    protected $addableblocks = null; // Will be a subset of $allblocks.
+
+    protected $blocksbyregion = null; // Will be an array region-name => array(block_instances);
+
 /// Constructor ================================================================
 
     /**
@@ -101,6 +101,86 @@ class block_manager {
         return $this->defaultregion;
     }
 
+    /**
+     * The list of block types that may be added to this page.
+     * @return array block id => record from block table.
+     */
+    public function get_addable_blocks() {
+        $this->check_is_loaded();
+
+        if (!is_null($this->addableblocks)) {
+            return $this->addableblocks;
+        }
+
+        // Lazy load.
+        $this->addableblocks = array();
+
+        $allblocks = blocks_get_record();
+        if (empty($allblocks)) {
+            return $this->addableblocks;
+        }
+
+        $pageformat = $page->pagetype;
+        foreach($allblocks as $block) {
+            if ($block->visible &&
+                    ($block->multiple || !$this->is_block_present($block->id)) &&
+                    blocks_name_allowed_in_format($block->name, $pageformat)) {
+                $this->addableblocks[$block->id] = $block;
+            }
+        }
+
+        return $this->addableblocks;
+    }
+
+    public function is_block_present($blocktypeid) {
+        // TODO
+    }
+
+    /**
+     * @param string $blockname the name of ta type of block.
+     * @param boolean $includeinvisible if false (default) only check 'visible' blocks, that is, blocks enabled by the admin.
+     * @return boolean true if this block in installed.
+     */
+    public function is_known_block_type($blockname, $includeinvisible = false) {
+        $blocks = $this->get_installed_blocks();
+        foreach ($blocks as $block) {
+            if ($block->name == $blockname && ($includeinvisible || $block->visible)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param string $region a region name
+     * @return boolean true if this retion exists on this page.
+     */
+    public function is_known_region($region) {
+        return array_key_exists($region, $this->regions);
+    }
+
+    /**
+     * @param $region a block region that exists on this page.
+     * @return array of block instances.
+     */
+    public function get_blocks_for_region($region) {
+        $this->check_is_loaded();
+        $this->check_region_is_known($region);
+        return $this->blocksbyregion[$region];
+    }
+
+    /**
+     * Get the list of all installed blocks.
+     * @return array contents of the block table.
+     */
+    public function get_installed_blocks() {
+        global $DB;
+        if (is_null($this->allblocks)) {
+            $this->allblocks = $DB->get_records('block');
+        }
+        return $this->allblocks;
+    }
+
 /// Setter methods =============================================================
 
     /**
@@ -129,26 +209,191 @@ class block_manager {
      */
     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->check_region_is_known($defaultregion);
         $this->defaultregion = $defaultregion;
     }
 
+/// Actions ====================================================================
+
+    /**
+     * This method actually loads the blocks for our page from the database.
+     */
+    public function load_blocks($includeinvisible = NULL) {
+        global $DB;
+        $this->check_not_yet_loaded();
+
+        if (is_null($includeinvisible)) {
+            $includeinvisible = $this->page->user_is_editing();
+        }
+        if ($includeinvisible) {
+            $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)';
+        } else {
+            $visiblecheck = '';
+        }
+
+        $context = $this->page->context;
+        $contexttest = 'bi.contextid = :contextid2';
+        $parentcontextparams = array();
+        $parentcontextids = get_parent_contexts($context);
+        if ($parentcontextids) {
+            list($parentcontexttest, $parentcontextparams) =
+                    $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext0000');
+            $contexttest = "($contexttest OR (bi.showinsubcontexts = 1 AND bi.contextid $parentcontexttest))";
+        }
+
+        $pagetypepatterns = $this->matching_page_type_patterns($this->page->pagetype);
+        list($pagetypepatterntest, $pagetypepatternparams) =
+                $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest0000');
+
+        $params = array(
+            'subpage1' => $this->page->subpage,
+            'subpage2' => $this->page->subpage,
+            'contextid1' => $context->id,
+            'contextid2' => $context->id,
+            'pagetype' => $this->page->pagetype,
+        );
+        $sql = "SELECT
+                    bi.id,
+                    bi.blockname,
+                    bi.contextid,
+                    bi.showinsubcontexts,
+                    bi.pagetypepattern,
+                    bi.subpagepattern,
+                    bp.visible,
+                    COALESCE(bp.region, bi.defaultregion) AS region,
+                    COALESCE(bp.weight, bi.defaultweight) AS weight,
+                    bi.configdata
+
+                FROM {block_instances} bi
+                JOIN {block} b ON bi.blockname = b.name
+                LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id
+                                                  AND bp.contextid = :contextid1
+                                                  AND bp.pagetype = :pagetype
+                                                  AND bp.subpage = :subpage1
+
+                WHERE
+                $contexttest
+                AND bi.pagetypepattern $pagetypepatterntest
+                AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2)
+                $visiblecheck
+                AND b.visible = 1
+
+                ORDER BY
+                    COALESCE(bp.region, bi.defaultregion),
+                    COALESCE(bp.weight, bi.defaultweight),
+                    bi.id";
+        $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams);
+
+        $this->blocksbyregion = array();
+        foreach ($this->regions as $region => $notused) {
+            $this->blocksbyregion[$region] = array();
+        }
+        $unknown = array();
+
+        foreach ($blockinstances as $bi) {
+            if ($this->is_known_region($bi->region)) {
+                $this->blocksbyregion[$bi->region][] = $bi;
+            } else {
+                $unknown[] = $bi;
+            }
+        }
+        $this->blocksbyregion[$this->defaultregion] = array_merge($this->blocksbyregion[$this->defaultregion], $unknown);
+    }
+
+    /**
+     * Add a block to the current page, or related pages. The block is added to
+     * context $this->page->contextid. If $pagetypepattern $subpagepattern
+     * @param string $blockname The type of block to add.
+     * @param string $region the block region on this page to add the block to.
+     * @param integer $weight determines the order where this block appears in the region.
+     * @param boolean $showinsubcontexts whether this block appears in subcontexts, or just the current context.
+     * @param string|null $pagetypepattern which page types this block should appear on. Defaults to just the current page type.
+     * @param string|null $subpagepattern which subpage this block should appear on. NULL = any (the default), otherwise only the specified subpage.
+     */
+    public function add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern = NULL, $subpagepattern = NULL) {
+        global $DB;
+        $this->check_known_block_type($blockname);
+        $this->check_region_is_known($region);
+
+        if (empty($pagetypepattern)) {
+            $pagetypepattern = $this->page->pagetype;
+        }
+
+        $blockinstance = new stdClass;
+        $blockinstance->blockname = $blockname;
+        $blockinstance->contextid = $this->page->context->id;
+        $blockinstance->showinsubcontexts = !empty($showinsubcontexts);
+        $blockinstance->pagetypepattern = $pagetypepattern;
+        $blockinstance->subpagepattern = $subpagepattern;
+        $blockinstance->defaultregion = $region;
+        $blockinstance->defaultweight = $weight;
+        $blockinstance->configdata = '';
+        $DB->insert_record('block_instances', $blockinstance);
+    }
+
 /// Inner workings =============================================================
 
+    /**
+     * Given a specific page type, return all the page type patterns that might
+     * match it.
+     * @param string $pagetype for example 'course-view-weeks' or 'mod-quiz-view'.
+     * @return array an array of all the page type patterns that might match this page type.
+     */
+    protected function matching_page_type_patterns($pagetype) {
+        $patterns = array($pagetype, '*');
+        $bits = explode('-', $pagetype);
+        if (count($bits) == 3 && $bits[0] == 'mod') {
+            if ($bits[2] == 'view') {
+                $patterns[] = 'mod-*-view';
+            } else if ($bits[2] == 'index') {
+                $patterns[] = 'mod-*-index';
+            }
+        }
+        while (count($bits) > 0) {
+            $patterns[] = implode('-', $bits) . '-*';
+            array_pop($bits);
+        }
+        return $patterns;
+    }
+
     protected function check_not_yet_loaded() {
-        if ($this->loaded) {
+        if (!is_null($this->blocksbyregion)) {
             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;
+    protected function check_is_loaded() {
+        if (is_null($this->blocksbyregion)) {
+            throw new coding_exception('block_manager has not yet loaded the blocks, to it is too soon to request the information you asked for.');
+        }
+    }
+
+    protected function check_known_block_type($blockname, $includeinvisible = false) {
+        if (!$this->is_known_block_type($blockname, $includeinvisible)) {
+            if ($this->is_known_block_type($blockname, true)) {
+                throw new coding_exception('Unknown block type ' . $blockname);
+            } else {
+                throw new coding_exception('Block type ' . $blockname . ' has been disabled by the administrator.');
+            }
+        }
+    }
+
+    protected function check_region_is_known($region) {
+        if (!$this->is_known_region($region)) {
+            throw new coding_exception('Trying to reference an unknown block region ' . $region);
+        }
     }
 }
 
-//This function retrieves a method-defined property of a class WITHOUT instantiating an object
+/// Helper functions for working with block classes ============================
+
+/**
+ * Call a class method (one that does not requrie a block instance) on a block class.
+ * @param string $blockname the name of the block.
+ * @param string $method the method name.
+ * @param array $param parameters to pass to the method.
+ * @return mixed whatever the method returns.
+ */
 function block_method_result($blockname, $method, $param = NULL) {
     if(!block_load_class($blockname)) {
         return NULL;
@@ -156,7 +401,12 @@ function block_method_result($blockname, $method, $param = NULL) {
     return call_user_func(array('block_'.$blockname, $method), $param);
 }
 
-//This function creates a new object of the specified block class
+/**
+ * Creates a new object of the specified block class.
+ * @param string $blockname the name of the block.
+ * @param $instance block_instances DB table row (optional).
+ * @return block_base the requested block instance.
+ */
 function block_instance($blockname, $instance = NULL) {
     if(!block_load_class($blockname)) {
         return false;
@@ -169,8 +419,11 @@ function block_instance($blockname, $instance = NULL) {
     return $retval;
 }
 
-//This function loads the necessary class files for a block
-//Whenever you want to load a block, use this first
+/**
+ * Load the block class for a particular type of block.
+ * @param string $blockname the name of the block.
+ * @return boolean success or failure.
+ */
 function block_load_class($blockname) {
     global $CFG;
 
@@ -190,26 +443,18 @@ function block_load_class($blockname) {
     return class_exists($classname);
 }
 
-// This function returns an array with the IDs of any blocks that you can add to your page.
-// Parameters are passed by reference for speed; they are not modified at all.
-function blocks_get_missing(&$page, &$pageblocks) {
-
-    $missingblocks = array();
-    $allblocks = blocks_get_record();
-    $pageformat = $page->pagetype;
+/// Functions that have been deprecated by block_manager =======================
 
-    if(!empty($allblocks)) {
-        foreach($allblocks as $block) {
-            if($block->visible && (!blocks_find_block($block->id, $pageblocks) || $block->multiple)) {
-                // And if it's applicable for display in this format...
-                if(blocks_name_allowed_in_format($block->name, $pageformat)) {
-                    // ...add it to the missing blocks
-                    $missingblocks[] = $block->id;
-                }
-            }
-        }
-    }
-    return $missingblocks;
+/**
+ * @deprecated since Moodle 2.0 - use $page->blocks->get
+ * This function returns an array with the IDs of any blocks that you can add to your page.
+ * Parameters are passed by reference for speed; they are not modified at all.
+ * @param $page the page object.
+ * @param $pageblocks Not used.
+ * @return array of block type ids.
+ */
+function blocks_get_missing(&$page, &$pageblocks) {
+    return array_keys($page->blocks->get_addable_blocks());
 }
 
 function blocks_remove_inappropriate($page) {
@@ -475,20 +720,22 @@ function blocks_preferred_width(&$instances) {
     return $width;
 }
 
-function blocks_get_record($blockid = NULL, $invalidate = false) {
-    global $DB;
-
-    static $cache = NULL;
-
-    if($invalidate || empty($cache)) {
-        $cache = $DB->get_records('block');
-    }
-
-    if($blockid === NULL) {
-        return $cache;
+/**
+ * Get the block record for a particulr blockid.
+ * @param $blockid block type id. If null, an array of all block types is returned.
+ * @param $notusedanymore No longer used.
+ * @return array|object row from block table, or all rows.
+ */
+function blocks_get_record($blockid = NULL, $notusedanymore = false) {
+    global $PAGE;
+    $blocks = $PAGE->blocks->get_installed_blocks();
+    if ($blockid === NULL) {
+        return $blocks;
+    } else if (isset($blocks[$blockid])) {
+        return $blocks[$blockid];
+    } else {
+        return false;
     }
-
-    return (isset($cache[$blockid])? $cache[$blockid] : false);
 }
 
 function blocks_find_block($blockid, $blocksarray) {
@@ -1021,7 +1268,7 @@ function blocks_get_by_page($page) {
 function blocks_print_adminblock(&$page, &$pageblocks) {
     global $USER;
 
-    $missingblocks = blocks_get_missing($page, $pageblocks);
+    $missingblocks = array_keys($page->blocks->get_addable_blocks());
 
     if (!empty($missingblocks)) {
         $strblocks = '<div class="title"><h2>';
index c2551e9f29efb5030f903a13abaccee150db2cb7..d498094b7bdb74920b088d86685006aff5b25a83 100644 (file)
@@ -88,7 +88,7 @@ class moodle_page {
 
     protected $_pagetype = null;
 
-    protected $_subpage = null;
+    protected $_subpage = '';
 
     protected $_docspath = null;
 
@@ -328,12 +328,7 @@ class moodle_page {
         }
 
         if ($state == self::STATE_PRINTING_HEADER) {
-            if (!$this->_course) {
-                global $SITE;
-                $this->set_course($SITE);
-            }
-
-            $this->initialise_standard_body_classes();
+            $this->starting_output();
         }
 
         $this->_state = $state;
@@ -448,7 +443,11 @@ class moodle_page {
      *      and pagetype, uniquely identifies this page.
      */
     public function set_subpage($subpage) {
-        $this->_subpage = $subpage;
+        if (empty($subpage)) {
+            $this->_subpage = '';
+        } else {
+            $this->_subpage = $subpage;
+        }
     }
 
     /**
@@ -550,6 +549,21 @@ class moodle_page {
 /// Initialisation methods =====================================================
 /// These set various things up in a default way.
 
+    /**
+     * This method is called when the page first moves out of the STATE_BEFORE_HEADER
+     * state. This is our last change to initialise things.
+     */
+    protected function starting_output() {
+        if (!$this->_course) {
+            global $SITE;
+            $this->set_course($SITE);
+        }
+
+        $this->initialise_standard_body_classes();
+
+        $this->blocks->load_blocks();
+    }
+
     /**
      * Sets ->pagetype from the script name. For example, if the script that was
      * run is mod/quiz/view.php, ->pagetype will be set to 'mod-quiz-view'.
index 5cb08c55c0f25abb5114a394046a3079ad918179..370702bd0a9dc14299e8e81f29207fc7ef4153dd 100644 (file)
@@ -40,14 +40,20 @@ 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();
+        $this->blocksbyregion = array();
+    }
+    public function get_loaded_blocks() {
+        return $this->blocksbyregion;
+    }
+    public function matching_page_type_patterns($pagetype) {
+        return parent::matching_page_type_patterns($pagetype);
     }
 }
 
 /**
  * Test functions that don't need to touch the database.
  */
-class moodle_page_test extends UnitTestCase {
+class moodle_block_manager_test extends UnitTestCase {
     protected $testpage;
     protected $blockmanager;
 
@@ -125,6 +131,226 @@ class moodle_page_test extends UnitTestCase {
         $this->blockmanager->set_default_region('too-late');
     }
 
+    public function test_matching_page_type_patterns() {
+        $this->assert(new ArraysHaveSameValuesExpectation(
+                array('site-index', 'site-index-*', 'site-*', '*')),
+                $this->blockmanager->matching_page_type_patterns('site-index'));
+
+        $this->assert(new ArraysHaveSameValuesExpectation(
+                array('mod-quiz-report-overview', 'mod-quiz-report-overview-*', 'mod-quiz-report-*', 'mod-quiz-*', 'mod-*', '*')),
+                $this->blockmanager->matching_page_type_patterns('mod-quiz-report-overview'));
+
+        $this->assert(new ArraysHaveSameValuesExpectation(
+                array('mod-forum-view', 'mod-*-view', 'mod-forum-view-*', 'mod-forum-*', 'mod-*', '*')),
+                $this->blockmanager->matching_page_type_patterns('mod-forum-view'));
+
+        $this->assert(new ArraysHaveSameValuesExpectation(
+                array('mod-forum-index', 'mod-*-index', 'mod-forum-index-*', 'mod-forum-*', 'mod-*', '*')),
+                $this->blockmanager->matching_page_type_patterns('mod-forum-index'));
+    }
 }
 
+/**
+ * Test methods that load and save data from block_instances and block_positions.
+ */
+class moodle_block_manager_test_saving_loading extends UnitTestCaseUsingDatabase {
+
+    public function setUp() {
+        parent::setUp();
+        $this->create_test_tables(array('block', 'block_instances', 'block_positions'), 'lib');
+        $this->switch_to_test_db();
+    }
+
+    public function tearDown() {
+        parent::tearDown();
+    }
+
+    protected function get_a_page_and_block_manager($regions, $context, $pagetype, $subpage = '') {
+        $page = new moodle_page;
+        $page->set_context($context);
+        $page->set_pagetype($pagetype);
+        $page->set_subpage($subpage);
+
+        $blockmanager = new testable_block_manager($page);
+        $blockmanager->add_regions($regions);
+        $blockmanager->set_default_region($regions[0]);
+
+        return array($page, $blockmanager);
+    }
+
+    protected function get_a_known_block_type() {
+        global $DB;
+        $block = new stdClass;
+        $block->name = 'ablocktype';
+        $this->testdb->insert_record('block', $block);
+        return $block->name;
+    }
+
+    protected function assertContainsBlocksOfType($typearray, $blockarray) {
+        if (!$this->assertEqual(count($typearray), count($blockarray), "Blocks array contains the wrong number of elements %s.")) {
+            return;
+        }
+        $types = array_values($typearray);
+        $i = 0;
+        foreach ($blockarray as $block) {
+            $blocktype = $types[$i];
+            $this->assertEqual($blocktype, $block->blockname, "Block types do not match at postition $i %s.");
+            $i++;
+        }
+    }
+
+    public function test_empty_initially() {
+        // Set up fixture.
+        list($page, $blockmanager) = $this->get_a_page_and_block_manager(array('a-region'),
+                get_context_instance(CONTEXT_SYSTEM), 'page-type');
+        // Exercise SUT.
+        $blockmanager->load_blocks();
+        // Validate.
+        $blocks = $blockmanager->get_loaded_blocks();
+        $this->assertEqual(array('a-region' => array()), $blocks);
+    }
+
+    public function test_adding_and_retrieving_one_block() {
+        // Set up fixture.
+        $regionname = 'a-region';
+        $blockname = $this->get_a_known_block_type();
+
+        list($page, $blockmanager) = $this->get_a_page_and_block_manager(array($regionname),
+                get_context_instance(CONTEXT_SYSTEM), 'page-type');
+
+        // Exercise SUT.
+        $blockmanager->add_block($blockname, $regionname, 0, false);
+        $blockmanager->load_blocks();
+        // Validate.
+        $blocks = $blockmanager->get_blocks_for_region($regionname);
+        $this->assertContainsBlocksOfType(array($blockname), $blocks);
+    }
+
+    public function test_adding_and_retrieving_two_blocks() {
+        // Set up fixture.
+        $regionname = 'a-region';
+        $blockname = $this->get_a_known_block_type();
+
+        list($page, $blockmanager) = $this->get_a_page_and_block_manager(array($regionname),
+                get_context_instance(CONTEXT_SYSTEM), 'page-type');
+
+        // Exercise SUT.
+        $blockmanager->add_block($blockname, $regionname, 0, false);
+        $blockmanager->add_block($blockname, $regionname, 1, false);
+        $blockmanager->load_blocks();
+        // Validate.
+        $blocks = $blockmanager->get_blocks_for_region($regionname);
+        $this->assertContainsBlocksOfType(array($blockname, $blockname), $blocks);
+    }
+
+    public function test_block_not_included_in_different_context() {
+        // Set up fixture.
+        $syscontext = get_context_instance(CONTEXT_SYSTEM);
+        $fakecontext = new stdClass;
+        $fakecontext->id = $syscontext->id + 1;
+        $regionname = 'a-region';
+        $blockname = $this->get_a_known_block_type();
+
+        list($addpage, $addbm) = $this->get_a_page_and_block_manager(array($regionname), $fakecontext, 'page-type');
+        list($viewpage, $viewbm) = $this->get_a_page_and_block_manager(array($regionname), $syscontext, 'page-type');
+
+        $addbm->add_block($blockname, $regionname, 0, false);
+
+        // Exercise SUT.
+        $viewbm->load_blocks();
+        // Validate.
+        $blocks = $viewbm->get_blocks_for_region($regionname);
+        $this->assertContainsBlocksOfType(array(), $blocks);
+    }
+
+    public function test_block_included_in_sub_context() {
+        // Set up fixture.
+        $syscontext = get_context_instance(CONTEXT_SYSTEM);
+        $childcontext = new stdClass;
+        $childcontext->id = $syscontext->id + 1;
+        $childcontext->path = '/' . $syscontext->id . '/' . $childcontext->id;
+        $regionname = 'a-region';
+        $blockname = $this->get_a_known_block_type();
+
+        list($addpage, $addbm) = $this->get_a_page_and_block_manager(array($regionname), $syscontext, 'page-type');
+        list($viewpage, $viewbm) = $this->get_a_page_and_block_manager(array($regionname), $childcontext, 'page-type');
+
+        $addbm->add_block($blockname, $regionname, 0, true);
+
+        // Exercise SUT.
+        $viewbm->load_blocks();
+        // Validate.
+        $blocks = $viewbm->get_blocks_for_region($regionname);
+        $this->assertContainsBlocksOfType(array($blockname), $blocks);
+    }
+
+    public function test_block_not_included_on_different_page_type() {
+        // Set up fixture.
+        $syscontext = get_context_instance(CONTEXT_SYSTEM);
+        $regionname = 'a-region';
+        $blockname = $this->get_a_known_block_type();
+
+        list($addpage, $addbm) = $this->get_a_page_and_block_manager(array($regionname), $syscontext, 'page-type');
+        list($viewpage, $viewbm) = $this->get_a_page_and_block_manager(array($regionname), $syscontext, 'other-page-type');
+
+        $addbm->add_block($blockname, $regionname, 0, true);
+
+        // Exercise SUT.
+        $viewbm->load_blocks();
+        // Validate.
+        $blocks = $viewbm->get_blocks_for_region($regionname);
+        $this->assertContainsBlocksOfType(array(), $blocks);
+    }
+
+    public function test_block_not_included_on_different_sub_page() {
+        // Set up fixture.
+        $regionname = 'a-region';
+        $blockname = $this->get_a_known_block_type();
+
+        list($page, $blockmanager) = $this->get_a_page_and_block_manager(array($regionname),
+                get_context_instance(CONTEXT_SYSTEM), 'page-type', 'sub-page');
+
+        $blockmanager->add_block($blockname, $regionname, 0, true, $page->pagetype, 'other-sub-page');
+
+        // Exercise SUT.
+        $blockmanager->load_blocks();
+        // Validate.
+        $blocks = $blockmanager->get_blocks_for_region($regionname);
+        $this->assertContainsBlocksOfType(array(), $blocks);
+    }
+
+    public function test_block_included_with_explicit_sub_page() {
+        // Set up fixture.
+        $regionname = 'a-region';
+        $blockname = $this->get_a_known_block_type();
+
+        list($page, $blockmanager) = $this->get_a_page_and_block_manager(array($regionname),
+                get_context_instance(CONTEXT_SYSTEM), 'page-type', 'sub-page');
+
+        $blockmanager->add_block($blockname, $regionname, 0, true, $page->pagetype, $page->subpage);
+
+        // Exercise SUT.
+        $blockmanager->load_blocks();
+        // Validate.
+        $blocks = $blockmanager->get_blocks_for_region($regionname);
+        $this->assertContainsBlocksOfType(array($blockname), $blocks);
+    }
+
+    public function test_block_included_with_page_type_pattern() {
+        // Set up fixture.
+        $regionname = 'a-region';
+        $blockname = $this->get_a_known_block_type();
+
+        list($page, $blockmanager) = $this->get_a_page_and_block_manager(array($regionname),
+                get_context_instance(CONTEXT_SYSTEM), 'page-type', 'sub-page');
+
+        $blockmanager->add_block($blockname, $regionname, 0, true, 'page-*', $page->subpage);
+
+        // Exercise SUT.
+        $blockmanager->load_blocks();
+        // Validate.
+        $blocks = $blockmanager->get_blocks_for_region($regionname);
+        $this->assertContainsBlocksOfType(array($blockname), $blocks);
+    }
+}
 ?>
index 84dd92db1750f8d8d25a083d3d42748b33a815b0..b3e326baca6fb10b57254d684fec6479f1f3ea59 100644 (file)
@@ -3245,6 +3245,20 @@ function theme_setup($theme = '', $params=NULL) {
         $CFG->stylesheets[] = $CFG->themewww.'/standard/rtl.css'.$paramstring;
         $CFG->stylesheets[] = $CFG->themewww.'/'.$theme.'/rtl.css'.$paramstring;
     }
+
+    /// Set up the block regions.
+    if (!empty($THEME->blockregions)) {
+        $PAGE->blocks->add_regions($THEME->blockregions);
+    } else {
+        // Support legacy themes by supplying a sensible default.
+        $PAGE->blocks->add_regions(array('side-pre', 'side-post'));
+    }
+    if (!empty($THEME->defaultblockregion)) {
+        $PAGE->blocks->set_default_region($THEME->defaultblockregion);
+    } else {
+        // Support legacy themes by supplying a sensible default.
+        $PAGE->blocks->set_default_region('side-post');
+    }
 }
 
 
index 13465c54fd3a64d895c7fe9c5d48e8d1be3f706c..f182eb0206175b30b3e52ba11b633f05d2f94bba 100644 (file)
@@ -167,4 +167,15 @@ $THEME->custompix = false;
 /// use &lt; &gt; &raquo; - these are confusing for blind users.
 ////////////////////////////////////////////////////////////////////////////////
 
+
+$THEME->blockregions = array('side-pre', 'side-post');
+$THEME->defaultblockregion = 'side-post';
+/// Areas where blocks may appear on any page that uses this theme. For each
+/// region you list in $THEME->blockregions you must call blocks_print_group
+/// with that region id somewhere in header.html or footer.html.
+/// defaultblockregion is the region where new blocks will be added, and
+/// where any blocks in unrecognised regions will be shown. (Suppose someone
+/// added a block when anther theme was selected).
+////////////////////////////////////////////////////////////////////////////////
+
 ?>