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