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