MDL-15107 feedback dml conversion
[moodle.git] / mod / feedback / lib.php
1 <?php // $Id$
2 /**
3 * includes the main-part of feedback-functions
4 *
5 * @version $Id$
6 * @author Andreas Grabs
7 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
8 * @package feedback
9 */
11 /// Library of functions and constants for module feedback
13 define('FEEDBACK_INCLUDE_TEST', 1);
14 define('FEEDBACK_ANONYMOUS_YES', 1);
15 define('FEEDBACK_ANONYMOUS_NO', 2);
16 define('FEEDBACK_MIN_ANONYMOUS_COUNT_IN_GROUP', 2);
17 define('FEEDBACK_DECIMAL', '.');
18 define('FEEDBACK_THOUSAND', ',');
19 define('FEEDBACK_RESETFORM_RESET', 'feedback_reset_data_');
20 define('FEEDBACK_RESETFORM_DROP', 'feedback_drop_feedback_');
21 define('FEEDBACK_MAX_PIX_LENGTH', '400'); //max. Breite des grafischen Balkens in der Auswertung
23 $feedback_names = feedback_load_feedback_items('mod/feedback/item');
25 /**
26 * this will create a new instance and return the id number 
27 * of the new instance.
28 * @param object $feedback the object given by mod_feedback_mod_form
29 * @return int
30 */
31 function feedback_add_instance($feedback) {
32     global $DB;
34     $feedback->timemodified = time();
35     $feedback->id = '';
37     //check if openenable and/or closeenable is set and set correctly to save in db
38     if(empty($feedback->openenable)) {
39         $feedback->timeopen = 0;
40     }
41     if(empty($feedback->closeenable)) {
42         $feedback->timeclose = 0;
43     }
44     if(empty($feedback->site_after_submit)) {
45         $feedback->site_after_submit = '';
46     }
48     //saving the feedback in db
49     if (!$feedbackid = $DB->insert_record("feedback", $feedback)) {
50         return false;
51     }
52     
53     feedback_set_events($feedback);
54     
55     return $feedbackid;
56 }
58 /**
59 * this will update a given instance
60 * @param object $feedback the object given by mod_feedback_mod_form
61 * @return boolean
62 */
63 function feedback_update_instance($feedback) {
64     global $DB;
66     $feedback->timemodified = time();
67     $feedback->id = $feedback->instance;
69     //check if openenable and/or closeenable is set and set correctly to save in db
70     if(empty($feedback->openenable)) {
71         $feedback->timeopen = 0;
72     }
73     if(empty($feedback->closeenable)) {
74         $feedback->timeclose = 0;
75     }
76     if(empty($feedback->site_after_submit)) {
77         $feedback->site_after_submit = '';
78     }
80     //save the feedback into the db
81     if (!$DB->update_record("feedback", $feedback)) {
82         return false;
83     }
85     //create or update the new events
86     feedback_set_events($feedback);
87      
88     return true;
89 }
91 /**
92 * this will delete a given instance.
93 * all referenced data also will be deleted
94 * @param int $id the instanceid of feedback
95 * @return boolean
96 */
97 function feedback_delete_instance($id) {
98     global $DB;
100     //get all referenced items
101     $feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$id));
102     
103     //deleting all referenced items and values
104     if (is_array($feedbackitems)){
105         foreach($feedbackitems as $feedbackitem){
106             $DB->delete_records("feedback_value", array("item"=>$feedbackitem->id));
107             $DB->delete_records("feedback_valuetmp", array("item"=>$feedbackitem->id));
108         }
109         $DB->delete_records("feedback_item", array("feedback"=>$id));
110     }
111     
112     //deleting the referenced tracking data
113     $DB->delete_records('feedback_tracking', array('feedback'=>$id));
114     
115     //deleting the completeds
116     $DB->delete_records("feedback_completed", array("feedback"=>$id));
117     
118     //deleting the unfinished completeds
119     $DB->delete_records("feedback_completedtmp", array("feedback"=>$id));
120     
121     //deleting old events
122     $DB->delete_records('event', array('modulename'=>'feedback', 'instance'=>$id));
123     return $DB->delete_records("feedback", array("id"=>$id));
126 /**
127 * this is called after deleting all instances if the course will be deleted.
128 * only templates have to be deleted
129 * @param object $course
130 * @return boolean
131 */
132 function feedback_delete_course($course) {
133     global $DB;
135     //delete all templates of given course
136     return $DB->delete_records('feedback_template', array('course'=>$course->id));
139 /**
140 * Return a small object with summary information about what a 
141 * user has done with a given particular instance of this module
142 * Used for user activity reports.
143 * $return->time = the time they did it
144 * $return->info = a short text description
145 * @param object $course
146 * @param object $user
147 * @param object $mod
148 * @param object $feedback
149 * @return object
150 */
151 function feedback_user_outline($course, $user, $mod, $feedback) {
152     return null;
155 /**
156 * Print a detailed representation of what a  user has done with
157 * a given particular instance of this module, for user activity reports.
158 * @param object $course
159 * @param object $user
160 * @param object $mod
161 * @param object $feedback
162 * @return object
163 */
164 function feedback_user_complete($course, $user, $mod, $feedback) {
165     return true;
169 function feedback_cron () {
170     return true;
173 function feedback_grades($feedbackid) {
174     return NULL;
177 function feedback_get_participants($feedbackid) {
178     return false;
181 function feedback_scale_used ($feedbackid,$scaleid) {
182     return false;
185 /**
186  * This function is used by the reset_course_userdata function in moodlelib.
187  * This function will remove all responses from the specified feedback
188  * and clean up any related data.
189  * @param $data the data submitted from the reset course.
190  * @return array status array
191  */
192 function feedback_reset_userdata($data) {
193     global $CFG, $DB;
194     
195     $resetfeedbacks = array();
196     $dropfeedbacks = array();
197     $status = array();
198     $componentstr = get_string('modulenameplural', 'feedback');
199     
200     //get the relevant entries from $data
201     foreach($data as $key => $value) {
202         switch(true) {
203             case substr($key, 0, strlen(FEEDBACK_RESETFORM_RESET)) == FEEDBACK_RESETFORM_RESET:
204                 if($value == 1) {
205                     $templist = explode('_', $key);
206                     if(isset($templist[3]))$resetfeedbacks[] = intval($templist[3]);
207                 }
208             break;
209             case substr($key, 0, strlen(FEEDBACK_RESETFORM_DROP)) == FEEDBACK_RESETFORM_DROP:
210                 if($value == 1) {
211                     $templist = explode('_', $key);
212                     if(isset($templist[3]))$dropfeedbacks[] = intval($templist[3]);
213                 }
214             break;
215         }
216     }
217     
218     //reset the selected feedbacks
219     foreach($resetfeedbacks as $id) {
220         $feedback = $DB->get_record('feedback', array('id'=>$id));
221         feedback_delete_all_completeds($id);
222         $status[] = array('component'=>$componentstr.':'.$feedback->name, 'item'=>get_string('resetting_data','feedback'), 'error'=>false);
223     }
224     
225     //drop the selected feedbacks
226     // foreach($dropfeedbacks as $id) {
227         // $cm = get_coursemodule_from_instance('feedback', $id);
228         // feedback_delete_instance($id);
229         // feedback_delete_course_module($cm->id);
230         // $status[] = array('component'=>$componentstr, 'item'=>get_string('drop_feedback','feedback'), 'error'=>false);
231     // }
232     return $status;
235 /**
236  * Called by course/reset.php
237  * @param $mform form passed by reference
238  */
239 function feedback_reset_course_form_definition(&$mform) {
240     global $COURSE, $DB;
242     $mform->addElement('header', 'feedbackheader', get_string('modulenameplural', 'feedback'));
243     
244     if(!$feedbacks = $DB->get_records('feedback', array('course'=>$COURSE->id), 'name')){
245         return;
246     }
248     $mform->addElement('static', 'hint', get_string('resetting_data','feedback'));
249     foreach($feedbacks as $feedback) {
250         $mform->addElement('checkbox', FEEDBACK_RESETFORM_RESET.$feedback->id, $feedback->name);
251         // $mform->addElement('checkbox', FEEDBACK_RESETFORM_DROP.$feedback->id, get_string('drop_feedback','feedback'));
252     }
255 /**
256  * Course reset form defaults.
257  */
258 function feedback_reset_course_form_defaults($course) {
259     global $DB;
261     $return = array();
262     if(!$feedbacks = $DB->get_records('feedback', array('course'=>$course->id), 'name')){
263         return;
264     }
265     foreach($feedbacks as $feedback) {
266         $return[FEEDBACK_RESETFORM_RESET.$feedback->id] = true;
267         // $return[FEEDBACK_RESETFORM_DROP.$feedback->id] = false;
268     }
269     return $return;
272 /** 
273  * Called by course/reset.php and shows the formdata by coursereset.
274  * it prints checkboxes for each feedback available at the given course
275  * there are two checkboxes: 1) delete userdata and keep the feedback 2) delete userdata and drop the feedback
276  * @param object $course
277  * @return void
278  */
279 function feedback_reset_course_form($course) {
280     global $DB;
282     echo get_string('resetting_feedbacks', 'feedback'); echo ':<br />';
283     if (!$feedbacks = $DB->get_records('feedback', array('course'=>$course->id), 'name')) {
284         return;
285     }
286     
287     foreach($feedbacks as $feedback) {
288         echo '<p>';
289         echo get_string('name','feedback').': '.$feedback->name.'<br />';
290         print_checkbox(FEEDBACK_RESETFORM_RESET.$feedback->id, 1, true, get_string('resetting_data','feedback'), '', '');  echo '<br />';
291         print_checkbox(FEEDBACK_RESETFORM_DROP.$feedback->id, 1, false, get_string('drop_feedback','feedback'), '', '');
292         echo '</p>';
293     }
296 /** 
297  *  This creates new events given as timeopen and closeopen by $feedback.
298  *  @param object $feedback
299  *  @return void
300  */
301 function feedback_set_events($feedback) {
302     global $DB;
304     // adding the feedback to the eventtable (I have seen this at quiz-module)
305     $DB->delete_records('event', array('modulename'=>'feedback', 'instance'=>$feedback->id));
307     // the open-event
308     if($feedback->timeopen > 0) {
309         $event = NULL;
310         $event->name          = get_string('start', 'feedback').' '.$feedback->name;
311         $event->description = $feedback->summary;
312         $event->courseid     = $feedback->course;
313         $event->groupid      = 0;
314         $event->userid        = 0;
315         $event->modulename  = 'feedback';
316         $event->instance     = $feedback->id;
317         $event->eventtype    = 'open';
318         $event->timestart    = $feedback->timeopen;
319         $event->visible      = instance_is_visible('feedback', $feedback);
320         if($feedback->timeclose > 0) {
321             $event->timeduration = ($feedback->timeclose - $feedback->timeopen);
322         } else {
323             $event->timeduration = 0;
324         }
325     
326         add_event($event);
327     }
329     // the close-event
330     if($feedback->timeclose > 0) {
331         $event = NULL;
332         $event->name          = get_string('stop', 'feedback').' '.$feedback->name;
333         $event->description = $feedback->summary;
334         $event->courseid     = $feedback->course;
335         $event->groupid      = 0;
336         $event->userid        = 0;
337         $event->modulename  = 'feedback';
338         $event->instance     = $feedback->id;
339         $event->eventtype    = 'close';
340         $event->timestart    = $feedback->timeclose;
341         $event->visible      = instance_is_visible('feedback', $feedback);
342         $event->timeduration = 0;
344         add_event($event);
345     }
348 /** 
349  *  this function is called by {@link feedback_delete_userdata()}
350  *  it drops the feedback-instance from the course_module table
351  *  @param int $id the id from the coursemodule
352  *  @return boolean
353  */
354 function feedback_delete_course_module($id) {
355     global $DB;
357     if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
358         return true;
359     }
360     return $DB->delete_records('course_modules', array('id'=>$cm->id));
365 ////////////////////////////////////////////////
366 //functions to handle capabilities
367 ////////////////////////////////////////////////
369 /** 
370  *  returns the context-id related to the given coursemodule-id
371  *  @param int $cmid the coursemodule-id
372  *  @return object $context
373  */
374 function feedback_get_context($cmid) {
375     static $context;
376     
377     if(isset($context)) return $context;
378     
379     if (!$context = get_context_instance(CONTEXT_MODULE, $cmid)) {
380             print_error('badcontext');
381     }
382     return $context;
385 /** 
386  *  get the capabilities for the feedback
387  *  @param int $cmid
388  *  @return object the available capabilities from current user
389  */
390 function feedback_load_capabilities($cmid) {
391     static $cb;
392     
393     if(isset($cb)) return $cb;
394     
395     $context = feedback_get_context($cmid);
396     
397     $cb = new object;
398     $cb->view = has_capability('mod/feedback:view', $context, NULL, false);
399     $cb->complete = has_capability('mod/feedback:complete', $context, NULL, false);
400     $cb->deletesubmissions = has_capability('mod/feedback:deletesubmissions', $context, NULL, false);
401     $cb->mapcourse = has_capability('mod/feedback:mapcourse', $context, NULL, false);
402     $cb->edititems = has_capability('mod/feedback:edititems', $context, NULL, false);
403     $cb->viewreports = has_capability('mod/feedback:viewreports', $context, NULL, false);
404     $cb->receivemail = has_capability('mod/feedback:receivemail', $context, NULL, false);
405     $cb->createprivatetemplate = has_capability('mod/feedback:createprivatetemplate', $context, NULL, false);
406     $cb->createpublictemplate = has_capability('mod/feedback:createpublictemplate', $context, NULL, false);
407     $cb->deletetemplate = has_capability('mod/feedback:deletetemplate', $context, NULL, false);
408     
409     $cb->siteadmin = has_capability('moodle/site:doanything', $context);
410     
411     $cb->viewhiddenactivities = has_capability('moodle/course:viewhiddenactivities', $context, NULL, false);
412     
413     return $cb;
417 /** 
418  *  get the capabilities for the course.
419  *  this is used by feedback/index.php
420  *  @param int $courseid
421  *  @return object the available capabilities from current user
422  */
423 function feedback_load_course_capabilities($courseid) {
424     static $ccb;
425     
426     if(isset($ccb)) return $ccb;
427     
428     $context = get_context_instance(CONTEXT_COURSE, $courseid);
429     
430     $ccb = new object;
431     $ccb->view = has_capability('mod/feedback:view', $context, NULL, false);
432     $ccb->complete = has_capability('mod/feedback:complete', $context, NULL, false);
433     $ccb->deletesubmissions = has_capability('mod/feedback:deletesubmissions', $context, NULL, false);
434     $ccb->mapcourse = has_capability('mod/feedback:mapcourse', $context, NULL, false);
435     $ccb->edititems = has_capability('mod/feedback:edititems', $context, NULL, false);
436     $ccb->viewreports = has_capability('mod/feedback:viewreports', $context, NULL, false);
437     $ccb->receivemail = has_capability('mod/feedback:receivemail', $context, NULL, false);
438     $ccb->createprivatetemplate = has_capability('mod/feedback:createprivatetemplate', $context, NULL, false);
439     $ccb->createpublictemplate = has_capability('mod/feedback:createpublictemplate', $context, NULL, false);
440     $ccb->deletetemplate = has_capability('mod/feedback:deletetemplate', $context, NULL, false);
441     
442     $ccb->siteadmin = has_capability('moodle/site:doanything', $context);
443     
444     $ccb->viewhiddenactivities = has_capability('moodle/course:viewhiddenactivities', $context, NULL, false);
445     
446     return $ccb;
450 /** 
451  *  returns true if the current role is faked by switching role feature
452  *  @return boolean
453  */
454 function feedback_check_is_switchrole(){
455     global $USER;
456     if(isset($USER->switchrole) AND is_array($USER->switchrole) AND count($USER->switchrole) > 0) {
457         return true;
458     }
459     return false;
462 /** 
463  *  get users which have the complete-capability
464  *  @param int $cmid
465  *  @param mixed $groups single groupid or array of groupids - group(s) user is in
466  *  @return object the userrecords
467  */
468 function feedback_get_complete_users($cmid, $groups = false) {
470     if (!$context = get_context_instance(CONTEXT_MODULE, $cmid)) {
471             print_error('badcontext');
472     }
473     
474     //description of the call below: get_users_by_capability($context, $capability, $fields='', $sort='', $limitfrom='', $limitnum='', $groups='', $exceptions='', $doanything=true)
475     return get_users_by_capability($context, 'mod/feedback:complete', '', 'lastname', '', '', $groups, '', false);
478 /** 
479  *  get users which have the viewreports-capability
480  *  @param int $cmid
481  *  @param mixed $groups single groupid or array of groupids - group(s) user is in
482  *  @return object the userrecords
483  */
484 function feedback_get_viewreports_users($cmid, $groups = false) {
486     if (!$context = get_context_instance(CONTEXT_MODULE, $cmid)) {
487             print_error('badcontext');
488     }
489     
490     //description of the call below: get_users_by_capability($context, $capability, $fields='', $sort='', $limitfrom='', $limitnum='', $groups='', $exceptions='', $doanything=true)
491     return get_users_by_capability($context, 'mod/feedback:viewreports', '', 'lastname', '', '', $groups, '', false);
494 /** 
495  *  get users which have the receivemail-capability
496  *  @param int $cmid
497  *  @param mixed $groups single groupid or array of groupids - group(s) user is in
498  *  @return object the userrecords
499  */
500 function feedback_get_receivemail_users($cmid, $groups = false) {
502     if (!$context = get_context_instance(CONTEXT_MODULE, $cmid)) {
503             print_error('badcontext');
504     }
505     
506     //description of the call below: get_users_by_capability($context, $capability, $fields='', $sort='', $limitfrom='', $limitnum='', $groups='', $exceptions='', $doanything=true)
507     return get_users_by_capability($context, 'mod/feedback:receivemail', '', 'lastname', '', '', $groups, '', true);
510 ////////////////////////////////////////////////
511 //functions to handle the templates
512 ////////////////////////////////////////////////
513 ////////////////////////////////////////////////
515 /** 
516  *  creates a new template-record.
517  *  @param int $courseid
518  *  @param string $name the name of template shown in the templatelist
519  *  @param int $ispublic 0:privat 1:public
520  *  @return int the new templateid
521  */
522 function feedback_create_template($courseid, $name, $ispublic = 0) {
523     global $DB;
525     $templ = new object();
526     $templ->course   = $courseid;
527     $templ->name     = $name;
528     $templ->ispublic = $ispublic;
530     return $DB->insert_record('feedback_template', $templ);
533 /** 
534  *  creates new template items.
535  *  all items will be copied and the attribute feedback will be set to 0
536  *  and the attribute template will be set to the new templateid
537  *  @param object $feedback
538  *  @param string $name the name of template shown in the templatelist
539  *  @param int $ispublic 0:privat 1:public
540  *  @return boolean
541  */
542 function feedback_save_as_template($feedback, $name, $ispublic = 0) {
543     global $DB;
545     if (!$feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$feedback->id))) {
546         return false;
547     }
548     
549     if (!$newtempl = feedback_create_template($feedback->course, $name, $ispublic)) {
550         return false;
551     }
552     //create items of this new template
553     foreach($feedbackitems as $item) {
554         unset($item->id);
555         $item->feedback = 0;
556         $item->template     = $newtempl;
557         $DB->insert_record('feedback_item', $nitem);
558     }
559     return true;
562 /** 
563  *  deletes all feedback_items related to the given template id
564  *  @param int $id the templateid
565  *  @return void
566  */
567 function feedback_delete_template($id) {
568     global $DB;
570     $DB->delete_records("feedback_item", array("template"=>$id));
571     $DB->delete_records("feedback_template", array("id"=>$id));
574 /** 
575  *  creates new feedback_item-records from template.
576  *  if $deleteold is set true so the existing items of the given feedback will be deleted
577  *  if $deleteold is set false so the new items will be appanded to the old items
578  *  @param object $feedback
579  *  @param int $templateid
580  *  @param boolean $deleteold
581  */
582 function feedback_items_from_template($feedback, $templateid, $deleteold = false) {
583     global $DB;
585     //get all templateitems
586     if(!$templitems = $DB->get_records('feedback_item', array('template'=>$templateid))) {
587         return false;
588     }
589     
590     //if deleteold then delete all old items before
591     //get all items
592     if($deleteold) {
593         if($feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$feedback->id))) {
594             //delete all items of this feedback
595             foreach($feedbackitems as $item) {
596                 feedback_delete_item($item->id, false);
597             }
598             //delete tracking-data
599             $DB->delete_records('feedback_tracking', array('feedback'=>$feedback->id));
600             $DB->delete_records('feedback_completed', array('feedback'=>$feedback->id));
601             $DB->delete_records('feedback_completedtmp', array('feedback'=>$feedback->id));
602             $positionoffset = 0;
603         }
604     } else {
605         //if the old items are kept the new items will be appended
606         //therefor the new position has an offset
607         $positionoffset = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
608     }
609     
610     foreach($templitems as $newitem) {
611         unset($newitem->id);
612         $newitem->feedback = $feedback->id;
613         $newitem->template = 0;
614         $newitem->position = $newitem->position + $positionoffset;
616         $DB->insert_record('feedback_item', $newitem);
617     }
620 /** 
621  *  get the list of available templates.
622  *  if the $onlyown param is set true so only templates from own course will be served
623  *  this is important for droping templates
624  *  @param object $course
625  *  @param boolean $onlyown
626  *  @return array the template recordsets
627  */
628 function feedback_get_template_list($course, $onlyown = false) {
629     global $DB;
631     if ($onlyown) {
632         $templates = $DB->get_records('feedback_template', array('course'=>$course->id));
633     } else {
634         $templates = $DB->get_records_select('feedback_template', 'course = ? OR ispublic = 1', array($course->id));
635     }
636     return $templates;
639 ////////////////////////////////////////////////
640 //Handling der Items
641 ////////////////////////////////////////////////
642 ////////////////////////////////////////////////
644 /** 
645  *  load the available item plugins from given subdirectory of $CFG->dirroot
646  *  the default is "mod/feedback/item"
647  *  @param string $dir the subdir
648  *  @return array pluginnames as string
649  */
650 function feedback_load_feedback_items($dir = 'mod/feedback/item') {
651     global $CFG;
652     $names =get_list_of_plugins($dir);
653     $ret_names = array();
655     foreach($names as $name) {
656         require_once($CFG->dirroot.'/'.$dir.'/'.$name.'/lib.php');
657         if(class_exists('feedback_item_'.$name)) {
658           $ret_names[] = $name;
659         }
660     }
661     return $ret_names;
664 /** 
665  *  load the available item plugins to use as dropdown-options
666  *  @return array pluginnames as string
667  */
668 function feedback_load_feedback_items_options() {
669     global $CFG;
670     
671     $feedback_options = array("pagebreak" => get_string('add_pagebreak', 'feedback'));
672     
673     if (!$feedback_names = feedback_load_feedback_items('mod/feedback/item')) {
674         return array();
675     }
676     
677     foreach($feedback_names as $fn) {
678         $feedback_options[$fn] = get_string($fn,'feedback');
679     }
680     asort($feedback_options);
681     $feedback_options = array_merge( array(' ' => get_string('select')), $feedback_options );    
682     return $feedback_options;
685 /** 
686  *  creates a new item-record
687  *  @param object $data the data from edit_item_form
688  *  @return int the new itemid
689  */
690 function feedback_create_item($data) {
691     global $DB;
693     $item = new object;
694     $item->feedback = $data->feedbackid;
696     $item->template=0;
697     if (isset($data->templateid)) {
698                 $item->template = intval($data->templateid);
699     }    
701     $itemname = trim($data->itemname);
702     $item->name = ($itemname ? $data->itemname : get_string('no_itemname', 'feedback'));
703     
704     //get the used class from item-typ
705     $itemclass = 'feedback_item_'.$data->typ;
706     //get the instance of the item class
707     $itemobj = new $itemclass();
708     $item->presentation = $itemobj->get_presentation($data);
709     
710     $item->hasvalue = $itemobj->get_hasvalue();
711     
712     $item->typ = $data->typ;
713     $item->position = $data->position;
715     $item->required=0;
716     if (isset($data->required)) {
717                 $item->required=$data->required;
718     }    
720     return $DB->insert_record('feedback_item', $item);
723 /** 
724  *  save the changes of a given item.
725  *  @param object $item
726  *  @param object $data the data from edit_item_form
727  *  @return boolean
728  */
729 function feedback_update_item($item, $data = null){
730     global $DB;
732     if($data != null){
733         $itemname = trim($data->itemname);
734         $item->name = ($itemname ? $data->itemname : get_string('no_itemname', 'feedback'));
735     
736         //get the used class from item-typ
737         $itemclass = 'feedback_item_'.$data->typ;
738         //get the instance of the item class
739         $itemobj = new $itemclass();
740         $item->presentation = $itemobj->get_presentation($data);
742         $item->required=0;
743         if (isset($data->required)) {
744                 $item->required=$data->required;
745         } 
746     }else {
747         $item->name = $item->name;
748         $item->presentation = $item->presentation;
749     }
751     return $DB->update_record("feedback_item", $item);
754 /** 
755  *  deletes a item and also deletes all related values
756  *  @param int $itemid
757  *  @param boolean $renumber should the kept items renumbered Yes/No
758  *  @return void
759  */
760 function feedback_delete_item($itemid, $renumber = true){
761     global $DB;
763     $item = $DB->get_record('feedback_item', array('id'=>$itemid));
764     $DB->delete_records("feedback_value", array("item"=>$itemid));
765     $DB->delete_records("feedback_valuetmp", array("item"=>$itemid));
766     $DB->delete_records("feedback_item", array("id"=>$itemid));
767     if($renumber) {
768         feedback_renumber_items($item->feedback);
769     }
772 /** 
773  *  deletes all items of the given feedbackid
774  *  @param int $feedbackid
775  *  @return void
776  */
777 function feedback_delete_all_items($feedbackid){
778     global $DB;
780     if(!$items = $DB->get_records('feedback_item', array('feedback'=>$feedbackid))) {
781         return;
782     }
783     foreach($items as $item) {
784         feedback_delete_item($item->id, false);
785     }
786     $DB->delete_records('feedback_completedtmp', array('feedback'=>$feedbackid));
787     $DB->delete_records('feedback_completed', array('feedback'=>$feedbackid));
790 /** 
791  *  this function toggled the item-attribute required (yes/no)
792  *  @param object $item
793  *  @return boolean
794  */
795 function feedback_switch_item_required($item) {
796     global $DB;
798     if($item->required == 1) {
799         $item->required = 0;
800     } else {
801         $item->required = 1;
802     }
803     $item->name = $item->name;
804     $item->presentation = $item->presentation;
805     return $DB->update_record('feedback_item', $item);
808 /** 
809  *  renumbers all items of the given feedbackid
810  *  @param int $feedbackid
811  *  @return void
812  */
813 function feedback_renumber_items($feedbackid){
814     global $DB;
816     $items = $DB->get_records('feedback_item', array('feedback'=>$feedbackid), 'position');
817     $pos = 1;
818     if($items) {
819         foreach($items as $item){
820             $item->position = $pos;
821             $pos++;
822             feedback_update_item($item);
823         }
824     }
827 /** 
828  *  this decreases the position of the given item
829  *  @param object $item
830  *  @return void
831  */
832 function feedback_moveup_item($item){
833     global $DB;
835     if($item->position == 1) return;
836     $item_before = $DB->get_record('feedback_item', array('feedback'=>$item->feedback, 'position'=>$item->position-1));
837     $item_before->position = $item->position;
838     $item->position--;
839     feedback_update_item($item_before);
840     feedback_update_item($item);
843 /** 
844  *  this increased the position of the given item
845  *  @param object $item
846  *  @return void
847  */
848 function feedback_movedown_item($item){
849     global $DB;
851     if(!$item_after = $DB->get_record('feedback_item', array('feedback'=>$item->feedback, 'position'=>$item->position+1))) {
852         return;
853     }
854     
855     $item_after->position = $item->position;
856     $item->position++;
857     feedback_update_item($item_after);
858     feedback_update_item($item);
861 /** 
862  *  here the position of the given item will be set to the value in $pos
863  *  @param object $moveitem
864  *  @param int $pos
865  *  @return boolean
866  */
867 function feedback_move_item($moveitem, $pos){
868     global $DB;
870     if ($moveitem->position == $pos) {
871         return true;
872     }
873     if (!$allitems = $DB->get_records('feedback_item', array('feedback'=>$moveitem->feedback), 'position')) {
874         return false;
875     }
876     if (is_array($allitems)) {
877         $index = 1;
878         foreach($allitems as $item) {
879             if($item->id == $moveitem->id) continue; //the moving item is handled special
880             
881             if($index == $pos) {
882                 $moveitem->position = $index;
883                 feedback_update_item($moveitem);
884                 $index++;
885             }
886             $item->position = $index;
887             feedback_update_item($item);
888             $index++;
889         }
890         if($pos >= count($allitems)) {
891             $moveitem->position = $index;
892             feedback_update_item($moveitem);
893         }
894         return true;
895     }
896     return false;
899 /** 
900  *  prints the given item.
901  *  if $readonly is set true so the ouput only is for showing responses and not for editing or completing.
902  *  each item-class has an own print_item function implemented.
903  *  @param object $item the item what we want to print out
904  *  @param mixed $value the value if $readonly is set true and we showing responses
905  *  @param boolean $readonly
906  *  @param boolean $edit should the item print out for completing or for editing?
907  *  @param boolean $highlightrequire if this set true and the value are false on completing so the item will be highlighted
908  *  @return void
909  */
910 function feedback_print_item($item, $value = false, $readonly = false, $edit = false, $highlightrequire = false){
911     if($item->typ == 'pagebreak') return;
912     if($readonly)$ro = 'readonly="readonly" disabled="disabled"';
913         
914     //get the class of the given item-typ
915     $itemclass = 'feedback_item_'.$item->typ;
916     //get the instance of the item-class
917     $itemobj = new $itemclass();
918     $itemobj->print_item($item, $value, $readonly, $edit, $highlightrequire);
921 /** 
922  *  if the user completes a feedback and there is a pagebreak so the values are saved temporary.
923  *  the values are saved permanently not until the user click on save button
924  *  @param object $feedbackcompleted
925  *  @return object temporary saved completed-record
926  */
927 function feedback_set_tmp_values($feedbackcompleted) {
928     global $DB;
930     //first we create a completedtmp
931     $tmpcpl = new object();
932     foreach($feedbackcompleted as $key => $value) {
933         $tmpcpl->{$key} = $value;
934     }
935     // $tmpcpl = $feedbackcompleted;
936     unset($tmpcpl->id);
937     $tmpcpl->timemodified = time();
938     if(!$tmpcpl->id = $DB->insert_record('feedback_completedtmp', $tmpcpl)) {
939         error('failed create completedtmp');
940     }
941     //get all values of original-completed
942     if(!$values = $DB->get_records('feedback_value', array('completed'=>$feedbackcompleted->id))) {
943         return;
944     }
945     foreach($values as $value) {
946         unset($value->id);
947         $value->completed = $tmpcpl->id;
948         $DB->insert_record('feedback_valuetmp', $value);
949     }
950     return $tmpcpl;
953 /** 
954  *  this saves the temporary saved values permanently
955  *  @param object $feedbackcompletedtmp the temporary completed
956  *  @param object $feedbackcompleted the target completed
957  *  @param int $userid
958  *  @return int the id of the completed
959  */
960 function feedback_save_tmp_values($feedbackcompletedtmp, $feedbackcompleted, $userid) {
961     global $DB;
963     $tmpcplid = $feedbackcompletedtmp->id;
964     if(!$feedbackcompleted) {
966         //first we create a completedtmp
967         $newcpl = new object();
968         foreach($feedbackcompletedtmp as $key => $value) {
969             $newcpl->{$key} = $value;
970         }
972         unset($newcpl->id);
973         $newcpl->userid = $userid;
974         $newcpl->timemodified = time();
975         if(!$newcpl->id = $DB->insert_record('feedback_completed', $newcpl)) {
976             error('failed create completed');
977         }
978         //get all values of tmp-completed
979         if(!$values = $DB->get_records('feedback_valuetmp', array('completed'=>$feedbackcompletedtmp->id))) {
980             return false;
981         }
983         foreach($values as $value) {
984             unset($value->id);
985             $value->completed = $newcpl->id;
986             $DB->insert_record('feedback_value', $value);
987         }
988         //drop all the tmpvalues
989         $DB->delete_records('feedback_valuetmp', array('completed'=>$tmpcplid));
990         $DB->delete_records('feedback_completedtmp', array('id'=>$tmpcplid));
991         return $newcpl->id;
993     } else {
994         //first drop all existing values
995         $DB->delete_records('feedback_value', array('completed'=>$feedbackcompleted->id));
996         //update the current completed
997         $feedbackcompleted->timemodified = time();
998         $DB->update_record('feedback_completed', $feedbackcompleted);
999         //save all the new values from feedback_valuetmp
1000         //get all values of tmp-completed
1001         if(!$values = $DB->get_records('feedback_valuetmp', array('completed'=>$feedbackcompletedtmp->id))) {
1002             return false;
1003         }
1004         foreach($values as $value) {
1005             unset($value->id);
1006             $value->completed = $feedbackcompleted->id;
1007             $DB->insert_record('feedback_value', $value);
1008         }
1009         //drop all the tmpvalues
1010         $DB->delete_records('feedback_valuetmp', array('completed'=>$tmpcplid));
1011         $DB->delete_records('feedback_completedtmp', array('id'=>$tmpcplid));
1012         return $feedbackcompleted->id;
1013     }
1016 /** 
1017  *  deletes the given temporary completed and all related temporary values
1018  *  @param int $tmpcplid
1019  *  @return void
1020  */
1021 function feedback_delete_completedtmp($tmpcplid) {
1022     global $DB;
1024     $DB->delete_records('feedback_valuetmp', array('completed'=>$tmpcplid));
1025     $DB->delete_records('feedback_completedtmp', array('id'=>$tmpcplid));
1028 ////////////////////////////////////////////////
1029 ////////////////////////////////////////////////
1030 ////////////////////////////////////////////////
1031 //functions to handle the pagebreaks
1032 ////////////////////////////////////////////////
1034 /** 
1035  *  this creates a pagebreak.
1036  *  a pagebreak is a special kind of item
1037  *  @param int $feedbackid
1038  *  @return mixed false if there already is a pagebreak on last position or the id of the pagebreak-item
1039  */
1040 function feedback_create_pagebreak($feedbackid) {
1041     global $DB;
1043     //check if there already is a pagebreak on the last position
1044     $lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedbackid));
1045     if($lastposition == feedback_get_last_break_position($feedbackid)) {
1046         return false;
1047     }
1048     
1049     $item = new object();
1050     $item->feedback = $feedbackid;
1052     $item->template=0;
1054     $item->name = '';
1055     
1056     $item->presentation = '';
1057     $item->hasvalue = 0;
1058     
1059     $item->typ = 'pagebreak';
1060     $item->position = $lastposition + 1;
1062     $item->required=0;
1064     return $DB->insert_record('feedback_item', $item);
1067 /** 
1068  *  get all positions of pagebreaks in the given feedback
1069  *  @param int $feedbackid
1070  *  @return array all ordered pagebreak positions
1071  */
1072 function feedback_get_all_break_positions($feedbackid) {
1073     global $DB;
1075     if(!$allbreaks = $DB->get_records_menu('feedback_item', array('typ'=>'pagebreak', 'feedback'=>$feedbackid), 'position', 'id, position')) return false;
1076     return array_values($allbreaks);
1079 /** 
1080  *  get the position of the last pagebreak
1081  *  @param int $feedbackid
1082  *  @return int the position of the last pagebreak
1083  */
1084 function feedback_get_last_break_position($feedbackid) {
1085     if(!$allbreaks = feedback_get_all_break_positions($feedbackid)) return false;
1086     return $allbreaks[count($allbreaks) - 1];
1089 /** 
1090  *  this returns the position where the user can continue the completing.
1091  *  @param int $feedbackid
1092  *  @param int $courseid
1093  *  @param string $guestid this id will be saved temporary and is unique
1094  *  @return int the position to continue
1095  */
1096 function feedback_get_page_to_continue($feedbackid, $courseid = false, $guestid) {
1097     global $CFG, $USER, $DB;
1098     
1099     //is there any break?
1100     
1101     if(!$allbreaks = feedback_get_all_break_positions($feedbackid)) return false;
1103     $params = array();
1104     if($courseid) {
1105         $courseselect = "fv.course_id = :courseid";
1106         $params['courseid'] = $courseid;
1107     }else {
1108         $courseselect = "1";
1109     }
1110     
1111     if($guestid) {
1112         $userselect = "AND fc.guestid = :guestid";
1113         $usergroup = "GROUP BY fc.guestid";
1114         $params['guestid'] = $guestid;
1115     }else {
1116         $userselect = "AND fc.userid = :userid";
1117         $usergroup = "GROUP BY fc.userid";
1118         $params['userid'] = $USER->id;
1119     }
1121     $sql =  "SELECT MAX(fi.position)
1122                FROM {feedback_completedtmp} AS fc, {feedback_valuetmp} AS fv, {feedback_item} AS fi
1123               WHERE fc.id = fv.completed
1124                     $userselect
1125                     AND fc.feedback = :feedbackid
1126                     AND $courseselect
1127                     AND fi.id = fv.item
1128          $usergroup";
1129     $params['feedbackid'] = $feedbackid;
1131     $lastpos = $DB->get_field_sql($sql, $params);
1133     //the index of found pagebreak is the searched pagenumber
1134     foreach($allbreaks as $pagenr => $br) {
1135         if($lastpos < $br) return $pagenr;
1136     }
1137     return count($allbreaks);
1140 ////////////////////////////////////////////////
1141 ////////////////////////////////////////////////
1142 ////////////////////////////////////////////////
1143 //functions to handle the values
1144 ////////////////////////////////////////////////
1146 /** 
1147  *  this saves the values of an completed.
1148  *  if the param $tmp is set true so the values are saved temporary in table feedback_valuetmp
1149  *  if there is already a completed and the userid is set so the values are updated
1150  *  on all other things new value records will be created
1151  *  @param object $data the data from complete form
1152  *  @param int $userid
1153  *  @param boolean $tmp
1154  *  @return mixed false on error or the completeid
1155  */
1156 function feedback_save_values($data, $usrid, $tmp = false) {
1157     global $DB;
1159     $tmpstr = $tmp ? 'tmp' : '';
1160          $time = time(); //arb
1161          $timemodified = mktime(0, 0, 0, date('m', $time),date('d', $time),date('Y', $time)); //arb
1162 //         $timemodified = time();              
1163     if($usrid == 0) {
1164         return feedback_create_values($data, $usrid, $timemodified, $tmp);
1165     }
1166     if(!$data['completedid'] or !$completed = $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$data['completedid']))) {
1167         return feedback_create_values($data, $usrid, $timemodified, $tmp);
1168     }else{
1169         $completed->timemodified = $timemodified;
1170         return feedback_update_values($data, $completed, $tmp);
1171     }
1174 /** 
1175  *  this saves the values from anonymous user such as guest on the main-site
1176  *  @param object $data the data form complete_guest form
1177  *  @param string $guestid the unique guestidentifier
1178  *  @return mixed false on error or the completeid
1179  */
1180 function feedback_save_guest_values($data, $guestid) {
1181     global $DB;
1183     $timemodified = time();
1184     if(!$completed = $DB->get_record('feedback_completedtmp', array('id'=>$data['completedid']))) {
1185         return feedback_create_values($data, 0, $timemodified, true, $guestid);
1186     }else {
1187         $completed->timemodified = $timemodified;
1188         return feedback_update_values($data, $completed, true);
1189     }
1192 /** 
1193  *  get the value from the given item related to the given completed.
1194  *  the value can come as temporary or as permanently value. the deciding is done by $tmp
1195  *  @param int $completeid
1196  *  @param int $itemid
1197  *  @param boolean $tmp
1198  *  @return mixed the value, the type depends on plugin-definition
1199  */
1200 function feedback_get_item_value($completedid, $itemid, $tmp = false) {
1201     global $DB;
1203     $tmpstr = $tmp ? 'tmp' : '';
1204     return $DB->get_field('feedback_value'.$tmpstr, 'value', array('completed'=>$completedid, 'item'=>$itemid));
1207 /** 
1208  *  this function checks the correctness of values.
1209  *  the rules for this are implemented in the class of each item.
1210  *  it can be the required attribute or the value self e.g. numeric.
1211  *  the params first/lastitem are given to determine the visible range between pagebreaks.
1212  *  @param object $data the data of complete form
1213  *  @param int $firstitem the position of firstitem for checking
1214  *  @param int $lastitem the position of lastitem for checking
1215  *  @return boolean
1216  */
1217 function feedback_check_values($data, $firstitem, $lastitem) {
1218     global $DB;
1220     //get all items between the first- and lastitem
1221     $select = "feedback = ?
1222                     AND position >= ?
1223                     AND position <= ?
1224                     AND hasvalue = 1";
1225     $params = array(intval($data['feedbackid']), $firstitem, $lastitem);
1226     if(!$feedbackitems = $DB->get_records_select('feedback_item', $select, $params)) {
1227         //if no values are given so no values can be wrong ;-)
1228         return true;
1229     }
1231     foreach($feedbackitems as $item) {
1232         //the name of the input field of the completeform is given in a special form:
1233         //<item-typ>_<item-id> eg. numeric_234
1234         //this is the key to get the value for the correct item
1235         $formvalname = $item->typ . '_' . $item->id;
1236         
1237         //check if the value is set
1238         if((!isset($data[$formvalname])) AND ($item->required == 1)) {
1239             return false;
1240         }
1241         
1242         //if there is a value so save it temporary
1243         $value = isset($data[$formvalname]) ? $data[$formvalname] : '';
1245         //get the class of the item-typ
1246         $itemclass = 'feedback_item_'.$item->typ;
1247         //get the instance of the item-class
1248         $itemobj = new $itemclass();
1249         
1250         //now we let check the value by the item-class
1251         if(!$itemobj->check_value($value, $item)) {
1252             return false;
1253         }
1254     }
1255     //if no wrong values so we can return true
1256     return true;
1259 /** 
1260  *  this function create a complete-record and the related value-records.
1261  *  depending on the $tmp (true/false) the values are saved temporary or permanently
1262  *  @param object $data the data of the complete form
1263  *  @param int $userid
1264  *  @param int $timemodified
1265  *  @param boolean $tmp
1266  *  @param string $guestid a unique identifier to save temporary data
1267  *  @return mixed false on error or the completedid
1268  */
1269 function feedback_create_values($data, $usrid, $timemodified, $tmp = false, $guestid = false){
1270     global $DB;
1272     $tmpstr = $tmp ? 'tmp' : '';
1273     //first we create a new completed record
1274     $completed = new object();
1275     $completed->feedback           = $data['feedbackid'];
1276     $completed->userid             = $usrid;
1277     $completed->guestid            = $guestid;
1278     $completed->timemodified       = $timemodified;
1279     $completed->anonymous_response = $data['anonymous_response'];
1280     
1281     if (!$completedid = $DB->insert_record('feedback_completed'.$tmpstr, $completed)) {
1282         return false;
1283     }
1284     
1285     $completed = $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$completedid));
1287     //$data includes an associative array. the keys are in the form like abc_xxx
1288     //with explode we make an array with(abc, xxx) and (abc=typ und xxx=itemnr)
1289     $keys = array_keys($data);
1290     $errcount = 0;
1291     foreach($keys as $key){
1292         //ensure the keys are what we want
1293         if(eregi('([a-z0-9]{1,})_([0-9]{1,})',$key)){            
1294             $value = new object();
1295             $itemnr = explode('_', $key);
1296             $value->item = intval($itemnr[1]);
1297             $value->completed = $completed->id;
1298             $value->course_id = intval($data['courseid']);
1299             
1300             //get the class of item-typ
1301             $itemclass = 'feedback_item_'.$itemnr[0];
1302             //get the instance of item-class
1303             $itemobj = new $itemclass();
1304             //the kind of values can be absolutely different so we run create_value directly by the item-class
1305             $value->value = $itemobj->create_value($data[$key]);
1307             if (!$DB->insert_record('feedback_value'.$tmpstr, $value)) {
1308                 $errcount++;
1309             }
1310         }
1311     }
1312     
1313     //if nothing is wrong so we can return the completedid otherwise false
1314     return $errcount == 0 ? $completed->id : false;
1317 /** 
1318  *  this function updates a complete-record and the related value-records.
1319  *  depending on the $tmp (true/false) the values are saved temporary or permanently
1320  *  @param object $data the data of the complete form
1321  *  @param object $completed
1322  *  @param boolean $tmp
1323  *  @return int the completedid
1324  */
1325 function feedback_update_values($data, $completed, $tmp = false) {
1326     global $DB;
1328     $tmpstr = $tmp ? 'tmp' : '';
1329     
1330     $DB->update_record('feedback_completed'.$tmpstr, $completed);
1331     //get the values of this completed
1332     $values = $DB->get_records('feedback_value'.$tmpstr, array('completed'=>$completed->id));
1333     
1334     //$data includes an associative array. the keys are in the form like abc_xxx
1335     //with explode we make an array with(abc, xxx) and (abc=typ und xxx=itemnr)
1336     $keys = array_keys($data);
1337     foreach($keys as $key){
1338         //ensure the keys are what we want
1339         if(eregi('([a-z0-9]{1,})_([0-9]{1,})',$key)){            
1340             //build the new value to update([id], item, completed, value)
1341             $itemnr = explode('_', $key);
1342             $newvalue = new object();
1343             $newvalue->item      = $itemnr[1];
1344             $newvalue->completed = $completed->id;
1345             $newvalue->course_id = $data['courseid'];
1346             
1347             //get the class of item-typ
1348             $itemclass = 'feedback_item_'.$itemnr[0];
1349             //get the instace of the item-class
1350             $itemobj = new $itemclass();
1351             //the kind of values can be absolutely different so we run create_value directly by the item-class
1352             $newvalue->value = $itemobj->create_value($data[$key]);
1353             
1354             //check, if we have to create or update the value
1355             $exist = false;
1356             foreach($values as $value){
1357                 if($value->item == $newvalue->item){
1358                     $newvalue->id = $value->id;
1359                     $exist = true;
1360                     break;
1361                 }
1362             }
1363             if($exist){
1364                 $DB->update_record('feedback_value'.$tmpstr, $newvalue);
1365             }else {
1366                 $DB->insert_record('feedback_value'.$tmpstr, $newvalue);
1367             }
1368             
1369         }
1370     }
1372     return $completed->id;
1375 /** 
1376  *  get the values of an item depending on the given groupid.
1377  *  if the feedback is anonymous so the values are shuffled
1378  *  @param object $item
1379  *  @param int $groupid
1380  *  @param int $courseid
1381  *  @return array the value-records
1382  */
1383 function feedback_get_group_values($item, $groupid = false, $courseid = false){
1384     global $CFG, $DB;
1386     //if the groupid is given?
1387     if (intval($groupid) > 0) {
1388         $query = 'SELECT fbv .  *
1389                     FROM {feedback_value} AS fbv, {feedback_completed} AS fbc, {groups_members} AS gm
1390                    WHERE fbv.item = ?
1391                          AND fbv.completed = fbc.id 
1392                          AND fbc.userid = gm.userid 
1393                          AND gm.groupid = ?
1394                 ORDER BY fbc.timemodified';
1395         $values = $DB->get_records_sql($query, array($item->id, $groupid));
1397     } else {
1398         if ($courseid) {
1399              $values = $DB->get_records('feedback_value', array('item'=>$item->id, 'course_id'=>$courseid));
1400         } else {
1401              $values = $DB->get_records('feedback_value', array('item'=>$item->id));
1402         }
1403     }    
1404     if ($DB->get_field('feedback', 'anonymous', array('id'=>$item->feedback)) == FEEDBACK_ANONYMOUS_YES) {
1405         if(is_array($values))
1406             shuffle($values);
1407     }
1408     return $values;
1411 /** 
1412  *  check for multiple_submit = false.
1413  *  if the feedback is global so the courseid must be given
1414  *  @param int $feedbackid
1415  *  @param int $courseid
1416  *  @return boolean true if the feedback already is submitted otherwise false
1417  */
1418 function feedback_is_already_submitted($feedbackid, $courseid = false) {
1419     global $USER, $DB;
1420     
1421     if (!$trackings = $DB->get_records_menu('feedback_tracking', array('userid'=>$USER->id, 'feedback'=>$feedbackid), '', 'id, completed')) {
1422         return false;
1423     }
1425     if($courseid) {
1426         $select = 'completed IN ('.implode(',',$trackings).') AND course_id = ?';
1427         if(!$values = $DB->get_records_select('feedback_value', $select, array($courseid))) {
1428             return false;
1429         }
1430     }
1432     return true;
1435 /** 
1436  *  if the completion of a feedback will be continued eg. by pagebreak or by multiple submit so the complete must be found.
1437  *  if the param $tmp is set true so all things are related to temporary completeds
1438  *  @param int $feedbackid
1439  *  @param boolean $tmp
1440  *  @param int $courseid
1441  *  @param string $guestid
1442  *  return int the id of the found completed
1443  */
1444 function feedback_get_current_completed($feedbackid, $tmp = false, $courseid = false, $guestid = false) {
1445     global $USER, $CFG, $DB;
1446     
1447     $tmpstr = $tmp ? 'tmp' : '';
1448     
1449     if(!$courseid) {
1450         if($guestid) {
1451             return $DB->get_record('feedback_completed'.$tmpstr, array('feedback'=>$feedbackid, 'guestid'=>$guestid));
1452         }else {
1453             return $DB->get_record('feedback_completed'.$tmpstr, array('feedback'=>$feedbackid, 'userid'=>$USER->id));
1454         }
1455     }
1456     
1457     $params = array();
1458     
1459     if ($guestid) {
1460         $userselect = "AND fc.guestid = :guestid";
1461         $params['guestid'] = $guestid;
1462     }else {
1463         $userselect = "AND fc.userid = :userid";
1464         $params['userid'] = $USER->id;
1465     }
1466     //if courseid is set the feedback is global. there can be more than one completed on one feedback
1467     $sql =  "SELECT fc.*
1468                FROM {feedback_value{$tmpstr}} AS fv, {feedback_completed{$tmpstr}} AS fc
1469               WHERE fv.course_id = :courseid
1470                     AND fv.completed = fc.id
1471                     $userselect
1472                     AND fc.feedback = :feedbackid";
1473     $params['courseid']   = intval($courseid);
1474     $params['feedbackid'] = $feedbackid;
1476     if (!$sqlresult = $DB->get_records_sql($sql)) {
1477         return false;
1478     }
1479     foreach($sqlresult as $r) {
1480         return $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$r->id));
1481     }
1484 /** 
1485  *  get the completeds depending on the given groupid.
1486  *  @param object $feedback
1487  *  @param int $groupid
1488  *  @return mixed array of found completeds otherwise false
1489  */
1490 function feedback_get_completeds_group($feedback, $groupid = false) {
1491     global $CFG, $DB;
1493     if (intval($groupid) > 0){
1494         $query = "SELECT fbc.*
1495                     FROM {feedback_completed} AS fbc, {groups_members} AS gm
1496                    WHERE fbc.feedback = ?
1497                          AND gm.groupid = ?
1498                          AND fbc.userid = gm.userid";
1499         if ($values = $DB->get_records_sql($query, array($feedback->id, $groupid))) {
1500             return $values;
1501         } else {
1502             return false;
1503         }
1504     } else {
1505         if ($values = $DB->get_records('feedback_completed', array('feedback'=>$feedback->id))) {
1506             return $values;
1507         } else {
1508             return false;
1509         }
1510     }
1513 /** 
1514  *  get the count of completeds depending on the given groupid.
1515  *  @param object $feedback
1516  *  @param int $groupid
1517  *  @param int $courseid
1518  *  @return mixed count of completeds or false
1519  */
1520 function feedback_get_completeds_group_count($feedback, $groupid = false, $courseid = false) {
1521     global $CFG, $DB;
1523     if ($courseid > 0 AND !$groupid <= 0) {
1524         $sql = "SELECT id, COUNT(item) AS ci
1525                   FROM {feedback_value} 
1526                  WHERE course_id  = ?
1527               GROUP BY item ORDER BY ci DESC";
1528         if ($foundrecs = $DB->get_records_sql($sql, array($courseid))) {
1529             $foundrecs = array_values($foundrecs);
1530             return $foundrecs[0]->ci;
1531         }
1532         return false;
1533     }
1534     if($values = feedback_get_completeds_group($feedback, $groupid)) {
1535         return sizeof($values);
1536     }else {
1537         return false;
1538     }
1541 /* get the own groupid.
1542 @param object $course
1543 @param object $cm
1544 function feedback_get_groupid($course, $cm) {
1545     $groupmode = groupmode($course, $cm);
1546     
1547     //get groupid
1548     if($groupmode > 0 && !has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) {
1549         if($mygroupid = mygroupid($course->id)) {
1550             return $mygroupid[0]; //get the first groupid
1551         }
1552     }else {
1553         return false;
1554     }
1556  */
1558 /** 
1559  *  deletes all completed-recordsets from a feedback.
1560  *  all related data such as values also will be deleted
1561  *  @param int $feedbackid
1562  *  @return void
1563  */
1564 function feedback_delete_all_completeds($feedbackid) {
1565     global $DB;
1567     if (!$completeds = $DB->get_records('feedback_completed', array('feedback'=>$feedbackid))) {
1568         return;
1569     }
1570     foreach($completeds as $completed) {
1571         feedback_delete_completed($completed->id);
1572     }
1575 /** 
1576  *  deletes a completed given by completedid.
1577  *  all related data such values or tracking data also will be deleted
1578  *  @param int $completedid
1579  *  @return boolean
1580  */
1581 function feedback_delete_completed($completedid) {
1582     global $DB;
1584     if (!$completed = $DB->get_record('feedback_completed', array('id'=>$completedid))) {
1585         return false;
1586     }
1587     //first we delete all related values
1588     $DB->delete_records('feedback_value', array('completed'=>$completed->id));
1589     
1590     //now we delete all tracking data
1591     if($tracking = $DB->get_record('feedback_tracking', array('completed'=>$completed->id, 'feedback'=>$completed->feedback))) {
1592         $DB->delete_records('feedback_tracking', array('completed'=>$completed->id));
1593     }
1594         
1595     //last we delete the completed-record
1596     return $DB->delete_records('feedback_completed', array('id'=>$completed->id));
1599 ////////////////////////////////////////////////
1600 ////////////////////////////////////////////////
1601 ////////////////////////////////////////////////
1602 //functions to handle sitecourse mapping
1603 ////////////////////////////////////////////////
1605 /** 
1606  *  checks if the course and the feedback is in the table feedback_sitecourse_map.
1607  *  @param int $feedbackid
1608  *  @param int $courseid
1609  *  @return int the count of records
1610  */
1611 function feedback_is_course_in_sitecourse_map($feedbackid, $courseid) {
1612     global $DB;
1613     return $DB->count_records('feedback_sitecourse_map', array('feedbackid'=>$feedbackid, 'courseid'=>$courseid));
1616 /** 
1617  *  checks if the feedback is in the table feedback_sitecourse_map.
1618  *  @param int $feedbackid
1619  *  @return boolean
1620  */
1621 function feedback_is_feedback_in_sitecourse_map($feedbackid) {
1622     global $Db;
1623     return $DB->record_exists('feedback_sitecourse_map', array('feedbackid'=>$feedbackid));
1626 /** 
1627  *  gets the feedbacks from table feedback_sitecourse_map.
1628  *  this is used to show the global feedbacks on the feedback block
1629  *  all feedbacks with the following criteria will be selected:<br />
1630  *  1) all feedbacks which id are listed together with the courseid in sitecoursemap and<br />
1631  *  2) all feedbacks which not are listed in sitecoursemap
1632  *  @param int $courseid
1633  *  @return array the feedback-records
1634  */
1635 function feedback_get_feedbacks_from_sitecourse_map($courseid) {
1636     global $DB;
1637     
1638     //first get all feedbacks listed in sitecourse_map with named courseid
1639     $sql = "SELECT f.id AS id, cm.id AS cmid, f.name AS name, f.timeopen AS timeopen, f.timeclose AS timeclose
1640               FROM {feedback} f, {course_modules} cm, {feedback_sitecourse_map} sm, {modules} m
1641              WHERE f.id = cm.instance
1642                    AND f.course = '".SITEID."'
1643                    AND m.id = cm.module 
1644                    AND m.name = 'feedback'
1645                    AND sm.courseid = ? 
1646                    AND sm.feedbackid = f.id";
1647     
1648     if (!$feedbacks1 = $DB->get_records_sql($sql, array($courseid))) {
1649         $feedbacks1 = array();
1650     }
1651     
1652     //second get all feedbacks not listed in sitecourse_map
1653     $feedbacks2 = array();
1654     $sql = "SELECT f.id AS id, cm.id AS cmid, f.name AS name, f.timeopen AS timeopen, f.timeclose AS timeclose
1655               FROM {feedback} f, {course_modules} cm, {modules} m
1656              WHERE f.id = cm.instance
1657                    AND f.course = '".SITEID."'
1658                    AND m.id = cm.module
1659                    AND m.name = 'feedback'";
1660     if (!$allfeedbacks = $DB->get_records_sql($sql)) {
1661         $allfeedbacks = array();
1662     }
1663     foreach($allfeedbacks as $a) {
1664         if(!$DB->record_exists('feedback_sitecourse_map', array('feedbackid'=>$a->id))) {
1665             $feedbacks2[] = $a;
1666         }
1667     }
1668     
1669     return array_merge($feedbacks1, $feedbacks2);
1670     
1673 /** 
1674  *  gets the courses from table feedback_sitecourse_map.
1675  *  @param int $feedbackid
1676  *  @return array the course-records
1677  */
1678 function feedback_get_courses_from_sitecourse_map($feedbackid) {
1679     global $DB;
1680     
1681     $sql = "SELECT f.id, f.courseid, c.fullname, c.shortname
1682               FROM {feedback_sitecourse_map} f, {course} c
1683              WHERE c.id = f.courseid
1684                    AND f.feedbackid = ?
1685           ORDER BY c.fullname";
1686     
1687     return $DB->get_records_sql($sql, array($feedbackid));
1688     
1691 /** 
1692  *  removes non existing courses or feedbacks from sitecourse_map.
1693  *  it shouldn't be called all too often
1694  *  a good place for it could be the mapcourse.php or unmapcourse.php
1695  *  @return void
1696  */
1697 function feedback_clean_up_sitecourse_map() {
1698     global $DB;
1700     $maps = $DB->get_records('feedback_sitecourse_map');
1701     foreach($maps as $map) {
1702         if (!$DB->get_record('course', array('id'=>$map->courseid))) {
1703             $DB->delete_records('feedback_sitecourse_map', array('courseid'=>$map->courseid, 'feedbackid'=>$map->feedbackid));
1704             continue;
1705         }
1706         if (!$DB->get_record('feedback', array('id'=>$map->feedbackid))) {
1707             $DB->delete_records('feedback_sitecourse_map', array('courseid'=>$map->courseid, 'feedbackid'=>$map->feedbackid));
1708             continue;
1709         }
1710         
1711     }
1714 ////////////////////////////////////////////////
1715 ////////////////////////////////////////////////
1716 ////////////////////////////////////////////////
1717 //not relatable functions
1718 ////////////////////////////////////////////////
1720 /** 
1721  *  prints the option items of a selection-input item (dropdownlist).
1722  *  @param int $startval the first value of the list
1723  *  @param int $endval the last value of the list
1724  *  @param int $selectval which item should be selected
1725  *  @param int $interval the stepsize from the first to the last value
1726  *  @return void
1727  */
1728 function feedback_print_numeric_option_list($startval, $endval, $selectval = '', $interval = 1){
1729     for($i = $startval; $i <= $endval; $i += $interval){
1730         if($selectval == ($i)){
1731             $selected = 'selected="selected"';
1732         }else{
1733             $selected = '';
1734         }
1735         echo '<option '.$selected.'>'.$i.'</option>';
1736     }
1739 /** 
1740  *  sends an email to the teachers of the course where the given feedback is placed.
1741  *  @param object $cm the coursemodule-record
1742  *  @param $feedback
1743  *  @param $course
1744  *  @param $userid
1745  *  @return void
1746  */
1747 function feedback_send_email($cm, $feedback, $course, $userid) {
1748     global $CFG, $DB;
1749     
1750     if ($feedback->email_notification == 0) {  // No need to do anything
1751         return;
1752     }
1753     
1754     $user = $DB->get_record('user', array('id'=>$userid));
1755     
1756     if (groupmode($course, $cm) == SEPARATEGROUPS) {    // Separate groups are being used
1757         $groups = $DB->get_records_sql_menu("SELECT g.name, g.id
1758                                                FROM {groups} g, {groups_members} m
1759                                               WHERE g.courseid = ?
1760                                                     AND g.id = m.groupid
1761                                                     AND m.userid = ?
1762                                            ORDER BY name ASC", array($course->id, $userid));
1763         $groups = array_values($groups);
1764         
1765         $teachers = feedback_get_receivemail_users($cm->id, $groups);
1766     } else {
1767         $teachers = feedback_get_receivemail_users($cm->id);
1768     }
1769     
1770     if ($teachers) {
1772         $strfeedbacks = get_string('modulenameplural', 'feedback');
1773         $strfeedback  = get_string('modulename', 'feedback');
1774         $strcompleted  = get_string('completed', 'feedback');
1775         $printusername = $feedback->anonymous == FEEDBACK_ANONYMOUS_NO ? fullname($user) : get_string('anonymous_user', 'feedback');
1776         
1777         foreach ($teachers as $teacher) {
1778             $info = new object();
1779             $info->username = $printusername;
1780             $info->feedback = format_string($feedback->name,true);
1781             $info->url = $CFG->wwwroot.'/mod/feedback/show_entries.php?id='.$cm->id.'&userid='.$userid.'&do_show=showentries';
1783             $postsubject = $strcompleted.': '.$info->username.' -> '.$feedback->name;
1784             $posttext = feedback_send_email_text($info, $course);
1785             $posthtml = ($teacher->mailformat == 1) ? feedback_send_email_html($info, $course, $cm) : '';
1786             
1787             if($feedback->anonymous == FEEDBACK_ANONYMOUS_NO) {
1788                 @email_to_user($teacher, $user, $postsubject, $posttext, $posthtml);
1789             }else {
1790                 @email_to_user($teacher, $teacher, $postsubject, $posttext, $posthtml);
1791             }
1792         }
1793     }
1796 /** 
1797  *  sends an email to the teachers of the course where the given feedback is placed.
1798  *  @param object $cm the coursemodule-record
1799  *  @param $feedback
1800  *  @param $course
1801  *  @return void
1802  */
1803 function feedback_send_email_anonym($cm, $feedback, $course) {
1804     global $CFG;
1805     
1806     if ($feedback->email_notification == 0) {             // No need to do anything
1807         return;
1808     }
1809     
1810     $teachers = feedback_get_receivemail_users($cm->id);
1812     if ($teachers) {
1814         $strfeedbacks = get_string('modulenameplural', 'feedback');
1815         $strfeedback  = get_string('modulename', 'feedback');
1816         $strcompleted  = get_string('completed', 'feedback');
1817         $printusername = get_string('anonymous_user', 'feedback');
1818         
1819         foreach ($teachers as $teacher) {
1820             $info = new object();
1821             $info->username = $printusername;
1822             $info->feedback = format_string($feedback->name,true);
1823             $info->url = $CFG->wwwroot.'/mod/feedback/show_entries_anonym.php?id='.$cm->id;
1825             $postsubject = $strcompleted.': '.$info->username.' -> '.$feedback->name;
1826             $posttext = feedback_send_email_text($info, $course);
1827             $posthtml = ($teacher->mailformat == 1) ? feedback_send_email_html($info, $course, $cm) : '';
1828             
1829             @email_to_user($teacher, $teacher, $postsubject, $posttext, $posthtml);
1830         }
1831     }
1834 /** 
1835  *  send the text-part of the email
1836  *  @param object $info includes some infos about the feedback you want to send
1837  *  @param object $course
1838  *  @return string the text you want to post
1839  */
1840 function feedback_send_email_text($info, $course) {
1841     $posttext  = $course->shortname.' -> '.get_string('modulenameplural', 'feedback').' -> '.
1842                     $info->feedback."\n";
1843     $posttext .= '---------------------------------------------------------------------'."\n";
1844     $posttext .= get_string("emailteachermail", "feedback", $info)."\n";
1845     $posttext .= '---------------------------------------------------------------------'."\n";
1846     return $posttext;
1850 /** 
1851  *  send the html-part of the email
1852  *  @param object $info includes some infos about the feedback you want to send
1853  *  @param object $course
1854  *  @return string the text you want to post
1855  */
1856 function feedback_send_email_html($info, $course, $cm) {
1857     global $CFG;
1858     $posthtml  = '<p><font face="sans-serif">'.
1859                 '<a href="'.$CFG->wwwroot.htmlspecialchars('/course/view.php?id='.$course->id).'">'.$course->shortname.'</a> ->'.
1860                 '<a href="'.$CFG->wwwroot.htmlspecialchars('/mod/feedback/index.php?id='.$course->id).'">'.get_string('modulenameplural', 'feedback').'</a> ->'.
1861                 '<a href="'.$CFG->wwwroot.htmlspecialchars('/mod/feedback/view.php?id='.$cm->id).'">'.$info->feedback.'</a></font></p>';
1862     $posthtml .= '<hr /><font face="sans-serif">';
1863     $posthtml .= '<p>'.get_string('emailteachermailhtml', 'feedback', $info).'</p>';
1864     $posthtml .= '</font><hr />';
1865     return $posthtml;
1868 /** 
1869  *  print some errors to inform users about this.
1870  *  @return void
1871  */
1872 function feedback_print_errors() {
1873  
1874     global $SESSION;
1875                 
1876     if(empty($SESSION->feedback->errors)) {
1877                 return;
1878     }
1880     // print_simple_box_start("center", "60%", "#FFAAAA", 20, "noticebox");
1881     print_box_start('generalbox errorboxcontent boxaligncenter boxwidthnormal');
1882     print_heading(get_string('handling_error', 'feedback'));
1884     echo '<p align="center"><b><font color="black"><pre>';
1885     print_r($SESSION->feedback->errors) . "\n";
1886     echo '</pre></font></b></p>';
1887         
1888     // print_simple_box_end();
1889     print_box_end();
1890     echo '<br /><br />';
1891     $SESSION->feedback->errors = array(); //remove errors
1892
1894 function feedback_encode_target_url($url) {
1895     if (strpos($url, '?')) {
1896         list($part1, $part2) = explode('?', $url, 2); //maximal 2 parts
1897         return $part1 . '?' . htmlentities($part2);
1898     } else {
1899         return $url;
1900     }
1902 ?>