MDL-58651 logstore_database: Add ability to not send database options
[moodle.git] / admin / tool / log / store / database / classes / log / store.php
CommitLineData
7eaca5a8
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/**
ed8f7c30 18 * External database store.
7eaca5a8
19 *
20 * @package logstore_database
21 * @copyright 2013 Petr Skoda {@link http://skodak.org}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25namespace logstore_database\log;
7eaca5a8
26defined('MOODLE_INTERNAL') || die();
27
1cfce08e 28class store implements \tool_log\log\writer, \core\log\sql_reader {
ed8f7c30
AA
29 use \tool_log\helper\store,
30 \tool_log\helper\reader,
8bae0d0d 31 \tool_log\helper\buffered_writer {
0852f9c6
32 dispose as helper_dispose;
33 }
ed8f7c30 34
7eaca5a8
35 /** @var \moodle_database $extdb */
36 protected $extdb;
37
ed8f7c30
AA
38 /** @var bool $logguests true if logging guest access */
39 protected $logguests;
40
a3cfbccd
AA
41 /** @var array $includelevels An array of education levels to include */
42 protected $includelevels = array();
ed8f7c30 43
a3cfbccd
AA
44 /** @var array $includeactions An array of actions types to include */
45 protected $includeactions = array();
ed8f7c30
AA
46
47 /**
48 * Construct
49 *
50 * @param \tool_log\log\manager $manager
51 */
7eaca5a8 52 public function __construct(\tool_log\log\manager $manager) {
ed8f7c30
AA
53 $this->helper_setup($manager);
54 $this->buffersize = $this->get_config('buffersize', 50);
55 $this->logguests = $this->get_config('logguests', 1);
a3cfbccd
AA
56 $actions = $this->get_config('includeactions', '');
57 $levels = $this->get_config('includelevels', '');
58 $this->includeactions = $actions === '' ? array() : explode(',', $actions);
59 $this->includelevels = $levels === '' ? array() : explode(',', $levels);
7eaca5a8
60 }
61
ed8f7c30
AA
62 /**
63 * Setup the Database.
64 *
65 * @return bool
66 */
7eaca5a8
67 protected function init() {
68 if (isset($this->extdb)) {
69 return !empty($this->extdb);
70 }
71
72 $dbdriver = $this->get_config('dbdriver');
24b293e4 73 if (empty($dbdriver)) {
7eaca5a8
74 $this->extdb = false;
75 return false;
76 }
ed8f7c30 77 list($dblibrary, $dbtype) = explode('/', $dbdriver);
7eaca5a8
78
79 if (!$db = \moodle_database::get_driver_instance($dbtype, $dblibrary, true)) {
80 debugging("Unknown driver $dblibrary/$dbtype", DEBUG_DEVELOPER);
81 $this->extdb = false;
82 return false;
83 }
84
85 $dboptions = array();
86 $dboptions['dbpersist'] = $this->get_config('dbpersist', '0');
87 $dboptions['dbsocket'] = $this->get_config('dbsocket', '');
88 $dboptions['dbport'] = $this->get_config('dbport', '');
89 $dboptions['dbschema'] = $this->get_config('dbschema', '');
90 $dboptions['dbcollation'] = $this->get_config('dbcollation', '');
556ceb20 91 $dboptions['dbhandlesoptions'] = $this->get_config('dbhandlesoptions', false);
7eaca5a8
92 try {
93 $db->connect($this->get_config('dbhost'), $this->get_config('dbuser'), $this->get_config('dbpass'),
ed8f7c30
AA
94 $this->get_config('dbname'), false, $dboptions);
95 $tables = $db->get_tables();
96 if (!in_array($this->get_config('dbtable'), $tables)) {
97 debugging('Cannot find the specified table', DEBUG_DEVELOPER);
98 $this->extdb = false;
99 return false;
100 }
7eaca5a8 101 } catch (\moodle_exception $e) {
ed8f7c30 102 debugging('Cannot connect to external database: ' . $e->getMessage(), DEBUG_DEVELOPER);
7eaca5a8
103 $this->extdb = false;
104 return false;
105 }
106
107 $this->extdb = $db;
108 return true;
109 }
110
e23bd110
111 /**
112 * Should the event be ignored (== not logged)?
113 * @param \core\event\base $event
114 * @return bool
115 */
116 protected function is_event_ignored(\core\event\base $event) {
a3cfbccd
AA
117 if (!in_array($event->crud, $this->includeactions) &&
118 !in_array($event->edulevel, $this->includelevels)
e23bd110
119 ) {
120 // Ignore event if the store settings do not want to store it.
121 return true;
122 }
123 if ((!CLI_SCRIPT or PHPUNIT_TEST) and !$this->logguests) {
124 // Always log inside CLI scripts because we do not login there.
125 if (!isloggedin() or isguestuser()) {
126 return true;
127 }
128 }
129 return false;
130 }
131
ed8f7c30
AA
132 /**
133 * Insert events in bulk to the database.
134 *
e23bd110 135 * @param array $evententries raw event data
ed8f7c30 136 */
e23bd110 137 protected function insert_event_entries($evententries) {
ed8f7c30
AA
138 if (!$this->init()) {
139 return;
140 }
141 if (!$dbtable = $this->get_config('dbtable')) {
142 return;
143 }
ed8f7c30 144 try {
e23bd110 145 $this->extdb->insert_records($dbtable, $evententries);
ed8f7c30
AA
146 } catch (\moodle_exception $e) {
147 debugging('Cannot write to external database: ' . $e->getMessage(), DEBUG_DEVELOPER);
7eaca5a8 148 }
7eaca5a8
149 }
150
ed8f7c30
AA
151 /**
152 * Get an array of events based on the passed on params.
153 *
154 * @param string $selectwhere select conditions.
0852f9c6
155 * @param array $params params.
156 * @param string $sort sortorder.
157 * @param int $limitfrom limit constraints.
158 * @param int $limitnum limit constraints.
ed8f7c30
AA
159 *
160 * @return array|\core\event\base[] array of events.
161 */
993d8d83 162 public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
7eaca5a8 163 if (!$this->init()) {
ed8f7c30 164 return array();
7eaca5a8
165 }
166
167 if (!$dbtable = $this->get_config('dbtable')) {
ed8f7c30
AA
168 return array();
169 }
170
a8d7d617
PS
171 $sort = self::tweak_sort_by_id($sort);
172
ed8f7c30
AA
173 $events = array();
174 $records = $this->extdb->get_records_select($dbtable, $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
175
176 foreach ($records as $data) {
1cfce08e
DM
177 if ($event = $this->get_log_event($data)) {
178 $events[$data->id] = $event;
877d5a32 179 }
7eaca5a8
180 }
181
ed8f7c30
AA
182 return $events;
183 }
184
1cfce08e
DM
185 /**
186 * Fetch records using given criteria returning a Traversable object.
187 *
188 * Note that the traversable object contains a moodle_recordset, so
189 * remember that is important that you call close() once you finish
190 * using it.
191 *
192 * @param string $selectwhere
193 * @param array $params
194 * @param string $sort
195 * @param int $limitfrom
196 * @param int $limitnum
197 * @return \core\dml\recordset_walk|\core\event\base[]
198 */
199 public function get_events_select_iterator($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
200 if (!$this->init()) {
201 return array();
202 }
203
204 if (!$dbtable = $this->get_config('dbtable')) {
205 return array();
206 }
207
208 $sort = self::tweak_sort_by_id($sort);
209
210 $recordset = $this->extdb->get_recordset_select($dbtable, $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
211
212 return new \core\dml\recordset_walk($recordset, array($this, 'get_log_event'));
213 }
214
215 /**
216 * Returns an event from the log data.
217 *
218 * @param stdClass $data Log data
219 * @return \core\event\base
220 */
221 public function get_log_event($data) {
222
223 $extra = array('origin' => $data->origin, 'ip' => $data->ip, 'realuserid' => $data->realuserid);
224 $data = (array)$data;
225 $id = $data['id'];
226 $data['other'] = unserialize($data['other']);
227 if ($data['other'] === false) {
228 $data['other'] = array();
229 }
230 unset($data['origin']);
231 unset($data['ip']);
232 unset($data['realuserid']);
233 unset($data['id']);
234
235 if (!$event = \core\event\base::restore($data, $extra)) {
236 return null;
237 }
238
239 return $event;
240 }
241
ed8f7c30
AA
242 /**
243 * Get number of events present for the given select clause.
244 *
245 * @param string $selectwhere select conditions.
0852f9c6 246 * @param array $params params.
ed8f7c30
AA
247 *
248 * @return int Number of events available for the given conditions
249 */
993d8d83 250 public function get_events_select_count($selectwhere, array $params) {
ed8f7c30
AA
251 if (!$this->init()) {
252 return 0;
253 }
254
255 if (!$dbtable = $this->get_config('dbtable')) {
256 return 0;
7eaca5a8 257 }
7eaca5a8 258
ed8f7c30 259 return $this->extdb->count_records_select($dbtable, $selectwhere, $params);
7eaca5a8
260 }
261
bcfa51ca
MN
262 /**
263 * Get a config value for the store.
264 *
265 * @param string $name Config name
266 * @param mixed $default default value
267 * @return mixed config value if set, else the default value.
268 */
269 public function get_config_value($name, $default = null) {
270 return $this->get_config($name, $default);
271 }
272
273 /**
274 * Get the external database object.
275 *
276 * @return \moodle_database $extdb
277 */
278 public function get_extdb() {
279 if (!$this->init()) {
280 return false;
281 }
282
283 return $this->extdb;
284 }
285
bdae738e
286 /**
287 * Are the new events appearing in the reader?
288 *
289 * @return bool true means new log events are being added, false means no new data will be added
290 */
291 public function is_logging() {
292 if (!$this->init()) {
293 return false;
294 }
295 return true;
296 }
297
ed8f7c30
AA
298 /**
299 * Dispose off database connection after pushing any buffered events to the database.
300 */
7eaca5a8 301 public function dispose() {
ed8f7c30 302 $this->helper_dispose();
7eaca5a8
303 if ($this->extdb) {
304 $this->extdb->dispose();
305 }
306 $this->extdb = null;
307 }
308}