MDL-41944 block_onlines_users: Improve performance
[moodle.git] / blocks / online_users / classes / fetcher.php
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/>.
17 /**
18  * File containing onlineusers class.
19  *
20  * @package    block_online_users
21  * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace block_online_users;
27 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Class used to list and count online users
31  *
32  * @package    block_online_users
33  * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
34  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
36 class fetcher {
38     /** @var string The SQL query for retrieving a list of online users */
39     public $sql;
40     /** @var string The SQL query for counting the number of online users */
41     public $csql;
42     /** @var string The params for the SQL queries */
43     public $params;
45     /**
46      * Class constructor
47      *
48      * @param int $currentgroup The group (if any) to filter on
49      * @param int $now Time now
50      * @param int $timetoshowusers Number of seconds to show online users
51      * @param context $context Context object used to generate the sql for users enrolled in a specific course
52      * @param bool $sitelevel Whether to check online users at site level.
53      * @param int $courseid The course id to check
54      */
55     public function __construct($currentgroup, $now, $timetoshowusers, $context, $sitelevel = true, $courseid = null) {
56         $this->set_sql($currentgroup, $now, $timetoshowusers, $context, $sitelevel, $courseid);
57     }
59     /**
60      * Store the SQL queries & params for listing online users
61      *
62      * @param int $currentgroup The group (if any) to filter on
63      * @param int $now Time now
64      * @param int $timetoshowusers Number of seconds to show online users
65      * @param context $context Context object used to generate the sql for users enrolled in a specific course
66      * @param bool $sitelevel Whether to check online users at site level.
67      * @param int $courseid The course id to check
68      */
69     protected function set_sql($currentgroup, $now, $timetoshowusers, $context, $sitelevel, $courseid) {
70         $timefrom = 100 * floor(($now - $timetoshowusers) / 100); // Round to nearest 100 seconds for better query cache.
72         $groupmembers = "";
73         $groupselect  = "";
74         $groupby       = "";
75         $lastaccess    = ", lastaccess";
76         $timeaccess    = ", ul.timeaccess AS lastaccess";
77         $params = array();
79         $userfields = \user_picture::fields('u', array('username'));
81         // Add this to the SQL to show only group users.
82         if ($currentgroup !== null) {
83             $groupmembers = ", {groups_members} gm";
84             $groupselect = "AND u.id = gm.userid AND gm.groupid = :currentgroup";
85             $groupby = "GROUP BY $userfields";
86             $lastaccess = ", MAX(u.lastaccess) AS lastaccess";
87             $timeaccess = ", MAX(ul.timeaccess) AS lastaccess";
88             $params['currentgroup'] = $currentgroup;
89         }
91         $params['now'] = $now;
92         $params['timefrom'] = $timefrom;
93         if ($sitelevel) {
94             $sql = "SELECT $userfields $lastaccess
95                       FROM {user} u $groupmembers
96                      WHERE u.lastaccess > :timefrom
97                            AND u.lastaccess <= :now
98                            AND u.deleted = 0
99                            $groupselect $groupby
100                   ORDER BY lastaccess DESC ";
102             $csql = "SELECT COUNT(u.id)
103                       FROM {user} u $groupmembers
104                      WHERE u.lastaccess > :timefrom
105                            AND u.lastaccess <= :now
106                            AND u.deleted = 0
107                            $groupselect";
109         } else {
110             // Course level - show only enrolled users for now.
111             // TODO: add a new capability for viewing of all users (guests+enrolled+viewing).
112             list($esqljoin, $eparams) = get_enrolled_sql($context);
113             $params = array_merge($params, $eparams);
115             $sql = "SELECT $userfields $timeaccess
116                       FROM {user_lastaccess} ul $groupmembers, {user} u
117                       JOIN ($esqljoin) euj ON euj.id = u.id
118                      WHERE ul.timeaccess > :timefrom
119                            AND u.id = ul.userid
120                            AND ul.courseid = :courseid
121                            AND ul.timeaccess <= :now
122                            AND u.deleted = 0
123                            $groupselect $groupby
124                   ORDER BY lastaccess DESC";
126             $csql = "SELECT COUNT(u.id)
127                       FROM {user_lastaccess} ul $groupmembers, {user} u
128                       JOIN ($esqljoin) euj ON euj.id = u.id
129                      WHERE ul.timeaccess > :timefrom
130                            AND u.id = ul.userid
131                            AND ul.courseid = :courseid
132                            AND ul.timeaccess <= :now
133                            AND u.deleted = 0
134                            $groupselect";
136             $params['courseid'] = $courseid;
137         }
138         $this->sql = $sql;
139         $this->csql = $csql;
140         $this->params = $params;
141     }
143     /**
144      * Get a list of the most recent online users
145      *
146      * @param int $userlimit The maximum number of users that will be returned (optional, unlimited if not set)
147      * @return array
148      */
149     public function get_users($userlimit = 0) {
150         global $DB;
151         $users = $DB->get_records_sql($this->sql, $this->params, 0, $userlimit);
152         return $users;
153     }
155     /**
156      * Count the number of online users
157      *
158      * @return int
159      */
160     public function count_users() {
161         global $DB;
162         return $DB->count_records_sql($this->csql, $this->params);
163     }