Fixes bug MDL-8234, "New groups code & AS keyword"
[moodle-pu.git] / mod / choice / lib.php
blobebd1118071186c67340feec78ecb2025205778ef
1 <?php // $Id$
3 $COLUMN_HEIGHT = 300;
5 define('CHOICE_PUBLISH_ANONYMOUS', '0');
6 define('CHOICE_PUBLISH_NAMES', '1');
8 define('CHOICE_SHOWRESULTS_NOT', '0');
9 define('CHOICE_SHOWRESULTS_AFTER_ANSWER', '1');
10 define('CHOICE_SHOWRESULTS_AFTER_CLOSE', '2');
11 define('CHOICE_SHOWRESULTS_ALWAYS', '3');
13 define('CHOICE_DISPLAY_HORIZONTAL', '0');
14 define('CHOICE_DISPLAY_VERTICAL', '1');
16 $CHOICE_PUBLISH = array (CHOICE_PUBLISH_ANONYMOUS => get_string('publishanonymous', 'choice'),
17 CHOICE_PUBLISH_NAMES => get_string('publishnames', 'choice'));
19 $CHOICE_SHOWRESULTS = array (CHOICE_SHOWRESULTS_NOT => get_string('publishnot', 'choice'),
20 CHOICE_SHOWRESULTS_AFTER_ANSWER => get_string('publishafteranswer', 'choice'),
21 CHOICE_SHOWRESULTS_AFTER_CLOSE => get_string('publishafterclose', 'choice'),
22 CHOICE_SHOWRESULTS_ALWAYS => get_string('publishalways', 'choice'));
24 $CHOICE_DISPLAY = array (CHOICE_DISPLAY_HORIZONTAL => get_string('displayhorizontal', 'choice'),
25 CHOICE_DISPLAY_VERTICAL => get_string('displayvertical','choice'));
27 /// Standard functions /////////////////////////////////////////////////////////
29 function choice_user_outline($course, $user, $mod, $choice) {
30 if ($answer = get_record('choice_answers', 'choiceid', $choice->id, 'userid', $user->id)) {
31 $result->info = "'".format_string(choice_get_option_text($choice, $answer->optionid))."'";
32 $result->time = $answer->timemodified;
33 return $result;
35 return NULL;
39 function choice_user_complete($course, $user, $mod, $choice) {
40 if ($answer = get_record('choice_answers', "choiceid", $choice->id, "userid", $user->id)) {
41 $result->info = "'".format_string(choice_get_option_text($choice, $answer->optionid))."'";
42 $result->time = $answer->timemodified;
43 echo get_string("answered", "choice").": $result->info. ".get_string("updated", '', userdate($result->time));
44 } else {
45 print_string("notanswered", "choice");
50 function choice_add_instance($choice) {
51 // Given an object containing all the necessary data,
52 // (defined by the form in mod.html) this function
53 // will create a new instance and return the id number
54 // of the new instance.
56 $choice->timemodified = time();
58 if (empty($choice->timerestrict)) {
59 $choice->timeopen = 0;
60 $choice->timeclose = 0;
63 //insert answers
64 if ($choice->id = insert_record("choice", $choice)) {
65 foreach ($choice->option as $key => $value) {
66 $value = trim($value);
67 if (isset($value) && $value <> '') {
68 $option = new object();
69 $option->text = $value;
70 $option->choiceid = $choice->id;
71 if (isset($choice->limit[$key])) {
72 $option->maxanswers = $choice->limit[$key];
74 $option->timemodified = time();
75 insert_record("choice_options", $option);
79 return $choice->id;
83 function choice_update_instance($choice) {
84 // Given an object containing all the necessary data,
85 // (defined by the form in mod.html) this function
86 // will update an existing instance with new data.
88 $choice->id = $choice->instance;
89 $choice->timemodified = time();
92 if (empty($choice->timerestrict)) {
93 $choice->timeopen = 0;
94 $choice->timeclose = 0;
97 //update, delete or insert answers
98 foreach ($choice->option as $key => $value) {
99 $value = trim($value);
100 $option = new object();
101 $option->text = $value;
102 $option->choiceid = $choice->id;
103 if (isset($choice->limit[$key])) {
104 $option->maxanswers = $choice->limit[$key];
106 $option->timemodified = time();
107 if (isset($choice->optionid[$key]) && !empty($choice->optionid[$key])){//existing choice record
108 $option->id=$choice->optionid[$key];
109 if (isset($value) && $value <> '') {
110 update_record("choice_options", $option);
111 } else { //empty old option - needs to be deleted.
112 delete_records("choice_options", "id", $option->id);
114 } else {
115 if (isset($value) && $value <> '') {
116 insert_record("choice_options", $option);
121 return update_record('choice', $choice);
125 function choice_show_form($choice, $user, $cm) {
127 //$cdisplay is an array of the display info for a choice $cdisplay[$optionid]->text - text name of option.
128 // ->maxanswers -maxanswers for this option
129 // ->full - whether this option is full or not. 0=not full, 1=full
130 $cdisplay = array();
132 $aid = 0;
133 foreach ($choice->option as $optionid => $text) {
134 if (isset($text)) { //make sure there are no dud entries in the db with blank text values.
135 $countanswers = (get_records("choice_answers", "optionid", $optionid));
136 $countans = 0;
137 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
138 if (!empty($countanswers)) {
139 foreach ($countanswers as $ca) { //only return enrolled users.
140 if (has_capability('mod/choice:choose', $context)) {
141 $countans = $countans+1;
145 if ($countanswers) {
146 $countanswers = count($countanswers);
147 } else {
148 $countanswers = 0;
150 $maxans = $choice->maxanswers[$optionid];
152 $cdisplay[$aid]->optionid = $optionid;
153 $cdisplay[$aid]->text = $text;
154 $cdisplay[$aid]->maxanswers = $maxans;
155 $cdisplay[$aid]->countanswers = $countans;
157 if ($current = get_record('choice_answers', 'choiceid', $choice->id, 'userid', $user->id, 'optionid', $optionid)) {
158 $cdisplay[$aid]->checked = ' checked="checked" ';
159 } else {
160 $cdisplay[$aid]->checked = '';
162 if ($choice->limitanswers && ($countans >= $maxans) && (empty($cdisplay[$aid]->checked)) ) {
163 $cdisplay[$aid]->disabled = ' disabled="disabled" ';
164 } else {
165 $cdisplay[$aid]->disabled = '';
167 $aid++;
171 switch ($choice->display) {
172 case CHOICE_DISPLAY_HORIZONTAL:
173 echo "<table cellpadding=\"20\" cellspacing=\"20\" class=\"boxaligncenter\"><tr>";
175 foreach ($cdisplay as $cd) {
176 echo "<td align=\"center\" valign=\"top\">";
177 echo "<input type=\"radio\" name=\"answer\" value=\"".$cd->optionid."\" alt=\"".strip_tags(format_text($cd->text))."\"". $cd->checked.$cd->disabled." />";
178 if (!empty($cd->disabled)) {
179 echo format_text($cd->text."<br /><strong>".get_string('full', 'choice')."</strong>");
180 } else {
181 echo format_text($cd->text);
183 echo "</td>";
185 echo "</tr>";
186 echo "</table>";
187 break;
189 case CHOICE_DISPLAY_VERTICAL:
190 $displayoptions->para = false;
191 echo "<table cellpadding=\"10\" cellspacing=\"10\" class=\"boxaligncenter\">";
192 foreach ($cdisplay as $cd) {
193 echo "<tr><td align=\"left\">";
194 echo "<input type=\"radio\" name=\"answer\" value=\"".$cd->optionid."\" alt=\"".strip_tags(format_text($cd->text))."\"". $cd->checked.$cd->disabled." />";
196 echo format_text($cd->text. ' ', FORMAT_MOODLE, $displayoptions); //display text for option.
198 if ($choice->limitanswers && ($choice->showresults==CHOICE_SHOWRESULTS_ALWAYS) ){ //if limit is enabled, and show results always has been selected, display info beside each choice.
199 echo "</td><td>";
201 if (!empty($cd->disabled)) {
202 echo get_string('full', 'choice');
203 } elseif(!empty($cd->checked)) {
204 //currently do nothing - maybe some text could be added here to signfy that the choice has been 'selected'
205 } elseif ($cd->maxanswers-$cd->countanswers==1) {
206 echo ($cd->maxanswers - $cd->countanswers);
207 echo " ".get_string('spaceleft', 'choice');
208 } else {
209 echo ($cd->maxanswers - $cd->countanswers);
210 echo " ".get_string('spacesleft', 'choice');
212 echo "</td>";
213 } else if ($choice->limitanswers && ($cd->countanswers >= $cd->maxanswers)) { //if limitanswers and answers exceeded, display "full" beside the choice.
214 echo " <strong>".get_string('full', 'choice')."</strong>";
216 echo "</td>";
217 echo "</tr>";
219 echo "</table>";
220 break;
222 //show save choice button
223 echo '<div class="button">';
224 echo "<input type=\"hidden\" name=\"id\" value=\"$cm->id\" />";
225 if (!isguest()) { //don't show save button if the logged in user is the guest user.
226 echo "<input type=\"submit\" value=\"".get_string("savemychoice","choice")."\" />";
227 } else {
228 print_string('havetologin', 'choice');
230 echo "</div>";
233 function choice_user_submit_response($formanswer, $choice, $userid, $courseid, $cm) {
235 $current = get_record('choice_answers', 'choiceid', $choice->id, 'userid', $userid);
236 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
237 $countanswers = get_records("choice_answers", "optionid", $formanswer);
238 if ($countanswers) {
239 $countans = 0;
240 foreach ($countanswers as $ca) { //only return enrolled users.
241 if (has_capability('mod/choice:choose', $context)) {
242 $countans = $countans+1;
246 $countanswers = $countans;
247 } else {
248 $countanswers = 0;
250 $maxans = $choice->maxanswers[$formanswer];
252 if (!($choice->limitanswers && ($countanswers >= $maxans) )) {
253 if ($current) {
255 $newanswer = $current;
256 $newanswer->optionid = $formanswer;
257 $newanswer->timemodified = time();
258 if (! update_record("choice_answers", $newanswer)) {
259 error("Could not update your choice because of a database error");
261 add_to_log($courseid, "choice", "choose again", "view.php?id=$cm->id", $choice->id, $cm->id);
262 } else {
263 $newanswer = NULL;
264 $newanswer->choiceid = $choice->id;
265 $newanswer->userid = $userid;
266 $newanswer->optionid = $formanswer;
267 $newanswer->timemodified = time();
268 if (! insert_record("choice_answers", $newanswer)) {
269 error("Could not save your choice");
271 add_to_log($courseid, "choice", "choose", "view.php?id=$cm->id", $choice->id, $cm->id);
273 } else {
274 if (!($current->optionid==$formanswer)) { //check to see if current choice already selected - if not display error
275 error("this choice is full!");
281 function choice_show_reportlink($choice, $courseid, $cmid) {
282 $context = get_context_instance(CONTEXT_MODULE, $cmid);
283 if ( $allanswers = get_records("choice_answers", "choiceid", $choice->id)) {
284 $responsecount = 0;
285 foreach ($allanswers as $aa) {
286 if (has_capability('mod/choice:readresponses', $context)) {
287 $responsecount++;
290 } else {
291 $responsecount = 0;
293 echo '<div class="reportlink">';
294 echo "<a href=\"report.php?id=$cmid\">".get_string("viewallresponses", "choice", $responsecount)."</a>";
295 echo '</div>';
298 function choice_show_results($choice, $course, $cm, $forcepublish='') {
300 global $CFG, $COLUMN_HEIGHT, $USER;
301 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
302 print_heading(get_string("responses", "choice"));
303 if (empty($forcepublish)) { //alow the publish setting to be overridden
304 $forcepublish = $choice->publish;
307 /// Check to see if groups are being used in this choice
308 if ($groupmode = groupmode($course, $cm)) { // Groups are being used
309 $currentgroup = setup_and_print_groups($course, $groupmode, $_SERVER['PHP_SELF']."?id=$cm->id");
310 } else {
311 $currentgroup = false;
314 if ($currentgroup) {
315 $users = get_group_users($currentgroup, "u.firstname ASC", '', 'u.id, u.picture, u.firstname, u.lastname, u.idnumber');
316 } else {
317 $users = get_users_by_capability($context, 'mod/choice:choose', 'u.id, u.picture, u.firstname, u.lastname, u.idnumber', 'u.firstname ASC');
320 if (!$users) {
321 print_heading(get_string("nousersyet"));
324 if ($allresponses = get_records("choice_answers", "choiceid", $choice->id)) {
325 foreach ($allresponses as $aa) {
326 $answers[$aa->userid] = $aa;
328 } else {
329 $answers = array () ;
332 $timenow = time();
334 foreach ($choice->option as $optionid => $text) {
335 $useranswer[$optionid] = array();
337 if (!empty($users)) {
338 foreach ($users as $user) {
339 if (!empty($user->id) and !empty($answers[$user->id])) {
340 $answer = $answers[$user->id];
341 $useranswer[(int)$answer->optionid][] = $user;
342 } else {
343 $useranswer[0][] = $user;
347 foreach ($choice->option as $optionid => $text) {
348 if (!$choice->option[$optionid]) {
349 unset($useranswer[$optionid]); // Throw away any data that doesn't apply
352 ksort($useranswer);
353 switch ($forcepublish) {
354 case CHOICE_PUBLISH_NAMES:
356 $tablewidth = (int) (100.0 / count($useranswer));
357 if (has_capability('mod/choice:readresponses', $context)) {
358 echo '<div id="tablecontainer">';
359 echo '<form id="attemptsform" method="post" action="'.$_SERVER['PHP_SELF'].'" onsubmit="var menu = document.getElementById(\'menuaction\'); return (menu.options[menu.selectedIndex].value == \'delete\' ? \''.addslashes(get_string('deleteattemptcheck','quiz')).'\' : true);">';
360 echo '<div>';
361 echo '<input type="hidden" name="id" value="'.$cm->id.'" />';
362 echo '<input type="hidden" name="mode" value="overview" />';
365 echo "<table cellpadding=\"5\" cellspacing=\"10\" class=\"results names\">";
366 echo "<tr>";
367 $count = 0;
368 foreach ($useranswer as $optionid => $userlist) {
369 if ($optionid) {
370 echo "<th class=\"col$count header\" style=\"width:$tablewidth%\" scope=\"col\">";
371 } else if ($choice->showunanswered) {
372 echo "<th class=\"col$count header\" style=\"width:$tablewidth%\" scope=\"col\">";
373 } else {
374 continue;
376 echo format_string(choice_get_option_text($choice, $optionid));
377 echo "</th>";
378 $count++;
380 echo "</tr><tr>";
382 $count = 0;
383 foreach ($useranswer as $optionid => $userlist) {
384 if ($optionid) {
385 echo "<td class=\"col$count data\" style=\"width:$tablewidth%;\">";
386 } else if ($choice->showunanswered) {
387 echo "<td class=\"col$count data\" style=\"width:$tablewidth%;\">";
388 } else {
389 continue;
392 // added empty row so that when the next iteration is empty,
393 // we do not get <table></table> erro from w3c validator
394 // MDL-7861
395 echo "<table class=\"choiceresponse\"><tr><td></td></tr>";
396 foreach ($userlist as $user) {
397 // this needs to be fixed
398 // hide admin/editting teacher (users with editting privilages)
399 // show users without? I could be wrong.
400 if (!($optionid==0 && has_capability('mod/choice:readresponses', $context, $user->id))) { // make sure admins and hidden teachers are not shown in not answered yet column.
401 echo "<tr>";
402 if (has_capability('mod/choice:readresponses', $context) && $optionid!=0) {
403 echo '<td class="attemptcell"><input type="checkbox" name="attemptid[]" value="'. $answers[$user->id]->id. '" /></td>';
405 echo "<td class=\"picture\">";
406 print_user_picture($user->id, $course->id, $user->picture);
407 echo "</td><td class=\"fullname\">";
408 echo "<a href=\"$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">";
409 echo fullname($user, has_capability('moodle/site:viewfullnames', $context));
410 echo "</a>";
411 echo "</td></tr>";
414 $count++;
415 echo "</table>";
417 echo "</td>";
419 echo "</tr><tr>";
420 $count = 0;
421 foreach ($useranswer as $optionid => $userlist) {
422 if (!$optionid and !$choice->showunanswered) {
423 continue;
425 echo "<td align=\"center\" class=\"count\">";
426 $countanswers = get_records("choice_answers", "optionid", $optionid);
427 $countans = 0;
428 if (!empty($countanswers)) {
429 foreach ($countanswers as $ca) { //only return enrolled users.
430 if (has_capability('mod/choice:choose', get_context_instance(CONTEXT_MODULE, $cm->id))) {
431 $countans = $countans+1;
435 if ($choice->limitanswers && !$optionid==0) {
436 echo get_string("taken", "choice").":";
437 echo $countans;
438 echo "<br/>";
439 echo get_string("limit", "choice").":";
440 $choice_option = get_record("choice_options", "id", $optionid);
441 echo $choice_option->maxanswers;
443 echo "</td>";
444 $count++;
446 echo "</tr>";
448 /// Print "Select all" etc.
449 if (has_capability('mod/choice:readresponses', $context)) {
450 echo '<tr><td></td><td>';
451 echo '<a href="javascript:select_all_in(\'DIV\',null,\'tablecontainer\');">'.get_string('selectall', 'quiz').'</a> / ';
452 echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'tablecontainer\');">'.get_string('selectnone', 'quiz').'</a> ';
453 echo '&nbsp;&nbsp;';
454 $options = array('delete' => get_string('delete'));
455 echo choose_from_menu($options, 'action', '', get_string('withselected', 'quiz'), 'if(this.selectedIndex > 0) submitFormById(\'attemptsform\');', '', true);
456 echo '<noscript id="noscriptmenuaction" style="display: inline;">';
457 echo '<div>';
458 echo '<input type="submit" value="'.get_string('go').'" /></div></noscript>';
459 echo '<script type="text/javascript">'."\n<!--\n".'document.getElementById("noscriptmenuaction").style.display = "none";'."\n-->\n".'</script>';
460 echo '</td><td></td></tr>';
463 echo "</table>";
464 if (has_capability('mod/choice:readresponses', $context)) {
465 echo "</div></form></div>";
467 break;
470 case CHOICE_PUBLISH_ANONYMOUS:
472 $tablewidth = (int) (100.0 / count($useranswer));
474 echo "<table cellpadding=\"5\" cellspacing=\"0\" class=\"results anonymous\">";
475 echo "<tr>";
476 $count = 0;
477 foreach ($useranswer as $optionid => $userlist) {
478 if ($optionid) {
479 echo "<th style=\"width:$tablewidth%\" class=\"col$count header\" scope=\"col\">";
480 } else if ($choice->showunanswered) {
481 echo "<th style=\"width:$tablewidth%\" class=\"col$count header\" scope=\"col\">";
482 } else {
483 continue;
485 echo format_string(choice_get_option_text($choice, $optionid));
486 echo "</th>";
487 $count++;
489 echo "</tr>";
491 $maxcolumn = 0;
492 foreach ($useranswer as $optionid => $userlist) {
493 if (!$optionid and !$choice->showunanswered) {
494 continue;
496 $column[$optionid] = 0;
497 foreach ($userlist as $user) {
498 if (!($optionid==0 && has_capability('mod/choice:readresponses', $context, $user->id))) { //make sure admins and hidden teachers are not shown in not answered yet column.
499 $column[$optionid]++;
502 if ($column[$optionid] > $maxcolumn) {
503 $maxcolumn = $column[$optionid];
507 echo "<tr>";
508 $count = 0;
509 foreach ($useranswer as $optionid => $userlist) {
510 if (!$optionid and !$choice->showunanswered) {
511 continue;
513 $height = 0;
514 if ($maxcolumn) {
515 $height = $COLUMN_HEIGHT * ((float)$column[$optionid] / (float)$maxcolumn);
517 echo "<td valign=\"bottom\" align=\"center\" class=\"col$count data\">";
518 echo "<img src=\"column.png\" height=\"$height\" width=\"49\" alt=\"\" />";
519 echo "</td>";
520 $count++;
522 echo "</tr>";
524 echo "<tr>";
525 $count = 0;
526 foreach ($useranswer as $optionid => $userlist) {
527 if (!$optionid and !$choice->showunanswered) {
528 continue;
530 echo "<td align=\"center\" class=\"col$count count\">";
531 if ($choice->limitanswers && !$optionid==0) {
532 echo get_string("taken", "choice").":";
533 echo $column[$optionid];
534 echo "<br/>";
535 echo get_string("limit", "choice").":";
536 $choice_option = get_record("choice_options", "id", $optionid);
537 echo $choice_option->maxanswers;
538 } else {
539 echo $column[$optionid];
541 echo "</td>";
542 $count++;
544 echo "</tr></table>";
546 break;
551 function choice_delete_responses($attemptids) {
553 if(!is_array($attemptids) || empty($attemptids)) {
554 return false;
557 foreach($attemptids as $num => $attemptid) {
558 if(empty($attemptid)) {
559 unset($attemptids[$num]);
563 foreach($attemptids as $attemptid) {
564 if ($todelete = get_record('choice_answers', 'id', $attemptid)) {
565 delete_records('choice_answers', 'id', $attemptid);
568 return true;
572 function choice_delete_instance($id) {
573 // Given an ID of an instance of this module,
574 // this function will permanently delete the instance
575 // and any data that depends on it.
577 if (! $choice = get_record("choice", "id", "$id")) {
578 return false;
581 $result = true;
583 if (! delete_records("choice_answers", "choiceid", "$choice->id")) {
584 $result = false;
587 if (! delete_records("choice_options", "choiceid", "$choice->id")) {
588 $result = false;
591 if (! delete_records("choice", "id", "$choice->id")) {
592 $result = false;
595 return $result;
598 function choice_get_participants($choiceid) {
599 //Returns the users with data in one choice
600 //(users with records in choice_responses, students)
602 global $CFG;
604 //Get students
605 $students = get_records_sql("SELECT DISTINCT u.id, u.id
606 FROM {$CFG->prefix}user u,
607 {$CFG->prefix}choice_answers a
608 WHERE a.choiceid = '$choiceid' and
609 u.id = a.userid");
611 //Return students array (it contains an array of unique users)
612 return ($students);
616 function choice_get_option_text($choice, $id) {
617 // Returns text string which is the answer that matches the id
618 if ($result = get_record("choice_options", "id", $id)) {
619 return $result->text;
620 } else {
621 return get_string("notanswered", "choice");
625 function choice_get_choice($choiceid) {
626 // Gets a full choice record
628 if ($choice = get_record("choice", "id", $choiceid)) {
629 if ($options = get_records("choice_options", "choiceid", $choiceid, "id")) {
630 foreach ($options as $option) {
631 $choice->option[$option->id] = $option->text;
632 $choice->maxanswers[$option->id] = $option->maxanswers;
634 return $choice;
637 return false;
640 function choice_get_view_actions() {
641 return array('view','view all','report');
644 function choice_get_post_actions() {
645 return array('choose','choose again');