MDL-35386 completion report: Update code and improve report/csv
authorAaron Barnes <aaronb@catalyst.net.nz>
Thu, 20 Sep 2012 02:01:21 +0000 (14:01 +1200)
committerAaron Barnes <aaronb@catalyst.net.nz>
Tue, 16 Oct 2012 11:03:09 +0000 (00:03 +1300)
report/completion/index.php
report/completion/lang/en/report_completion.php
report/completion/styles.css [new file with mode: 0644]

index 457560e..a09a3dc 100644 (file)
@@ -24,8 +24,8 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-require('../../config.php');
-require_once($CFG->libdir.'/completionlib.php');
+require_once(dirname(__FILE__).'/../../config.php');
+require_once("{$CFG->libdir}/completionlib.php");
 
 /**
  * Configuration
@@ -55,6 +55,11 @@ $firstnamesort = ($sort == 'firstname');
 $excel = ($format == 'excelcsv');
 $csv = ($format == 'csv' || $excel);
 
+// Load CSV library
+if ($csv) {
+    require_once("{$CFG->libdir}/csvlib.class.php");
+}
+
 // Paging
 $start   = optional_param('start', 0, PARAM_INT);
 $sifirst = optional_param('sifirst', 'all', PARAM_ALPHA);
@@ -64,17 +69,6 @@ $silast  = optional_param('silast', 'all', PARAM_ALPHA);
 $extrafields = get_extra_user_fields($context);
 $leftcols = 1 + count($extrafields);
 
-// Function for quoting csv cell values
-function csv_quote($value) {
-    global $excel;
-    if ($excel) {
-        return textlib::convert('"'.str_replace('"',"'",$value).'"','UTF-8','UTF-16LE');
-    } else {
-        return '"'.str_replace('"',"'",$value).'"';
-    }
-}
-
-
 // Check permissions
 require_login($course);
 
@@ -146,20 +140,12 @@ if (!$csv) {
  * Setup page header
  */
 if ($csv) {
+
     $shortname = format_string($course->shortname, true, array('context' => $context));
-    header('Content-Disposition: attachment; filename=progress.'.
-        preg_replace('/[^a-z0-9-]/','_',textlib::strtolower(strip_tags($shortname))).'.csv');
-    // Unicode byte-order mark for Excel
-    if ($excel) {
-        header('Content-Type: text/csv; charset=UTF-16LE');
-        print chr(0xFF).chr(0xFE);
-        $sep="\t".chr(0);
-        $line="\n".chr(0);
-    } else {
-        header('Content-Type: text/csv; charset=UTF-8');
-        $sep=",";
-        $line="\n";
-    }
+    $shortname = preg_replace('/[^a-z0-9-]/', '_',textlib::strtolower(strip_tags($shortname)));
+
+    $export = new csv_export_writer();
+    $export->set_filename('completion-'.$shortname);
 
 } else {
     // Navigation and header
@@ -177,7 +163,6 @@ if ($csv) {
     groups_print_course_menu($course, $CFG->wwwroot.'/report/completion/?course='.$course->id);
 }
 
-
 // Generate where clause
 $where = array();
 $where_params = array();
@@ -220,7 +205,6 @@ if ($total) {
     );
 }
 
-
 // Build link for paging
 $link = $CFG->wwwroot.'/report/completion/?course='.$course->id;
 if (strlen($sort)) {
@@ -308,7 +292,6 @@ if ($total > COMPLETION_REPORT_PAGE) {
     $pagingbar .= '</div>';
 }
 
-
 /*
  * Draw table header
  */
@@ -328,7 +311,6 @@ if (!$csv) {
         exit;
     }
 
-    print '<div id="completion-progress-wrapper" class="no-overflow">';
     print '<table id="completion-progress" class="generaltable flexible boxaligncenter completionreport" style="text-align: left" cellpadding="5" border="1">';
 
     // Print criteria group names
@@ -423,7 +405,6 @@ if (!$csv) {
 
     print '</tr>';
 
-
     // Print criteria titles
     if (COMPLETION_REPORT_COL_TITLES) {
 
@@ -441,9 +422,7 @@ if (!$csv) {
 
         // Overall course completion status
         print '<th scope="col" class="colheader criterianame">';
-
         print '<span class="completion-criterianame">'.get_string('coursecomplete', 'completion').'</span>';
-
         print '</th></tr>';
     }
 
@@ -466,7 +445,6 @@ if (!$csv) {
     }
     print '</th>';
 
-
     // Print user identity columns
     foreach ($extrafields as $field) {
         echo '<th scope="col" class="completion-identifyfield">' .
@@ -486,6 +464,7 @@ if (!$csv) {
         switch ($criterion->criteriatype) {
 
             case COMPLETION_CRITERIA_TYPE_ACTIVITY:
+
                 // Display icon
                 $icon = $OUTPUT->pix_url('icon', $criterion->module);
                 $iconlink = $CFG->wwwroot.'/mod/'.$criterion->module.'/view.php?id='.$criterion->moduleinstance;
@@ -534,11 +513,37 @@ if (!$csv) {
 
     print '</tr>';
 
-
 } else {
-    // The CSV file does not contain any headers
-}
+    // The CSV headers
+    $row = array();
 
+    $row[] = get_string('id', 'report_completion');
+    $row[] = get_string('name', 'report_completion');
+    foreach ($extrafields as $field) {
+       $row[] = get_user_field_name($field);
+    }
+
+    // Add activity headers
+    foreach ($criteria as $criterion) {
+
+        // Handle activity completion differently
+        if ($criterion->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
+
+            // Load activity
+            $mod = $criterion->get_mod_instance();
+            $row[] = $mod->name;
+            $row[] = $mod->name . ' - ' . get_string('completiondate', 'report_completion');
+        }
+        else {
+            // Handle all other criteria
+            $row[] = strip_tags($criterion->get_title_detailed());
+        }
+    }
+
+    $row[] = get_string('coursecomplete', 'completion');
+
+    $export->add_data($row);
+}
 
 ///
 /// Display a row for each user
@@ -547,23 +552,28 @@ foreach ($progress as $user) {
 
     // User name
     if ($csv) {
-        print csv_quote(fullname($user));
+        $row = array();
+        $row[] = $user->id;
+        $row[] = fullname($user);
         foreach ($extrafields as $field) {
-            echo $sep . csv_quote($user->{$field});
+            $row[] = $user->{$field};
         }
     } else {
         print PHP_EOL.'<tr id="user-'.$user->id.'">';
 
-        print '<th scope="row"><a href="'.$CFG->wwwroot.'/user/view.php?id='.
-            $user->id.'&amp;course='.$course->id.'">'.fullname($user).'</a></th>';
+        $userurl = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id));
+        print '<th scope="row"><a href="'.$userurl->out().'">'.fullname($user).'</a></th>';
         foreach ($extrafields as $field) {
-            echo '<td>' . s($user->{$field}) . '</td>';
+            echo '<td>'.s($user->{$field}).'</td>';
         }
     }
 
     // Progress for each course completion criteria
     foreach ($criteria as $criterion) {
 
+        $criteria_completion = $completion->get_user_completion($user->id, $criterion);
+        $is_complete = $criteria_completion->is_complete();
+
         // Handle activity completion differently
         if ($criterion->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
 
@@ -571,39 +581,42 @@ foreach ($progress as $user) {
             $activity = $modinfo->cms[$criterion->moduleinstance];
 
             // Get progress information and state
-            if (array_key_exists($activity->id,$user->progress)) {
-                $thisprogress=$user->progress[$activity->id];
-                $state=$thisprogress->completionstate;
-                $date=userdate($thisprogress->timemodified);
+            if ($is_complete) {
+                $date = userdate($criteria_completion->timecompleted, get_string('strftimedatetimeshort', 'langconfig'));
+
+                if (array_key_exists($activity->id, $user->progress)) {
+                    $thisprogress = $user->progress[$activity->id];
+                    $state = $thisprogress->completionstate;
+                } else {
+                    $state = COMPLETION_COMPLETE;
+                }
             } else {
-                $state=COMPLETION_INCOMPLETE;
-                $date='';
+                $date = '';
+                $state = COMPLETION_INCOMPLETE;
             }
 
-            $criteria_completion = $completion->get_user_completion($user->id, $criterion);
-
             // Work out how it corresponds to an icon
             switch($state) {
-                case COMPLETION_INCOMPLETE : $completiontype='n'; break;
-                case COMPLETION_COMPLETE : $completiontype='y'; break;
-                case COMPLETION_COMPLETE_PASS : $completiontype='pass'; break;
-                case COMPLETION_COMPLETE_FAIL : $completiontype='fail'; break;
+                case COMPLETION_INCOMPLETE    : $completiontype = 'n';    break;
+                case COMPLETION_COMPLETE      : $completiontype = 'y';    break;
+                case COMPLETION_COMPLETE_PASS : $completiontype = 'pass'; break;
+                case COMPLETION_COMPLETE_FAIL : $completiontype = 'fail'; break;
             }
 
-            $completionicon='completion-'.
-                ($activity->completion==COMPLETION_TRACKING_AUTOMATIC ? 'auto' : 'manual').
-                '-'.$completiontype;
+            $auto = $activity->completion == COMPLETION_TRACKING_AUTOMATIC;
+            $completionicon = 'completion-'.($auto ? 'auto' : 'manual').'-'.$completiontype;
 
-            $describe = get_string('completion-' . $completiontype, 'completion');
-            $a=new StdClass;
-            $a->state=$describe;
-            $a->date=$date;
-            $a->user=fullname($user);
-            $a->activity=strip_tags($activity->name);
-            $fulldescribe=get_string('progress-title','completion',$a);
+            $describe = get_string('completion-'.$completiontype, 'completion');
+            $a = new StdClass();
+            $a->state     = $describe;
+            $a->date      = $date;
+            $a->user      = fullname($user);
+            $a->activity  = strip_tags($activity->name);
+            $fulldescribe = get_string('progress-title', 'completion', $a);
 
             if ($csv) {
-                print $sep.csv_quote($describe).$sep.csv_quote($date);
+                $row[] = $describe;
+                $row[] = $date;
             } else {
                 print '<td class="completion-progresscell">';
 
@@ -617,37 +630,50 @@ foreach ($progress as $user) {
         }
 
         // Handle all other criteria
-        $criteria_completion = $completion->get_user_completion($user->id, $criterion);
-        $is_complete = $criteria_completion->is_complete();
-
         $completiontype = $is_complete ? 'y' : 'n';
         $completionicon = 'completion-auto-'.$completiontype;
 
-        $describe = get_string('completion-' . $completiontype, 'completion');
+        $describe = get_string('completion-'.$completiontype, 'completion');
 
         $a = new stdClass();
         $a->state    = $describe;
-        $a->date     = $is_complete ? userdate($criteria_completion->timecompleted) : '';
+
+        if ($is_complete) {
+            $a->date = userdate($criteria_completion->timecompleted, get_string('strftimedatetimeshort', 'langconfig'));
+        } else {
+            $a->date = '';
+        }
+
         $a->user     = fullname($user);
         $a->activity = strip_tags($criterion->get_title());
         $fulldescribe = get_string('progress-title', 'completion', $a);
 
         if ($csv) {
-            print $sep.csv_quote($describe);
+            $row[] = $a->date;
         } else {
 
-            if ($allow_marking_criteria === $criterion->id) {
-                $describe = get_string('completion-' . $completiontype, 'completion');
+            print '<td class="completion-progresscell">';
 
-                print '<td class="completion-progresscell">'.
-                    '<a href="'.$CFG->wwwroot.'/course/togglecompletion.php?user='.$user->id.'&amp;course='.$course->id.'&amp;rolec='.$allow_marking_criteria.'&amp;sesskey='.sesskey().'">'.
-                    '<img src="'.$OUTPUT->pix_url('i/completion-manual-'.($is_complete ? 'y' : 'n')).
+            if ($allow_marking_criteria === $criterion->id) {
+                $describe = get_string('completion-'.$completiontype, 'completion');
+
+                $toggleurl = new moodle_url(
+                    '/course/togglecompletion.php',
+                    array(
+                        'user' => $user->id,
+                        'course' => $course->id,
+                        'rolec' => $allow_marking_criteria,
+                        'sesskey' => sesskey()
+                    )
+                );
+
+                print '<a href="'.$toggleurl->out().'"><img src="'.$OUTPUT->pix_url('i/completion-manual-'.($is_complete ? 'y' : 'n')).
                     '" alt="'.$describe.'" class="icon" title="'.get_string('markcomplete', 'completion').'" /></a></td>';
             } else {
-                print '<td class="completion-progresscell">'.
-                    '<img src="'.$OUTPUT->pix_url('i/'.$completionicon).
-                    '" alt="'.$describe.'" class="icon" title="'.$fulldescribe.'" /></td>';
+                print '<img src="'.$OUTPUT->pix_url('i/'.$completionicon).'" alt="'.$describe.'" class="icon" title="'.$fulldescribe.'" /></td>';
             }
+
+            print '</td>';
         }
     }
 
@@ -662,17 +688,23 @@ foreach ($progress as $user) {
     $ccompletion = new completion_completion($params);
     $completiontype =  $ccompletion->is_complete() ? 'y' : 'n';
 
-    $describe = get_string('completion-' . $completiontype, 'completion');
+    $describe = get_string('completion-'.$completiontype, 'completion');
 
     $a = new StdClass;
+
+    if ($ccompletion->is_complete()) {
+        $a->date = userdate($ccompletion->timecompleted, get_string('strftimedatetimeshort', 'langconfig'));
+    } else {
+        $a->date = '';
+    }
+
     $a->state    = $describe;
-    $a->date     = '';
     $a->user     = fullname($user);
     $a->activity = strip_tags(get_string('coursecomplete', 'completion'));
     $fulldescribe = get_string('progress-title', 'completion', $a);
 
     if ($csv) {
-        print $sep.csv_quote($describe);
+        $row[] = $a->date;
     } else {
 
         print '<td class="completion-progresscell">';
@@ -685,22 +717,25 @@ foreach ($progress as $user) {
     }
 
     if ($csv) {
-        print $line;
+        $export->add_data($row);
     } else {
         print '</tr>';
     }
 }
 
 if ($csv) {
-    exit;
+    $export->download_file();
 }
+
 print '</table>';
-print '</div>';
 print $pagingbar;
 
-print '<ul class="progress-actions"><li><a href="index.php?course='.$course->id.
-    '&amp;format=csv">'.get_string('csvdownload','completion').'</a></li>
-    <li><a href="index.php?course='.$course->id.'&amp;format=excelcsv">'.
-    get_string('excelcsvdownload','completion').'</a></li></ul>';
+$csvurl = new moodle_url('/report/completion/index.php', array('course' => $course->id, 'format' => 'csv'));
+$excelurl = new moodle_url('/report/completion/index.php', array('course' => $course->id, 'format' => 'excelcsv'));
+
+print '<ul class="export-actions">';
+print '<li><a href="'.$csvurl->out().'">'.get_string('csvdownload','completion').'</a></li>';
+print '<li><a href="'.$excelurl->out().'">'.get_string('excelcsvdownload','completion').'</a></li>';
+print '</ul>';
 
 echo $OUTPUT->footer($course);
index e3e8354..3492b1f 100644 (file)
@@ -26,6 +26,8 @@
 
 $string['completion:view'] = 'View course completion report';
 $string['completiondate'] = 'Completion date';
+$string['id'] = 'ID';
+$string['name'] = 'Name';
 $string['page-report-completion-x'] = 'Any completion report';
 $string['page-report-completion-index'] = 'Course completion report';
 $string['page-report-completion-user'] = 'User course completion report';
diff --git a/report/completion/styles.css b/report/completion/styles.css
new file mode 100644 (file)
index 0000000..ed84511
--- /dev/null
@@ -0,0 +1,8 @@
+#page-report-completion-index table#completion-progress {
+    margin-top: 20px;
+    margin-bottom: 30px;
+}
+
+#page-report-completion-index .export-actions {
+    text-align: center;
+}