Added missing string for ldap_opt_deref
[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);
a9c75a9c 239 // DH - users can configure this instance if the block class allows multiple instances, not just if the administrator has allowed this block class to display multiple for the given site as would be found in $block->multiple
240 $options |= BLOCK_CONFIGURE * ( $obj->instance_allow_multiple() );
9b4b78fd 241 $obj->add_edit_controls($options);
242 }
0f3fe4b6 243
9b4b78fd 244 if(!$instance->visible) {
245 if($isediting) {
246 $obj->print_shadow();
0f3fe4b6 247 }
248 }
9b4b78fd 249 else {
250 $obj->print_block();
251 }
0f3fe4b6 252 }
253}
254
255//This iterates over an array of blocks and calculates the preferred width
9b4b78fd 256function blocks_preferred_width($instances) {
0f3fe4b6 257 $width = 0;
258
9b4b78fd 259 if(empty($instances) || !is_array($instances)) {
0f3fe4b6 260 return 0;
261 }
9b4b78fd 262 foreach($instances as $instance) {
263 if(!$instance->visible) {
fe78a3dc 264 continue;
0c9c6363 265 }
9b4b78fd 266 $block = blocks_get_record($instance->blockid);
267 $pref = block_method_result($block->name, 'preferred_width');
268 if($pref === NULL) {
269 continue;
270 }
271 if($pref > $width) {
272 $width = $pref;
0f3fe4b6 273 }
274 }
275 return $width;
276}
277
9b4b78fd 278function blocks_get_record($blockid = NULL, $invalidate = false) {
279 static $cache = NULL;
0f3fe4b6 280
9b4b78fd 281 if($invalidate || empty($cache)) {
282 $cache = get_records('block');
283 }
0f3fe4b6 284
9b4b78fd 285 if($blockid === NULL) {
286 return $cache;
287 }
0f3fe4b6 288
9b4b78fd 289 return (isset($cache[$blockid])? $cache[$blockid] : false);
290}
291
292function blocks_find_block($blockid, $blocksarray) {
293 foreach($blocksarray as $blockgroup) {
294 foreach($blockgroup as $instance) {
295 if($instance->blockid == $blockid) {
296 return $instance;
297 }
298 }
299 }
300 return false;
301}
302
303function blocks_find_instance($instanceid, $blocksarray) {
304 foreach($blocksarray as $subarray) {
305 foreach($subarray as $instance) {
306 if($instance->id == $instanceid) {
307 return $instance;
308 }
309 }
310 }
311 return false;
312}
313
314function blocks_execute_action($page, &$pageblocks, $blockaction, $instanceorid) {
315 global $CFG;
316
a9c75a9c 317 if (is_int($instanceorid)) {
9b4b78fd 318 $blockid = $instanceorid;
a9c75a9c 319 } else if (is_object($instanceorid)) {
9b4b78fd 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)) {
a9c75a9c 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)) {
a9c75a9c 390 error('Invalid block instance for '. $blockaction);
9b4b78fd 391 }
89a5baab 392 // This configuration will make sure that even if somehow the weights
393 // become not continuous, block move operations will eventually bring
394 // the situation back to normal without printing any warnings.
395 if(!empty($pageblocks[$instance->position][$instance->weight - 1])) {
396 $other = $pageblocks[$instance->position][$instance->weight - 1];
397 }
9b4b78fd 398 if(!empty($other)) {
9b4b78fd 399 ++$other->weight;
9b4b78fd 400 update_record('block_instance', $other);
0f3fe4b6 401 }
89a5baab 402 --$instance->weight;
403 update_record('block_instance', $instance);
0f3fe4b6 404 break;
405 case 'movedown':
9b4b78fd 406 if(empty($instance)) {
a9c75a9c 407 error('Invalid block instance for '. $blockaction);
9b4b78fd 408 }
89a5baab 409 // This configuration will make sure that even if somehow the weights
410 // become not continuous, block move operations will eventually bring
411 // the situation back to normal without printing any warnings.
412 if(!empty($pageblocks[$instance->position][$instance->weight + 1])) {
413 $other = $pageblocks[$instance->position][$instance->weight + 1];
414 }
9b4b78fd 415 if(!empty($other)) {
9b4b78fd 416 --$other->weight;
9b4b78fd 417 update_record('block_instance', $other);
0f3fe4b6 418 }
89a5baab 419 ++$instance->weight;
420 update_record('block_instance', $instance);
0f3fe4b6 421 break;
9b4b78fd 422 case 'moveleft':
423 if(empty($instance)) {
a9c75a9c 424 error('Invalid block instance for '. $blockaction);
9b4b78fd 425 }
426 $sql = '';
427 switch($instance->position) {
428 case BLOCK_POS_RIGHT:
429 // To preserve the continuity of block weights
a9c75a9c 430 $sql = 'UPDATE '. $CFG->prefix .'block_instance SET weight = weight - 1 WHERE pagetype = \''. $instance->pagetype.
431 '\' AND pageid = '. $instance->pageid .' AND position = \'' .$instance->position.
432 '\' AND weight > '. $instance->weight;
9b4b78fd 433
434 $instance->position = BLOCK_POS_LEFT;
435 $maxweight = max(array_keys($pageblocks[$instance->position]));
436 $instance->weight = $maxweight + 1;
437 break;
438 }
439 if($sql) {
440 update_record('block_instance', $instance);
441 execute_sql($sql, false);
0f3fe4b6 442 }
443 break;
9b4b78fd 444 case 'moveright':
445 if(empty($instance)) {
a9c75a9c 446 error('Invalid block instance for '. $blockaction);
9b4b78fd 447 }
448 $sql = '';
449 switch($instance->position) {
450 case BLOCK_POS_LEFT:
451 // To preserve the continuity of block weights
a9c75a9c 452 $sql = 'UPDATE '. $CFG->prefix .'block_instance SET weight = weight - 1 WHERE pagetype = \''. $instance->pagetype.
453 '\' AND pageid = '. $instance->pageid .' AND position = \''. $instance->position.
454 '\' AND weight > '. $instance->weight;
9b4b78fd 455
456 $instance->position = BLOCK_POS_RIGHT;
457 $maxweight = max(array_keys($pageblocks[$instance->position]));
458 $instance->weight = $maxweight + 1;
459 break;
460 }
461 if($sql) {
462 update_record('block_instance', $instance);
463 execute_sql($sql, false);
464 }
465 break;
466 case 'add':
467 // Add a new instance of this block, if allowed
468 $block = blocks_get_record($blockid);
0f3fe4b6 469
9b4b78fd 470 if(!$block->visible) {
471 // Only allow adding if the block is enabled
472 return false;
473 }
0f3fe4b6 474
89a5baab 475 if(!$block->multiple && blocks_find_block($blockid, $pageblocks) !== false) {
476 // If no multiples are allowed and we already have one, return now
477 return false;
478 }
479
a9c75a9c 480 $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 .'\'');
9b4b78fd 481
482 $newinstance = new stdClass;
483 $newinstance->blockid = $blockid;
484 $newinstance->pageid = $page->id;
485 $newinstance->pagetype = $page->type;
486 $newinstance->position = BLOCK_POS_RIGHT;
487 $newinstance->weight = $weight->nextfree;
488 $newinstance->visible = 1;
489 $newinstance->configdata = '';
490 insert_record('block_instance', $newinstance);
491 break;
492 }
0f3fe4b6 493}
494
9b4b78fd 495function blocks_get_by_page($page) {
a9c75a9c 496 $blocks = get_records_select('block_instance', 'pageid = '. $page->id .' AND pagetype = \''. $page->type .'\'', 'position, weight');
0f3fe4b6 497
9b4b78fd 498 $arr = array(BLOCK_POS_LEFT => array(), BLOCK_POS_RIGHT => array());
499 if(empty($blocks)) {
500 return $arr;
501 }
0f3fe4b6 502
9b4b78fd 503 foreach($blocks as $block) {
504 $arr[$block->position][$block->weight] = $block;
0f3fe4b6 505 }
506
9b4b78fd 507 return $arr;
508}
0f3fe4b6 509
9b4b78fd 510//This function prints the block to admin blocks as necessary
511function blocks_print_adminblock($page, $missingblocks) {
512 global $USER;
0f3fe4b6 513
9b4b78fd 514 $strblocks = get_string('blocks');
515 $stradd = get_string('add');
516 if (!empty($missingblocks)) {
517 foreach ($missingblocks as $blockid) {
518 $block = blocks_get_record($blockid);
519
520 switch($page->type) {
521 case MOODLE_PAGE_COURSE:
522 $course = get_record('course', 'id', $page->id);
523 break;
a9c75a9c 524 default: die('unknown pagetype: '. $page->type);
9b4b78fd 525 }
0f3fe4b6 526
9b4b78fd 527 $blockobject = block_instance($block->name);
528 if ($blockobject === false) {
529 continue;
530 }
531 $menu[$block->id] = $blockobject->get_title();
532 }
0f3fe4b6 533
9b4b78fd 534 if($page->id == SITEID) {
535 $target = 'index.php';
536 }
537 else {
538 $target = 'view.php';
539 }
a9c75a9c 540 $content = popup_form($target .'?id='. $course->id .'&amp;sesskey='. $USER->sesskey .'&amp;blockaction=add&amp;blockid=',
541 $menu, 'add_block', '', $stradd .'...', '', '', true);
542 $content = '<div align="center">'. $content .'</div>';
9b4b78fd 543 print_side_block($strblocks, $content, NULL, NULL, NULL);
0f3fe4b6 544 }
0f3fe4b6 545}
546
9b4b78fd 547function blocks_repopulate_page($page) {
548 global $CFG;
5b224948 549
9b4b78fd 550 /// If the site override has been defined, it is the only valid one.
551 if (!empty($CFG->defaultblocks_override)) {
552 $blocknames = $CFG->defaultblocks_override;
553 }
554 /// Else, try to find out what page this is
555 else {
556 switch($page->type) {
557 case MOODLE_PAGE_COURSE:
558 // Is it the site?
559 if($page->id == SITEID) {
560 if (!empty($CFG->defaultblocks_site)) {
561 $blocknames = $CFG->defaultblocks_site;
562 }
563 /// Failsafe - in case nothing was defined.
564 else {
565 $blocknames = 'site_main_menu,admin,course_list:course_summary,calendar_month';
0f3fe4b6 566 }
89adb174 567 }
9b4b78fd 568 // It's a normal course, so do it accodring to the course format
89adb174 569 else {
9b4b78fd 570 $course = get_record('course', 'id', $page->id);
a9c75a9c 571 if (!empty($CFG->{'defaultblocks_'. $course->format})) {
572 $blocknames = $CFG->{'defaultblocks_'. $course->format};
9b4b78fd 573 }
574 else {
575 $format_config = $CFG->dirroot.'/course/format/'.$course->format.'/config.php';
576 if (@is_file($format_config) && is_readable($format_config)) {
577 require($format_config);
578 }
579 if (!empty($format['defaultblocks'])) {
580 $blocknames = $format['defaultblocks'];
581 }
582 else if (!empty($CFG->defaultblocks)){
583 $blocknames = $CFG->defaultblocks;
584 }
585 /// Failsafe - in case nothing was defined.
586 else {
587 $blocknames = 'participants,activity_modules,search_forums,admin,course_list:news_items,calendar_upcoming,recent_activity';
588 }
589 }
89adb174 590 }
9b4b78fd 591 break;
592 default:
a9c75a9c 593 error('Invalid page type: '. $page->type);
9b4b78fd 594 break;
595 }
596 }
597
598 $allblocks = blocks_get_record();
599
600 if(empty($allblocks)) {
601 error('Could not retrieve blocks from the database');
602 }
603
604 // We have the blocks, make up two arrays
605 $left = '';
606 $right = '';
607 @list($left, $right) = explode(':', $blocknames);
608 $instances = array(BLOCK_POS_LEFT => explode(',', $left), BLOCK_POS_RIGHT => explode(',', $right));
609
610 // Arrays are fine, now we have to correlate block names to ids
611 $idforname = array();
612 foreach($allblocks as $block) {
613 $idforname[$block->name] = $block->id;
614 }
615
616 // Ready to start creating block instances, but first drop any existing ones
617 delete_records('block_instance', 'pageid', $page->id, 'pagetype', $page->type);
618
619 foreach($instances as $position => $blocknames) {
620 $weight = 0;
621 foreach($blocknames as $blockname) {
622 $newinstance = new stdClass;
623 $newinstance->blockid = $idforname[$blockname];
624 $newinstance->pageid = $page->id;
625 $newinstance->pagetype = $page->type;
626 $newinstance->position = $position;
627 $newinstance->weight = $weight;
628 $newinstance->visible = 1;
629 $newinstance->configdata = '';
630 insert_record('block_instance', $newinstance);
631 $weight++;
0f3fe4b6 632 }
633 }
9b4b78fd 634
635 return true;
0f3fe4b6 636}
637
638function upgrade_blocks_db($continueto) {
639/// This function upgrades the blocks tables, if necessary
640/// It's called from admin/index.php
641
642 global $CFG, $db;
643
a9c75a9c 644 require_once ($CFG->dirroot .'/blocks/version.php'); // Get code versions
0f3fe4b6 645
646 if (empty($CFG->blocks_version)) { // Blocks have never been installed.
a9c75a9c 647 $strdatabaseupgrades = get_string('databaseupgrades');
0f3fe4b6 648 print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades,
a9c75a9c 649 '', '', false, '&nbsp;', '&nbsp;');
0f3fe4b6 650
651 $db->debug=true;
a9c75a9c 652 if (modify_database($CFG->dirroot .'/blocks/db/'. $CFG->dbtype .'.sql')) {
0f3fe4b6 653 $db->debug = false;
a9c75a9c 654 if (set_config('blocks_version', $blocks_version)) {
655 notify(get_string('databasesuccess'), 'green');
656 notify(get_string('databaseupgradeblocks', '', $blocks_version));
0f3fe4b6 657 print_continue($continueto);
658 exit;
659 } else {
a9c75a9c 660 error('Upgrade of blocks system failed! (Could not update version in config table)');
0f3fe4b6 661 }
662 } else {
a9c75a9c 663 error('Blocks tables could NOT be set up successfully!');
0f3fe4b6 664 }
665 }
666
667
668 if ($blocks_version > $CFG->blocks_version) { // Upgrade tables
a9c75a9c 669 $strdatabaseupgrades = get_string('databaseupgrades');
0f3fe4b6 670 print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades);
671
a9c75a9c 672 require_once ($CFG->dirroot .'/blocks/db/'. $CFG->dbtype .'.php');
0f3fe4b6 673
674 $db->debug=true;
675 if (blocks_upgrade($CFG->blocks_version)) {
676 $db->debug=false;
a9c75a9c 677 if (set_config('blocks_version', $blocks_version)) {
678 notify(get_string('databasesuccess'), 'green');
679 notify(get_string('databaseupgradeblocks', '', $blocks_version));
0f3fe4b6 680 print_continue($continueto);
681 exit;
682 } else {
a9c75a9c 683 error('Upgrade of blocks system failed! (Could not update version in config table)');
0f3fe4b6 684 }
685 } else {
686 $db->debug=false;
a9c75a9c 687 error('Upgrade failed! See blocks/version.php');
0f3fe4b6 688 }
689
690 } else if ($blocks_version < $CFG->blocks_version) {
a9c75a9c 691 notify('WARNING!!! The code you are using is OLDER than the version that made these databases!');
0f3fe4b6 692 }
693}
694
695//This function finds all available blocks and install them
696//into blocks table or do all the upgrade process if newer
697function upgrade_blocks_plugins($continueto) {
698
699 global $CFG;
700
701 $blocktitles = array();
702 $invalidblocks = array();
703 $validblocks = array();
704 $notices = array();
705
706 //Count the number of blocks in db
9b4b78fd 707 $blockcount = count_records('block');
0f3fe4b6 708 //If there isn't records. This is the first install, so I remember it
709 if ($blockcount == 0) {
710 $first_install = true;
711 } else {
712 $first_install = false;
713 }
714
715 $site = get_site();
716
9b4b78fd 717 if (!$blocks = get_list_of_plugins('blocks', 'db') ) {
a9c75a9c 718 error('No blocks installed!');
0f3fe4b6 719 }
720
a9c75a9c 721 include_once($CFG->dirroot .'/blocks/moodleblock.class.php');
0f3fe4b6 722 if(!class_exists('moodleblock')) {
723 error('Class MoodleBlock is not defined or file not found for /blocks/moodleblock.class.php');
724 }
725
726 foreach ($blocks as $blockname) {
727
a9c75a9c 728 if ($blockname == 'NEWBLOCK') { // Someone has unzipped the template, ignore it
0f3fe4b6 729 continue;
730 }
731
a9c75a9c 732 $fullblock = $CFG->dirroot .'/blocks/'. $blockname;
0f3fe4b6 733
9b4b78fd 734 if ( is_readable($fullblock.'/block_'.$blockname.'.php')) {
735 include_once($fullblock.'/block_'.$blockname.'.php');
0f3fe4b6 736 } else {
a9c75a9c 737 $notices[] = 'Block '. $blockname .': '. $fullblock .'/block_'. $blockname .'.php was not readable';
0f3fe4b6 738 continue;
739 }
740
a9c75a9c 741 if ( @is_dir($fullblock .'/db/')) {
742 if ( @is_readable($fullblock .'/db/'. $CFG->dbtype .'.php')) {
89a5baab 743 include_once($fullblock .'/db/'. $CFG->dbtype .'.php'); // defines upgrading function
828c4e09 744 } else {
a9c75a9c 745 $notices[] ='Block '. $blockname .': '. $fullblock .'/db/'. $CFG->dbtype .'.php was not readable';
828c4e09 746 continue;
747 }
0f3fe4b6 748 }
749
750 $classname = 'CourseBlock_'.$blockname;
751 if(!class_exists($classname)) {
a9c75a9c 752 $notices[] = 'Block '. $blockname .': '. $classname .' not implemented';
0f3fe4b6 753 continue;
754 }
755
9b4b78fd 756 // Here is the place to see if the block implements a constructor (old style),
757 // an init() function (new style) or nothing at all (error time).
758
33bee34c 759 $constructor = get_class_constructor($classname);
760 if(empty($constructor)) {
0f3fe4b6 761 // No constructor
a9c75a9c 762 $notices[] = 'Block '. $blockname .': class does not have a constructor';
0f3fe4b6 763 $invalidblocks[] = $blockname;
764 continue;
765 }
9b4b78fd 766 $methods = get_class_methods($classname);
767 if(!in_array('init', $methods)) {
768 // This is an old-style block
a9c75a9c 769 $notices[] = 'Block '. $blockname .' is an old style block and needs to be updated by a programmer.';
9b4b78fd 770 $invalidblocks[] = $blockname;
771 continue;
772 }
0f3fe4b6 773
9b4b78fd 774 $block = new stdClass; // This may be used to update the db below
775 $blockobj = new $classname; // This is what we 'll be testing
0f3fe4b6 776
777 // Inherits from MoodleBlock?
33bee34c 778 if(!is_subclass_of($blockobj, 'moodleblock')) {
a9c75a9c 779 $notices[] = 'Block '. $blockname .': class does not inherit from MoodleBlock';
0f3fe4b6 780 continue;
781 }
782
783 // OK, it's as we all hoped. For further tests, the object will do them itself.
784 if(!$blockobj->_self_test()) {
a9c75a9c 785 $notices[] = 'Block '. $blockname .': self test failed';
0f3fe4b6 786 continue;
787 }
788 $block->version = $blockobj->get_version();
789
790 if (!isset($block->version)) {
a9c75a9c 791 $notices[] = 'Block '. $blockname .': has no version support. It must be updated by a programmer.';
0f3fe4b6 792 continue;
793 }
794
795 $block->name = $blockname; // The name MUST match the directory
796 $blocktitle = $blockobj->get_title();
797
9b4b78fd 798 if ($currblock = get_record('block', 'name', $block->name)) {
0f3fe4b6 799 if ($currblock->version == $block->version) {
800 // do nothing
801 } else if ($currblock->version < $block->version) {
802 if (empty($updated_blocks)) {
a9c75a9c 803 $strblocksetup = get_string('blocksetup');
804 print_header($strblocksetup, $strblocksetup, $strblocksetup, '', '', false, '&nbsp;', '&nbsp;');
0f3fe4b6 805 }
b88f7004 806 print_heading('New version of '.$blocktitle.' ('.$block->name.') exists');
807 $upgrade_function = $block->name.'_upgrade';
0f3fe4b6 808 if (function_exists($upgrade_function)) {
809 $db->debug=true;
810 if ($upgrade_function($currblock->version, $block)) {
b88f7004 811
812 $upgradesuccess = true;
0f3fe4b6 813 } else {
b88f7004 814 $upgradesuccess = false;
815 }
816 $db->debug=false;
817 }
818 else {
819 $upgradesuccess = true;
820 }
821 if(!$upgradesuccess) {
a9c75a9c 822 notify('Upgrading block '. $block->name .' from '. $currblock->version .' to '. $block->version .' FAILED!');
b88f7004 823 }
824 else {
9b4b78fd 825 // OK so far, now update the block record
b88f7004 826 $block->id = $currblock->id;
9b4b78fd 827 if (! update_record('block', $block)) {
a9c75a9c 828 error('Could not update block '. $block->name .' record in block table!');
0f3fe4b6 829 }
b88f7004 830 notify(get_string('blocksuccess', '', $blocktitle), 'green');
831 echo '<hr />';
0f3fe4b6 832 }
833 $updated_blocks = true;
834 } else {
a9c75a9c 835 error('Version mismatch: block '. $block->name .' can\'t downgrade '. $currblock->version .' -> '. $block->version .'!');
0f3fe4b6 836 }
837
838 } else { // block not installed yet, so install it
839
9b4b78fd 840 // If it allows multiples, start with it enabled
841 $block->multiple = $blockobj->instance_allow_multiple();
842
0f3fe4b6 843 // [pj] Normally this would be inline in the if, but we need to
844 // check for NULL (necessary for 4.0.5 <= PHP < 4.2.0)
845 $conflictblock = array_search($blocktitle, $blocktitles);
846 if($conflictblock !== false && $conflictblock !== NULL) {
0f3fe4b6 847 // Duplicate block titles are not allowed, they confuse people
848 // AND PHP's associative arrays ;)
849 error('<strong>Naming conflict</strong>: block <strong>'.$block->name.'</strong> has the same title with an existing block, <strong>'.$conflictblock.'</strong>!');
850 }
851 if (empty($updated_blocks)) {
a9c75a9c 852 $strblocksetup = get_string('blocksetup');
853 print_header($strblocksetup, $strblocksetup, $strblocksetup, '', '', false, '&nbsp;', '&nbsp;');
0f3fe4b6 854 }
855 print_heading($block->name);
856 $updated_blocks = true;
857 $db->debug = true;
a71bfa1c 858 @set_time_limit(0); // To allow slow databases to complete the long SQL
a9c75a9c 859 if (!is_dir($fullblock .'/db/') || modify_database($fullblock .'/db/'. $CFG->dbtype .'.sql')) {
0f3fe4b6 860 $db->debug = false;
9b4b78fd 861 if ($block->id = insert_record('block', $block)) {
0f3fe4b6 862 notify(get_string('blocksuccess', '', $blocktitle), 'green');
a9c75a9c 863 echo '<hr />';
0f3fe4b6 864 } else {
a9c75a9c 865 error($block->name .' block could not be added to the block list!');
0f3fe4b6 866 }
867 } else {
a9c75a9c 868 error('Block '. $block->name .' tables could NOT be set up successfully!');
0f3fe4b6 869 }
870 }
871
872 $blocktitles[$block->name] = $blocktitle;
873 }
874
875 if(!empty($notices)) {
876 foreach($notices as $notice) {
877 notify($notice);
878 }
879 }
880
9b4b78fd 881 // Finally, if we are in the first_install of BLOCKS (this means that we are
882 // upgrading from Moodle < 1.3), put blocks in all existing courses.
0f3fe4b6 883 if ($first_install) {
884 //Iterate over each course
9b4b78fd 885 if ($courses = get_records('course')) {
0f3fe4b6 886 foreach ($courses as $course) {
9b4b78fd 887 $page = new stdClass;
888 $page->type = MOODLE_PAGE_COURSE;
889 $page->id = $course->id;
890 blocks_repopulate_page($page);
0f3fe4b6 891 }
892 }
893 }
894
e02c35b2 895 if (!empty($CFG->siteblocksadded)) { /// This is a once-off hack to make a proper upgrade
9b4b78fd 896 $page = new stdClass;
897 $page->type = MOODLE_PAGE_COURSE;
898 $page->id = SITEID;
899 blocks_repopulate_page($page);
e02c35b2 900 delete_records('config', 'name', 'siteblocksadded');
901 }
902
0f3fe4b6 903 if (!empty($updated_blocks)) {
904 print_continue($continueto);
905 die;
906 }
907}
908
0f3fe4b6 909?>