added comment for new specialization function
[moodle.git] / lib / blocklib.php
CommitLineData
dcb1bd3c 1<?php //$Id$
0f3fe4b6 2
3//This library includes all the necessary stuff to use blocks in course pages
4
0f3fe4b6 5define('BLOCK_MOVE_LEFT', 0x01);
6define('BLOCK_MOVE_RIGHT', 0x02);
7define('BLOCK_MOVE_UP', 0x04);
8define('BLOCK_MOVE_DOWN', 0x08);
9b4b78fd 9define('BLOCK_CONFIGURE', 0x10);
0f3fe4b6 10
9b4b78fd 11define('MOODLE_PAGE_COURSE', 'course');
12define('BLOCK_POS_LEFT', 'l');
13define('BLOCK_POS_RIGHT', 'r');
0e9af917 14
9b4b78fd 15function page_get_format($page) {
16 switch($page->type) {
17 case MOODLE_PAGE_COURSE:
18 if($page->id == SITEID) {
19 return 'site';
20 }
21 else {
22 $course = get_record('course', 'id', $page->id);
23 return $course->format;
24 }
25 break;
0e9af917 26 }
9b4b78fd 27 return NULL;
28}
29
30function blocks_get_missing($page, $pageblocks) {
31 $missingblocks = array();
32 $allblocks = blocks_get_record();
33
34 if(!empty($allblocks)) {
35 foreach($allblocks as $block) {
36 if($block->visible && (!blocks_find_block($block->id, $pageblocks) || $block->multiple)) {
37 // And if it's applicable for display in this format...
38 $formats = block_method_result($block->name, 'applicable_formats');
39 $pageformat = page_get_format($page);
40 if(isset($formats[$pageformat]) ? $formats[$pageformat] : !empty($formats['all'])) {
41 // Add it to the missing blocks
42 $missingblocks[] = $block->id;
43 }
44 }
45 }
0e9af917 46 }
9b4b78fd 47 return $missingblocks;
48}
49
50function blocks_remove_inappropriate($page) {
51 $pageblocks = blocks_get_by_page($page);
52
53 if(empty($pageblocks)) {
54 return;
0e9af917 55 }
56
9b4b78fd 57 switch($page->type) {
58 case MOODLE_PAGE_COURSE:
59 $course = get_record('course', 'id', $page->id);
60 if($page->id == SITEID) {
61 $pageformat = 'site';
0e9af917 62 }
9b4b78fd 63 else {
64 $pageformat = $course->format;
65 }
66 break;
67 default:
68 return;
69 break;
0e9af917 70 }
9b4b78fd 71
72 foreach($pageblocks as $position) {
73 foreach($position as $instance) {
74 $block = blocks_get_record($instance->blockid);
75 $formats = block_method_result($block->name, 'applicable_formats');
76 if(! (isset($formats[$pageformat]) ? $formats[$pageformat] : !empty($formats['all']))) {
77 // Translation: if the course format is explicitly accepted/rejected, use
78 // that setting. Otherwise, fallback to the 'all' format. The empty() test
79 // uses the trick that empty() fails if 'all' is either !isset() or false.
80
81 blocks_delete_instance($instance);
0e9af917 82 }
83 }
84 }
9b4b78fd 85}
0e9af917 86
9b4b78fd 87function blocks_delete_instance($instance) {
88 global $CFG;
89
90 delete_records('block_instance', 'id', $instance->id);
91 // And now, decrement the weight of all blocks after this one
92 execute_sql('UPDATE '.$CFG->prefix.'block_instance SET weight = weight - 1 WHERE pagetype = \''.$instance->pagetype.
93 '\' AND pageid = '.$instance->pageid.' AND position = \''.$instance->position.
94 '\' AND weight > '.$instance->weight, false);
0e9af917 95}
0f3fe4b6 96
33bee34c 97// Returns the case-sensitive name of the class' constructor function. This includes both
98// PHP5- and PHP4-style constructors. If no appropriate constructor can be found, returns NULL.
99// If there is no such class, returns boolean false.
100function get_class_constructor($classname) {
101 // Caching
102 static $constructors = array();
103
104 if(!class_exists($classname)) {
105 return false;
106 }
107
108 // Tests indicate this doesn't hurt even in PHP5.
109 $classname = strtolower($classname);
110
111 // Return cached value, if exists
112 if(isset($constructors[$classname])) {
113 return $constructors[$classname];
114 }
115
116 // Get a list of methods. After examining several different ways of
117 // doing the check, (is_callable, method_exists, function_exists etc)
118 // it seems that this is the most reliable one.
119 $methods = get_class_methods($classname);
120
121 // PHP5 constructor?
122 if(phpversion() >= '5') {
123 if(in_array('__construct', $methods)) {
124 return $constructors[$classname] = '__construct';
125 }
126 }
127
128 // If we have PHP5 but no magic constructor, we have to lowercase the methods
129 $methods = array_map('strtolower', $methods);
130
131 if(in_array($classname, $methods)) {
132 return $constructors[$classname] = $classname;
133 }
134
135 return $constructors[$classname] = NULL;
136}
137
0f3fe4b6 138//This function retrieves a method-defined property of a class WITHOUT instantiating an object
139//It seems that the only way to use the :: operator with variable class names is eval() :(
140//For caveats with this technique, see the PHP docs on operator ::
141function block_method_result($blockname, $method) {
142 if(!block_load_class($blockname)) {
143 return NULL;
144 }
145 return eval('return CourseBlock_'.$blockname.'::'.$method.'();');
146}
147
148//This function creates a new object of the specified block class
9b4b78fd 149function block_instance($blockname, $instance = NULL) {
0f3fe4b6 150 if(!block_load_class($blockname)) {
151 return false;
152 }
153 $classname = 'CourseBlock_'.$blockname;
9b4b78fd 154 $retval = New $classname;
155 if($instance !== NULL) {
156 $retval->load_instance($instance);
157 }
158 return $retval;
0f3fe4b6 159}
160
161//This function loads the necessary class files for a block
162//Whenever you want to load a block, use this first
163function block_load_class($blockname) {
164 global $CFG;
165
166 @include_once($CFG->dirroot.'/blocks/moodleblock.class.php');
167 $classname = 'CourseBlock_'.$blockname;
168 @include_once($CFG->dirroot.'/blocks/'.$blockname.'/block_'.$blockname.'.php');
169
170 // After all this, return value indicating success or failure
171 return class_exists($classname);
172}
173
9b4b78fd 174function blocks_have_content($instances) {
175 foreach($instances as $instance) {
176 if(!$instance->visible) {
177 continue;
178 }
179 $record = blocks_get_record($instance->blockid);
180 $obj = block_instance($record->name, $instance);
181 $content = $obj->get_content();
182 $type = $obj->get_content_type();
183 switch($type) {
184 case BLOCK_TYPE_LIST:
185 if(!empty($content->items) || !empty($content->footer)) {
186 return true;
187 }
188 break;
189 case BLOCK_TYPE_TEXT:
190 case BLOCK_TYPE_NUKE:
191 if(!empty($content->text) || !empty($content->footer)) {
192 return true;
193 }
194 break;
0f3fe4b6 195 }
196 }
9b4b78fd 197
0f3fe4b6 198 return false;
199}
200
201//This function print the one side of blocks in course main page
9b4b78fd 202function blocks_print_group($page, $instances) {
203
204 if(empty($instances)) {
205 return;
206 }
0f3fe4b6 207
9b4b78fd 208 switch($page->type) {
209 case MOODLE_PAGE_COURSE:
210 $isediting = isediting($page->id);
211 $ismoving = ismoving($page->id);
212 $isteacheredit = isteacheredit($page->id);
213 break;
214 }
0f3fe4b6 215
9b4b78fd 216 // Include the base class
217 @include_once($CFG->dirroot.'/blocks/moodleblock.class.php');
218 if(!class_exists('moodleblock')) {
219 error('Class MoodleBlock is not defined or file not found for /course/blocks/moodleblock.class.php');
220 }
0f3fe4b6 221
9b4b78fd 222 $maxweight = max(array_keys($instances));
0f3fe4b6 223
9b4b78fd 224 foreach($instances as $instance) {
225 $block = blocks_get_record($instance->blockid);
226 if(!$block->visible) {
227 // Disabled by the admin
228 continue;
229 }
0f3fe4b6 230
9b4b78fd 231 $obj = block_instance($block->name, $instance);
0f3fe4b6 232
9b4b78fd 233 if ($isediting && !$ismoving && $isteacheredit) {
234 $options = 0;
235 $options |= BLOCK_MOVE_UP * ($instance->weight != 0);
236 $options |= BLOCK_MOVE_DOWN * ($instance->weight != $maxweight);
237 $options |= BLOCK_MOVE_RIGHT * ($instance->position != BLOCK_POS_RIGHT);
238 $options |= BLOCK_MOVE_LEFT * ($instance->position != BLOCK_POS_LEFT);
239 $options |= BLOCK_CONFIGURE * ($block->multiple);
240 $obj->add_edit_controls($options);
241 }
0f3fe4b6 242
9b4b78fd 243 if(!$instance->visible) {
244 if($isediting) {
245 $obj->print_shadow();
0f3fe4b6 246 }
247 }
9b4b78fd 248 else {
249 $obj->print_block();
250 }
0f3fe4b6 251 }
252}
253
254//This iterates over an array of blocks and calculates the preferred width
9b4b78fd 255function blocks_preferred_width($instances) {
0f3fe4b6 256 $width = 0;
257
9b4b78fd 258 if(empty($instances) || !is_array($instances)) {
0f3fe4b6 259 return 0;
260 }
9b4b78fd 261 foreach($instances as $instance) {
262 if(!$instance->visible) {
fe78a3dc 263 continue;
0c9c6363 264 }
9b4b78fd 265 $block = blocks_get_record($instance->blockid);
266 $pref = block_method_result($block->name, 'preferred_width');
267 if($pref === NULL) {
268 continue;
269 }
270 if($pref > $width) {
271 $width = $pref;
0f3fe4b6 272 }
273 }
274 return $width;
275}
276
9b4b78fd 277function blocks_get_record($blockid = NULL, $invalidate = false) {
278 static $cache = NULL;
0f3fe4b6 279
9b4b78fd 280 if($invalidate || empty($cache)) {
281 $cache = get_records('block');
282 }
0f3fe4b6 283
9b4b78fd 284 if($blockid === NULL) {
285 return $cache;
286 }
0f3fe4b6 287
9b4b78fd 288 return (isset($cache[$blockid])? $cache[$blockid] : false);
289}
290
291function blocks_find_block($blockid, $blocksarray) {
292 foreach($blocksarray as $blockgroup) {
293 foreach($blockgroup as $instance) {
294 if($instance->blockid == $blockid) {
295 return $instance;
296 }
297 }
298 }
299 return false;
300}
301
302function blocks_find_instance($instanceid, $blocksarray) {
303 foreach($blocksarray as $subarray) {
304 foreach($subarray as $instance) {
305 if($instance->id == $instanceid) {
306 return $instance;
307 }
308 }
309 }
310 return false;
311}
312
313function blocks_execute_action($page, &$pageblocks, $blockaction, $instanceorid) {
314 global $CFG;
315
316 if(is_int($instanceorid)) {
317 $blockid = $instanceorid;
318 }
319 else if(is_object($instanceorid)) {
320 $instance = $instanceorid;
321 }
0f3fe4b6 322
323 switch($blockaction) {
9b4b78fd 324 case 'config':
325 // Series of ugly hacks following...
326 global $course, $USER; // First hack; we need $course to print out the headers
327 $block = blocks_get_record($instance->blockid);
328 $blockobject = block_instance($block->name, $instance);
329 if ($blockobject === false) {
330 continue;
331 }
332 optional_param('submitted', 0, PARAM_INT);
333
27ec21a0 334 // Define the data we're going to silently include in the instance config form here,
9b4b78fd 335 // so we can strip them from the submitted data BEFORE serializing it.
336 $hiddendata = array(
337 'sesskey' => $USER->sesskey,
338 'id' => $course->id,
339 'instanceid' => $instance->id,
340 'blockaction' => 'config'
341 );
342 // The 'id' thing is a crude hack in all its glory...
343 // Redirecting the form submission back to ourself with qualified_me() was a good idea since otherwise
27ec21a0 344 // we'd need to have an "extra" script that would have to infer where to redirect us back just from
9b4b78fd 345 // the data in $instance (pagetype and pageid). But, "ourself" is most likely course/view.php and it needs
346 // a course id. Hence the hack.
347
348 if($data = data_submitted()) {
349 $remove = array_keys($hiddendata);
350 foreach($remove as $item) {
351 unset($data->$item);
0f3fe4b6 352 }
9b4b78fd 353 if(!$blockobject->instance_config_save($data)) {
354 error('Error saving block configuration');
0f3fe4b6 355 }
9b4b78fd 356 // And nothing more, continue with displaying the page
0f3fe4b6 357 }
9b4b78fd 358 else {
27ec21a0 359 $loggedinas = '<p class="logininfo">'. user_login_string($course, $USER) .'</p>';
9b4b78fd 360 print_header(get_string('blockconfigin', 'moodle', $course->fullname), $course->fullname, $course->shortname,
27ec21a0 361 '', '', true, update_course_icon($course->id), $loggedinas);
9b4b78fd 362 print_heading(get_string('blockconfiga', 'moodle', $block->name));
27ec21a0 363 echo '<form method="post" action="'. strip_querystring(qualified_me()) .'">'; // This I wouldn't call a hack but it sure looks cheeky
9b4b78fd 364 echo '<p>';
365 foreach($hiddendata as $name => $val) {
27ec21a0 366 echo '<input type="hidden" name="'. $name .'" value="'. $val .'" />';
0f3fe4b6 367 }
9b4b78fd 368 echo '</p>';
369 $blockobject->instance_config_print();
370 echo '</form>';
371 print_footer();
372 die(); // Do not go on with the other course-related stuff
0f3fe4b6 373 }
374 break;
9b4b78fd 375 case 'toggle':
376 if(empty($instance)) {
377 error('Invalid block instance for '.$blockaction);
0f3fe4b6 378 }
9b4b78fd 379 $instance->visible = ($instance->visible) ? 0 : 1;
380 update_record('block_instance', $instance);
381 break;
382 case 'delete':
383 if(empty($instance)) {
384 error('Invalid block instance for '.$blockaction);
0f3fe4b6 385 }
9b4b78fd 386 blocks_delete_instance($instance);
0f3fe4b6 387 break;
388 case 'moveup':
9b4b78fd 389 if(empty($instance)) {
390 error('Invalid block instance for '.$blockaction);
391 }
392 $other = $pageblocks[$instance->position][$instance->weight - 1];
393 if(!empty($other)) {
394 --$instance->weight;
395 ++$other->weight;
396 update_record('block_instance', $instance);
397 update_record('block_instance', $other);
0f3fe4b6 398 }
399 break;
400 case 'movedown':
9b4b78fd 401 if(empty($instance)) {
402 error('Invalid block instance for '.$blockaction);
403 }
404 $other = $pageblocks[$instance->position][$instance->weight + 1];
405 if(!empty($other)) {
406 ++$instance->weight;
407 --$other->weight;
408 update_record('block_instance', $instance);
409 update_record('block_instance', $other);
0f3fe4b6 410 }
9b4b78fd 411
0f3fe4b6 412 break;
9b4b78fd 413 case 'moveleft':
414 if(empty($instance)) {
415 error('Invalid block instance for '.$blockaction);
416 }
417 $sql = '';
418 switch($instance->position) {
419 case BLOCK_POS_RIGHT:
420 // To preserve the continuity of block weights
421 $sql = 'UPDATE '.$CFG->prefix.'block_instance SET weight = weight - 1 WHERE pagetype = \''.$instance->pagetype.
422 '\' AND pageid = '.$instance->pageid.' AND position = \''.$instance->position.
423 '\' AND weight > '.$instance->weight;
424
425 $instance->position = BLOCK_POS_LEFT;
426 $maxweight = max(array_keys($pageblocks[$instance->position]));
427 $instance->weight = $maxweight + 1;
428 break;
429 }
430 if($sql) {
431 update_record('block_instance', $instance);
432 execute_sql($sql, false);
0f3fe4b6 433 }
434 break;
9b4b78fd 435 case 'moveright':
436 if(empty($instance)) {
437 error('Invalid block instance for '.$blockaction);
438 }
439 $sql = '';
440 switch($instance->position) {
441 case BLOCK_POS_LEFT:
442 // To preserve the continuity of block weights
443 $sql = 'UPDATE '.$CFG->prefix.'block_instance SET weight = weight - 1 WHERE pagetype = \''.$instance->pagetype.
444 '\' AND pageid = '.$instance->pageid.' AND position = \''.$instance->position.
445 '\' AND weight > '.$instance->weight;
446
447 $instance->position = BLOCK_POS_RIGHT;
448 $maxweight = max(array_keys($pageblocks[$instance->position]));
449 $instance->weight = $maxweight + 1;
450 break;
451 }
452 if($sql) {
453 update_record('block_instance', $instance);
454 execute_sql($sql, false);
455 }
456 break;
457 case 'add':
458 // Add a new instance of this block, if allowed
459 $block = blocks_get_record($blockid);
0f3fe4b6 460
9b4b78fd 461 if(!$block->visible) {
462 // Only allow adding if the block is enabled
463 return false;
464 }
0f3fe4b6 465
9b4b78fd 466 $weight = get_record_sql('SELECT 1, max(weight) + 1 AS nextfree FROM '.$CFG->prefix.'block_instance WHERE pageid = '.$page->id.' AND pagetype = \''.$page->type.'\' AND position = \''.BLOCK_POS_RIGHT.'\'');
467
468 $newinstance = new stdClass;
469 $newinstance->blockid = $blockid;
470 $newinstance->pageid = $page->id;
471 $newinstance->pagetype = $page->type;
472 $newinstance->position = BLOCK_POS_RIGHT;
473 $newinstance->weight = $weight->nextfree;
474 $newinstance->visible = 1;
475 $newinstance->configdata = '';
476 insert_record('block_instance', $newinstance);
477 break;
478 }
0f3fe4b6 479}
480
9b4b78fd 481function blocks_get_by_page($page) {
482 $blocks = get_records_select('block_instance', 'pageid = '.$page->id.' AND pagetype = \''.$page->type.'\'', 'position, weight');
0f3fe4b6 483
9b4b78fd 484 $arr = array(BLOCK_POS_LEFT => array(), BLOCK_POS_RIGHT => array());
485 if(empty($blocks)) {
486 return $arr;
487 }
0f3fe4b6 488
9b4b78fd 489 foreach($blocks as $block) {
490 $arr[$block->position][$block->weight] = $block;
0f3fe4b6 491 }
492
9b4b78fd 493 return $arr;
494}
0f3fe4b6 495
9b4b78fd 496//This function prints the block to admin blocks as necessary
497function blocks_print_adminblock($page, $missingblocks) {
498 global $USER;
0f3fe4b6 499
9b4b78fd 500 $strblocks = get_string('blocks');
501 $stradd = get_string('add');
502 if (!empty($missingblocks)) {
503 foreach ($missingblocks as $blockid) {
504 $block = blocks_get_record($blockid);
505
506 switch($page->type) {
507 case MOODLE_PAGE_COURSE:
508 $course = get_record('course', 'id', $page->id);
509 break;
510 default: die('unknown pagetype: '.$page->type);
511 }
0f3fe4b6 512
9b4b78fd 513 $blockobject = block_instance($block->name);
514 if ($blockobject === false) {
515 continue;
516 }
517 $menu[$block->id] = $blockobject->get_title();
518 }
0f3fe4b6 519
9b4b78fd 520 if($page->id == SITEID) {
521 $target = 'index.php';
522 }
523 else {
524 $target = 'view.php';
525 }
526 $content = popup_form($target.'?id='.$course->id.'&amp;sesskey='.$USER->sesskey.'&amp;blockaction=add&amp;blockid=',
527 $menu, 'add_block', '', "$stradd...", '', '', true);
528 $content = '<div align="center">'.$content.'</div>';
529 print_side_block($strblocks, $content, NULL, NULL, NULL);
0f3fe4b6 530 }
0f3fe4b6 531}
532
9b4b78fd 533function blocks_repopulate_page($page) {
534 global $CFG;
5b224948 535
9b4b78fd 536 /// If the site override has been defined, it is the only valid one.
537 if (!empty($CFG->defaultblocks_override)) {
538 $blocknames = $CFG->defaultblocks_override;
539 }
540 /// Else, try to find out what page this is
541 else {
542 switch($page->type) {
543 case MOODLE_PAGE_COURSE:
544 // Is it the site?
545 if($page->id == SITEID) {
546 if (!empty($CFG->defaultblocks_site)) {
547 $blocknames = $CFG->defaultblocks_site;
548 }
549 /// Failsafe - in case nothing was defined.
550 else {
551 $blocknames = 'site_main_menu,admin,course_list:course_summary,calendar_month';
0f3fe4b6 552 }
89adb174 553 }
9b4b78fd 554 // It's a normal course, so do it accodring to the course format
89adb174 555 else {
9b4b78fd 556 $course = get_record('course', 'id', $page->id);
557 if (!empty($CFG->{'defaultblocks_'.$course->format})) {
558 $blocknames = $CFG->{'defaultblocks_'.$course->format};
559 }
560 else {
561 $format_config = $CFG->dirroot.'/course/format/'.$course->format.'/config.php';
562 if (@is_file($format_config) && is_readable($format_config)) {
563 require($format_config);
564 }
565 if (!empty($format['defaultblocks'])) {
566 $blocknames = $format['defaultblocks'];
567 }
568 else if (!empty($CFG->defaultblocks)){
569 $blocknames = $CFG->defaultblocks;
570 }
571 /// Failsafe - in case nothing was defined.
572 else {
573 $blocknames = 'participants,activity_modules,search_forums,admin,course_list:news_items,calendar_upcoming,recent_activity';
574 }
575 }
89adb174 576 }
9b4b78fd 577 break;
578 default:
579 error('Invalid page type: '.$page->type);
580 break;
581 }
582 }
583
584 $allblocks = blocks_get_record();
585
586 if(empty($allblocks)) {
587 error('Could not retrieve blocks from the database');
588 }
589
590 // We have the blocks, make up two arrays
591 $left = '';
592 $right = '';
593 @list($left, $right) = explode(':', $blocknames);
594 $instances = array(BLOCK_POS_LEFT => explode(',', $left), BLOCK_POS_RIGHT => explode(',', $right));
595
596 // Arrays are fine, now we have to correlate block names to ids
597 $idforname = array();
598 foreach($allblocks as $block) {
599 $idforname[$block->name] = $block->id;
600 }
601
602 // Ready to start creating block instances, but first drop any existing ones
603 delete_records('block_instance', 'pageid', $page->id, 'pagetype', $page->type);
604
605 foreach($instances as $position => $blocknames) {
606 $weight = 0;
607 foreach($blocknames as $blockname) {
608 $newinstance = new stdClass;
609 $newinstance->blockid = $idforname[$blockname];
610 $newinstance->pageid = $page->id;
611 $newinstance->pagetype = $page->type;
612 $newinstance->position = $position;
613 $newinstance->weight = $weight;
614 $newinstance->visible = 1;
615 $newinstance->configdata = '';
616 insert_record('block_instance', $newinstance);
617 $weight++;
0f3fe4b6 618 }
619 }
9b4b78fd 620
621 return true;
0f3fe4b6 622}
623
624function upgrade_blocks_db($continueto) {
625/// This function upgrades the blocks tables, if necessary
626/// It's called from admin/index.php
627
628 global $CFG, $db;
629
630 require_once ("$CFG->dirroot/blocks/version.php"); // Get code versions
631
632 if (empty($CFG->blocks_version)) { // Blocks have never been installed.
633 $strdatabaseupgrades = get_string("databaseupgrades");
634 print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades,
635 "", "", false, "&nbsp;", "&nbsp;");
636
637 $db->debug=true;
638 if (modify_database("$CFG->dirroot/blocks/db/$CFG->dbtype.sql")) {
639 $db->debug = false;
640 if (set_config("blocks_version", $blocks_version)) {
641 notify(get_string("databasesuccess"), "green");
642 notify(get_string("databaseupgradeblocks", "", $blocks_version));
643 print_continue($continueto);
644 exit;
645 } else {
646 error("Upgrade of blocks system failed! (Could not update version in config table)");
647 }
648 } else {
649 error("Blocks tables could NOT be set up successfully!");
650 }
651 }
652
653
654 if ($blocks_version > $CFG->blocks_version) { // Upgrade tables
655 $strdatabaseupgrades = get_string("databaseupgrades");
656 print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades);
657
658 require_once ("$CFG->dirroot/blocks/db/$CFG->dbtype.php");
659
660 $db->debug=true;
661 if (blocks_upgrade($CFG->blocks_version)) {
662 $db->debug=false;
663 if (set_config("blocks_version", $blocks_version)) {
664 notify(get_string("databasesuccess"), "green");
665 notify(get_string("databaseupgradeblocks", "", $blocks_version));
666 print_continue($continueto);
667 exit;
668 } else {
669 error("Upgrade of blocks system failed! (Could not update version in config table)");
670 }
671 } else {
672 $db->debug=false;
673 error("Upgrade failed! See blocks/version.php");
674 }
675
676 } else if ($blocks_version < $CFG->blocks_version) {
677 notify("WARNING!!! The code you are using is OLDER than the version that made these databases!");
678 }
679}
680
681//This function finds all available blocks and install them
682//into blocks table or do all the upgrade process if newer
683function upgrade_blocks_plugins($continueto) {
684
685 global $CFG;
686
687 $blocktitles = array();
688 $invalidblocks = array();
689 $validblocks = array();
690 $notices = array();
691
692 //Count the number of blocks in db
9b4b78fd 693 $blockcount = count_records('block');
0f3fe4b6 694 //If there isn't records. This is the first install, so I remember it
695 if ($blockcount == 0) {
696 $first_install = true;
697 } else {
698 $first_install = false;
699 }
700
701 $site = get_site();
702
9b4b78fd 703 if (!$blocks = get_list_of_plugins('blocks', 'db') ) {
0f3fe4b6 704 error("No blocks installed!");
705 }
706
9b4b78fd 707 include_once($CFG->dirroot.'/blocks/moodleblock.class.php');
0f3fe4b6 708 if(!class_exists('moodleblock')) {
709 error('Class MoodleBlock is not defined or file not found for /blocks/moodleblock.class.php');
710 }
711
712 foreach ($blocks as $blockname) {
713
5216e2c6 714 if ($blockname == "NEWBLOCK") { // Someone has unzipped the template, ignore it
0f3fe4b6 715 continue;
716 }
717
718 $fullblock = "$CFG->dirroot/blocks/$blockname";
719
9b4b78fd 720 if ( is_readable($fullblock.'/block_'.$blockname.'.php')) {
721 include_once($fullblock.'/block_'.$blockname.'.php');
0f3fe4b6 722 } else {
723 $notices[] = "Block $blockname: ".$fullblock."/block_".$blockname.".php was not readable";
724 continue;
725 }
726
9b4b78fd 727 if ( @is_dir("$fullblock/db/")) {
728 if ( @is_readable("$fullblock/db/$CFG->dbtype.php")) {
828c4e09 729 include_once("$fullblock/db/$CFG->dbtype.php"); # defines upgrading function
730 } else {
731 $notices[] ="Block $blockname: $fullblock/db/$CFG->dbtype.php was not readable";
732 continue;
733 }
0f3fe4b6 734 }
735
736 $classname = 'CourseBlock_'.$blockname;
737 if(!class_exists($classname)) {
738 $notices[] = "Block $blockname: $classname not implemented";
739 continue;
740 }
741
9b4b78fd 742 // Here is the place to see if the block implements a constructor (old style),
743 // an init() function (new style) or nothing at all (error time).
744
33bee34c 745 $constructor = get_class_constructor($classname);
746 if(empty($constructor)) {
0f3fe4b6 747 // No constructor
748 $notices[] = "Block $blockname: class does not have a constructor";
749 $invalidblocks[] = $blockname;
750 continue;
751 }
9b4b78fd 752 $methods = get_class_methods($classname);
753 if(!in_array('init', $methods)) {
754 // This is an old-style block
755 $notices[] = "Block $blockname is an old style block and needs to be updated by a programmer.";
756 $invalidblocks[] = $blockname;
757 continue;
758 }
0f3fe4b6 759
9b4b78fd 760 $block = new stdClass; // This may be used to update the db below
761 $blockobj = new $classname; // This is what we 'll be testing
0f3fe4b6 762
763 // Inherits from MoodleBlock?
33bee34c 764 if(!is_subclass_of($blockobj, 'moodleblock')) {
0f3fe4b6 765 $notices[] = "Block $blockname: class does not inherit from MoodleBlock";
766 continue;
767 }
768
769 // OK, it's as we all hoped. For further tests, the object will do them itself.
770 if(!$blockobj->_self_test()) {
771 $notices[] = "Block $blockname: self test failed";
772 continue;
773 }
774 $block->version = $blockobj->get_version();
775
776 if (!isset($block->version)) {
777 $notices[] = "Block $blockname: hasn't version support";
778 continue;
779 }
780
781 $block->name = $blockname; // The name MUST match the directory
782 $blocktitle = $blockobj->get_title();
783
9b4b78fd 784 if ($currblock = get_record('block', 'name', $block->name)) {
0f3fe4b6 785 if ($currblock->version == $block->version) {
786 // do nothing
787 } else if ($currblock->version < $block->version) {
788 if (empty($updated_blocks)) {
789 $strblocksetup = get_string("blocksetup");
790 print_header($strblocksetup, $strblocksetup, $strblocksetup, "", "", false, "&nbsp;", "&nbsp;");
791 }
b88f7004 792 print_heading('New version of '.$blocktitle.' ('.$block->name.') exists');
793 $upgrade_function = $block->name.'_upgrade';
0f3fe4b6 794 if (function_exists($upgrade_function)) {
795 $db->debug=true;
796 if ($upgrade_function($currblock->version, $block)) {
b88f7004 797
798 $upgradesuccess = true;
0f3fe4b6 799 } else {
b88f7004 800 $upgradesuccess = false;
801 }
802 $db->debug=false;
803 }
804 else {
805 $upgradesuccess = true;
806 }
807 if(!$upgradesuccess) {
808 notify("Upgrading block $block->name from $currblock->version to $block->version FAILED!");
809 }
810 else {
9b4b78fd 811 // OK so far, now update the block record
b88f7004 812 $block->id = $currblock->id;
9b4b78fd 813 if (! update_record('block', $block)) {
814 error("Could not update block $block->name record in block table!");
0f3fe4b6 815 }
b88f7004 816 notify(get_string('blocksuccess', '', $blocktitle), 'green');
817 echo '<hr />';
0f3fe4b6 818 }
819 $updated_blocks = true;
820 } else {
821 error("Version mismatch: block $block->name can't downgrade $currblock->version -> $block->version !");
822 }
823
824 } else { // block not installed yet, so install it
825
9b4b78fd 826 // If it allows multiples, start with it enabled
827 $block->multiple = $blockobj->instance_allow_multiple();
828
0f3fe4b6 829 // [pj] Normally this would be inline in the if, but we need to
830 // check for NULL (necessary for 4.0.5 <= PHP < 4.2.0)
831 $conflictblock = array_search($blocktitle, $blocktitles);
832 if($conflictblock !== false && $conflictblock !== NULL) {
0f3fe4b6 833 // Duplicate block titles are not allowed, they confuse people
834 // AND PHP's associative arrays ;)
835 error('<strong>Naming conflict</strong>: block <strong>'.$block->name.'</strong> has the same title with an existing block, <strong>'.$conflictblock.'</strong>!');
836 }
837 if (empty($updated_blocks)) {
838 $strblocksetup = get_string("blocksetup");
839 print_header($strblocksetup, $strblocksetup, $strblocksetup, "", "", false, "&nbsp;", "&nbsp;");
840 }
841 print_heading($block->name);
842 $updated_blocks = true;
843 $db->debug = true;
a71bfa1c 844 @set_time_limit(0); // To allow slow databases to complete the long SQL
828c4e09 845 if (!is_dir("$fullblock/db/") || modify_database("$fullblock/db/$CFG->dbtype.sql")) {
0f3fe4b6 846 $db->debug = false;
9b4b78fd 847 if ($block->id = insert_record('block', $block)) {
0f3fe4b6 848 notify(get_string('blocksuccess', '', $blocktitle), 'green');
9a58f7cb 849 echo "<hr />";
0f3fe4b6 850 } else {
851 error("$block->name block could not be added to the block list!");
852 }
853 } else {
854 error("Block $block->name tables could NOT be set up successfully!");
855 }
856 }
857
858 $blocktitles[$block->name] = $blocktitle;
859 }
860
861 if(!empty($notices)) {
862 foreach($notices as $notice) {
863 notify($notice);
864 }
865 }
866
9b4b78fd 867 // Finally, if we are in the first_install of BLOCKS (this means that we are
868 // upgrading from Moodle < 1.3), put blocks in all existing courses.
0f3fe4b6 869 if ($first_install) {
870 //Iterate over each course
9b4b78fd 871 if ($courses = get_records('course')) {
0f3fe4b6 872 foreach ($courses as $course) {
9b4b78fd 873 $page = new stdClass;
874 $page->type = MOODLE_PAGE_COURSE;
875 $page->id = $course->id;
876 blocks_repopulate_page($page);
0f3fe4b6 877 }
878 }
879 }
880
e02c35b2 881 if (!empty($CFG->siteblocksadded)) { /// This is a once-off hack to make a proper upgrade
9b4b78fd 882 $page = new stdClass;
883 $page->type = MOODLE_PAGE_COURSE;
884 $page->id = SITEID;
885 blocks_repopulate_page($page);
e02c35b2 886 delete_records('config', 'name', 'siteblocksadded');
887 }
888
0f3fe4b6 889 if (!empty($updated_blocks)) {
890 print_continue($continueto);
891 die;
892 }
893}
894
0f3fe4b6 895//This function returns the id of the block, searching it by name
896function block_get_id_by_name ($blockname) {
897
9b4b78fd 898 if ($block = get_record('block','name',$blockname)) {
0f3fe4b6 899 return $block->id;
900 } else {
901 return 0;
902 }
903}
904
905//This function returns the name of the block, searching it by id
906function block_get_name_by_id ($blockid) {
907
9b4b78fd 908 if ($block = get_record('block','id',$blockid)) {
0f3fe4b6 909 return $block->name;
910 } else {
911 return NULL;
912 }
913}
914
915//This function return the necessary contents to update course->blockinfo
916//with default values. It accepts a list of block_names as parameter. They
917//will be converted to their blockids equivalent. If a course is specified
918//then the function will update the field too!
919
e02c35b2 920function blocks_get_default_blocks ($courseid = NULL, $blocknames = '') {
89adb174 921
a7b44978 922 global $CFG;
923
924 if (empty($blocknames)) {
25d18413 925 if (!empty($CFG->defaultblocks_override)) {
926 $blocknames = $CFG->defaultblocks_override;
a7b44978 927 } else {
25d18413 928 $blocknames = $CFG->defaultblocks;
a7b44978 929 }
930 }
0f3fe4b6 931
9b4b78fd 932 // Make up and store the blockinfo field
0f3fe4b6 933}
934
25d18413 935// This function returns the appropriate block default configuration string
936// according to the $format argument. It will return the site override defined
937// in the site config, a format override defined in the site config, a specific
938// config defined in the course format config, or the site default.
939// To request the site format, leave $format blank.
940function blocks_get_config_default ($cformat='') {
941
942 global $CFG;
943
944 /// If the site override has been defined, it is the only valid one.
945 if (!empty($CFG->defaultblocks_override)) {
946 return $CFG->defaultblocks_override;
947 }
948 /// If not format is specified, return the site default.
3d90760a 949 else if ($cformat == '' || $cformat == 'site') {
25d18413 950 if (!empty($CFG->defaultblocks_site)) {
951 return $CFG->defaultblocks_site;
952 }
658724df 953 /// Failsafe - in case nothing was defined.
25d18413 954 else {
658724df 955 return 'site_main_menu,admin,course_list:course_summary,calendar_month';
25d18413 956 }
957 }
958 /// Return the appropriate block string for the format.
959 else if (!empty($CFG->{'defaultblocks_'.$cformat})) {
960 return $CFG->{'defaultblocks_'.$cformat};
961 }
962 else {
963 $format_config = $CFG->dirroot.'/course/format/'.$cformat.'/config.php';
eceb9c5c 964 if (@is_file($format_config) && is_readable($format_config)) {
25d18413 965 require($format_config);
966 }
967 if (!empty($format['defaultblocks'])) {
968 return $format['defaultblocks'];
969 }
658724df 970 else if (!empty($CFG->defaultblocks)){
25d18413 971 return $CFG->defaultblocks;
972 }
658724df 973 /// Failsafe - in case nothing was defined.
974 else {
975 return 'participants,activity_modules,search_forums,admin,course_list:news_items,calendar_upcoming,recent_activity';
976 }
25d18413 977 }
978}
979
229f852a 980//This function will return the names representation of the blockinfo field.
981//It's used to include that info in backups. To restore we'll use the
982//blocks_get_block_ids() function. It makes the opposite conversion
983//(from names to ids)
984function blocks_get_block_names ($blockinfo) {
985
986 //Calculate left and right blocks
987 $blocksn = $blockinfo;
988 $delimpos = strpos($blocksn, ':');
989
990 if($delimpos === false) {
991 // No ':' found, we have all left blocks
992 $leftblocksn = explode(',', $blocksn);
993 $rightblocksn = array();
994 } else if($delimpos === 0) {
995 // ':' at start of string, we have all right blocks
996 $blocksn = substr($blocksn, 1);
997 $leftblocksn = array();
998 $rightblocksn = explode(',', $blocksn);
999 }
1000 else {
1001 // Both left and right blocks
1002 $leftpartn = substr($blocksn, 0, $delimpos);
1003 $rightpartn = substr($blocksn, $delimpos + 1);
1004 $leftblocksn = explode(',', $leftpartn);
1005 $rightblocksn = explode(',', $rightpartn);
1006 }
1007
1008 //Now I have blocks separated
1009
1010 $leftblocks = array();
1011 $rightblocks = array();
1012
1013 if ($leftblocksn) {
1014 foreach($leftblocksn as $leftblockn) {
1015 //Convert id to blockname
1016 $leftblock = block_get_name_by_id(abs($leftblockn));
1017 if ($leftblock) {
1018 //Check it's visible
9b4b78fd 1019 if($block = get_record('block','name',$leftblock,'visible','1')) {
229f852a 1020 //Check if it's hidden oe no in the course
1021 if($leftblockn<0) {
1022 $leftblocks[] = '-'.$leftblock;
1023 } else {
1024 $leftblocks[] = $leftblock;
1025 }
1026 }
1027 }
1028 }
1029 }
1030
1031 if ($rightblocksn) {
1032 foreach($rightblocksn as $rightblockn) {
1033 //Convert id to blockname
1034 $rightblock = block_get_name_by_id(abs($rightblockn));
1035 if ($rightblock) {
1036 //Check it's visible
9b4b78fd 1037 if($block = get_record('block', 'name', $rightblock, 'visible', '1')) {
229f852a 1038 //Check if it's hidden oe no in the course
1039 if($rightblockn<0) {
1040 $rightblocks[] = '-'.$rightblock;
1041 } else {
1042 $rightblocks[] = $rightblock;
1043 }
1044 }
1045 }
1046 }
1047 }
1048
1049 //Calculate the blockinfo field
1050 if ($leftblocks || $rightblocks) {
1051 $blockinfo = '';
1052 if ($leftblocks) {
1053 $blockinfo .= implode(",", $leftblocks);
1054 }
1055 if ($rightblocks) {
1056 $blockinfo .= ':'.implode(",",$rightblocks);
1057 }
1058 } else {
1059 $blockinfo = '';
1060 }
1061
1062 //Returns the blockinfo
1063 return $blockinfo;
1064}
1065
1066//This function will return the ids representation of the blockinfo field.
1067//It's used to load that info from backups. This function is the opposite
1068//to the blocks_get_block_names() used in backup
1069function blocks_get_block_ids ($blockinfo) {
1070
1071 //Just call this with the appropiate parammeters.
1072 return blocks_get_default_blocks(NULL,$blockinfo);
1073}
0784eb7e 1074
9b4b78fd 1075function blocks_print_blocks($page, $position) {
1076 $blocks = get_records('block_instance', 'pageid', $page->id, 'pagetype', $page->type, 'visible', '1');
1077 echo "blocks_print_blocks()<br />";
1078 print_object($blocks);
0784eb7e 1079}
1080
9b4b78fd 1081
0f3fe4b6 1082?>