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