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