Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/statslib.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00025 defined('MOODLE_INTERNAL') || die();
00026 
00029 define('STATS_REPORT_LOGINS',1); // double impose logins and unique logins on a line graph. site course only.
00030 define('STATS_REPORT_READS',2); // double impose student reads and teacher reads on a line graph.
00031 define('STATS_REPORT_WRITES',3); // double impose student writes and teacher writes on a line graph.
00032 define('STATS_REPORT_ACTIVITY',4); // 2+3 added up, teacher vs student.
00033 define('STATS_REPORT_ACTIVITYBYROLE',5); // all activity, reads vs writes, selected by role.
00034 
00035 // user level stats reports.
00036 define('STATS_REPORT_USER_ACTIVITY',7);
00037 define('STATS_REPORT_USER_ALLACTIVITY',8);
00038 define('STATS_REPORT_USER_LOGINS',9);
00039 define('STATS_REPORT_USER_VIEW',10);  // this is the report you see on the user profile.
00040 
00041 // admin only ranking stats reports
00042 define('STATS_REPORT_ACTIVE_COURSES',11);
00043 define('STATS_REPORT_ACTIVE_COURSES_WEIGHTED',12);
00044 define('STATS_REPORT_PARTICIPATORY_COURSES',13);
00045 define('STATS_REPORT_PARTICIPATORY_COURSES_RW',14);
00046 
00047 // start after 0 = show dailies.
00048 define('STATS_TIME_LASTWEEK',1);
00049 define('STATS_TIME_LAST2WEEKS',2);
00050 define('STATS_TIME_LAST3WEEKS',3);
00051 define('STATS_TIME_LAST4WEEKS',4);
00052 
00053 // start after 10 = show weeklies
00054 define('STATS_TIME_LAST2MONTHS',12);
00055 
00056 define('STATS_TIME_LAST3MONTHS',13);
00057 define('STATS_TIME_LAST4MONTHS',14);
00058 define('STATS_TIME_LAST5MONTHS',15);
00059 define('STATS_TIME_LAST6MONTHS',16);
00060 
00061 // start after 20 = show monthlies
00062 define('STATS_TIME_LAST7MONTHS',27);
00063 define('STATS_TIME_LAST8MONTHS',28);
00064 define('STATS_TIME_LAST9MONTHS',29);
00065 define('STATS_TIME_LAST10MONTHS',30);
00066 define('STATS_TIME_LAST11MONTHS',31);
00067 define('STATS_TIME_LASTYEAR',32);
00068 
00069 // different modes for what reports to offer
00070 define('STATS_MODE_GENERAL',1);
00071 define('STATS_MODE_DETAILED',2);
00072 define('STATS_MODE_RANKED',3); // admins only - ranks courses
00073 
00078 function stats_daily_progress($ident) {
00079     static $start = 0;
00080     static $init  = 0;
00081 
00082     if ($ident == 'init') {
00083         $init = $start = time();
00084         return;
00085     }
00086 
00087     $elapsed = time() - $start;
00088     $start   = time();
00089 
00090     if (debugging('', DEBUG_ALL)) {
00091         mtrace("$ident:$elapsed ", '');
00092     } else {
00093         mtrace('.', '');
00094     }
00095 }
00096 
00102 function stats_cron_daily($maxdays=1) {
00103     global $CFG, $DB;
00104 
00105     $now = time();
00106 
00107     $fpcontext = get_context_instance(CONTEXT_COURSE, SITEID, MUST_EXIST);
00108 
00109     // read last execution date from db
00110     if (!$timestart = get_config(NULL, 'statslastdaily')) {
00111         $timestart = stats_get_base_daily(stats_get_start_from('daily'));
00112         set_config('statslastdaily', $timestart);
00113     }
00114 
00115     // calculate scheduled time
00116     $scheduledtime = stats_get_base_daily() + $CFG->statsruntimestarthour*60*60 + $CFG->statsruntimestartminute*60;
00117 
00118     // Note: This will work fine for sites running cron each 4 hours or less (hopefully, 99.99% of sites). MDL-16709
00119     // check to make sure we're due to run, at least 20 hours after last run
00120     if (isset($CFG->statslastexecution) and ((time() - 20*60*60) < $CFG->statslastexecution)) {
00121         mtrace("...preventing stats to run, last execution was less than 20 hours ago.");
00122         return false;
00123     // also check that we are a max of 4 hours after scheduled time, stats won't run after that
00124     } else if (time() > $scheduledtime + 4*60*60) {
00125         mtrace("...preventing stats to run, more than 4 hours since scheduled time.");
00126         return false;
00127     } else {
00128         set_config('statslastexecution', time()); 
00129     }
00130 
00131     $nextmidnight = stats_get_next_day_start($timestart);
00132 
00133     // are there any days that need to be processed?
00134     if ($now < $nextmidnight) {
00135         return true; // everything ok and up-to-date
00136     }
00137 
00138 
00139     $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime;
00140 
00141     if (!set_cron_lock('statsrunning', $now + $timeout)) {
00142         return false;
00143     }
00144 
00145     // first delete entries that should not be there yet
00146     $DB->delete_records_select('stats_daily',      "timeend > $timestart");
00147     $DB->delete_records_select('stats_user_daily', "timeend > $timestart");
00148 
00149     // Read in a few things we'll use later
00150     $viewactions = stats_get_action_names('view');
00151     $postactions = stats_get_action_names('post');
00152 
00153     $guest           = (int)$CFG->siteguest;
00154     $guestrole       = (int)$CFG->guestroleid;
00155     $defaultfproleid = (int)$CFG->defaultfrontpageroleid;
00156 
00157     mtrace("Running daily statistics gathering, starting at $timestart:");
00158 
00159     $days = 0;
00160     $failed = false; // failed stats flag
00161 
00162     while ($now > $nextmidnight) {
00163         if ($days >= $maxdays) {
00164             mtrace("...stopping early, reached maximum number of $maxdays days - will continue next time.");
00165             set_cron_lock('statsrunning', null);
00166             return false;
00167         }
00168 
00169         $days++;
00170         @set_time_limit($timeout - 200);
00171 
00172         if ($days > 1) {
00173             // move the lock
00174             set_cron_lock('statsrunning', time() + $timeout, true);
00175         }
00176 
00177         $daystart = time();
00178 
00179         $timesql  = "l.time >= $timestart  AND l.time  < $nextmidnight";
00180         $timesql1 = "l1.time >= $timestart AND l1.time < $nextmidnight";
00181         $timesql2 = "l2.time >= $timestart AND l2.time < $nextmidnight";
00182 
00183         stats_daily_progress('init');
00184 
00185 
00187         $sql = "SELECT 'x'
00188                   FROM {log} l
00189                  WHERE $timesql";
00190         $logspresent = $DB->get_records_sql($sql, null, 0, 1);
00191 
00193         $sql = "INSERT INTO {stats_user_daily} (stattype, timeend, courseid, userid, statsreads)
00194 
00195                 SELECT 'logins', timeend, courseid, userid, count(statsreads)
00196                  FROM (
00197                           SELECT $nextmidnight AS timeend, ".SITEID." AS courseid, l.userid, l.id AS statsreads
00198                             FROM {log} l
00199                            WHERE action = 'login' AND $timesql
00200                        ) inline_view
00201               GROUP BY timeend, courseid, userid
00202                 HAVING count(statsreads) > 0";
00203 
00204         if ($logspresent and !$DB->execute($sql)) {
00205             $failed = true;
00206             break;
00207         }
00208         stats_daily_progress('1');
00209 
00210         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00211 
00212                 SELECT 'logins' AS stattype, $nextmidnight AS timeend, ".SITEID." as courseid, 0,
00213                        COALESCE((SELECT SUM(statsreads)
00214                                        FROM {stats_user_daily} s1
00215                                       WHERE s1.stattype = 'logins' AND timeend = $nextmidnight), 0) AS stat1,
00216                        (SELECT COUNT('x')
00217                           FROM {stats_user_daily} s2
00218                          WHERE s2.stattype = 'logins' AND timeend = $nextmidnight) AS stat2" .
00219                 $DB->sql_null_from_clause();
00220 
00221         if ($logspresent and !$DB->execute($sql)) {
00222             $failed = true;
00223             break;
00224         }
00225         stats_daily_progress('2');
00226 
00227 
00228         // Enrolments and active enrolled users
00229         //
00230         // Unfortunately, we do not know how many users were registered
00231         // at given times in history :-(
00232         // - stat1: enrolled users
00233         // - stat2: enrolled users active in this period
00234         // - SITEID is special case here, because it's all about default enrolment
00235         //   in that case, we'll count non-deleted users.
00236         //
00237 
00238         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00239 
00240                 SELECT 'enrolments', timeend, courseid, roleid, COUNT(DISTINCT userid), 0
00241                   FROM (
00242                            SELECT $nextmidnight AS timeend, e.courseid, ra.roleid, ue.userid
00243                              FROM {role_assignments} ra
00244                              JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :courselevel)
00245                              JOIN {enrol} e ON e.courseid = c.instanceid
00246                              JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid)
00247                         ) inline_view
00248               GROUP BY timeend, courseid, roleid";
00249 
00250         if (!$DB->execute($sql, array('courselevel'=>CONTEXT_COURSE))) {
00251             $failed = true;
00252             break;
00253         }
00254         stats_daily_progress('3');
00255 
00256         // using table alias in UPDATE does not work in pg < 8.2
00257         $sql = "UPDATE {stats_daily}
00258                    SET stat2 = (SELECT COUNT(DISTINCT ra.userid)
00259                                   FROM {role_assignments} ra
00260                                   JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :courselevel)
00261                                   JOIN {enrol} e ON e.courseid = c.instanceid
00262                                   JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid)
00263                                   WHERE ra.roleid = {stats_daily}.roleid AND
00264                                        e.courseid = {stats_daily}.courseid AND
00265                                        EXISTS (SELECT 'x'
00266                                                  FROM {log} l
00267                                                 WHERE l.course = {stats_daily}.courseid AND
00268                                                       l.userid = ra.userid AND $timesql))
00269                  WHERE {stats_daily}.stattype = 'enrolments' AND
00270                        {stats_daily}.timeend = $nextmidnight AND
00271                        {stats_daily}.courseid IN
00272                           (SELECT DISTINCT l.course
00273                              FROM {log} l
00274                             WHERE $timesql)";
00275 
00276         if (!$DB->execute($sql, array('courselevel'=>CONTEXT_COURSE))) {
00277             $failed = true;
00278             break;
00279         }
00280         stats_daily_progress('4');
00281 
00283         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00284 
00285                 SELECT 'enrolments', timeend, id, nroleid, COUNT(DISTINCT userid), 0
00286                   FROM (
00287                            SELECT $nextmidnight AS timeend, e.courseid AS id, 0 AS nroleid, ue.userid
00288                              FROM {enrol} e
00289                              JOIN {user_enrolments} ue ON ue.enrolid = e.id
00290                        ) inline_view
00291               GROUP BY timeend, id, nroleid
00292                 HAVING COUNT(DISTINCT userid) > 0";
00293 
00294         if ($logspresent and !$DB->execute($sql)) {
00295             $failed = true;
00296             break;
00297         }
00298         stats_daily_progress('5');
00299 
00300         $sql = "UPDATE {stats_daily}
00301                    SET stat2 = (SELECT COUNT(DISTINCT ue.userid)
00302                                   FROM {enrol} e
00303                                   JOIN {user_enrolments} ue ON ue.enrolid = e.id
00304                                  WHERE e.courseid = {stats_daily}.courseid AND
00305                                        EXISTS (SELECT 'x'
00306                                                  FROM {log} l
00307                                                 WHERE l.course = {stats_daily}.courseid AND
00308                                                       l.userid = ue.userid AND $timesql))
00309                  WHERE {stats_daily}.stattype = 'enrolments' AND
00310                        {stats_daily}.timeend = $nextmidnight AND
00311                        {stats_daily}.roleid = 0 AND
00312                        {stats_daily}.courseid IN
00313                           (SELECT l.course
00314                              FROM {log} l
00315                             WHERE $timesql AND l.course <> ".SITEID.")";
00316 
00317         if ($logspresent and !$DB->execute($sql, array())) {
00318             $failed = true;
00319             break;
00320         }
00321         stats_daily_progress('6');
00322 
00324         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00325 
00326                 SELECT 'enrolments', $nextmidnight, ".SITEID.", 0,
00327                        (SELECT COUNT('x')
00328                           FROM {user} u
00329                          WHERE u.deleted = 0) AS stat1,
00330                        (SELECT COUNT(DISTINCT u.id)
00331                           FROM {user} u
00332                                JOIN {log} l ON l.userid = u.id
00333                          WHERE u.deleted = 0 AND $timesql) AS stat2" .
00334                 $DB->sql_null_from_clause();
00335 
00336         if ($logspresent and !$DB->execute($sql)) {
00337             $failed = true;
00338             break;
00339         }
00340         stats_daily_progress('7');
00341 
00343         if ($defaultfproleid) {
00344             // first remove default frontpage role counts if created by previous query
00345             $sql = "DELETE
00346                       FROM {stats_daily}
00347                      WHERE stattype = 'enrolments' AND courseid = ".SITEID." AND
00348                            roleid = $defaultfproleid AND timeend = $nextmidnight";
00349             if ($logspresent and !$DB->execute($sql)) {
00350                 $failed = true;
00351                 break;
00352             }
00353             stats_daily_progress('8');
00354 
00355             $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00356 
00357                     SELECT 'enrolments', $nextmidnight, ".SITEID.", $defaultfproleid,
00358                            (SELECT COUNT('x')
00359                               FROM {user} u
00360                              WHERE u.deleted = 0) AS stat1,
00361                            (SELECT COUNT(DISTINCT u.id)
00362                               FROM {user} u
00363                                    JOIN {log} l ON l.userid = u.id
00364                              WHERE u.deleted = 0 AND $timesql) AS stat2" .
00365                     $DB->sql_null_from_clause();;
00366 
00367             if ($logspresent and !$DB->execute($sql)) {
00368                 $failed = true;
00369                 break;
00370             }
00371             stats_daily_progress('9');
00372 
00373         } else {
00374             stats_daily_progress('x');
00375             stats_daily_progress('x');
00376         }
00377 
00378 
00379 
00381         list($viewactionssql, $params1) = $DB->get_in_or_equal($viewactions, SQL_PARAMS_NAMED, 'view');
00382         list($postactionssql, $params2) = $DB->get_in_or_equal($postactions, SQL_PARAMS_NAMED, 'post');
00383         $sql = "INSERT INTO {stats_user_daily} (stattype, timeend, courseid, userid, statsreads, statswrites)
00384 
00385                 SELECT 'activity' AS stattype, $nextmidnight AS timeend, d.courseid, d.userid,
00386                        (SELECT COUNT('x')
00387                           FROM {log} l
00388                          WHERE l.userid = d.userid AND
00389                                l.course = d.courseid AND $timesql AND
00390                                l.action $viewactionssql) AS statsreads,
00391                        (SELECT COUNT('x')
00392                           FROM {log} l
00393                          WHERE l.userid = d.userid AND
00394                                l.course = d.courseid AND $timesql AND
00395                                l.action $postactionssql) AS statswrites
00396                   FROM (SELECT DISTINCT u.id AS userid, l.course AS courseid
00397                           FROM {user} u, {log} l
00398                          WHERE u.id = l.userid AND $timesql
00399                        UNION
00400                         SELECT 0 AS userid, ".SITEID." AS courseid" . $DB->sql_null_from_clause() . ") d";
00401                         // can not use group by here because pg can not handle it :-(
00402 
00403         if ($logspresent and !$DB->execute($sql, array_merge($params1, $params2))) {
00404             $failed = true;
00405             break;
00406         }
00407         stats_daily_progress('10');
00408 
00409 
00411         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00412 
00413                 SELECT 'activity' AS stattype, $nextmidnight AS timeend, c.id AS courseid, 0,
00414                        (SELECT COUNT('x')
00415                           FROM {log} l1
00416                          WHERE l1.course = c.id AND l1.action $viewactionssql AND
00417                                $timesql1) AS stat1,
00418                        (SELECT COUNT('x')
00419                           FROM {log} l2
00420                          WHERE l2.course = c.id AND l2.action $postactionssql AND
00421                                $timesql2) AS stat2
00422                   FROM {course} c
00423                  WHERE EXISTS (SELECT 'x'
00424                                  FROM {log} l
00425                                 WHERE l.course = c.id and $timesql)";
00426 
00427         if ($logspresent and !$DB->execute($sql, array_merge($params1, $params2))) {
00428             $failed = true;
00429             break;
00430         }
00431         stats_daily_progress('11');
00432 
00433 
00435 
00436         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00437 
00438                 SELECT 'activity', timeend, courseid, roleid, SUM(statsreads), SUM(statswrites)
00439                   FROM (
00440                            SELECT $nextmidnight AS timeend, pl.courseid, pl.roleid, sud.statsreads, sud.statswrites
00441                              FROM {stats_user_daily} sud,
00442                                       (SELECT DISTINCT ra.userid, ra.roleid, e.courseid
00443                                          FROM {role_assignments} ra
00444                                          JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :courselevel)
00445                                          JOIN {enrol} e ON e.courseid = c.instanceid
00446                                          JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid)
00447                                         WHERE ra.roleid <> $guestrole AND
00448                                               ra.userid <> $guest
00449                                       ) pl
00450                             WHERE sud.userid = pl.userid AND
00451                                   sud.courseid = pl.courseid AND
00452                                   sud.timeend = $nextmidnight AND
00453                                   sud.stattype='activity'
00454                        ) inline_view
00455               GROUP BY timeend, courseid, roleid
00456                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
00457 
00458         if ($logspresent and !$DB->execute($sql, array('courselevel'=>CONTEXT_COURSE))) {
00459             $failed = true;
00460             break;
00461         }
00462         stats_daily_progress('12');
00463 
00466 
00467         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00468 
00469                 SELECT 'activity', timeend, courseid, nroleid, SUM(statsreads), SUM(statswrites)
00470                   FROM (
00471                            SELECT $nextmidnight AS timeend, sud.courseid, $guestrole AS nroleid, sud.statsreads, sud.statswrites
00472                              FROM {stats_user_daily} sud
00473                             WHERE sud.timeend = $nextmidnight AND sud.courseid <> ".SITEID." AND
00474                                   sud.stattype='activity' AND
00475                                   (sud.userid = $guest OR sud.userid
00476                                     NOT IN (SELECT ue.userid
00477                                               FROM {user_enrolments} ue
00478                                               JOIN {enrol} e ON ue.enrolid = e.id
00479                                              WHERE e.courseid = sud.courseid))
00480                        ) inline_view
00481               GROUP BY timeend, courseid, nroleid
00482                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
00483 
00484         if ($logspresent and !$DB->execute($sql, array())) {
00485             $failed = true;
00486             break;
00487         }
00488         stats_daily_progress('13');
00489 
00490 
00492         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00493 
00494                 SELECT 'activity', timeend, courseid, roleid, SUM(statsreads), SUM(statswrites)
00495                   FROM (
00496                            SELECT $nextmidnight AS timeend, pl.courseid, pl.roleid, sud.statsreads, sud.statswrites
00497                              FROM {stats_user_daily} sud,
00498                                       (SELECT DISTINCT ra.userid, ra.roleid, c.instanceid AS courseid
00499                                          FROM {role_assignments} ra
00500                                          JOIN {context} c ON c.id = ra.contextid
00501                                         WHERE ra.contextid = :fpcontext AND
00502                                               ra.roleid <> $defaultfproleid AND
00503                                               ra.roleid <> $guestrole AND
00504                                               ra.userid <> $guest
00505                                       ) pl
00506                             WHERE sud.userid = pl.userid AND
00507                                   sud.courseid = pl.courseid AND
00508                                   sud.timeend = $nextmidnight AND
00509                                   sud.stattype='activity'
00510                        ) inline_view
00511               GROUP BY timeend, courseid, roleid
00512                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
00513 
00514         if ($logspresent and !$DB->execute($sql, array('fpcontext'=>$fpcontext->id))) {
00515             $failed = true;
00516             break;
00517         }
00518         stats_daily_progress('14');
00519 
00520 
00522         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00523 
00524                 SELECT 'activity', timeend, courseid, nroleid, SUM(statsreads), SUM(statswrites)
00525                   FROM (
00526                            SELECT sud.timeend AS timeend, sud.courseid, $defaultfproleid AS nroleid, sud.statsreads, sud.statswrites
00527                              FROM {stats_user_daily} sud
00528                             WHERE sud.timeend = :nextm AND sud.courseid = :siteid AND
00529                                   sud.stattype='activity' AND
00530                                   sud.userid <> $guest AND sud.userid <> 0 AND sud.userid
00531                                   NOT IN (SELECT ra.userid
00532                                             FROM {role_assignments} ra
00533                                            WHERE ra.roleid <> $guestrole AND
00534                                                  ra.roleid <> $defaultfproleid AND ra.contextid = :fpcontext)
00535                        ) inline_view
00536               GROUP BY timeend, courseid, nroleid
00537                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
00538 
00539         if ($logspresent and !$DB->execute($sql, array('fpcontext'=>$fpcontext->id, 'siteid'=>SITEID, 'nextm'=>$nextmidnight))) {
00540             $failed = true;
00541             break;
00542         }
00543         stats_daily_progress('15');
00544 
00546         $sql = "INSERT INTO {stats_daily} (stattype, timeend, courseid, roleid, stat1, stat2)
00547 
00548                 SELECT 'activity', timeend, courseid, nroleid, SUM(statsreads), SUM(statswrites)
00549                   FROM (
00550                            SELECT $nextmidnight AS timeend, ".SITEID." AS courseid, $guestrole AS nroleid, pl.statsreads, pl.statswrites
00551                              FROM (
00552                                       SELECT sud.statsreads, sud.statswrites
00553                                         FROM {stats_user_daily} sud
00554                                        WHERE (sud.userid = $guest OR sud.userid = 0) AND
00555                                              sud.timeend = $nextmidnight AND sud.courseid = ".SITEID." AND
00556                                              sud.stattype='activity'
00557                                   ) pl
00558                        ) inline_view
00559               GROUP BY timeend, courseid, nroleid
00560                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
00561 
00562         if ($logspresent and !$DB->execute($sql)) {
00563             $failed = true;
00564             break;
00565         }
00566         stats_daily_progress('16');
00567 
00568         // remember processed days
00569         set_config('statslastdaily', $nextmidnight);
00570         mtrace("  finished until $nextmidnight: ".userdate($nextmidnight)." (in ".(time()-$daystart)." s)");
00571 
00572         $timestart    = $nextmidnight;
00573         $nextmidnight = stats_get_next_day_start($nextmidnight);
00574     }
00575 
00576     set_cron_lock('statsrunning', null);
00577 
00578     if ($failed) {
00579         $days--;
00580         mtrace("...error occurred, completed $days days of statistics.");
00581         return false;
00582 
00583     } else {
00584         mtrace("...completed $days days of statistics.");
00585         return true;
00586     }
00587 }
00588 
00589 
00594 function stats_cron_weekly() {
00595     global $CFG, $DB;
00596 
00597     $now = time();
00598 
00599     // read last execution date from db
00600     if (!$timestart = get_config(NULL, 'statslastweekly')) {
00601         $timestart = stats_get_base_daily(stats_get_start_from('weekly'));
00602         set_config('statslastweekly', $timestart);
00603     }
00604 
00605     $nextstartweek = stats_get_next_week_start($timestart);
00606 
00607     // are there any weeks that need to be processed?
00608     if ($now < $nextstartweek) {
00609         return true; // everything ok and up-to-date
00610     }
00611 
00612     $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime;
00613 
00614     if (!set_cron_lock('statsrunning', $now + $timeout)) {
00615         return false;
00616     }
00617 
00618     // fisrt delete entries that should not be there yet
00619     $DB->delete_records_select('stats_weekly',      "timeend > $timestart");
00620     $DB->delete_records_select('stats_user_weekly', "timeend > $timestart");
00621 
00622     mtrace("Running weekly statistics gathering, starting at $timestart:");
00623 
00624     $weeks = 0;
00625     while ($now > $nextstartweek) {
00626         @set_time_limit($timeout - 200);
00627         $weeks++;
00628 
00629         if ($weeks > 1) {
00630             // move the lock
00631             set_cron_lock('statsrunning', time() + $timeout, true);
00632         }
00633 
00634         $logtimesql  = "l.time >= $timestart AND l.time < $nextstartweek";
00635         $stattimesql = "timeend > $timestart AND timeend <= $nextstartweek";
00636 
00638         $sql = "INSERT INTO {stats_user_weekly} (stattype, timeend, courseid, userid, statsreads)
00639 
00640                 SELECT 'logins', timeend, courseid, userid, COUNT(statsreads)
00641                   FROM (
00642                            SELECT $nextstartweek AS timeend, ".SITEID." as courseid, l.userid, l.id AS statsreads
00643                              FROM {log} l
00644                             WHERE action = 'login' AND $logtimesql
00645                        ) inline_view
00646               GROUP BY timeend, courseid, userid
00647                 HAVING count(statsreads) > 0";
00648 
00649         $DB->execute($sql);
00650 
00651         $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2)
00652 
00653                 SELECT 'logins' AS stattype, $nextstartweek AS timeend, ".SITEID." as courseid, 0,
00654                        COALESCE((SELECT SUM(statsreads)
00655                                    FROM {stats_user_weekly} s1
00656                                   WHERE s1.stattype = 'logins' AND timeend = $nextstartweek), 0) AS nstat1,
00657                        (SELECT COUNT('x')
00658                           FROM {stats_user_weekly} s2
00659                          WHERE s2.stattype = 'logins' AND timeend = $nextstartweek) AS nstat2" .
00660                 $DB->sql_null_from_clause();
00661 
00662         $DB->execute($sql);
00663 
00664 
00666         $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2)
00667 
00668                 SELECT 'enrolments', ntimeend, courseid, roleid, " . $DB->sql_ceil('AVG(stat1)') . ", " . $DB->sql_ceil('AVG(stat2)') . "
00669                   FROM (
00670                            SELECT $nextstartweek AS ntimeend, courseid, roleid, stat1, stat2
00671                              FROM {stats_daily} sd
00672                             WHERE stattype = 'enrolments' AND $stattimesql
00673                        ) inline_view
00674               GROUP BY ntimeend, courseid, roleid";
00675 
00676         $DB->execute($sql);
00677 
00678 
00680         $sql = "INSERT INTO {stats_weekly} (stattype, timeend, courseid, roleid, stat1, stat2)
00681 
00682                 SELECT 'activity', ntimeend, courseid, roleid, SUM(stat1), SUM(stat2)
00683                   FROM (
00684                            SELECT $nextstartweek AS ntimeend, courseid, roleid, stat1, stat2
00685                              FROM {stats_daily}
00686                             WHERE stattype = 'activity' AND $stattimesql
00687                        ) inline_view
00688               GROUP BY ntimeend, courseid, roleid";
00689 
00690         $DB->execute($sql);
00691 
00692 
00694         $sql = "INSERT INTO {stats_user_weekly} (stattype, timeend, courseid, userid, statsreads, statswrites)
00695 
00696                 SELECT 'activity', ntimeend, courseid, userid, SUM(statsreads), SUM(statswrites)
00697                   FROM (
00698                            SELECT $nextstartweek AS ntimeend, courseid, userid, statsreads, statswrites
00699                              FROM {stats_user_daily}
00700                             WHERE stattype = 'activity' AND $stattimesql
00701                        ) inline_view
00702               GROUP BY ntimeend, courseid, userid";
00703 
00704         $DB->execute($sql);
00705 
00706         set_config('statslastweekly', $nextstartweek);
00707         mtrace(" finished until $nextstartweek: ".userdate($nextstartweek));
00708 
00709         $timestart     = $nextstartweek;
00710         $nextstartweek = stats_get_next_week_start($nextstartweek);
00711     }
00712 
00713     set_cron_lock('statsrunning', null);
00714     mtrace("...completed $weeks weeks of statistics.");
00715     return true;
00716 }
00717 
00722 function stats_cron_monthly() {
00723     global $CFG, $DB;
00724 
00725     $now = time();
00726 
00727     // read last execution date from db
00728     if (!$timestart = get_config(NULL, 'statslastmonthly')) {
00729         $timestart = stats_get_base_monthly(stats_get_start_from('monthly'));
00730         set_config('statslastmonthly', $timestart);
00731     }
00732 
00733     $nextstartmonth = stats_get_next_month_start($timestart);
00734 
00735     // are there any months that need to be processed?
00736     if ($now < $nextstartmonth) {
00737         return true; // everything ok and up-to-date
00738     }
00739 
00740     $timeout = empty($CFG->statsmaxruntime) ? 60*60*24 : $CFG->statsmaxruntime;
00741 
00742     if (!set_cron_lock('statsrunning', $now + $timeout)) {
00743         return false;
00744     }
00745 
00746     // fisr delete entries that should not be there yet
00747     $DB->delete_records_select('stats_monthly', "timeend > $timestart");
00748     $DB->delete_records_select('stats_user_monthly', "timeend > $timestart");
00749 
00750     $startmonth = stats_get_base_monthly($now);
00751 
00752 
00753     mtrace("Running monthly statistics gathering, starting at $timestart:");
00754 
00755     $months = 0;
00756     while ($now > $nextstartmonth) {
00757         @set_time_limit($timeout - 200);
00758         $months++;
00759 
00760         if ($months > 1) {
00761             // move the lock
00762             set_cron_lock('statsrunning', time() + $timeout, true);
00763         }
00764 
00765         $logtimesql  = "l.time >= $timestart AND l.time < $nextstartmonth";
00766         $stattimesql = "timeend > $timestart AND timeend <= $nextstartmonth";
00767 
00769         $sql = "INSERT INTO {stats_user_monthly} (stattype, timeend, courseid, userid, statsreads)
00770 
00771                 SELECT 'logins', timeend, courseid, userid, COUNT(statsreads)
00772                   FROM (
00773                            SELECT $nextstartmonth AS timeend, ".SITEID." as courseid, l.userid, l.id AS statsreads
00774                              FROM {log} l
00775                             WHERE action = 'login' AND $logtimesql
00776                        ) inline_view
00777               GROUP BY timeend, courseid, userid";
00778 
00779         $DB->execute($sql);
00780 
00781         $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2)
00782 
00783                 SELECT 'logins' AS stattype, $nextstartmonth AS timeend, ".SITEID." as courseid, 0,
00784                        COALESCE((SELECT SUM(statsreads)
00785                                    FROM {stats_user_monthly} s1
00786                                   WHERE s1.stattype = 'logins' AND timeend = $nextstartmonth), 0) AS nstat1,
00787                        (SELECT COUNT('x')
00788                           FROM {stats_user_monthly} s2
00789                          WHERE s2.stattype = 'logins' AND timeend = $nextstartmonth) AS nstat2" .
00790                 $DB->sql_null_from_clause();
00791 
00792         $DB->execute($sql);
00793 
00794 
00796         $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2)
00797 
00798                 SELECT 'enrolments', ntimeend, courseid, roleid, " . $DB->sql_ceil('AVG(stat1)') . ", " . $DB->sql_ceil('AVG(stat2)') . "
00799                   FROM (
00800                            SELECT $nextstartmonth AS ntimeend, courseid, roleid, stat1, stat2
00801                              FROM {stats_daily} sd
00802                             WHERE stattype = 'enrolments' AND $stattimesql
00803                        ) inline_view
00804               GROUP BY ntimeend, courseid, roleid";
00805 
00806         $DB->execute($sql);
00807 
00808 
00810         $sql = "INSERT INTO {stats_monthly} (stattype, timeend, courseid, roleid, stat1, stat2)
00811 
00812                 SELECT 'activity', ntimeend, courseid, roleid, SUM(stat1), SUM(stat2)
00813                   FROM (
00814                            SELECT $nextstartmonth AS ntimeend, courseid, roleid, stat1, stat2
00815                              FROM {stats_daily}
00816                             WHERE stattype = 'activity' AND $stattimesql
00817                        ) inline_view
00818               GROUP BY ntimeend, courseid, roleid";
00819 
00820         $DB->execute($sql);
00821 
00822 
00824         $sql = "INSERT INTO {stats_user_monthly} (stattype, timeend, courseid, userid, statsreads, statswrites)
00825 
00826                 SELECT 'activity', ntimeend, courseid, userid, SUM(statsreads), SUM(statswrites)
00827                   FROM (
00828                            SELECT $nextstartmonth AS ntimeend, courseid, userid, statsreads, statswrites
00829                              FROM {stats_user_daily}
00830                             WHERE stattype = 'activity' AND $stattimesql
00831                        ) inline_view
00832               GROUP BY ntimeend, courseid, userid";
00833 
00834         $DB->execute($sql);
00835 
00836         set_config('statslastmonthly', $nextstartmonth);
00837         mtrace(" finished until $nextstartmonth: ".userdate($nextstartmonth));
00838 
00839         $timestart      = $nextstartmonth;
00840         $nextstartmonth = stats_get_next_month_start($nextstartmonth);
00841     }
00842 
00843     set_cron_lock('statsrunning', null);
00844     mtrace("...completed $months months of statistics.");
00845     return true;
00846 }
00847 
00853 function stats_get_start_from($str) {
00854     global $CFG, $DB;
00855 
00856     // are there any data in stats table? Should not be...
00857     if ($timeend = $DB->get_field_sql('SELECT MAX(timeend) FROM {stats_'.$str.'}')) {
00858         return $timeend;
00859     }
00860     // decide what to do based on our config setting (either all or none or a timestamp)
00861     switch ($CFG->statsfirstrun) {
00862         case 'all':
00863             if ($firstlog = $DB->get_field_sql('SELECT MIN(time) FROM {log}')) {
00864                 return $firstlog;
00865             }
00866         default:
00867             if (is_numeric($CFG->statsfirstrun)) {
00868                 return time() - $CFG->statsfirstrun;
00869             }
00870             // not a number? use next instead
00871         case 'none':
00872             return strtotime('-3 day', time());
00873     }
00874 }
00875 
00881 function stats_get_base_daily($time=0) {
00882     global $CFG;
00883 
00884     if (empty($time)) {
00885         $time = time();
00886     }
00887     if ($CFG->timezone == 99) {
00888         $time = strtotime(date('d-M-Y', $time));
00889         return $time;
00890     } else {
00891         $offset = get_timezone_offset($CFG->timezone);
00892         $gtime = $time + $offset;
00893         $gtime = intval($gtime / (60*60*24)) * 60*60*24;
00894         return $gtime - $offset;
00895     }
00896 }
00897 
00903 function stats_get_base_weekly($time=0) {
00904     global $CFG;
00905 
00906     $time = stats_get_base_daily($time);
00907     $startday = $CFG->calendar_startwday;
00908     if ($CFG->timezone == 99) {
00909         $thisday = date('w', $time);
00910     } else {
00911         $offset = get_timezone_offset($CFG->timezone);
00912         $gtime = $time + $offset;
00913         $thisday = gmdate('w', $gtime);
00914     }
00915     if ($thisday > $startday) {
00916         $time = $time - (($thisday - $startday) * 60*60*24);
00917     } else if ($thisday < $startday) {
00918         $time = $time - ((7 + $thisday - $startday) * 60*60*24);
00919     }
00920     return $time;
00921 }
00922 
00928 function stats_get_base_monthly($time=0) {
00929     global $CFG;
00930 
00931     if (empty($time)) {
00932         $time = time();
00933     }
00934     if ($CFG->timezone == 99) {
00935         return strtotime(date('1-M-Y', $time));
00936 
00937     } else {
00938         $time = stats_get_base_daily($time);
00939         $offset = get_timezone_offset($CFG->timezone);
00940         $gtime = $time + $offset;
00941         $day = gmdate('d', $gtime);
00942         if ($day == 1) {
00943             return $time;
00944         }
00945         return $gtime - (($day-1) * 60*60*24);
00946     }
00947 }
00948 
00954 function stats_get_next_day_start($time) {
00955     $next = stats_get_base_daily($time);
00956     $next = $next + 60*60*26;
00957     $next = stats_get_base_daily($next);
00958     if ($next <= $time) {
00959         //DST trouble - prevent infinite loops
00960         $next = $next + 60*60*24;
00961     }
00962     return $next;
00963 }
00964 
00970 function stats_get_next_week_start($time) {
00971     $next = stats_get_base_weekly($time);
00972     $next = $next + 60*60*24*9;
00973     $next = stats_get_base_weekly($next);
00974     if ($next <= $time) {
00975         //DST trouble - prevent infinite loops
00976         $next = $next + 60*60*24*7;
00977     }
00978     return $next;
00979 }
00980 
00986 function stats_get_next_month_start($time) {
00987     $next = stats_get_base_monthly($time);
00988     $next = $next + 60*60*24*33;
00989     $next = stats_get_base_monthly($next);
00990     if ($next <= $time) {
00991         //DST trouble - prevent infinite loops
00992         $next = $next + 60*60*24*31;
00993     }
00994     return $next;
00995 }
00996 
01000 function stats_clean_old() {
01001     global $DB;
01002     mtrace("Running stats cleanup tasks...");
01003     $deletebefore =  stats_get_base_monthly();
01004 
01005     // delete dailies older than 3 months (to be safe)
01006     $deletebefore = strtotime('-3 months', $deletebefore);
01007     $DB->delete_records_select('stats_daily',      "timeend < $deletebefore");
01008     $DB->delete_records_select('stats_user_daily', "timeend < $deletebefore");
01009 
01010     // delete weeklies older than 9  months (to be safe)
01011     $deletebefore = strtotime('-6 months', $deletebefore);
01012     $DB->delete_records_select('stats_weekly',      "timeend < $deletebefore");
01013     $DB->delete_records_select('stats_user_weekly', "timeend < $deletebefore");
01014 
01015     // don't delete monthlies
01016 
01017     mtrace("...stats cleanup finished");
01018 }
01019 
01020 function stats_get_parameters($time,$report,$courseid,$mode,$roleid=0) {
01021     global $CFG, $DB;
01022 
01023     $param = new stdClass();
01024     $param->params = array();
01025 
01026     if ($time < 10) { // dailies
01027         // number of days to go back = 7* time
01028         $param->table = 'daily';
01029         $param->timeafter = strtotime("-".($time*7)." days",stats_get_base_daily());
01030     } elseif ($time < 20) { // weeklies
01031         // number of weeks to go back = time - 10 * 4 (weeks) + base week
01032         $param->table = 'weekly';
01033         $param->timeafter = strtotime("-".(($time - 10)*4)." weeks",stats_get_base_weekly());
01034     } else { // monthlies.
01035         // number of months to go back = time - 20 * months + base month
01036         $param->table = 'monthly';
01037         $param->timeafter = strtotime("-".($time - 20)." months",stats_get_base_monthly());
01038     }
01039 
01040     $param->extras = '';
01041 
01042     switch ($report) {
01043     // ******************** STATS_MODE_GENERAL ******************** //
01044     case STATS_REPORT_LOGINS:
01045         $param->fields = 'timeend,sum(stat1) as line1,sum(stat2) as line2';
01046         $param->fieldscomplete = true;
01047         $param->stattype = 'logins';
01048         $param->line1 = get_string('statslogins');
01049         $param->line2 = get_string('statsuniquelogins');
01050         if ($courseid == SITEID) {
01051             $param->extras = 'GROUP BY timeend';
01052         }
01053         break;
01054 
01055     case STATS_REPORT_READS:
01056         $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, stat1 as line1';
01057         $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries.
01058         $param->aggregategroupby = 'roleid';
01059         $param->stattype = 'activity';
01060         $param->crosstab = true;
01061         $param->extras = 'GROUP BY timeend,roleid,stat1';
01062         if ($courseid == SITEID) {
01063             $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat1) as line1';
01064             $param->extras = 'GROUP BY timeend,roleid';
01065         }
01066         break;
01067 
01068     case STATS_REPORT_WRITES:
01069         $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, stat2 as line1';
01070         $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries.
01071         $param->aggregategroupby = 'roleid';
01072         $param->stattype = 'activity';
01073         $param->crosstab = true;
01074         $param->extras = 'GROUP BY timeend,roleid,stat2';
01075         if ($courseid == SITEID) {
01076             $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat2) as line1';
01077             $param->extras = 'GROUP BY timeend,roleid';
01078         }
01079         break;
01080 
01081     case STATS_REPORT_ACTIVITY:
01082         $param->fields = $DB->sql_concat('timeend','roleid').' AS uniqueid, timeend, roleid, sum(stat1+stat2) as line1';
01083         $param->fieldscomplete = true; // set this to true to avoid anything adding stuff to the list and breaking complex queries.
01084         $param->aggregategroupby = 'roleid';
01085         $param->stattype = 'activity';
01086         $param->crosstab = true;
01087         $param->extras = 'GROUP BY timeend,roleid';
01088         if ($courseid == SITEID) {
01089             $param->extras = 'GROUP BY timeend,roleid';
01090         }
01091         break;
01092 
01093     case STATS_REPORT_ACTIVITYBYROLE;
01094         $param->fields = 'stat1 AS line1, stat2 AS line2';
01095         $param->stattype = 'activity';
01096         $rolename = $DB->get_field('role','name', array('id'=>$roleid));
01097         $param->line1 = $rolename . get_string('statsreads');
01098         $param->line2 = $rolename . get_string('statswrites');
01099         if ($courseid == SITEID) {
01100             $param->extras = 'GROUP BY timeend';
01101         }
01102         break;
01103 
01104     // ******************** STATS_MODE_DETAILED ******************** //
01105     case STATS_REPORT_USER_ACTIVITY:
01106         $param->fields = 'statsreads as line1, statswrites as line2';
01107         $param->line1 = get_string('statsuserreads');
01108         $param->line2 = get_string('statsuserwrites');
01109         $param->stattype = 'activity';
01110         break;
01111 
01112     case STATS_REPORT_USER_ALLACTIVITY:
01113         $param->fields = 'statsreads+statswrites as line1';
01114         $param->line1 = get_string('statsuseractivity');
01115         $param->stattype = 'activity';
01116         break;
01117 
01118     case STATS_REPORT_USER_LOGINS:
01119         $param->fields = 'statsreads as line1';
01120         $param->line1 = get_string('statsuserlogins');
01121         $param->stattype = 'logins';
01122         break;
01123 
01124     case STATS_REPORT_USER_VIEW:
01125         $param->fields = 'statsreads as line1, statswrites as line2, statsreads+statswrites as line3';
01126         $param->line1 = get_string('statsuserreads');
01127         $param->line2 = get_string('statsuserwrites');
01128         $param->line3 = get_string('statsuseractivity');
01129         $param->stattype = 'activity';
01130         break;
01131 
01132     // ******************** STATS_MODE_RANKED ******************** //
01133     case STATS_REPORT_ACTIVE_COURSES:
01134         $param->fields = 'sum(stat1+stat2) AS line1';
01135         $param->stattype = 'activity';
01136         $param->orderby = 'line1 DESC';
01137         $param->line1 = get_string('activity');
01138         $param->graphline = 'line1';
01139         break;
01140 
01141     case STATS_REPORT_ACTIVE_COURSES_WEIGHTED:
01142         $threshold = 0;
01143         if (!empty($CFG->statsuserthreshold) && is_numeric($CFG->statsuserthreshold)) {
01144             $threshold = $CFG->statsuserthreshold;
01145         }
01146         $param->fields = '';
01147         $param->sql = 'SELECT activity.courseid, activity.all_activity AS line1, enrolments.highest_enrolments AS line2,
01148                         activity.all_activity / enrolments.highest_enrolments as line3
01149                        FROM (
01150                             SELECT courseid, sum(stat1+stat2) AS all_activity
01151                               FROM {stats_'.$param->table.'}
01152                              WHERE stattype=\'activity\' AND timeend >= '.(int)$param->timeafter.' AND roleid = 0 GROUP BY courseid
01153                        ) activity
01154                        INNER JOIN
01155                             (
01156                             SELECT courseid, max(stat1) AS highest_enrolments
01157                               FROM {stats_'.$param->table.'}
01158                              WHERE stattype=\'enrolments\' AND timeend >= '.(int)$param->timeafter.' AND stat1 > '.(int)$threshold.'
01159                           GROUP BY courseid
01160                       ) enrolments
01161                       ON (activity.courseid = enrolments.courseid)
01162                       ORDER BY line3 DESC';
01163         $param->line1 = get_string('activity');
01164         $param->line2 = get_string('users');
01165         $param->line3 = get_string('activityweighted');
01166         $param->graphline = 'line3';
01167         break;
01168 
01169     case STATS_REPORT_PARTICIPATORY_COURSES:
01170         $threshold = 0;
01171         if (!empty($CFG->statsuserthreshold) && is_numeric($CFG->statsuserthreshold)) {
01172             $threshold = $CFG->statsuserthreshold;
01173         }
01174         $param->fields = '';
01175         $param->sql = 'SELECT courseid, ' . $DB->sql_ceil('avg(all_enrolments)') . ' as line1, ' .
01176                          $DB->sql_ceil('avg(active_enrolments)') . ' as line2, avg(proportion_active) AS line3
01177                        FROM (
01178                            SELECT courseid, timeend, stat2 as active_enrolments,
01179                                   stat1 as all_enrolments, '.$DB->sql_cast_char2real('stat2').'/'.$DB->sql_cast_char2real('stat1').' AS proportion_active
01180                              FROM {stats_'.$param->table.'}
01181                             WHERE stattype=\'enrolments\' AND roleid = 0 AND stat1 > '.(int)$threshold.'
01182                        ) aq
01183                        WHERE timeend >= '.(int)$param->timeafter.'
01184                        GROUP BY courseid
01185                        ORDER BY line3 DESC';
01186 
01187         $param->line1 = get_string('users');
01188         $param->line2 = get_string('activeusers');
01189         $param->line3 = get_string('participationratio');
01190         $param->graphline = 'line3';
01191         break;
01192 
01193     case STATS_REPORT_PARTICIPATORY_COURSES_RW:
01194         $param->fields = '';
01195         $param->sql =  'SELECT courseid, sum(views) AS line1, sum(posts) AS line2,
01196                            avg(proportion_active) AS line3
01197                          FROM (
01198                            SELECT courseid, timeend, stat1 as views, stat2 AS posts,
01199                                   '.$DB->sql_cast_char2real('stat2').'/'.$DB->sql_cast_char2real('stat1').' as proportion_active
01200                              FROM {stats_'.$param->table.'}
01201                             WHERE stattype=\'activity\' AND roleid = 0 AND stat1 > 0
01202                        ) aq
01203                        WHERE timeend >= '.(int)$param->timeafter.'
01204                        GROUP BY courseid
01205                        ORDER BY line3 DESC';
01206         $param->line1 = get_string('views');
01207         $param->line2 = get_string('posts');
01208         $param->line3 = get_string('participationratio');
01209         $param->graphline = 'line3';
01210         break;
01211     }
01212 
01213     /*
01214     if ($courseid == SITEID && $mode != STATS_MODE_RANKED) { // just aggregate all courses.
01215         $param->fields = preg_replace('/(?:sum)([a-zA-Z0-9+_]*)\W+as\W+([a-zA-Z0-9_]*)/i','sum($1) as $2',$param->fields);
01216         $param->extras = ' GROUP BY timeend'.((!empty($param->aggregategroupby)) ? ','.$param->aggregategroupby : '');
01217     }
01218     */
01219     //TODO must add the SITEID reports to the rest of the reports.
01220     return $param;
01221 }
01222 
01223 function stats_get_view_actions() {
01224     return array('view','view all','history');
01225 }
01226 
01227 function stats_get_post_actions() {
01228     return array('add','delete','edit','add mod','delete mod','edit section'.'enrol','loginas','new','unenrol','update','update mod');
01229 }
01230 
01231 function stats_get_action_names($str) {
01232     global $CFG, $DB;
01233 
01234     $mods = $DB->get_records('modules');
01235     $function = 'stats_get_'.$str.'_actions';
01236     $actions = $function();
01237     foreach ($mods as $mod) {
01238         $file = $CFG->dirroot.'/mod/'.$mod->name.'/lib.php';
01239         if (!is_readable($file)) {
01240             continue;
01241         }
01242         require_once($file);
01243         $function = $mod->name.'_get_'.$str.'_actions';
01244         if (function_exists($function)) {
01245             $mod_actions = $function();
01246             if (is_array($mod_actions)) {
01247                 $actions = array_merge($actions, $mod_actions);
01248             }
01249         }
01250     }
01251 
01252     // The array_values() forces a stack-like array
01253     // so we can later loop over safely...
01254     $actions =  array_values(array_unique($actions));
01255     $c = count($actions);
01256     for ($n=0;$n<$c;$n++) {
01257         $actions[$n] = $actions[$n];
01258     }
01259     return $actions;
01260 }
01261 
01262 function stats_get_time_options($now,$lastweekend,$lastmonthend,$earliestday,$earliestweek,$earliestmonth) {
01263 
01264     $now = stats_get_base_daily(time());
01265     // it's really important that it's TIMEEND in the table. ie, tuesday 00:00:00 is monday night.
01266     // so we need to take a day off here (essentially add a day to $now
01267     $now += 60*60*24;
01268 
01269     $timeoptions = array();
01270 
01271     if ($now - (60*60*24*7) >= $earliestday) {
01272         $timeoptions[STATS_TIME_LASTWEEK] = get_string('numweeks','moodle',1);
01273     }
01274     if ($now - (60*60*24*14) >= $earliestday) {
01275         $timeoptions[STATS_TIME_LAST2WEEKS] = get_string('numweeks','moodle',2);
01276     }
01277     if ($now - (60*60*24*21) >= $earliestday) {
01278         $timeoptions[STATS_TIME_LAST3WEEKS] = get_string('numweeks','moodle',3);
01279     }
01280     if ($now - (60*60*24*28) >= $earliestday) {
01281         $timeoptions[STATS_TIME_LAST4WEEKS] = get_string('numweeks','moodle',4);// show dailies up to (including) here.
01282     }
01283     if ($lastweekend - (60*60*24*56) >= $earliestweek) {
01284         $timeoptions[STATS_TIME_LAST2MONTHS] = get_string('nummonths','moodle',2);
01285     }
01286     if ($lastweekend - (60*60*24*84) >= $earliestweek) {
01287         $timeoptions[STATS_TIME_LAST3MONTHS] = get_string('nummonths','moodle',3);
01288     }
01289     if ($lastweekend - (60*60*24*112) >= $earliestweek) {
01290         $timeoptions[STATS_TIME_LAST4MONTHS] = get_string('nummonths','moodle',4);
01291     }
01292     if ($lastweekend - (60*60*24*140) >= $earliestweek) {
01293         $timeoptions[STATS_TIME_LAST5MONTHS] = get_string('nummonths','moodle',5);
01294     }
01295     if ($lastweekend - (60*60*24*168) >= $earliestweek) {
01296         $timeoptions[STATS_TIME_LAST6MONTHS] = get_string('nummonths','moodle',6); // show weeklies up to (including) here
01297     }
01298     if (strtotime('-7 months',$lastmonthend) >= $earliestmonth) {
01299         $timeoptions[STATS_TIME_LAST7MONTHS] = get_string('nummonths','moodle',7);
01300     }
01301     if (strtotime('-8 months',$lastmonthend) >= $earliestmonth) {
01302         $timeoptions[STATS_TIME_LAST8MONTHS] = get_string('nummonths','moodle',8);
01303     }
01304     if (strtotime('-9 months',$lastmonthend) >= $earliestmonth) {
01305         $timeoptions[STATS_TIME_LAST9MONTHS] = get_string('nummonths','moodle',9);
01306     }
01307     if (strtotime('-10 months',$lastmonthend) >= $earliestmonth) {
01308         $timeoptions[STATS_TIME_LAST10MONTHS] = get_string('nummonths','moodle',10);
01309     }
01310     if (strtotime('-11 months',$lastmonthend) >= $earliestmonth) {
01311         $timeoptions[STATS_TIME_LAST11MONTHS] = get_string('nummonths','moodle',11);
01312     }
01313     if (strtotime('-1 year',$lastmonthend) >= $earliestmonth) {
01314         $timeoptions[STATS_TIME_LASTYEAR] = get_string('lastyear');
01315     }
01316 
01317     $years = (int)date('y', $now) - (int)date('y', $earliestmonth);
01318     if ($years > 1) {
01319         for($i = 2; $i <= $years; $i++) {
01320             $timeoptions[$i*12+20] = get_string('numyears', 'moodle', $i);
01321         }
01322     }
01323 
01324     return $timeoptions;
01325 }
01326 
01327 function stats_get_report_options($courseid,$mode) {
01328     global $CFG, $DB;
01329 
01330     $reportoptions = array();
01331 
01332     switch ($mode) {
01333     case STATS_MODE_GENERAL:
01334         $reportoptions[STATS_REPORT_ACTIVITY] = get_string('statsreport'.STATS_REPORT_ACTIVITY);
01335         if ($courseid != SITEID && $context = get_context_instance(CONTEXT_COURSE, $courseid)) {
01336             $sql = 'SELECT r.id, r.name FROM {role} r JOIN {stats_daily} s ON s.roleid = r.id WHERE s.courseid = :courseid GROUP BY r.id, r.name';
01337             if ($roles = $DB->get_records_sql($sql, array('courseid' => $courseid))) {
01338                 foreach ($roles as $role) {
01339                     $reportoptions[STATS_REPORT_ACTIVITYBYROLE.$role->id] = get_string('statsreport'.STATS_REPORT_ACTIVITYBYROLE). ' '.$role->name;
01340                 }
01341             }
01342         }
01343         $reportoptions[STATS_REPORT_READS] = get_string('statsreport'.STATS_REPORT_READS);
01344         $reportoptions[STATS_REPORT_WRITES] = get_string('statsreport'.STATS_REPORT_WRITES);
01345         if ($courseid == SITEID) {
01346             $reportoptions[STATS_REPORT_LOGINS] = get_string('statsreport'.STATS_REPORT_LOGINS);
01347         }
01348 
01349         break;
01350     case STATS_MODE_DETAILED:
01351         $reportoptions[STATS_REPORT_USER_ACTIVITY] = get_string('statsreport'.STATS_REPORT_USER_ACTIVITY);
01352         $reportoptions[STATS_REPORT_USER_ALLACTIVITY] = get_string('statsreport'.STATS_REPORT_USER_ALLACTIVITY);
01353         if (has_capability('report/stats:view', get_context_instance(CONTEXT_SYSTEM))) {
01354             $site = get_site();
01355             $reportoptions[STATS_REPORT_USER_LOGINS] = get_string('statsreport'.STATS_REPORT_USER_LOGINS);
01356         }
01357         break;
01358     case STATS_MODE_RANKED:
01359         if (has_capability('report/stats:view', get_context_instance(CONTEXT_SYSTEM))) {
01360             $reportoptions[STATS_REPORT_ACTIVE_COURSES] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES);
01361             $reportoptions[STATS_REPORT_ACTIVE_COURSES_WEIGHTED] = get_string('statsreport'.STATS_REPORT_ACTIVE_COURSES_WEIGHTED);
01362             $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES);
01363             $reportoptions[STATS_REPORT_PARTICIPATORY_COURSES_RW] = get_string('statsreport'.STATS_REPORT_PARTICIPATORY_COURSES_RW);
01364         }
01365      break;
01366     }
01367 
01368     return $reportoptions;
01369 }
01370 
01371 function stats_fix_zeros($stats,$timeafter,$timestr,$line2=true,$line3=false) {
01372 
01373     if (empty($stats)) {
01374         return;
01375     }
01376 
01377     $timestr = str_replace('user_','',$timestr); // just in case.
01378     $fun = 'stats_get_base_'.$timestr;
01379 
01380     $now = $fun();
01381 
01382     $times = array();
01383     // add something to timeafter since it is our absolute base
01384     $actualtimes = array();
01385     foreach ($stats as $statid=>$s) {
01386         //normalize the times in stats - those might have been created in different timezone, DST etc.
01387         $s->timeend = $fun($s->timeend + 60*60*5);
01388         $stats[$statid] = $s;
01389 
01390         $actualtimes[] = $s->timeend;
01391     }
01392 
01393     $timeafter = array_pop(array_values($actualtimes));
01394 
01395     while ($timeafter < $now) {
01396         $times[] = $timeafter;
01397         if ($timestr == 'daily') {
01398             $timeafter = stats_get_next_day_start($timeafter);
01399         } else if ($timestr == 'weekly') {
01400             $timeafter = stats_get_next_week_start($timeafter);
01401         } else if ($timestr == 'monthly') {
01402             $timeafter = stats_get_next_month_start($timeafter);
01403         } else {
01404             return $stats; // this will put us in a never ending loop.
01405         }
01406     }
01407 
01408     foreach ($times as $count => $time) {
01409         if (!in_array($time,$actualtimes) && $count != count($times) -1) {
01410             $newobj = new StdClass;
01411             $newobj->timeend = $time;
01412             $newobj->id = 0;
01413             $newobj->roleid = 0;
01414             $newobj->line1 = 0;
01415             if (!empty($line2)) {
01416                 $newobj->line2 = 0;
01417             }
01418             if (!empty($line3)) {
01419                 $newobj->line3 = 0;
01420             }
01421             $newobj->zerofixed = true;
01422             $stats[] = $newobj;
01423         }
01424     }
01425 
01426     usort($stats,"stats_compare_times");
01427     return $stats;
01428 
01429 }
01430 
01431 // helper function to sort arrays by $obj->timeend
01432 function stats_compare_times($a,$b) {
01433    if ($a->timeend == $b->timeend) {
01434        return 0;
01435    }
01436    return ($a->timeend > $b->timeend) ? -1 : 1;
01437 }
01438 
01439 function stats_check_uptodate($courseid=0) {
01440     global $CFG, $DB;
01441 
01442     if (empty($courseid)) {
01443         $courseid = SITEID;
01444     }
01445 
01446     $latestday = stats_get_start_from('daily');
01447 
01448     if ((time() - 60*60*24*2) < $latestday) { // we're ok
01449         return NULL;
01450     }
01451 
01452     $a = new stdClass();
01453     $a->daysdone = $DB->get_field_sql("SELECT COUNT(DISTINCT(timeend)) FROM {stats_daily}");
01454 
01455     // how many days between the last day and now?
01456     $a->dayspending = ceil((stats_get_base_daily() - $latestday)/(60*60*24));
01457 
01458     if ($a->dayspending == 0 && $a->daysdone != 0) {
01459         return NULL; // we've only just started...
01460     }
01461 
01462     //return error as string
01463     return get_string('statscatchupmode','error',$a);
01464 }
 All Data Structures Namespaces Files Functions Variables Enumerations