diff --git a/course/report/stats/graph.php b/course/report/stats/graph.php index 09c69d5d1ea..90d0e9a2bc7 100644 --- a/course/report/stats/graph.php +++ b/course/report/stats/graph.php @@ -9,6 +9,7 @@ $time = required_param('time', PARAM_INT); $mode = required_param('mode', PARAM_INT); $userid = optional_param('userid', 0, PARAM_INT); + $roleid = optional_param('roleid',0,PARAM_INT); if (!$course = get_record("course","id",$courseid)) { error("That's an invalid course id"); @@ -35,14 +36,18 @@ $param->table = 'user_'.$param->table; } - $sql = 'SELECT timeend,'.$param->fields.' FROM '.$CFG->prefix.'stats_'.$param->table.' WHERE ' - . (($course->id == SITEID) ? '' : ' courseid = '.$course->id.' AND ') - . ((!empty($userid)) ? ' userid = '.$userid.' AND ' : '') + $sql = 'SELECT '.((empty($param->fieldscomplete)) ? 'id,roleid,timeend,' : '').$param->fields + .' FROM '.$CFG->prefix.'stats_'.$param->table.'_tmp WHERE ' + .(($course->id == SITEID) ? '' : ' courseid = '.$course->id.' AND ') + .((!empty($userid)) ? ' userid = '.$userid.' AND ' : '') + .((!empty($roleid)) ? ' roleid = '.$roleid.' AND ' : '') . ((!empty($param->stattype)) ? ' stattype = \''.$param->stattype.'\' AND ' : '') .' timeend >= '.$param->timeafter - .$param->extras - .' ORDER BY timeend DESC'; - + .$param->extras + .' ORDER BY timeend DESC'; + +error_log($sql); + $stats = get_records_sql($sql); $stats = stats_fix_zeros($stats,$param->timeafter,$param->table,(!empty($param->line2)),(!empty($param->line3))); @@ -57,26 +62,55 @@ $graph->parameter['title'] = false; // moodle will do a nicer job. $graph->y_tick_labels = null; - foreach ($stats as $stat) { - $graph->x_data[] = userdate($stat->timeend,get_string('strftimedate'),$CFG->timezone); - $graph->y_data['line1'][] = $stat->line1; - if (isset($stat->line2)) { - $graph->y_data['line2'][] = $stat->line2; + $c = array_keys($graph->colour); + + if (empty($param->crosstab)) { + foreach ($stats as $stat) { + $graph->x_data[] = userdate($stat->timeend,get_string('strftimedate'),$CFG->timezone); + $graph->y_data['line1'][] = $stat->line1; + if (isset($stat->line2)) { + $graph->y_data['line2'][] = $stat->line2; + } + if (isset($stat->line3)) { + $graph->y_data['line3'][] = $stat->line3; + } } - if (isset($stat->line3)) { - $graph->y_data['line3'][] = $stat->line3; + $graph->y_order = array('line1','line2'); + if (!empty($param->line3)) { + $graph->y_order[] = 'line3'; + } + $graph->y_format['line1'] = array('colour' => $c[1],'line' => 'line','legend' => $param->line1); + if (!empty($param->line2)) { + $graph->y_format['line2'] = array('colour' => $c[2],'line' => 'line','legend' => $param->line2); + } + if (!empty($param->line3)) { + $graph->y_format['line3'] = array('colour' => $c[3],'line' => 'line','legend' => $param->line3); + } + } else { + $times = array(); + $roles = array(); + foreach ($stats as $stat) { + $data[$stat->roleid][$stat->timeend] = $stat->line1; + if (!array_key_exists($stat->roleid,$roles)) { + $roles[$stat->roleid] = get_field('role','name','id',$stat->roleid); + } + if (!array_key_exists($stat->timeend,$times)) { + $times[$stat->timeend] = userdate($stat->timeend,get_string('strftimedate'),$CFG->timezone); + } + } + + foreach (array_keys($data) as $roleid) { + $graph->y_order[] = $roleid; + $graph->y_format[$roleid] = array('colour' => $c[$roleid], 'line' => 'line','legend' => $roles[$roleid]); + } + foreach (array_keys($data[$roleid]) as $time) { + $graph->x_data[] = $times[$time]; + } + foreach ($data as $roleid => $t) { + foreach ($t as $time => $data) { + $graph->y_data[$roleid][] = $data; + } } - } - $graph->y_order = array('line1','line2'); - if (!empty($param->line3)) { - $graph->y_order[] = 'line3'; - } - $graph->y_format['line1'] = array('colour' => 'blue','line' => 'line','legend' => $param->line1); - if (!empty($param->line2)) { - $graph->y_format['line2'] = array('colour' => 'red','line' => 'line','legend' => $param->line2); - } - if (!empty($param->line3)) { - $graph->y_format['line3'] = array('colour' => 'black','line' => 'line','legend' => $param->line3); } $graph->draw_stack(); diff --git a/course/report/stats/index.php b/course/report/stats/index.php index 6554fb7f17b..fe4147211fa 100644 --- a/course/report/stats/index.php +++ b/course/report/stats/index.php @@ -14,6 +14,11 @@ $mode = optional_param('mode', STATS_MODE_GENERAL, PARAM_INT); $userid = optional_param('userid', 0, PARAM_INT); + if ($report > 50) { + $roleid = substr($report,1); + $report = 5; + } + if ($report == STATS_REPORT_USER_LOGINS) { $courseid = SITEID; //override } diff --git a/course/report/stats/lib.php b/course/report/stats/lib.php index b8ec0a97422..c262513606c 100644 --- a/course/report/stats/lib.php +++ b/course/report/stats/lib.php @@ -10,13 +10,13 @@ function report_stats_mode_menu($course, $mode, $time) { global $CFG; - + /* $reportoptions = stats_get_report_options($course->id, $mode); $timeoptions = report_stats_timeoptions($mode); - if (empty($timeoptions)) { error(get_string('nostatstodisplay'), $CFG->wwwroot.'/course/view.php?id='.$course->id); } + */ $options = array(); $options[STATS_MODE_GENERAL] = get_string('statsmodegeneral'); diff --git a/course/report/stats/report.php b/course/report/stats/report.php index 4e9ed321aaa..3e2accfe950 100644 --- a/course/report/stats/report.php +++ b/course/report/stats/report.php @@ -1,7 +1,5 @@ <?php - // all queries on teacher table will break (i mean already broken) - $courses = get_courses('all','c.shortname','c.id,c.shortname,c.fullname'); $courseoptions = array(); @@ -19,6 +17,10 @@ $reportoptions = stats_get_report_options($course->id, $mode); $timeoptions = report_stats_timeoptions($mode); + if (empty($timeoptions)) { + error(get_string('nostatstodisplay'), $CFG->wwwroot.'/course/view.php?id='.$course->id); + } + $table->width = '*'; if ($mode == STATS_MODE_DETAILED) { @@ -76,13 +78,13 @@ $table->align = array('left','left','left','left','left','left','left','left'); $table->data[] = array(get_string('course'),choose_from_menu($courseoptions,'course',$course->id,'','','',true), get_string('users'),choose_from_menu($users,'userid',$userid,'','','',true), - get_string('statsreporttype'),choose_from_menu($reportoptions,'report',$report,'','','',true), + get_string('statsreporttype'),choose_from_menu($reportoptions,'report',($report == 5) ? $report.$roleid : $report,'','','',true), get_string('statstimeperiod'),choose_from_menu($timeoptions,'time',$time,'','','',true), '<input type="submit" value="'.get_string('view').'" />') ; } else { $table->align = array('left','left','left','left','left','left','left'); $table->data[] = array(get_string('course'),choose_from_menu($courseoptions,'course',$course->id,'','','',true), - get_string('statsreporttype'),choose_from_menu($reportoptions,'report',$report,'','','',true), + get_string('statsreporttype'),choose_from_menu($reportoptions,'report',($report == 5) ? $report.$roleid : $report,'','','',true), get_string('statstimeperiod'),choose_from_menu($timeoptions,'time',$time,'','','',true), '<input type="submit" value="'.get_string('view').'" />') ; } @@ -96,26 +98,31 @@ error("This type of report is only available for the site course"); } $param = stats_get_parameters($time,$report,$course->id,$mode); + if ($mode == STATS_MODE_DETAILED) { $param->table = 'user_'.$param->table; } - $sql = 'SELECT timeend,'.$param->fields.' FROM '.$CFG->prefix.'stats_'.$param->table.' WHERE ' + $sql = 'SELECT '.((empty($param->fieldscomplete)) ? 'id,roleid,timeend,' : '').$param->fields + .' FROM '.$CFG->prefix.'stats_'.$param->table.'_tmp WHERE ' .(($course->id == SITEID) ? '' : ' courseid = '.$course->id.' AND ') .((!empty($userid)) ? ' userid = '.$userid.' AND ' : '') + .((!empty($roleid)) ? ' roleid = '.$roleid.' AND ' : '') . ((!empty($param->stattype)) ? ' stattype = \''.$param->stattype.'\' AND ' : '') .' timeend >= '.$param->timeafter .$param->extras .' ORDER BY timeend DESC'; - $stats = get_records_sql($sql); if (empty($stats)) { error(get_string('statsnodata'.((!empty($user)) ? 'user' : '')),$CFG->wwwroot.'/stats/index.php?course='.$course->id.'&mode='.$mode.'&time='.$time); } - + $stats = stats_fix_zeros($stats,$param->timeafter,$param->table,(!empty($param->line2))); - print_heading($course->shortname.' - '.get_string('statsreport'.$report).((!empty($user)) ? ' '.get_string('statsreportforuser').' ' .fullname($user,true) : '')); + print_heading($course->shortname.' - '.get_string('statsreport'.$report) + .((!empty($user)) ? ' '.get_string('statsreportforuser').' ' .fullname($user,true) : '') + .((!empty($roleid)) ? ' '.get_field('role','name','id',$roleid) : '')); + if (empty($CFG->gdversion)) { echo "(".get_string("gdneed").")"; @@ -123,28 +130,67 @@ if ($mode == STATS_MODE_DETAILED) { echo '<center><img src="'.$CFG->wwwroot.'/course/report/stats/graph.php?mode='.$mode.'&course='.$course->id.'&time='.$time.'&report='.$report.'&userid='.$userid.'" /></center>'; } else { - echo '<center><img src="'.$CFG->wwwroot.'/course/report/stats/graph.php?mode='.$mode.'&course='.$course->id.'&time='.$time.'&report='.$report.'" /></center>'; + echo '<center><img src="'.$CFG->wwwroot.'/course/report/stats/graph.php?mode='.$mode.'&course='.$course->id.'&time='.$time.'&report='.$report.'&roleid='.$roleid.'" /></center>'; } } - $table = new object(); + $table = new StdClass; $table->align = array('left','center','center','center'); $param->table = str_replace('user_','',$param->table); - $table->head = array(get_string('periodending','moodle',$param->table),$param->line1); - if (!empty($param->line2)) { - $table->head[] = $param->line2; + $table->head = array(get_string('periodending','moodle',$param->table)); + if (empty($param->crosstab)) { + $table->head[] = $param->line1; + if (!empty($param->line2)) { + $table->head[] = $param->line2; + } + } + $lasttime = null; // used for crosstab + $lastrecord = null; + $lastlink = null; + $headerdone = false; + + foreach ($stats as $stat) { + if (empty($param->crosstab)) { + $a = array(userdate($stat->timeend-(60*60*24),get_string('strftimedate'),$CFG->timezone),$stat->line1); + if (isset($stat->line2)) { + $a[] = $stat->line2; + } + if (empty($CFG->loglifetime) || ($stat->timeend-(60*60*24)) >= (time()-60*60*24*$CFG->loglifetime)) { + $a[] = '<a href="'.$CFG->wwwroot.'/course/report/log/index.php?id='. + $course->id.'&chooselog=1&showusers=1&showcourses=1&user=' + .$userid.'&date='.usergetmidnight($stat->timeend-(60*60*24)).'">' + .get_string('course').' ' .get_string('logs').'</a> '; + } + $table->data[] = $a; + } else { + if ($stat->timeend == $lasttime) { + $lastrecord[] = $stat->line1; + if (empty($headerdone)) { + $table->head[] = get_field('role','name','id',$stat->roleid); + } + } else { + if (!empty($lastrecord)) { // we won't have one if this is the first time round... + $lastrecord[] = $lastlink; + $table->data[] = $lastrecord; + $headerdone = true; + } else { + $table->head[] = get_field('role','name','id',$stat->roleid); + } + $lastrecord = array(userdate($stat->timeend-(60*60*24),get_string('strftimedate'),$CFG->timezone),$stat->line1); + if (empty($CFG->loglifetime) || ($stat->timeend-(60*60*24)) >= (time()-60*60*24*$CFG->loglifetime)) { + $lastlink = '<a href="'.$CFG->wwwroot.'/course/report/log/index.php?id=' + .$course->id.'&chooselog=1&showusers=1&showcourses=1&user='.$userid + .'&date='.usergetmidnight($stat->timeend-(60*60*24)).'">' + .get_string('course').' ' .get_string('logs').'</a> '; + } + $lasttime = $stat->timeend; + } + } } $table->head[] = get_string('logs'); - - foreach ($stats as $stat) { - $a = array(userdate($stat->timeend-(60*60*24),get_string('strftimedate'),$CFG->timezone),$stat->line1); - if (isset($stat->line2)) { - $a[] = $stat->line2; - } - if (empty($CFG->loglifetime) || ($stat->timeend-(60*60*24)) >= (time()-60*60*24*$CFG->loglifetime)) { - $a[] = '<a href="'.$CFG->wwwroot.'/course/report/log/index.php?id='.$course->id.'&chooselog=1&showusers=1&showcourses=1&user='.$userid.'&date='.usergetmidnight($stat->timeend-(60*60*24)).'">'.get_string('course').' ' .get_string('logs').'</a> '; - } - $table->data[] = $a; + if (!empty($lastrecord)) { + $lastrecord[] = $lastlink; + $table->data[] = $lastrecord; } print_table($table); } diff --git a/lang/en_utf8/moodle.php b/lang/en_utf8/moodle.php index de331115f7f..a1d746fc0aa 100644 --- a/lang/en_utf8/moodle.php +++ b/lang/en_utf8/moodle.php @@ -1220,18 +1220,18 @@ $string['stats'] = 'Statistics'; $string['statsnodata'] = 'There is no available data for that combination of course and time period.'; $string['statsnodatauser'] = 'There is no available data for that combination of course, user and time period.'; $string['statsoff'] = 'Statistics is not currently enabled'; +$string['statsreads'] = 'Views'; +$string['statswrites'] = 'Posts'; $string['statsreportlogins'] = 'Logins'; -$string['statsreportreads'] = 'Views (teacher and student)'; -$string['statsreportwrites'] = 'Posts (teacher and student)'; -$string['statsreportactivity'] = 'All activity (teacher and student)'; -$string['statsreportstudentactivity'] = 'All student activity (views and posts)'; -$string['statsreportteacheractivity'] = 'All teacher activity (views and posts)'; +$string['statsreportreads'] = 'Views (all roles)'; +$string['statsreportwrites'] = 'Posts (all roles)'; +$string['statsreportactivity'] = 'All activity (all roles)'; +$string['statsreportactivitybyrole'] = 'All activity (views and posts)'; $string['statsreport1'] = 'Logins'; -$string['statsreport2'] = 'Views (teacher and student)'; -$string['statsreport3'] = 'Posts (teacher and student)'; -$string['statsreport4'] = 'All activity (teacher and student)'; -$string['statsreport5'] = 'All student activity (views and posts)'; -$string['statsreport6'] = 'All teacher activity (views and posts)'; +$string['statsreport2'] = 'Views (all roles)'; +$string['statsreport3'] = 'Posts (all roles)'; +$string['statsreport4'] = 'All activity (all roles)'; +$string['statsreport5'] = 'All activity (views and posts)'; $string['statsreport7'] = 'User activity (views and posts)'; $string['statsreport8'] = 'All User activity'; $string['statsreport9'] = 'Logins (site course)'; diff --git a/lib/statslib.php b/lib/statslib.php index 6452ea233bb..591caeff13d 100644 --- a/lib/statslib.php +++ b/lib/statslib.php @@ -6,9 +6,8 @@ define('STATS_REPORT_READS',2); // double impose student reads and teacher reads on a line graph. define('STATS_REPORT_WRITES',3); // double impose student writes and teacher writes on a line graph. define('STATS_REPORT_ACTIVITY',4); // 2+3 added up, teacher vs student. - define('STATS_REPORT_STUDENTACTIVITY',5); // all student activity, reads vs writes - define('STATS_REPORT_TEACHERACTIVITY',6); // all teacher activity, reads vs writes - + define('STATS_REPORT_ACTIVITYBYROLE',5); // all activity, reads vs writes, seleted by role. + // user level stats reports. define('STATS_REPORT_USER_ACTIVITY',7); define('STATS_REPORT_USER_ALLACTIVITY',8); @@ -134,7 +133,7 @@ function stats_cron_daily () { } $context = get_record('context','instanceid',$course->id,'contextlevel',CONTEXT_COURSE); - if (!$roles = get_roles_used_in_context($context)) { + if (!$roles = get_roles_on_exact_context($context)) { // no roles.. nothing to log. continue; } @@ -582,8 +581,8 @@ function stats_clean_old() { // don't delete monthlies } -function stats_get_parameters($time,$report,$courseid,$mode) { - global $CFG; +function stats_get_parameters($time,$report,$courseid,$mode,$roleid=0) { + global $CFG,$db; if ($time < 10) { // dailies // number of days to go back = 7* time $param->table = 'daily'; @@ -607,35 +606,39 @@ function stats_get_parameters($time,$report,$courseid,$mode) { } switch ($report) { - case STATS_REPORT_LOGINS: - $param->fields = 'logins as line1,uniquelogins as line2'; + case STATS_REPORT_LOGINS: // done + $param->fields = 'stat1 as line1,stat2 as line2'; + $param->stattype = 'logins'; $param->line1 = get_string('statslogins'); $param->line2 = get_string('statsuniquelogins'); break; - case STATS_REPORT_READS: - $param->fields = 'studentreads as line1,teacherreads as line2'; - $param->line1 = get_string('statsstudentreads'); - $param->line2 = get_string('statsteacherreads'); + case STATS_REPORT_READS: // done + $param->fields = $db->Concat('timeend','roleid').' AS UNIQUE, timeend, roleid, stat1 as line1'; + $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries. + $param->stattype = 'activity'; + $param->crosstab = true; + $param->extras = 'GROUP BY timeend,roleid,stat1'; break; - case STATS_REPORT_WRITES: - $param->fields = 'studentwrites as line1,teacherwrites as line2'; - $param->line1 = get_string('statsstudentwrites'); - $param->line2 = get_string('statsteacherwrites'); + case STATS_REPORT_WRITES: //done + $param->fields = $db->Concat('timeend','roleid').' AS UNIQUE, timeend, roleid, stat2 as line1'; + $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries. + $param->stattype = 'activity'; + $param->crosstab = true; + $param->extras = 'GROUP BY timeend,roleid,stat2'; break; - case STATS_REPORT_ACTIVITY: - $param->fields = 'studentreads+studentwrites as line1, teacherreads+teacherwrites as line2'; - $param->line1 = get_string('statsstudentactivity'); - $param->line2 = get_string('statsteacheractivity'); + case STATS_REPORT_ACTIVITY: //done + $param->fields = $db->Concat('timeend','roleid').' AS UNIQUE, timeend, roleid, sum(stat1+stat2) as line1'; + $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries. + $param->stattype = 'activity'; + $param->crosstab = true; + $param->extras = 'GROUP BY timeend,roleid'; break; - case STATS_REPORT_STUDENTACTIVITY: - $param->fields = 'studentreads as line1,studentwrites as line2'; - $param->line1 = get_string('statsstudentreads'); - $param->line2 = get_string('statsstudentwrites'); - break; - case STATS_REPORT_TEACHERACTIVITY: - $param->fields = 'teacherreads as line1,teacherwrites as line2'; - $param->line1 = get_string('statsteacherreads'); - $param->line2 = get_string('statsteacherwrites'); + case STATS_REPORT_ACTIVITYBYROLE; + $param->fields = 'stat1 AS line1, stat2 AS line2'; + $param->stattype = 'activity'; + $rolename = get_field('role','name','id',$roleid); + $param->line1 = $rolename . get_string('statsreads'); + $param->line2 = $rolename . get_string('statswrites'); break; case STATS_REPORT_USER_ACTIVITY: $param->fields = 'statsreads as line1, statswrites as line2'; @@ -704,7 +707,6 @@ function stats_get_parameters($time,$report,$courseid,$mode) { $param->graphline = 'line3'; break; } - if ($courseid == SITEID && $mode != STATS_MODE_RANKED) { // just aggregate all courses. $param->fields = preg_replace('/([a-zA-Z0-9+_]*)\W+as\W+([a-zA-Z0-9_]*)/','sum($1) as $2',$param->fields); $param->extras = ' GROUP BY timeend'; @@ -908,14 +910,21 @@ function stats_get_time_options($now,$lastweekend,$lastmonthend,$earliestday,$ea } function stats_get_report_options($courseid,$mode) { + global $CFG; $reportoptions = array(); switch ($mode) { case STATS_MODE_GENERAL: $reportoptions[STATS_REPORT_ACTIVITY] = get_string('statsreport'.STATS_REPORT_ACTIVITY); - $reportoptions[STATS_REPORT_STUDENTACTIVITY] = get_string('statsreport'.STATS_REPORT_STUDENTACTIVITY); - $reportoptions[STATS_REPORT_TEACHERACTIVITY] = get_string('statsreport'.STATS_REPORT_TEACHERACTIVITY); + if ($context = get_record('context','instanceid',$courseid,'contextlevel',CONTEXT_COURSE)) { + $sql = 'SELECT r.id,r.name FROM '.$CFG->prefix.'role r JOIN '.$CFG->prefix.'stats_daily s ON s.roleid = r.id WHERE s.courseid = '.$courseid; + if ($roles = get_records_sql($sql)) { + foreach ($roles as $role) { + $reportoptions[STATS_REPORT_ACTIVITYBYROLE.$role->id] = get_string('statsreport'.STATS_REPORT_ACTIVITYBYROLE). ' '.$role->name; + } + } + } $reportoptions[STATS_REPORT_READS] = get_string('statsreport'.STATS_REPORT_READS); $reportoptions[STATS_REPORT_WRITES] = get_string('statsreport'.STATS_REPORT_WRITES); if ($courseid == SITEID) { @@ -957,7 +966,10 @@ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { $times = array(); // add something to timeafter since it is our absolute base - $actualtimes = array_keys($stats); + $actualtimes = array(); + foreach ($stats as $s) { + $actualtimes[] = $s->timeend; + } $timeafter = array_pop($actualtimes); while ($timeafter < $now) { @@ -973,8 +985,8 @@ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { } } - foreach ($times as $time) { - if (!array_key_exists($time,$stats)) { + foreach ($times as $count => $time) { + if (!in_array($time,$actualtimes) && $count != count($times) -1) { $newobj = new StdClass; $newobj->timeend = $time; $newobj->id = 0; @@ -985,15 +997,23 @@ function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) { if (!empty($line3)) { $newobj->line3 = 0; } - $stats[$time] = $newobj; + $stats[] = $newobj; } } - krsort($stats); + usort($stats,"stats_compare_times"); return $stats; } +// helper function to sort arrays by $obj->timeend +function stats_compare_times($a,$b) { + if ($a->timeend == $b->timeend) { + return 0; + } + return ($a->timeend > $b->timeend) ? -1 : 1; +} + function stats_check_runtime() { global $CFG; @@ -1244,7 +1264,7 @@ function stats_upgrade_table_for_roles ($period) { execute_sql("INSERT INTO {$CFG->prefix}stats_{$period} (courseid, roleid, timeend, stattype, stat1, stat2) SELECT courseid, 0, timeend, 'logins', logins, uniquelogins - FROM {$CFG->prefix}stats_{$period}_tmp"); + FROM {$CFG->prefix}stats_{$period}_tmp WHERE course = ".SITEID); // Drop the temporary table $table = new XMLDBTable('stats_' . $period . '_tmp');