blocklib MDL-25654 fix API inconsistency be renaming add_pretend_block to add_fake_block.
[moodle.git] / lib / blocklib.php
CommitLineData
d4accfc0 1<?php
2
a19f419d 3// This file is part of Moodle - http://moodle.org/
4//
d4accfc0 5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
a19f419d 14//
d4accfc0 15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
e8c8cee9 17
18/**
d4accfc0 19 * Block Class and Functions
e8c8cee9 20 *
a19f419d 21 * This file defines the {@link block_manager} class,
d4a03c00 22 *
78bfb562
PS
23 * @package core
24 * @subpackage block
25 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
e8c8cee9 27 */
0f3fe4b6 28
78bfb562
PS
29defined('MOODLE_INTERNAL') || die();
30
13a0d3d3 31/**#@+
32 * @deprecated since Moodle 2.0. No longer used.
d4a03c00 33 */
0f3fe4b6 34define('BLOCK_MOVE_LEFT', 0x01);
35define('BLOCK_MOVE_RIGHT', 0x02);
36define('BLOCK_MOVE_UP', 0x04);
37define('BLOCK_MOVE_DOWN', 0x08);
9b4b78fd 38define('BLOCK_CONFIGURE', 0x10);
13a0d3d3 39/**#@-*/
0f3fe4b6 40
13a0d3d3 41/**#@+
42 * Default names for the block regions in the standard theme.
43 */
bb46a4fa 44define('BLOCK_POS_LEFT', 'side-pre');
45define('BLOCK_POS_RIGHT', 'side-post');
13a0d3d3 46/**#@-*/
0e9af917 47
13a0d3d3 48/**#@+
49 * @deprecated since Moodle 2.0. No longer used.
50 */
ee6055eb 51define('BLOCKS_PINNED_TRUE',0);
52define('BLOCKS_PINNED_FALSE',1);
53define('BLOCKS_PINNED_BOTH',2);
13a0d3d3 54/**#@-*/
ee6055eb 55
d4accfc0 56/**
d4a03c00 57 * Exception thrown when someone tried to do something with a block that does
58 * not exist on a page.
d4accfc0 59 *
d4a03c00 60 * @copyright 2009 Tim Hunt
61 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
62 * @since Moodle 2.0
d4accfc0 63 */
f4d38d20 64class block_not_on_page_exception extends moodle_exception {
d4accfc0 65 /**
847bed23 66 * Constructor
d4a03c00 67 * @param int $instanceid the block instance id of the block that was looked for.
68 * @param object $page the current page.
d4accfc0 69 */
f4d38d20 70 public function __construct($instanceid, $page) {
71 $a = new stdClass;
72 $a->instanceid = $instanceid;
2a3b0763 73 $a->url = $page->url->out();
74 parent::__construct('blockdoesnotexistonpage', '', $page->url->out(), $a);
f4d38d20 75 }
76}
77
86b5ea0f 78/**
79 * This class keeps track of the block that should appear on a moodle_page.
bb46a4fa 80 *
d4a03c00 81 * The page to work with as passed to the constructor.
1d00ec6a 82 *
d4a03c00 83 * @copyright 2009 Tim Hunt
84 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
85 * @since Moodle 2.0
86b5ea0f 86 */
d4a03c00 87class block_manager {
2cdb8d84 88 /**
89 * The UI normally only shows block weights between -MAX_WEIGHT and MAX_WEIGHT,
90 * although other weights are valid.
91 */
92 const MAX_WEIGHT = 10;
86b5ea0f 93
94/// Field declarations =========================================================
d4a03c00 95
d8ef60bd
SH
96 /**
97 * the moodle_page we are managing blocks for.
98 * @var moodle_page
99 */
86b5ea0f 100 protected $page;
d4a03c00 101
102 /** @var array region name => 1.*/
86b5ea0f 103 protected $regions = array();
d4a03c00 104
105 /** @var string the region where new blocks are added.*/
106 protected $defaultregion = null;
107
108 /** @var array will be $DB->get_records('blocks') */
109 protected $allblocks = null;
110
111 /**
112 * @var array blocks that this user can add to this page. Will be a subset
a2789e34 113 * of $allblocks, but with array keys block->name. Access this via the
114 * {@link get_addable_blocks()} method to ensure it is lazy-loaded.
d4a03c00 115 */
116 protected $addableblocks = null;
08eab897 117
bb46a4fa 118 /**
119 * Will be an array region-name => array(db rows loaded in load_blocks);
d4accfc0 120 * @var array
bb46a4fa 121 */
122 protected $birecordsbyregion = null;
123
124 /**
125 * array region-name => array(block objects); populated as necessary by
126 * the ensure_instances_exist method.
d4accfc0 127 * @var array
bb46a4fa 128 */
129 protected $blockinstances = array();
130
131 /**
847bed23 132 * array region-name => array(block_contents objects) what actually needs to
bb46a4fa 133 * be displayed in each region.
d4accfc0 134 * @var array
bb46a4fa 135 */
136 protected $visibleblockcontent = array();
08eab897 137
d4a03c00 138 /**
139 * array region-name => array(block_contents objects) extra block-like things
140 * to be displayed in each region, before the real blocks.
141 * @var array
142 */
143 protected $extracontent = array();
144
00a24d44 145 /**
847bed23 146 * Used by the block move id, to track whether a block is currently being moved.
00a24d44 147 *
847bed23
PS
148 * When you click on the move icon of a block, first the page needs to reload with
149 * extra UI for choosing a new position for a particular block. In that situation
00a24d44 150 * this field holds the id of the block being moved.
151 *
152 * @var integer|null
153 */
154 protected $movingblock = null;
155
56ed242b
SH
156 /**
157 * Show only fake blocks
158 */
159 protected $fakeblocksonly = false;
160
86b5ea0f 161/// Constructor ================================================================
162
163 /**
164 * Constructor.
165 * @param object $page the moodle_page object object we are managing the blocks for,
847bed23 166 * or a reasonable faxilimily. (See the comment at the top of this class
d4accfc0 167 * and {@link http://en.wikipedia.org/wiki/Duck_typing})
86b5ea0f 168 */
169 public function __construct($page) {
170 $this->page = $page;
171 }
172
173/// Getter methods =============================================================
174
175 /**
d4accfc0 176 * Get an array of all region names on this page where a block may appear
177 *
86b5ea0f 178 * @return array the internal names of the regions on this page where block may appear.
179 */
180 public function get_regions() {
78946b9b 181 if (is_null($this->defaultregion)) {
7d875874 182 $this->page->initialise_theme_and_output();
78946b9b 183 }
86b5ea0f 184 return array_keys($this->regions);
185 }
186
187 /**
d4accfc0 188 * Get the region name of the region blocks are added to by default
189 *
86b5ea0f 190 * @return string the internal names of the region where new blocks are added
191 * by default, and where any blocks from an unrecognised region are shown.
192 * (Imagine that blocks were added with one theme selected, then you switched
193 * to a theme with different block positions.)
194 */
195 public function get_default_region() {
d4a03c00 196 $this->page->initialise_theme_and_output();
86b5ea0f 197 return $this->defaultregion;
198 }
199
08eab897 200 /**
201 * The list of block types that may be added to this page.
d4accfc0 202 *
727ae436 203 * @return array block name => record from block table.
08eab897 204 */
205 public function get_addable_blocks() {
206 $this->check_is_loaded();
207
208 if (!is_null($this->addableblocks)) {
209 return $this->addableblocks;
210 }
211
212 // Lazy load.
213 $this->addableblocks = array();
214
215 $allblocks = blocks_get_record();
216 if (empty($allblocks)) {
217 return $this->addableblocks;
218 }
219
bb46a4fa 220 $pageformat = $this->page->pagetype;
08eab897 221 foreach($allblocks as $block) {
222 if ($block->visible &&
464c7e70 223 (block_method_result($block->name, 'instance_allow_multiple') || !$this->is_block_present($block->name)) &&
a2789e34 224 blocks_name_allowed_in_format($block->name, $pageformat) &&
225 block_method_result($block->name, 'user_can_addto', $this->page)) {
226 $this->addableblocks[$block->name] = $block;
08eab897 227 }
228 }
229
230 return $this->addableblocks;
231 }
232
d4accfc0 233 /**
464c7e70
MD
234 * Given a block name, find out of any of them are currently present in the page
235
236 * @param string $blockname - the basic name of a block (eg "navigation")
237 * @return boolean - is there one of these blocks in the current page?
d4accfc0 238 */
464c7e70
MD
239 public function is_block_present($blockname) {
240 if (empty($this->blockinstances)) {
241 return false;
242 }
243
244 foreach ($this->blockinstances as $region) {
245 foreach ($region as $instance) {
246 if (empty($instance->instance->blockname)) {
247 continue;
248 }
249 if ($instance->instance->blockname == $blockname) {
250 return true;
251 }
252 }
253 }
254 return false;
08eab897 255 }
256
257 /**
d4accfc0 258 * Find out if a block type is known by the system
259 *
847bed23 260 * @param string $blockname the name of the type of block.
08eab897 261 * @param boolean $includeinvisible if false (default) only check 'visible' blocks, that is, blocks enabled by the admin.
262 * @return boolean true if this block in installed.
263 */
264 public function is_known_block_type($blockname, $includeinvisible = false) {
265 $blocks = $this->get_installed_blocks();
266 foreach ($blocks as $block) {
267 if ($block->name == $blockname && ($includeinvisible || $block->visible)) {
268 return true;
269 }
270 }
271 return false;
272 }
273
274 /**
d4accfc0 275 * Find out if a region exists on a page
276 *
08eab897 277 * @param string $region a region name
847bed23 278 * @return boolean true if this region exists on this page.
08eab897 279 */
280 public function is_known_region($region) {
281 return array_key_exists($region, $this->regions);
282 }
283
284 /**
d4accfc0 285 * Get an array of all blocks within a given region
286 *
287 * @param string $region a block region that exists on this page.
08eab897 288 * @return array of block instances.
289 */
290 public function get_blocks_for_region($region) {
291 $this->check_is_loaded();
bb46a4fa 292 $this->ensure_instances_exist($region);
293 return $this->blockinstances[$region];
294 }
295
296 /**
d4accfc0 297 * Returns an array of block content objects that exist in a region
298 *
d4a03c00 299 * @param string $region a block region that exists on this page.
300 * @return array of block block_contents objects for all the blocks in a region.
bb46a4fa 301 */
d4a03c00 302 public function get_content_for_region($region, $output) {
bb46a4fa 303 $this->check_is_loaded();
d4a03c00 304 $this->ensure_content_created($region, $output);
bb46a4fa 305 return $this->visibleblockcontent[$region];
08eab897 306 }
307
00a24d44 308 /**
309 * Helper method used by get_content_for_region.
310 * @param string $region region name
311 * @param float $weight weight. May be fractional, since you may want to move a block
312 * between ones with weight 2 and 3, say ($weight would be 2.5).
313 * @return string URL for moving block $this->movingblock to this position.
314 */
315 protected function get_move_target_url($region, $weight) {
dd72b308 316 return new moodle_url($this->page->url, array('bui_moveid' => $this->movingblock,
b9bc2019 317 'bui_newregion' => $region, 'bui_newweight' => $weight, 'sesskey' => sesskey()));
00a24d44 318 }
319
d4a03c00 320 /**
321 * Determine whether a region contains anything. (Either any real blocks, or
322 * the add new block UI.)
78d27a90 323 *
324 * (You may wonder why the $output parameter is required. Unfortunately,
847bed23 325 * because of the way that blocks work, the only reliable way to find out
78d27a90 326 * if a block will be visible is to get the content for output, and to
327 * get the content, you need a renderer. Fortunately, this is not a
847bed23 328 * performance problem, because we cache the output that is generated, and
78d27a90 329 * in almost every case where we call region_has_content, we are about to
330 * output the blocks anyway, so we are not doing wasted effort.)
331 *
d4a03c00 332 * @param string $region a block region that exists on this page.
78946b9b 333 * @param object $output a core_renderer. normally the global $OUTPUT.
d4a03c00 334 * @return boolean Whether there is anything in this region.
335 */
78d27a90 336 public function region_has_content($region, $output) {
4f0c2d00 337
d4a03c00 338 if (!$this->is_known_region($region)) {
339 return false;
340 }
341 $this->check_is_loaded();
78d27a90 342 $this->ensure_content_created($region, $output);
d4a03c00 343 if ($this->page->user_is_editing() && $this->page->user_can_edit_blocks()) {
344 // If editing is on, we need all the block regions visible, for the
345 // move blocks UI.
346 return true;
347 }
78d27a90 348 return !empty($this->visibleblockcontent[$region]) || !empty($this->extracontent[$region]);
d4a03c00 349 }
350
08eab897 351 /**
d4accfc0 352 * Get an array of all of the installed blocks.
353 *
08eab897 354 * @return array contents of the block table.
355 */
356 public function get_installed_blocks() {
357 global $DB;
358 if (is_null($this->allblocks)) {
359 $this->allblocks = $DB->get_records('block');
360 }
361 return $this->allblocks;
362 }
363
86b5ea0f 364/// Setter methods =============================================================
365
366 /**
d4accfc0 367 * Add a region to a page
368 *
86b5ea0f 369 * @param string $region add a named region where blocks may appear on the
370 * current page. This is an internal name, like 'side-pre', not a string to
371 * display in the UI.
372 */
373 public function add_region($region) {
374 $this->check_not_yet_loaded();
375 $this->regions[$region] = 1;
376 }
377
378 /**
d4accfc0 379 * Add an array of regions
380 * @see add_region()
381 *
86b5ea0f 382 * @param array $regions this utility method calls add_region for each array element.
383 */
384 public function add_regions($regions) {
385 foreach ($regions as $region) {
386 $this->add_region($region);
387 }
388 }
389
390 /**
d4accfc0 391 * Set the default region for new blocks on the page
392 *
86b5ea0f 393 * @param string $defaultregion the internal names of the region where new
394 * blocks should be added by default, and where any blocks from an
395 * unrecognised region are shown.
396 */
397 public function set_default_region($defaultregion) {
398 $this->check_not_yet_loaded();
035b96a9 399 if ($defaultregion) {
400 $this->check_region_is_known($defaultregion);
401 }
86b5ea0f 402 $this->defaultregion = $defaultregion;
403 }
404
d4a03c00 405 /**
406 * Add something that looks like a block, but which isn't an actual block_instance,
407 * to this page.
408 *
d9c26e21 409 * @param block_contents $bc the content of the block-like thing.
d4a03c00 410 * @param string $region a block region that exists on this page.
411 */
d9c26e21 412 public function add_fake_block($bc, $region) {
d4a03c00 413 $this->page->initialise_theme_and_output();
bf2b43df
SH
414 if (!$this->is_known_region($region)) {
415 $region = $this->get_default_region();
416 }
d4a03c00 417 if (array_key_exists($region, $this->visibleblockcontent)) {
418 throw new coding_exception('block_manager has already prepared the blocks in region ' .
d9c26e21 419 $region . 'for output. It is too late to add a fake block.');
d4a03c00 420 }
421 $this->extracontent[$region][] = $bc;
422 }
423
d9c26e21
TH
424 /**
425 * When the block_manager class was created, the {@link add_fake_block()}
426 * was called add_pretend_block, which is inconsisted with
427 * {@link show_only_fake_blocks()}. To fix this inconsistency, this method
428 * was renamed to add_fake_block. Please update your code.
429 * @param block_contents $bc the content of the block-like thing.
430 * @param string $region a block region that exists on this page.
431 */
432 public function add_pretend_block($bc, $region) {
433 debugging(DEBUG_DEVELOPER, 'add_pretend_block has been renamed to add_fake_block. Please rename the method call in your code.');
434 $this->add_fake_block($bc, $region);
435 }
436
7e4617f7
SH
437 /**
438 * Checks to see whether all of the blocks within the given region are docked
439 *
4d6fd15c 440 * @see region_uses_dock
7e4617f7
SH
441 * @param string $region
442 * @return bool True if all of the blocks within that region are docked
443 */
444 public function region_completely_docked($region, $output) {
445 if (!$this->page->theme->enable_dock) {
446 return false;
447 }
448 $this->check_is_loaded();
449 $this->ensure_content_created($region, $output);
450 foreach($this->visibleblockcontent[$region] as $instance) {
451 if (!empty($instance->content) && !get_user_preferences('docked_block_instance_'.$instance->blockinstanceid, 0)) {
452 return false;
453 }
454 }
455 return true;
456 }
457
4d6fd15c
SH
458 /**
459 * Checks to see whether any of the blocks within the given regions are docked
460 *
461 * @see region_completely_docked
462 * @param array|string $regions array of regions (or single region)
463 * @return bool True if any of the blocks within that region are docked
464 */
465 public function region_uses_dock($regions, $output) {
466 if (!$this->page->theme->enable_dock) {
467 return false;
468 }
469 $this->check_is_loaded();
470 foreach((array)$regions as $region) {
471 $this->ensure_content_created($region, $output);
472 foreach($this->visibleblockcontent[$region] as $instance) {
473 if(!empty($instance->content) && get_user_preferences('docked_block_instance_'.$instance->blockinstanceid, 0)) {
474 return true;
475 }
476 }
477 }
478 return false;
479 }
480
08eab897 481/// Actions ====================================================================
482
483 /**
484 * This method actually loads the blocks for our page from the database.
d4accfc0 485 *
ae42ff6f 486 * @param boolean|null $includeinvisible
487 * null (default) - load hidden blocks if $this->page->user_is_editing();
488 * true - load hidden blocks.
489 * false - don't load hidden blocks.
08eab897 490 */
ae42ff6f 491 public function load_blocks($includeinvisible = null) {
d19e8195 492 global $DB, $CFG;
7d875874 493
bb46a4fa 494 if (!is_null($this->birecordsbyregion)) {
495 // Already done.
496 return;
497 }
08eab897 498
d19e8195 499 if ($CFG->version < 2009050619) {
500 // Upgrade/install not complete. Don't try too show any blocks.
501 $this->birecordsbyregion = array();
502 return;
503 }
504
d4a03c00 505 // Ensure we have been initialised.
7d875874 506 if (is_null($this->defaultregion)) {
b7009474 507 $this->page->initialise_theme_and_output();
d4a03c00 508 // If there are still no block regions, then there are no blocks on this page.
509 if (empty($this->regions)) {
510 $this->birecordsbyregion = array();
511 return;
512 }
b7009474 513 }
514
56ed242b
SH
515 // Check if we need to load normal blocks
516 if ($this->fakeblocksonly) {
517 $this->birecordsbyregion = $this->prepare_per_region_arrays();
518 return;
519 }
520
08eab897 521 if (is_null($includeinvisible)) {
522 $includeinvisible = $this->page->user_is_editing();
523 }
524 if ($includeinvisible) {
08eab897 525 $visiblecheck = '';
ae42ff6f 526 } else {
527 $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)';
08eab897 528 }
529
530 $context = $this->page->context;
13a0d3d3 531 $contexttest = 'bi.parentcontextid = :contextid2';
08eab897 532 $parentcontextparams = array();
533 $parentcontextids = get_parent_contexts($context);
534 if ($parentcontextids) {
535 list($parentcontexttest, $parentcontextparams) =
536 $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext0000');
13a0d3d3 537 $contexttest = "($contexttest OR (bi.showinsubcontexts = 1 AND bi.parentcontextid $parentcontexttest))";
08eab897 538 }
539
1d13c75c 540 $pagetypepatterns = matching_page_type_patterns($this->page->pagetype);
08eab897 541 list($pagetypepatterntest, $pagetypepatternparams) =
542 $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest0000');
543
4f0c2d00
PS
544 list($ccselect, $ccjoin) = context_instance_preload_sql('b.id', CONTEXT_BLOCK, 'ctx');
545
08eab897 546 $params = array(
547 'subpage1' => $this->page->subpage,
548 'subpage2' => $this->page->subpage,
549 'contextid1' => $context->id,
550 'contextid2' => $context->id,
551 'pagetype' => $this->page->pagetype,
552 );
553 $sql = "SELECT
554 bi.id,
d4a03c00 555 bp.id AS blockpositionid,
08eab897 556 bi.blockname,
13a0d3d3 557 bi.parentcontextid,
08eab897 558 bi.showinsubcontexts,
559 bi.pagetypepattern,
560 bi.subpagepattern,
ae42ff6f 561 bi.defaultregion,
562 bi.defaultweight,
bb46a4fa 563 COALESCE(bp.visible, 1) AS visible,
08eab897 564 COALESCE(bp.region, bi.defaultregion) AS region,
565 COALESCE(bp.weight, bi.defaultweight) AS weight,
4f0c2d00
PS
566 bi.configdata
567 $ccselect
08eab897 568
569 FROM {block_instances} bi
570 JOIN {block} b ON bi.blockname = b.name
571 LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id
572 AND bp.contextid = :contextid1
573 AND bp.pagetype = :pagetype
574 AND bp.subpage = :subpage1
4f0c2d00 575 $ccjoin
08eab897 576
577 WHERE
578 $contexttest
579 AND bi.pagetypepattern $pagetypepatterntest
580 AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2)
581 $visiblecheck
582 AND b.visible = 1
583
584 ORDER BY
585 COALESCE(bp.region, bi.defaultregion),
586 COALESCE(bp.weight, bi.defaultweight),
587 bi.id";
588 $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams);
589
bb46a4fa 590 $this->birecordsbyregion = $this->prepare_per_region_arrays();
08eab897 591 $unknown = array();
08eab897 592 foreach ($blockinstances as $bi) {
4f0c2d00 593 context_instance_preload($bi);
08eab897 594 if ($this->is_known_region($bi->region)) {
bb46a4fa 595 $this->birecordsbyregion[$bi->region][] = $bi;
08eab897 596 } else {
597 $unknown[] = $bi;
598 }
599 }
d4a03c00 600
601 // Pages don't necessarily have a defaultregion. The one time this can
602 // happen is when there are no theme block regions, but the script itself
603 // has a block region in the main content area.
604 if (!empty($this->defaultregion)) {
605 $this->birecordsbyregion[$this->defaultregion] =
606 array_merge($this->birecordsbyregion[$this->defaultregion], $unknown);
607 }
08eab897 608 }
609
610 /**
611 * Add a block to the current page, or related pages. The block is added to
612 * context $this->page->contextid. If $pagetypepattern $subpagepattern
d4accfc0 613 *
08eab897 614 * @param string $blockname The type of block to add.
615 * @param string $region the block region on this page to add the block to.
616 * @param integer $weight determines the order where this block appears in the region.
617 * @param boolean $showinsubcontexts whether this block appears in subcontexts, or just the current context.
618 * @param string|null $pagetypepattern which page types this block should appear on. Defaults to just the current page type.
619 * @param string|null $subpagepattern which subpage this block should appear on. NULL = any (the default), otherwise only the specified subpage.
620 */
621 public function add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern = NULL, $subpagepattern = NULL) {
622 global $DB;
51f96f5b
SM
623 // Allow invisible blocks because this is used when adding default page blocks, which
624 // might include invisible ones if the user makes some default blocks invisible
625 $this->check_known_block_type($blockname, true);
08eab897 626 $this->check_region_is_known($region);
627
628 if (empty($pagetypepattern)) {
629 $pagetypepattern = $this->page->pagetype;
630 }
631
632 $blockinstance = new stdClass;
633 $blockinstance->blockname = $blockname;
13a0d3d3 634 $blockinstance->parentcontextid = $this->page->context->id;
08eab897 635 $blockinstance->showinsubcontexts = !empty($showinsubcontexts);
636 $blockinstance->pagetypepattern = $pagetypepattern;
637 $blockinstance->subpagepattern = $subpagepattern;
638 $blockinstance->defaultregion = $region;
639 $blockinstance->defaultweight = $weight;
640 $blockinstance->configdata = '';
feed1900 641 $blockinstance->id = $DB->insert_record('block_instances', $blockinstance);
642
e92c286c 643 // Ensure the block context is created.
644 get_context_instance(CONTEXT_BLOCK, $blockinstance->id);
e03c0c1d 645
feed1900 646 // If the new instance was created, allow it to do additional setup
e92c286c 647 if ($block = block_instance($blockname, $blockinstance)) {
feed1900 648 $block->instance_create();
649 }
08eab897 650 }
651
21d33bdf 652 public function add_block_at_end_of_default_region($blockname) {
653 $defaulregion = $this->get_default_region();
2a3b0763 654
21d33bdf 655 $lastcurrentblock = end($this->birecordsbyregion[$defaulregion]);
2a3b0763 656 if ($lastcurrentblock) {
657 $weight = $lastcurrentblock->weight + 1;
658 } else {
659 $weight = 0;
660 }
661
21d33bdf 662 if ($this->page->subpage) {
663 $subpage = $this->page->subpage;
664 } else {
665 $subpage = null;
666 }
a2789e34 667
668 // Special case. Course view page type include the course format, but we
669 // want to add the block non-format-specifically.
670 $pagetypepattern = $this->page->pagetype;
671 if (strpos($pagetypepattern, 'course-view') === 0) {
672 $pagetypepattern = 'course-view-*';
673 }
674
2a3b0763 675 $this->add_block($blockname, $defaulregion, $weight, false, $pagetypepattern, $subpage);
21d33bdf 676 }
677
9d1d606e 678 /**
679 * Convenience method, calls add_block repeatedly for all the blocks in $blocks.
d4accfc0 680 *
2a3b0763 681 * @param array $blocks array with array keys the region names, and values an array of block names.
9d1d606e 682 * @param string $pagetypepattern optional. Passed to @see add_block()
683 * @param string $subpagepattern optional. Passed to @see add_block()
684 */
7d2a0492 685 public function add_blocks($blocks, $pagetypepattern = NULL, $subpagepattern = NULL, $showinsubcontexts=false, $weight=0) {
9d1d606e 686 $this->add_regions(array_keys($blocks));
687 foreach ($blocks as $region => $regionblocks) {
688 $weight = 0;
689 foreach ($regionblocks as $blockname) {
7d2a0492 690 $this->add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern, $subpagepattern);
9d1d606e 691 $weight += 1;
692 }
693 }
694 }
695
2cdb8d84 696 /**
697 * Move a block to a new position on this page.
698 *
699 * If this block cannot appear on any other pages, then we change defaultposition/weight
847bed23 700 * in the block_instances table. Otherwise we just set the position on this page.
2cdb8d84 701 *
702 * @param $blockinstanceid the block instance id.
703 * @param $newregion the new region name.
704 * @param $newweight the new weight.
705 */
706 public function reposition_block($blockinstanceid, $newregion, $newweight) {
707 global $DB;
708
709 $this->check_region_is_known($newregion);
710 $inst = $this->find_instance($blockinstanceid);
711
712 $bi = $inst->instance;
713 if ($bi->weight == $bi->defaultweight && $bi->region == $bi->defaultregion &&
714 !$bi->showinsubcontexts && strpos($bi->pagetypepattern, '*') === false &&
715 (!$this->page->subpage || $bi->subpagepattern)) {
716
717 // Set default position
718 $newbi = new stdClass;
719 $newbi->id = $bi->id;
720 $newbi->defaultregion = $newregion;
721 $newbi->defaultweight = $newweight;
722 $DB->update_record('block_instances', $newbi);
723
724 if ($bi->blockpositionid) {
725 $bp = new stdClass;
726 $bp->id = $bi->blockpositionid;
727 $bp->region = $newregion;
728 $bp->weight = $newweight;
729 $DB->update_record('block_positions', $bp);
730 }
731
732 } else {
733 // Just set position on this page.
734 $bp = new stdClass;
735 $bp->region = $newregion;
736 $bp->weight = $newweight;
737
738 if ($bi->blockpositionid) {
739 $bp->id = $bi->blockpositionid;
740 $DB->update_record('block_positions', $bp);
741
742 } else {
743 $bp->blockinstanceid = $bi->id;
744 $bp->contextid = $this->page->context->id;
745 $bp->pagetype = $this->page->pagetype;
746 if ($this->page->subpage) {
747 $bp->subpage = $this->page->subpage;
748 } else {
749 $bp->subpage = '';
750 }
751 $bp->visible = $bi->visible;
752 $DB->insert_record('block_positions', $bp);
753 }
754 }
755 }
756
f4d38d20 757 /**
a19f419d 758 * Find a given block by its instance id
d4accfc0 759 *
f4d38d20 760 * @param integer $instanceid
d4accfc0 761 * @return object
f4d38d20 762 */
763 public function find_instance($instanceid) {
764 foreach ($this->regions as $region => $notused) {
765 $this->ensure_instances_exist($region);
766 foreach($this->blockinstances[$region] as $instance) {
767 if ($instance->instance->id == $instanceid) {
768 return $instance;
769 }
770 }
771 }
772 throw new block_not_on_page_exception($instanceid, $this->page);
773 }
774
86b5ea0f 775/// Inner workings =============================================================
776
d4accfc0 777 /**
778 * Check whether the page blocks have been loaded yet
779 *
780 * @return void Throws coding exception if already loaded
781 */
86b5ea0f 782 protected function check_not_yet_loaded() {
bb46a4fa 783 if (!is_null($this->birecordsbyregion)) {
86b5ea0f 784 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.');
785 }
786 }
787
d4accfc0 788 /**
789 * Check whether the page blocks have been loaded yet
790 *
791 * Nearly identical to the above function {@link check_not_yet_loaded()} except different message
792 *
793 * @return void Throws coding exception if already loaded
794 */
08eab897 795 protected function check_is_loaded() {
bb46a4fa 796 if (is_null($this->birecordsbyregion)) {
08eab897 797 throw new coding_exception('block_manager has not yet loaded the blocks, to it is too soon to request the information you asked for.');
798 }
799 }
800
d4accfc0 801 /**
802 * Check if a block type is known and usable
803 *
804 * @param string $blockname The block type name to search for
847bed23 805 * @param bool $includeinvisible Include disabled block types in the initial pass
d4accfc0 806 * @return void Coding Exception thrown if unknown or not enabled
807 */
08eab897 808 protected function check_known_block_type($blockname, $includeinvisible = false) {
809 if (!$this->is_known_block_type($blockname, $includeinvisible)) {
810 if ($this->is_known_block_type($blockname, true)) {
811 throw new coding_exception('Unknown block type ' . $blockname);
812 } else {
813 throw new coding_exception('Block type ' . $blockname . ' has been disabled by the administrator.');
814 }
815 }
816 }
817
d4accfc0 818 /**
819 * Check if a region is known by its name
820 *
821 * @param string $region
822 * @return void Coding Exception thrown if the region is not known
823 */
08eab897 824 protected function check_region_is_known($region) {
825 if (!$this->is_known_region($region)) {
826 throw new coding_exception('Trying to reference an unknown block region ' . $region);
827 }
86b5ea0f 828 }
bb46a4fa 829
830 /**
d4accfc0 831 * Returns an array of region names as keys and nested arrays for values
832 *
bb46a4fa 833 * @return array an array where the array keys are the region names, and the array
834 * values are empty arrays.
835 */
836 protected function prepare_per_region_arrays() {
837 $result = array();
838 foreach ($this->regions as $region => $notused) {
839 $result[$region] = array();
840 }
841 return $result;
842 }
843
d4accfc0 844 /**
845 * Create a set of new block instance from a record array
846 *
847 * @param array $birecords An array of block instance records
848 * @return array An array of instantiated block_instance objects
849 */
bb46a4fa 850 protected function create_block_instances($birecords) {
851 $results = array();
852 foreach ($birecords as $record) {
d836aa4b 853 if ($blockobject = block_instance($record->blockname, $record, $this->page)) {
854 $results[] = $blockobject;
855 }
bb46a4fa 856 }
857 return $results;
858 }
859
4578a5eb 860 /**
847bed23 861 * Create all the block instances for all the blocks that were loaded by
4578a5eb 862 * load_blocks. This is used, for example, to ensure that all blocks get a
863 * chance to initialise themselves via the {@link block_base::specialize()}
864 * method, before any output is done.
865 */
866 public function create_all_block_instances() {
867 foreach ($this->get_regions() as $region) {
868 $this->ensure_instances_exist($region);
869 }
870 }
871
d4accfc0 872 /**
00a24d44 873 * Return an array of content objects from a set of block instances
d4accfc0 874 *
875 * @param array $instances An array of block instances
78946b9b 876 * @param renderer_base The renderer to use.
00a24d44 877 * @param string $region the region name.
878 * @return array An array of block_content (and possibly block_move_target) objects.
d4accfc0 879 */
00a24d44 880 protected function create_block_contents($instances, $output, $region) {
bb46a4fa 881 $results = array();
00a24d44 882
883 $lastweight = 0;
884 $lastblock = 0;
885 if ($this->movingblock) {
886 $first = reset($instances);
887 if ($first) {
888 $lastweight = $first->instance->weight - 2;
889 }
890
891 $strmoveblockhere = get_string('moveblockhere', 'block');
892 }
893
bb46a4fa 894 foreach ($instances as $instance) {
d4a03c00 895 $content = $instance->get_content_for_output($output);
00a24d44 896 if (empty($content)) {
897 continue;
898 }
899
900 if ($this->movingblock && $lastweight != $instance->instance->weight &&
901 $content->blockinstanceid != $this->movingblock && $lastblock != $this->movingblock) {
dd72b308 902 $results[] = new block_move_target($strmoveblockhere, $this->get_move_target_url($region, ($lastweight + $instance->instance->weight)/2));
00a24d44 903 }
904
905 if ($content->blockinstanceid == $this->movingblock) {
906 $content->add_class('beingmoved');
907 $content->annotation .= get_string('movingthisblockcancel', 'block',
75015e5f 908 html_writer::link($this->page->url, get_string('cancel')));
bb46a4fa 909 }
00a24d44 910
911 $results[] = $content;
912 $lastweight = $instance->instance->weight;
913 $lastblock = $instance->instance->id;
914 }
915
916 if ($this->movingblock && $lastblock != $this->movingblock) {
dd72b308 917 $results[] = new block_move_target($strmoveblockhere, $this->get_move_target_url($region, $lastweight + 1));
bb46a4fa 918 }
919 return $results;
920 }
921
d4accfc0 922 /**
923 * Ensure block instances exist for a given region
a19f419d 924 *
d4accfc0 925 * @param string $region Check for bi's with the instance with this name
926 */
bb46a4fa 927 protected function ensure_instances_exist($region) {
928 $this->check_region_is_known($region);
929 if (!array_key_exists($region, $this->blockinstances)) {
930 $this->blockinstances[$region] =
931 $this->create_block_instances($this->birecordsbyregion[$region]);
932 }
933 }
934
d4accfc0 935 /**
936 * Ensure that there is some content within the given region
937 *
938 * @param string $region The name of the region to check
939 */
d4a03c00 940 protected function ensure_content_created($region, $output) {
bb46a4fa 941 $this->ensure_instances_exist($region);
942 if (!array_key_exists($region, $this->visibleblockcontent)) {
d4a03c00 943 $contents = array();
944 if (array_key_exists($region, $this->extracontent)) {
945 $contents = $this->extracontent[$region];
946 }
00a24d44 947 $contents = array_merge($contents, $this->create_block_contents($this->blockinstances[$region], $output, $region));
d4a03c00 948 if ($region == $this->defaultregion) {
21d33bdf 949 $addblockui = block_add_block_ui($this->page, $output);
d4a03c00 950 if ($addblockui) {
951 $contents[] = $addblockui;
952 }
953 }
954 $this->visibleblockcontent[$region] = $contents;
bb46a4fa 955 }
956 }
a19f419d 957
958/// Process actions from the URL ===============================================
959
00a24d44 960 /**
961 * Get the appropriate list of editing icons for a block. This is used
962 * to set {@link block_contents::$controls} in {@link block_base::get_contents_for_output()}.
963 *
964 * @param $output The core_renderer to use when generating the output. (Need to get icon paths.)
965 * @return an array in the format for {@link block_contents::$controls}
966 */
967 public function edit_controls($block) {
968 global $CFG;
969
5afbd0e7 970 if (!isset($CFG->undeletableblocktypes) || (!is_array($CFG->undeletableblocktypes) && !is_string($CFG->undeletableblocktypes))) {
3406acde 971 $CFG->undeletableblocktypes = array('navigation','settings');
5afbd0e7 972 } else if (is_string($CFG->undeletableblocktypes)) {
973 $CFG->undeletableblocktypes = explode(',', $CFG->undeletableblocktypes);
974 }
975
00a24d44 976 $controls = array();
b9bc2019 977 $actionurl = $this->page->url->out(false, array('sesskey'=> sesskey()));
00a24d44 978
979 // Assign roles icon.
980 if (has_capability('moodle/role:assign', $block->context)) {
a4a04ada
PS
981 //TODO: please note it is sloppy to pass urls through page parameters!!
982 // it is shortened because some web servers (e.g. IIS by default) give
983 // a 'security' error if you try to pass a full URL as a GET parameter in another URL.
4f0c2d00 984
bc0663ab 985 $return = $this->page->url->out(false);
a4a04ada 986 $return = str_replace($CFG->wwwroot . '/', '', $return);
4f0c2d00 987
00a24d44 988 $controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin .
a4a04ada 989 '/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($return),
00a24d44 990 'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role'));
991 }
992
d8ef60bd 993 if ($this->page->user_can_edit_blocks() && $block->instance_can_be_hidden()) {
00a24d44 994 // Show/hide icon.
995 if ($block->instance->visible) {
996 $controls[] = array('url' => $actionurl . '&bui_hideid=' . $block->instance->id,
997 'icon' => 't/hide', 'caption' => get_string('hide'));
998 } else {
999 $controls[] = array('url' => $actionurl . '&bui_showid=' . $block->instance->id,
1000 'icon' => 't/show', 'caption' => get_string('show'));
1001 }
1002 }
1003
1004 if ($this->page->user_can_edit_blocks() || $block->user_can_edit()) {
1005 // Edit config icon - always show - needed for positioning UI.
1006 $controls[] = array('url' => $actionurl . '&bui_editid=' . $block->instance->id,
1007 'icon' => 't/edit', 'caption' => get_string('configuration'));
1008 }
1009
1010 if ($this->page->user_can_edit_blocks() && $block->user_can_edit() && $block->user_can_addto($this->page)) {
5afbd0e7 1011 if (!in_array($block->instance->blockname, $CFG->undeletableblocktypes)) {
1012 // Delete icon.
1013 $controls[] = array('url' => $actionurl . '&bui_deleteid=' . $block->instance->id,
1014 'icon' => 't/delete', 'caption' => get_string('delete'));
1015 }
00a24d44 1016 }
1017
1018 if ($this->page->user_can_edit_blocks()) {
1019 // Move icon.
1020 $controls[] = array('url' => $actionurl . '&bui_moveid=' . $block->instance->id,
1021 'icon' => 't/move', 'caption' => get_string('move'));
1022 }
1023
1024 return $controls;
1025 }
1026
a19f419d 1027 /**
1028 * Process any block actions that were specified in the URL.
1029 *
1030 * This can only be done given a valid $page object.
1031 *
1032 * @param moodle_page $page the page to add blocks to.
1033 * @return boolean true if anything was done. False if not.
1034 */
1035 public function process_url_actions() {
00a24d44 1036 if (!$this->page->user_is_editing()) {
1037 return false;
1038 }
a19f419d 1039 return $this->process_url_add() || $this->process_url_delete() ||
00a24d44 1040 $this->process_url_show_hide() || $this->process_url_edit() ||
1041 $this->process_url_move();
a19f419d 1042 }
1043
1044 /**
1045 * Handle adding a block.
1046 * @return boolean true if anything was done. False if not.
1047 */
1048 public function process_url_add() {
1049 $blocktype = optional_param('bui_addblock', null, PARAM_SAFEDIR);
1050 if (!$blocktype) {
1051 return false;
1052 }
1053
c74eec3b 1054 require_sesskey();
a19f419d 1055
1d7e341e 1056 if (!$this->page->user_can_edit_blocks()) {
a19f419d 1057 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('addblock'));
1058 }
1059
1060 if (!array_key_exists($blocktype, $this->get_addable_blocks())) {
1061 throw new moodle_exception('cannotaddthisblocktype', '', $this->page->url->out(), $blocktype);
1062 }
1063
1064 $this->add_block_at_end_of_default_region($blocktype);
1065
847bed23 1066 // If the page URL was a guess, it will contain the bui_... param, so we must make sure it is not there.
a19f419d 1067 $this->page->ensure_param_not_in_url('bui_addblock');
1068
1069 return true;
1070 }
1071
1072 /**
1073 * Handle deleting a block.
1074 * @return boolean true if anything was done. False if not.
1075 */
1076 public function process_url_delete() {
1077 $blockid = optional_param('bui_deleteid', null, PARAM_INTEGER);
1078 if (!$blockid) {
1079 return false;
1080 }
1081
c74eec3b 1082 require_sesskey();
a19f419d 1083
1084 $block = $this->page->blocks->find_instance($blockid);
1085
7bbc2890 1086 if (!$block->user_can_edit() || !$this->page->user_can_edit_blocks() || !$block->user_can_addto($this->page)) {
a19f419d 1087 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('deleteablock'));
1088 }
1089
1090 blocks_delete_instance($block->instance);
1091
847bed23 1092 // If the page URL was a guess, it will contain the bui_... param, so we must make sure it is not there.
a19f419d 1093 $this->page->ensure_param_not_in_url('bui_deleteid');
1094
1095 return true;
1096 }
1097
1098 /**
1099 * Handle showing or hiding a block.
1100 * @return boolean true if anything was done. False if not.
1101 */
1102 public function process_url_show_hide() {
1103 if ($blockid = optional_param('bui_hideid', null, PARAM_INTEGER)) {
1104 $newvisibility = 0;
1105 } else if ($blockid = optional_param('bui_showid', null, PARAM_INTEGER)) {
1106 $newvisibility = 1;
1107 } else {
1108 return false;
1109 }
1110
c74eec3b 1111 require_sesskey();
a19f419d 1112
1113 $block = $this->page->blocks->find_instance($blockid);
1114
d14edf06 1115 if (!$this->page->user_can_edit_blocks()) {
a19f419d 1116 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('hideshowblocks'));
d8ef60bd
SH
1117 } else if (!$block->instance_can_be_hidden()) {
1118 return false;
a19f419d 1119 }
1120
1121 blocks_set_visibility($block->instance, $this->page, $newvisibility);
1122
1123 // If the page URL was a guses, it will contain the bui_... param, so we must make sure it is not there.
1124 $this->page->ensure_param_not_in_url('bui_hideid');
1125 $this->page->ensure_param_not_in_url('bui_showid');
1126
1127 return true;
1128 }
1129
1130 /**
1131 * Handle showing/processing the submission from the block editing form.
1132 * @return boolean true if the form was submitted and the new config saved. Does not
1133 * return if the editing form was displayed. False otherwise.
1134 */
1135 public function process_url_edit() {
1136 global $CFG, $DB, $PAGE;
1137
1138 $blockid = optional_param('bui_editid', null, PARAM_INTEGER);
1139 if (!$blockid) {
1140 return false;
1141 }
1142
c74eec3b 1143 require_sesskey();
a19f419d 1144 require_once($CFG->dirroot . '/blocks/edit_form.php');
1145
1146 $block = $this->find_instance($blockid);
1147
d14edf06 1148 if (!$block->user_can_edit() && !$this->page->user_can_edit_blocks()) {
a19f419d 1149 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('editblock'));
1150 }
1151
1152 $editpage = new moodle_page();
3c14795a 1153 $editpage->set_pagelayout('admin');
a19f419d 1154 $editpage->set_course($this->page->course);
7bbc2890 1155 $editpage->set_context($block->context);
88f77c3c
SH
1156 if ($this->page->cm) {
1157 $editpage->set_cm($this->page->cm);
1158 }
24e4119a 1159 $editurlbase = str_replace($CFG->wwwroot . '/', '/', $this->page->url->out_omit_querystring());
a19f419d 1160 $editurlparams = $this->page->url->params();
1161 $editurlparams['bui_editid'] = $blockid;
1162 $editpage->set_url($editurlbase, $editurlparams);
05c92729 1163 $editpage->set_block_actions_done();
a19f419d 1164 // At this point we are either going to redirect, or display the form, so
1165 // overwrite global $PAGE ready for this. (Formslib refers to it.)
1166 $PAGE = $editpage;
1167
1168 $formfile = $CFG->dirroot . '/blocks/' . $block->name() . '/edit_form.php';
1169 if (is_readable($formfile)) {
1170 require_once($formfile);
1171 $classname = 'block_' . $block->name() . '_edit_form';
34a988e2
MD
1172 if (!class_exists($classname)) {
1173 $classname = 'block_edit_form';
1174 }
a19f419d 1175 } else {
1176 $classname = 'block_edit_form';
1177 }
1178
1179 $mform = new $classname($editpage->url, $block, $this->page);
1180 $mform->set_data($block->instance);
1181
1182 if ($mform->is_cancelled()) {
1183 redirect($this->page->url);
1184
1185 } else if ($data = $mform->get_data()) {
1186 $bi = new stdClass;
1187 $bi->id = $block->instance->id;
a19f419d 1188 $bi->pagetypepattern = $data->bui_pagetypepattern;
1189 if (empty($data->bui_subpagepattern) || $data->bui_subpagepattern == '%@NULL@%') {
1190 $bi->subpagepattern = null;
1191 } else {
1192 $bi->subpagepattern = $data->bui_subpagepattern;
1193 }
0aed347f
MD
1194
1195 $parentcontext = get_context_instance_by_id($data->bui_parentcontextid);
1196 $systemcontext = get_context_instance(CONTEXT_SYSTEM);
1197
1198 // Updating stickiness and contexts. See MDL-21375 for details.
1199 if (has_capability('moodle/site:manageblocks', $parentcontext)) { // Check permissions in destination
1200 // Explicitly set the context
1201 $bi->parentcontextid = $parentcontext->id;
1202
1203 // If the context type is > 0 then we'll explicitly set the block as sticky, otherwise not
1204 $bi->showinsubcontexts = (int)(!empty($data->bui_contexts));
1205
1206 // If the block wants to be system-wide, then explicitly set that
1207 if ($data->bui_contexts == 2) { // Only possible on a frontpage or system page
1208 $bi->parentcontextid = $systemcontext->id;
1209
1210 } else { // The block doesn't want to be system-wide, so let's ensure that
1211 if ($parentcontext->id == $systemcontext->id) { // We need to move it to the front page
1212 $frontpagecontext = get_context_instance(CONTEXT_COURSE, SITEID);
1213 $bi->parentcontextid = $frontpagecontext->id;
1214 $bi->pagetypepattern = '*'; // Just in case
1215 }
02ba576c
MD
1216 }
1217 }
0aed347f 1218
a19f419d 1219 $bi->defaultregion = $data->bui_defaultregion;
1220 $bi->defaultweight = $data->bui_defaultweight;
1221 $DB->update_record('block_instances', $bi);
1222
a23bbaa3 1223 if (!empty($block->config)) {
1224 $config = clone($block->config);
1225 } else {
1226 $config = new stdClass;
1227 }
a19f419d 1228 foreach ($data as $configfield => $value) {
1229 if (strpos($configfield, 'config_') !== 0) {
1230 continue;
1231 }
1232 $field = substr($configfield, 7);
1233 $config->$field = $value;
1234 }
1235 $block->instance_config_save($config);
1236
1237 $bp = new stdClass;
1238 $bp->visible = $data->bui_visible;
1239 $bp->region = $data->bui_region;
1240 $bp->weight = $data->bui_weight;
1241 $needbprecord = !$data->bui_visible || $data->bui_region != $data->bui_defaultregion ||
1242 $data->bui_weight != $data->bui_defaultweight;
1243
1244 if ($block->instance->blockpositionid && !$needbprecord) {
1245 $DB->delete_records('block_positions', array('id' => $block->instance->blockpositionid));
1246
1247 } else if ($block->instance->blockpositionid && $needbprecord) {
1248 $bp->id = $block->instance->blockpositionid;
1249 $DB->update_record('block_positions', $bp);
1250
1251 } else if ($needbprecord) {
1252 $bp->blockinstanceid = $block->instance->id;
a23bbaa3 1253 $bp->contextid = $this->page->context->id;
a19f419d 1254 $bp->pagetype = $this->page->pagetype;
1255 if ($this->page->subpage) {
1256 $bp->subpage = $this->page->subpage;
1257 } else {
a23bbaa3 1258 $bp->subpage = '';
a19f419d 1259 }
1260 $DB->insert_record('block_positions', $bp);
1261 }
1262
1263 redirect($this->page->url);
1264
1265 } else {
69c14bbd 1266 $strheading = get_string('blockconfiga', 'moodle', $block->get_title());
a19f419d 1267 $editpage->set_title($strheading);
1268 $editpage->set_heading($strheading);
3c14795a 1269 $editpage->navbar->add($strheading);
649cf95d 1270 $output = $editpage->get_renderer('core');
a19f419d 1271 echo $output->header();
1272 echo $output->heading($strheading, 2);
1273 $mform->display();
1274 echo $output->footer();
1275 exit;
1276 }
1277 }
00a24d44 1278
1279 /**
1280 * Handle showing/processing the submission from the block editing form.
1281 * @return boolean true if the form was submitted and the new config saved. Does not
1282 * return if the editing form was displayed. False otherwise.
1283 */
1284 public function process_url_move() {
1285 global $CFG, $DB, $PAGE;
1286
1287 $blockid = optional_param('bui_moveid', null, PARAM_INTEGER);
1288 if (!$blockid) {
1289 return false;
1290 }
1291
c74eec3b 1292 require_sesskey();
00a24d44 1293
1294 $block = $this->find_instance($blockid);
1295
1296 if (!$this->page->user_can_edit_blocks()) {
1297 throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('editblock'));
1298 }
1299
1300 $newregion = optional_param('bui_newregion', '', PARAM_ALPHANUMEXT);
1301 $newweight = optional_param('bui_newweight', null, PARAM_FLOAT);
1302 if (!$newregion || is_null($newweight)) {
1303 // Don't have a valid target position yet, must be just starting the move.
1304 $this->movingblock = $blockid;
1305 $this->page->ensure_param_not_in_url('bui_moveid');
1306 return false;
1307 }
1308
2cdb8d84 1309 if (!$this->is_known_region($newregion)) {
1310 throw new moodle_exception('unknownblockregion', '', $this->page->url, $newregion);
1311 }
1312
1313 // Move this block. This may involve moving other nearby blocks.
1314 $blocks = $this->birecordsbyregion[$newregion];
1315
f4e6a86e 1316 $maxweight = self::MAX_WEIGHT;
1317 $minweight = -self::MAX_WEIGHT;
1318
1319 // Initialise the used weights and spareweights array with the default values
2cdb8d84 1320 $spareweights = array();
1321 $usedweights = array();
f4e6a86e 1322 for ($i = $minweight; $i <= $maxweight; $i++) {
2cdb8d84 1323 $spareweights[$i] = $i;
1324 $usedweights[$i] = array();
1325 }
f4e6a86e 1326
1327 // Check each block and sort out where we have used weights
2cdb8d84 1328 foreach ($blocks as $bi) {
f4e6a86e 1329 if ($bi->weight > $maxweight) {
1330 // If this statement is true then the blocks weight is more than the
1331 // current maximum. To ensure that we can get the best block position
1332 // we will initialise elements within the usedweights and spareweights
1333 // arrays between the blocks weight (which will then be the new max) and
1334 // the current max
1335 $parseweight = $bi->weight;
1336 while (!array_key_exists($parseweight, $usedweights)) {
1337 $usedweights[$parseweight] = array();
1338 $spareweights[$parseweight] = $parseweight;
1339 $parseweight--;
1340 }
1341 $maxweight = $bi->weight;
1342 } else if ($bi->weight < $minweight) {
1343 // As above except this time the blocks weight is LESS than the
1344 // the current minimum, so we will initialise the array from the
1345 // blocks weight (new minimum) to the current minimum
1346 $parseweight = $bi->weight;
1347 while (!array_key_exists($parseweight, $usedweights)) {
1348 $usedweights[$parseweight] = array();
1349 $spareweights[$parseweight] = $parseweight;
1350 $parseweight++;
1351 }
1352 $minweight = $bi->weight;
1353 }
1354 if ($bi->id != $block->instance->id) {
1355 unset($spareweights[$bi->weight]);
1356 $usedweights[$bi->weight][] = $bi->id;
2cdb8d84 1357 }
2cdb8d84 1358 }
1359
f4e6a86e 1360 // First we find the nearest gap in the list of weights.
2cdb8d84 1361 $bestdistance = max(abs($newweight - self::MAX_WEIGHT), abs($newweight + self::MAX_WEIGHT)) + 1;
1362 $bestgap = null;
1363 foreach ($spareweights as $spareweight) {
1364 if (abs($newweight - $spareweight) < $bestdistance) {
1365 $bestdistance = abs($newweight - $spareweight);
1366 $bestgap = $spareweight;
1367 }
1368 }
1369
1370 // If there is no gap, we have to go outside -self::MAX_WEIGHT .. self::MAX_WEIGHT.
1371 if (is_null($bestgap)) {
1372 $bestgap = self::MAX_WEIGHT + 1;
1373 while (!empty($usedweights[$bestgap])) {
1374 $bestgap++;
1375 }
1376 }
1377
1378 // Now we know the gap we are aiming for, so move all the blocks along.
1379 if ($bestgap < $newweight) {
1380 $newweight = floor($newweight);
1381 for ($weight = $bestgap + 1; $weight <= $newweight; $weight++) {
1382 foreach ($usedweights[$weight] as $biid) {
1383 $this->reposition_block($biid, $newregion, $weight - 1);
1384 }
1385 }
1386 $this->reposition_block($block->instance->id, $newregion, $newweight);
1387 } else {
1388 $newweight = ceil($newweight);
1389 for ($weight = $bestgap - 1; $weight >= $newweight; $weight--) {
1390 foreach ($usedweights[$weight] as $biid) {
1391 $this->reposition_block($biid, $newregion, $weight + 1);
1392 }
1393 }
1394 $this->reposition_block($block->instance->id, $newregion, $newweight);
1395 }
6f5e0852 1396
00a24d44 1397 $this->page->ensure_param_not_in_url('bui_moveid');
1398 $this->page->ensure_param_not_in_url('bui_newregion');
1399 $this->page->ensure_param_not_in_url('bui_newweight');
1400 return true;
1401 }
56ed242b
SH
1402
1403 /**
1404 * Turns the display of normal blocks either on or off.
78bfb562 1405 *
56ed242b
SH
1406 * @param bool $setting
1407 */
1408 public function show_only_fake_blocks($setting = true) {
1409 $this->fakeblocksonly = $setting;
1410 }
86b5ea0f 1411}
1412
08eab897 1413/// Helper functions for working with block classes ============================
1414
1415/**
847bed23 1416 * Call a class method (one that does not require a block instance) on a block class.
d4accfc0 1417 *
08eab897 1418 * @param string $blockname the name of the block.
1419 * @param string $method the method name.
1420 * @param array $param parameters to pass to the method.
1421 * @return mixed whatever the method returns.
1422 */
11306331 1423function block_method_result($blockname, $method, $param = NULL) {
0f3fe4b6 1424 if(!block_load_class($blockname)) {
1425 return NULL;
1426 }
11306331 1427 return call_user_func(array('block_'.$blockname, $method), $param);
0f3fe4b6 1428}
1429
08eab897 1430/**
365a5941 1431 * Creates a new instance of the specified block class.
d4accfc0 1432 *
08eab897 1433 * @param string $blockname the name of the block.
1434 * @param $instance block_instances DB table row (optional).
bb46a4fa 1435 * @param moodle_page $page the page this block is appearing on.
08eab897 1436 * @return block_base the requested block instance.
1437 */
bb46a4fa 1438function block_instance($blockname, $instance = NULL, $page = NULL) {
0f3fe4b6 1439 if(!block_load_class($blockname)) {
1440 return false;
1441 }
e89d741a 1442 $classname = 'block_'.$blockname;
f032aa7a 1443 $retval = new $classname;
9b4b78fd 1444 if($instance !== NULL) {
bb46a4fa 1445 if (is_null($page)) {
1446 global $PAGE;
1447 $page = $PAGE;
1448 }
1449 $retval->_load_instance($instance, $page);
9b4b78fd 1450 }
1451 return $retval;
0f3fe4b6 1452}
1453
08eab897 1454/**
1455 * Load the block class for a particular type of block.
d4accfc0 1456 *
08eab897 1457 * @param string $blockname the name of the block.
1458 * @return boolean success or failure.
1459 */
0f3fe4b6 1460function block_load_class($blockname) {
1461 global $CFG;
1462
a9033ad5 1463 if(empty($blockname)) {
c7a9e293 1464 return false;
1465 }
1466
e89d741a 1467 $classname = 'block_'.$blockname;
a9033ad5 1468
1469 if(class_exists($classname)) {
1470 return true;
1471 }
1472
d836aa4b 1473 $blockpath = $CFG->dirroot.'/blocks/'.$blockname.'/block_'.$blockname.'.php';
1474
1475 if (file_exists($blockpath)) {
1476 require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
1477 include_once($blockpath);
1478 }else{
15822fe2 1479 //debugging("$blockname code does not exist in $blockpath", DEBUG_DEVELOPER);
d836aa4b 1480 return false;
1481 }
0f3fe4b6 1482
0f3fe4b6 1483 return class_exists($classname);
1484}
1485
1d13c75c 1486/**
1487 * Given a specific page type, return all the page type patterns that might
1488 * match it.
1489 *
1490 * @param string $pagetype for example 'course-view-weeks' or 'mod-quiz-view'.
1491 * @return array an array of all the page type patterns that might match this page type.
1492 */
1493function matching_page_type_patterns($pagetype) {
1494 $patterns = array($pagetype);
1495 $bits = explode('-', $pagetype);
1496 if (count($bits) == 3 && $bits[0] == 'mod') {
1497 if ($bits[2] == 'view') {
1498 $patterns[] = 'mod-*-view';
1499 } else if ($bits[2] == 'index') {
1500 $patterns[] = 'mod-*-index';
1501 }
1502 }
1503 while (count($bits) > 0) {
1504 $patterns[] = implode('-', $bits) . '-*';
1505 array_pop($bits);
1506 }
4d74c876 1507 $patterns[] = '*';
1d13c75c 1508 return $patterns;
1509}
1510
21d33bdf 1511/// Functions update the blocks if required by the request parameters ==========
1512
1513/**
1514 * Return a {@link block_contents} representing the add a new block UI, if
1515 * this user is allowed to see it.
1516 *
1517 * @return block_contents an appropriate block_contents, or null if the user
1518 * cannot add any blocks here.
1519 */
1520function block_add_block_ui($page, $output) {
d81b05e7 1521 global $CFG, $OUTPUT;
21d33bdf 1522 if (!$page->user_is_editing() || !$page->user_can_edit_blocks()) {
1523 return null;
1524 }
1525
1526 $bc = new block_contents();
1527 $bc->title = get_string('addblock');
1528 $bc->add_class('block_adminblock');
1529
a2789e34 1530 $missingblocks = $page->blocks->get_addable_blocks();
21d33bdf 1531 if (empty($missingblocks)) {
a2789e34 1532 $bc->content = get_string('noblockstoaddhere');
21d33bdf 1533 return $bc;
1534 }
1535
1536 $menu = array();
a2789e34 1537 foreach ($missingblocks as $block) {
21d33bdf 1538 $blockobject = block_instance($block->name);
1539 if ($blockobject !== false && $blockobject->user_can_addto($page)) {
1540 $menu[$block->name] = $blockobject->get_title();
1541 }
1542 }
c6947ba7 1543 textlib_get_instance()->asort($menu);
21d33bdf 1544
8afba50b 1545 $actionurl = new moodle_url($page->url, array('sesskey'=>sesskey()));
f8dab966
PS
1546 $select = new single_select($actionurl, 'bui_addblock', $menu, null, array(''=>get_string('adddots')), 'add_block');
1547 $bc->content = $OUTPUT->render($select);
21d33bdf 1548 return $bc;
1549}
1550
21d33bdf 1551// Functions that have been deprecated by block_manager =======================
f032aa7a 1552
08eab897 1553/**
a2789e34 1554 * @deprecated since Moodle 2.0 - use $page->blocks->get_addable_blocks();
d4accfc0 1555 *
08eab897 1556 * This function returns an array with the IDs of any blocks that you can add to your page.
1557 * Parameters are passed by reference for speed; they are not modified at all.
d4accfc0 1558 *
08eab897 1559 * @param $page the page object.
bb46a4fa 1560 * @param $blockmanager Not used.
08eab897 1561 * @return array of block type ids.
1562 */
bb46a4fa 1563function blocks_get_missing(&$page, &$blockmanager) {
a2789e34 1564 debugging('blocks_get_missing is deprecated. Please use $page->blocks->get_addable_blocks() instead.', DEBUG_DEVELOPER);
1565 $blocks = $page->blocks->get_addable_blocks();
1566 $ids = array();
1567 foreach ($blocks as $block) {
1568 $ids[] = $block->id;
1569 }
1570 return $ids;
f032aa7a 1571}
1572
bb46a4fa 1573/**
1574 * Actually delete from the database any blocks that are currently on this page,
1575 * but which should not be there according to blocks_name_allowed_in_format.
d4accfc0 1576 *
847bed23 1577 * @todo Write/Fix this function. Currently returns immediately
c679c358 1578 * @param $course
bb46a4fa 1579 */
c679c358 1580function blocks_remove_inappropriate($course) {
bb46a4fa 1581 // TODO
1582 return;
7604f5c1 1583 /*
bb46a4fa 1584 $blockmanager = blocks_get_by_page($page);
f032aa7a 1585
78946b9b 1586 if (empty($blockmanager)) {
f032aa7a 1587 return;
1588 }
1589
78946b9b 1590 if (($pageformat = $page->pagetype) == NULL) {
f032aa7a 1591 return;
1592 }
1593
f2c6739c 1594 foreach($blockmanager as $region) {
1595 foreach($region as $instance) {
f032aa7a 1596 $block = blocks_get_record($instance->blockid);
5bbbe0be 1597 if(!blocks_name_allowed_in_format($block->name, $pageformat)) {
a2789e34 1598 blocks_delete_instance($instance->instance);
f032aa7a 1599 }
1600 }
7604f5c1 1601 }*/
f032aa7a 1602}
1603
d4accfc0 1604/**
1605 * Check that a given name is in a permittable format
1606 *
1607 * @param string $name
1608 * @param string $pageformat
1609 * @return bool
1610 */
5bbbe0be 1611function blocks_name_allowed_in_format($name, $pageformat) {
cd2bc3c9 1612 $accept = NULL;
1613 $maxdepth = -1;
1614 $formats = block_method_result($name, 'applicable_formats');
1615 if (!$formats) {
1616 $formats = array();
1617 }
1618 foreach ($formats as $format => $allowed) {
1619 $formatregex = '/^'.str_replace('*', '[^-]*', $format).'.*$/';
1620 $depth = substr_count($format, '-');
1621 if (preg_match($formatregex, $pageformat) && $depth > $maxdepth) {
1622 $maxdepth = $depth;
1623 $accept = $allowed;
5bbbe0be 1624 }
1625 }
cd2bc3c9 1626 if ($accept === NULL) {
5bbbe0be 1627 $accept = !empty($formats['all']);
1628 }
1629 return $accept;
1630}
1631
feed1900 1632/**
1633 * Delete a block, and associated data.
d4accfc0 1634 *
feed1900 1635 * @param object $instance a row from the block_instances table
847bed23 1636 * @param bool $nolongerused legacy parameter. Not used, but kept for backwards compatibility.
d4accfc0 1637 * @param bool $skipblockstables for internal use only. Makes @see blocks_delete_all_for_context() more efficient.
feed1900 1638 */
1639function blocks_delete_instance($instance, $nolongerused = false, $skipblockstables = false) {
f4d38d20 1640 global $DB;
1641
1642 if ($block = block_instance($instance->blockname, $instance)) {
feed1900 1643 $block->instance_delete();
1644 }
1645 delete_context(CONTEXT_BLOCK, $instance->id);
f032aa7a 1646
feed1900 1647 if (!$skipblockstables) {
1648 $DB->delete_records('block_positions', array('blockinstanceid' => $instance->id));
1649 $DB->delete_records('block_instances', array('id' => $instance->id));
e2f4557a 1650 $DB->delete_records_list('user_preferences', 'name', array('block'.$instance->id.'hidden','docked_block_instance_'.$instance->id));
b33dd23a 1651 }
feed1900 1652}
b33dd23a 1653
feed1900 1654/**
1655 * Delete all the blocks that belong to a particular context.
d4accfc0 1656 *
d4accfc0 1657 * @param int $contextid the context id.
feed1900 1658 */
1659function blocks_delete_all_for_context($contextid) {
1660 global $DB;
a2789e34 1661 $instances = $DB->get_recordset('block_instances', array('parentcontextid' => $contextid));
feed1900 1662 foreach ($instances as $instance) {
1663 blocks_delete_instance($instance, true);
0d6b9d4f 1664 }
feed1900 1665 $instances->close();
13a0d3d3 1666 $DB->delete_records('block_instances', array('parentcontextid' => $contextid));
feed1900 1667 $DB->delete_records('block_positions', array('contextid' => $contextid));
f032aa7a 1668}
1669
ae42ff6f 1670/**
1671 * Set a block to be visible or hidden on a particular page.
1672 *
1673 * @param object $instance a row from the block_instances, preferably LEFT JOINed with the
1674 * block_positions table as return by block_manager.
1675 * @param moodle_page $page the back to set the visibility with respect to.
1676 * @param integer $newvisibility 1 for visible, 0 for hidden.
1677 */
1678function blocks_set_visibility($instance, $page, $newvisibility) {
1679 global $DB;
1680 if (!empty($instance->blockpositionid)) {
1681 // Already have local information on this page.
1682 $DB->set_field('block_positions', 'visible', $newvisibility, array('id' => $instance->blockpositionid));
1683 return;
1684 }
1685
1686 // Create a new block_positions record.
1687 $bp = new stdClass;
1688 $bp->blockinstanceid = $instance->id;
1689 $bp->contextid = $page->context->id;
1690 $bp->pagetype = $page->pagetype;
1691 if ($page->subpage) {
1692 $bp->subpage = $page->subpage;
1693 }
1694 $bp->visible = $newvisibility;
1695 $bp->region = $instance->defaultregion;
1696 $bp->weight = $instance->defaultweight;
1697 $DB->insert_record('block_positions', $bp);
1698}
1699
d4accfc0 1700/**
d4a03c00 1701 * @deprecated since 2.0
1702 * Delete all the blocks from a particular page.
d4accfc0 1703 *
d4a03c00 1704 * @param string $pagetype the page type.
1705 * @param integer $pageid the page id.
1706 * @return bool success or failure.
d4accfc0 1707 */
d4a03c00 1708function blocks_delete_all_on_page($pagetype, $pageid) {
1709 global $DB;
1710
1711 debugging('Call to deprecated function blocks_delete_all_on_page. ' .
1712 'This function cannot work any more. Doing nothing. ' .
1713 'Please update your code to use a block_manager method $PAGE->blocks->....', DEBUG_DEVELOPER);
1714 return false;
0f3fe4b6 1715}
1716
d4accfc0 1717/**
d4a03c00 1718 * Dispite what this function is called, it seems to be mostly used to populate
1719 * the default blocks when a new course (or whatever) is created.
d4accfc0 1720 *
d4a03c00 1721 * @deprecated since 2.0
d4accfc0 1722 *
d4a03c00 1723 * @param object $page the page to add default blocks to.
1724 * @return boolean success or failure.
d4accfc0 1725 */
d4a03c00 1726function blocks_repopulate_page($page) {
1727 global $CFG;
0f3fe4b6 1728
d4a03c00 1729 debugging('Call to deprecated function blocks_repopulate_page. ' .
1730 'Use a more specific method like blocks_add_default_course_blocks, ' .
1731 'or just call $PAGE->blocks->add_blocks()', DEBUG_DEVELOPER);
d23157d8 1732
d4a03c00 1733 /// If the site override has been defined, it is the only valid one.
1734 if (!empty($CFG->defaultblocks_override)) {
1735 $blocknames = $CFG->defaultblocks_override;
1736 } else {
1737 $blocknames = $page->blocks_get_default();
66492322 1738 }
0f3fe4b6 1739
d4a03c00 1740 $blocks = blocks_parse_default_blocks_list($blocknames);
1741 $page->blocks->add_blocks($blocks);
1742
1743 return true;
0f3fe4b6 1744}
1745
08eab897 1746/**
847bed23 1747 * Get the block record for a particular blockid - that is, a particular type os block.
d4accfc0 1748 *
d4accfc0 1749 * @param $int blockid block type id. If null, an array of all block types is returned.
1750 * @param bool $notusedanymore No longer used.
08eab897 1751 * @return array|object row from block table, or all rows.
1752 */
1753function blocks_get_record($blockid = NULL, $notusedanymore = false) {
1754 global $PAGE;
1755 $blocks = $PAGE->blocks->get_installed_blocks();
1756 if ($blockid === NULL) {
1757 return $blocks;
1758 } else if (isset($blocks[$blockid])) {
1759 return $blocks[$blockid];
1760 } else {
1761 return false;
9b4b78fd 1762 }
9b4b78fd 1763}
1764
d4accfc0 1765/**
1766 * Find a given block by its blockid within a provide array
1767 *
1768 * @param int $blockid
1769 * @param array $blocksarray
1770 * @return bool|object Instance if found else false
1771 */
9b4b78fd 1772function blocks_find_block($blockid, $blocksarray) {
0d6b9d4f 1773 if (empty($blocksarray)) {
1774 return false;
1775 }
9b4b78fd 1776 foreach($blocksarray as $blockgroup) {
0d6b9d4f 1777 if (empty($blockgroup)) {
1778 continue;
1779 }
9b4b78fd 1780 foreach($blockgroup as $instance) {
1781 if($instance->blockid == $blockid) {
1782 return $instance;
1783 }
1784 }
1785 }
1786 return false;
1787}
1788
d4a03c00 1789// Functions for programatically adding default blocks to pages ================
0f3fe4b6 1790
9d1d606e 1791/**
1792 * Parse a list of default blocks. See config-dist for a description of the format.
d4accfc0 1793 *
9d1d606e 1794 * @param string $blocksstr
1795 * @return array
1796 */
1797function blocks_parse_default_blocks_list($blocksstr) {
f474a4e5 1798 $blocks = array();
1799 $bits = explode(':', $blocksstr);
1800 if (!empty($bits)) {
7d2a0492 1801 $leftbits = trim(array_shift($bits));
1802 if ($leftbits != '') {
1803 $blocks[BLOCK_POS_LEFT] = explode(',', $leftbits);
1804 }
f474a4e5 1805 }
1806 if (!empty($bits)) {
7d2a0492 1807 $rightbits =trim(array_shift($bits));
1808 if ($rightbits != '') {
1809 $blocks[BLOCK_POS_RIGHT] = explode(',', $rightbits);
1810 }
f474a4e5 1811 }
1812 return $blocks;
9d1d606e 1813}
5b224948 1814
9d1d606e 1815/**
1816 * @return array the blocks that should be added to the site course by default.
1817 */
1818function blocks_get_default_site_course_blocks() {
1819 global $CFG;
9b4b78fd 1820
9d1d606e 1821 if (!empty($CFG->defaultblocks_site)) {
f474a4e5 1822 return blocks_parse_default_blocks_list($CFG->defaultblocks_site);
9d1d606e 1823 } else {
f474a4e5 1824 return array(
7d2a0492 1825 BLOCK_POS_LEFT => array('site_main_menu'),
9d1d606e 1826 BLOCK_POS_RIGHT => array('course_summary', 'calendar_month')
1827 );
9b4b78fd 1828 }
9d1d606e 1829}
1830
1831/**
1832 * Add the default blocks to a course.
d4accfc0 1833 *
9d1d606e 1834 * @param object $course a course object.
1835 */
1836function blocks_add_default_course_blocks($course) {
1837 global $CFG;
1838
1839 if (!empty($CFG->defaultblocks_override)) {
1840 $blocknames = blocks_parse_default_blocks_list($CFG->defaultblocks_override);
1841
1842 } else if ($course->id == SITEID) {
1843 $blocknames = blocks_get_default_site_course_blocks();
1844
1845 } else {
1846 $defaultblocks = 'defaultblocks_' . $course->format;
1847 if (!empty($CFG->$defaultblocks)) {
1848 $blocknames = blocks_parse_default_blocks_list($CFG->$defaultblocks);
1849
1850 } else {
1d00ec6a 1851 $formatconfig = $CFG->dirroot.'/course/format/'.$course->format.'/config.php';
9311b925 1852 $format = array(); // initialize array in external file
1d00ec6a 1853 if (is_readable($formatconfig)) {
9311b925 1854 include($formatconfig);
9d1d606e 1855 }
1856 if (!empty($format['defaultblocks'])) {
1857 $blocknames = blocks_parse_default_blocks_list($format['defaultblocks']);
9b4b78fd 1858
9d1d606e 1859 } else if (!empty($CFG->defaultblocks)){
1860 $blocknames = blocks_parse_default_blocks_list($CFG->defaultblocks);
1861
1862 } else {
1863 $blocknames = array(
7d2a0492 1864 BLOCK_POS_LEFT => array(),
1865 BLOCK_POS_RIGHT => array('search_forums', 'news_items', 'calendar_upcoming', 'recent_activity')
9d1d606e 1866 );
1867 }
1868 }
9b4b78fd 1869 }
1870
f474a4e5 1871 if ($course->id == SITEID) {
1872 $pagetypepattern = 'site-index';
1873 } else {
1874 $pagetypepattern = 'course-view-*';
1875 }
9d1d606e 1876 $page = new moodle_page();
1877 $page->set_course($course);
f474a4e5 1878 $page->blocks->add_blocks($blocknames, $pagetypepattern);
9d1d606e 1879}
1880
1881/**
1882 * Add the default system-context blocks. E.g. the admin tree.
1883 */
1884function blocks_add_default_system_blocks() {
03d9401e
MD
1885 global $DB;
1886
9d1d606e 1887 $page = new moodle_page();
1888 $page->set_context(get_context_instance(CONTEXT_SYSTEM));
3406acde 1889 $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('navigation', 'settings')), '*', null, true);
7d2a0492 1890 $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_bookmarks')), 'admin-*', null, null, 2);
03d9401e
MD
1891
1892 if ($defaultmypage = $DB->get_record('my_pages', array('userid'=>null, 'name'=>'__default', 'private'=>1))) {
1893 $subpagepattern = $defaultmypage->id;
1894 } else {
1895 $subpagepattern = null;
1896 }
1897
0184a3fd 1898 $page->blocks->add_blocks(array(BLOCK_POS_RIGHT => array('private_files', 'online_users'), 'content' => array('course_overview')), 'my-index', $subpagepattern, false);
9d1d606e 1899}