Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * @package     report_overviewstats
19
 * @copyright   2013 David Mudrak <david@moodle.com>
20
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21
 */
22
 
23
defined('MOODLE_INTERNAL') || die();
24
 
25
require_once($CFG->libdir.'/accesslib.php');
26
 
27
/**
28
 * Reports the new enrolments over time
29
 */
30
class report_overviewstats_chart_enrolments extends report_overviewstats_chart {
31
 
32
    /** @var int the number of currently enrolled users */
33
    protected $current = null;
34
 
35
    /**
36
     * @return array
37
     */
38
    public function get_content() {
39
 
40
        $this->prepare_data();
41
 
42
        $title = get_string('chart-enrolments', 'report_overviewstats');
43
        $titlemonth = get_string('chart-enrolments-month', 'report_overviewstats');
44
        $titleyear = get_string('chart-enrolments-year', 'report_overviewstats');
45
 
46
        return array($title => array(
47
            $titlemonth => html_writer::tag('div', '', array(
48
                'id' => 'chart_enrolments_lastmonth',
49
                'class' => 'chartplaceholder',
50
                'style' => 'min-height: 300px;',
51
            )),
52
            $titleyear => html_writer::tag('div', '', array(
53
                'id' => 'chart_enrolments_lastyear',
54
                'class' => 'chartplaceholder',
55
                'style' => 'min-height: 300px;',
56
            )),
57
        ));
58
    }
59
 
60
    /**
61
     * @see parent
62
     */
63
    public function inject_page_requirements(moodle_page $page) {
64
 
65
        $this->prepare_data();
66
 
67
        $page->requires->yui_module(
68
            'moodle-report_overviewstats-charts',
69
            'M.report_overviewstats.charts.enrolments.init',
70
            array($this->data)
71
        );
72
    }
73
 
74
    /**
75
     * Prepares data to report
76
     *
77
     * It is pretty tricky (actually impossible) to reconstruct the chart of the history
78
     * of enrolments. The only reliable solution would be to run a cron job every day and
79
     * store the actual number of enrolled users somewhere.
80
     *
81
     * To get at least some estimation, the report models the history using the following
82
     * algorithm. It starts at the current timestamp and gets the number of currently
83
     * enrolled users. Let us say there 42 users enrolled right now. Then it looks into
84
     * the {log} table and searches for recent 'enrol' and 'unenrol' actions. If, for example,
85
     * there is an 'enrol' action logged yesterday, then the report expects that there had
86
     * been just 41 users enrolled before that. It's not 100% accurate (for example it ignores
87
     * the enrolment duration, status etc) but gives at least something.
88
     */
89
    protected function prepare_data() {
90
        global $DB, $CFG;
91
 
92
        if (is_null($this->course)) {
93
            throw new coding_exception('Course level report invoked without the reference to the course!');
94
        }
95
 
96
        if (!is_null($this->data)) {
97
            return;
98
        }
99
 
100
        // Get the number of currently enrolled users.
101
 
102
        $context = context_course::instance($this->course->id);
103
        list($esql, $params) = get_enrolled_sql($context);
104
        $sql = "SELECT COUNT(u.id)
105
                  FROM {user} u
106
                  JOIN ($esql) je ON je.id = u.id
107
                 WHERE u.deleted = 0";
108
 
109
        $this->current = $DB->count_records_sql($sql, $params);
110
 
111
        // Construct the estimated number of enrolled users in the last month
112
        // and the last year using the current number and the log records.
113
 
114
        $now = time();
115
 
116
        $lastmonth = array();
117
        for ($i = 30; $i >= 0; $i--) {
118
            $lastmonth[$now - $i * DAYSECS] = $this->current;
119
        }
120
 
121
        $lastyear = array();
122
        for ($i = 12; $i >= 0; $i--) {
123
            $lastyear[$now - $i * 30 * DAYSECS] = $this->current;
124
        }
125
 
126
        // Fetch all the enrol/unrol log entries from the last year.
127
        if ($CFG->branch >= 27) {
128
 
129
            $logmanger = get_log_manager();
130
            if ($CFG->branch >= 29) {
131
                $readers = $logmanger->get_readers('\core\log\sql_reader');
132
            } else {
133
                $readers = $logmanger->get_readers('\core\log\sql_select_reader');
134
            }
135
            $reader = reset($readers);
136
            $select = "component = :component AND (eventname = :eventname1 OR eventname = :eventname2) AND timecreated >= :timestart";
137
            $params = array(
138
                'component' => 'core',
139
                'eventname1' => '\core\event\user_enrolment_created',
140
                'eventname2' => '\core\event\user_enrolment_deleted',
141
                'timestart' => $now - 30 * DAYSECS
142
            );
143
            $events = $reader->get_events_select($select, $params, 'timecreated DESC', 0, 0);
144
 
145
            foreach ($events as $event) {
146
                foreach (array_reverse($lastmonth, true) as $key => $value) {
147
                    if ($event->timecreated >= $key) {
148
                        // We need to amend all days up to the key.
149
                        foreach ($lastmonth as $mkey => $mvalue) {
150
                            if ($mkey <= $key) {
151
                                if ($event->eventname === '\core\event\user_enrolment_created' and $lastmonth[$mkey] > 0) {
152
                                    $lastmonth[$mkey]--;
153
                                } else if ($event->eventname === '\core\event\user_enrolment_deleted') {
154
                                    $lastmonth[$mkey]++;
155
                                }
156
                            }
157
                        }
158
                        break;
159
                    }
160
                }
161
                foreach (array_reverse($lastyear, true) as $key => $value) {
162
                    if ($event->timecreated >= $key) {
163
                        // We need to amend all months up to the key.
164
                        foreach ($lastyear as $ykey => $yvalue) {
165
                            if ($ykey <= $key) {
166
                                if ($event->eventname === '\core\event\user_enrolment_created' and $lastyear[$ykey] > 0) {
167
                                    $lastyear[$ykey]--;
168
                                } else if ($event->eventname === '\core\event\user_enrolment_deleted') {
169
                                    $lastyear[$ykey]++;
170
                                }
171
                            }
172
                        }
173
                        break;
174
                    }
175
                }
176
            }
177
 
178
        } else {
179
            $sql = "SELECT time, action
180
                      FROM {log}
181
                     WHERE time >= :timestart
182
                       AND course = :courseid
183
                       AND (action = 'enrol' OR action = 'unenrol')";
184
 
185
            $params = array(
186
                'timestart' => $now - YEARSECS,
187
                'courseid' => $this->course->id,
188
            );
189
 
190
            $rs = $DB->get_recordset_sql($sql, $params);
191
 
192
            foreach ($rs as $record) {
193
                foreach (array_reverse($lastmonth, true) as $key => $value) {
194
                    if ($record->time >= $key) {
195
                        // We need to amend all days up to the key.
196
                        foreach ($lastmonth as $mkey => $mvalue) {
197
                            if ($mkey <= $key) {
198
                                if ($record->action === 'enrol' and $lastmonth[$mkey] > 0) {
199
                                    $lastmonth[$mkey]--;
200
                                } else if ($record->action === 'unenrol') {
201
                                    $lastmonth[$mkey]++;
202
                                }
203
                            }
204
                        }
205
                        break;
206
                    }
207
                }
208
                foreach (array_reverse($lastyear, true) as $key => $value) {
209
                    if ($record->time >= $key) {
210
                        // We need to amend all months up to the key.
211
                        foreach ($lastyear as $ykey => $yvalue) {
212
                            if ($ykey <= $key) {
213
                                if ($record->action === 'enrol' and $lastyear[$ykey] > 0) {
214
                                    $lastyear[$ykey]--;
215
                                } else if ($record->action === 'unenrol') {
216
                                    $lastyear[$ykey]++;
217
                                }
218
                            }
219
                        }
220
                        break;
221
                    }
222
                }
223
            }
224
 
225
            $rs->close();
226
        }
227
 
228
        $this->data = array(
229
            'lastmonth' => array(),
230
            'lastyear' => array(),
231
        );
232
 
233
        $format = get_string('strftimedateshort', 'core_langconfig');
234
        foreach ($lastmonth as $timestamp => $enrolled) {
235
            $date = userdate($timestamp, $format);
236
            $this->data['lastmonth'][] = array('date' => $date, 'enrolled' => $enrolled);
237
        }
238
        foreach ($lastyear as $timestamp => $enrolled) {
239
            $date = userdate($timestamp, $format);
240
            $this->data['lastyear'][] = array('date' => $date, 'enrolled' => $enrolled);
241
        }
242
    }
243
}