MDL-50408 tool_log: Extra deprecation tip
[moodle.git] / admin / tool / log / classes / log / manager.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/**
18 * Log store manager.
19 *
20 * @package tool_log
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 tool_log\log;
26
27defined('MOODLE_INTERNAL') || die();
28
29class manager implements \core\log\manager {
30 /** @var \core\log\reader[] $readers list of initialised log readers */
31 protected $readers;
32
33 /** @var \tool_log\log\writer[] $writers list of initialised log writers */
34 protected $writers;
35
0852f9c6 36 /** @var \tool_log\log\store[] $stores list of all enabled stores */
7eaca5a8
37 protected $stores;
38
39 /**
40 * Delayed initialisation of singleton.
41 */
42 protected function init() {
43 if (isset($this->stores)) {
44 // Do not bother checking readers and writers here
45 // because everything is init here.
46 return;
47 }
48 $this->stores = array();
49 $this->readers = array();
50 $this->writers = array();
51
52 // Register shutdown handler - this may be useful for buffering, file handle closing, etc.
53 \core_shutdown_manager::register_function(array($this, 'dispose'));
54
55 $plugins = get_config('tool_log', 'enabled_stores');
56 if (empty($plugins)) {
57 return;
58 }
59
60 $plugins = explode(',', $plugins);
61 foreach ($plugins as $plugin) {
62 $classname = "\\$plugin\\log\\store";
63 if (class_exists($classname)) {
64 $store = new $classname($this);
65 $this->stores[$plugin] = $store;
66 if ($store instanceof \tool_log\log\writer) {
67 $this->writers[$plugin] = $store;
68 }
69 if ($store instanceof \core\log\reader) {
70 $this->readers[$plugin] = $store;
71 }
72 }
73 }
74 }
75
76 /**
77 * Called from the observer only.
78 *
79 * @param \core\event\base $event
80 */
81 public function process(\core\event\base $event) {
82 $this->init();
83 foreach ($this->writers as $plugin => $writer) {
84 try {
85 $writer->write($event, $this);
86 } catch (\Exception $e) {
0852f9c6
87 debugging('Exception detected when logging event ' . $event->eventname . ' in ' . $plugin . ': ' .
88 $e->getMessage(), DEBUG_NORMAL, $e->getTrace());
7eaca5a8
89 }
90 }
91 }
92
93 /**
94 * Returns list of available log readers.
95 *
96 * This way the reports find out available sources of data.
97 *
e083efe0
AA
98 * @param string $interface Returned stores must implement this interface.
99 *
7eaca5a8
100 * @return \core\log\reader[] list of available log data readers
101 */
e083efe0 102 public function get_readers($interface = null) {
7eaca5a8
103 $this->init();
104 $return = array();
105 foreach ($this->readers as $plugin => $reader) {
e083efe0
AA
106 if (empty($interface) || ($reader instanceof $interface)) {
107 $return[$plugin] = $reader;
108 }
5c73688b
DM
109 // TODO MDL-49291 These conditions should be removed as part of the 2nd stage deprecation.
110 if ($reader instanceof \core\log\sql_internal_reader) {
111 debugging('\core\log\sql_internal_reader has been deprecated in favour of \core\log\sql_internal_table_reader.' .
112 ' Update ' . get_class($reader) . ' to use the new interface.', DEBUG_DEVELOPER);
113 } else if ($reader instanceof \core\log\sql_select_reader) {
114 debugging('\core\log\sql_select_reader has been deprecated in favour of \core\log\sql_reader. Update ' .
115 get_class($reader) . ' to use the new interface.', DEBUG_DEVELOPER);
116 }
117 }
118
119 // TODO MDL-49291 This section below (until the final return) should be removed as part of the 2nd stage deprecation.
120 $isselectreader = (ltrim($interface, '\\') === 'core\log\sql_select_reader');
121 $isinternalreader = (ltrim($interface, '\\') === 'core\log\sql_internal_reader');
122 if ($isselectreader || $isinternalreader) {
123
124 if ($isselectreader) {
125 $alternative = '\core\log\sql_reader';
126 } else {
127 $alternative = '\core\log\sql_internal_table_reader';
128 }
129
130 if (count($return) === 0) {
131 // If there are no classes implementing the provided interface and the provided interface is one of
132 // the deprecated ones, we return the non-deprecated alternatives. It should be safe as the new interface
133 // is adding a new method but not changing the existing ones.
134 debugging($interface . ' has been deprecated in favour of ' . $alternative . '. Returning ' . $alternative .
135 ' instances instead. Please call get_readers() using the new interface.', DEBUG_DEVELOPER);
136 $return = $this->get_readers($alternative);
137 } else {
138 debugging($interface . ' has been deprecated in favour of ' . $alternative .
139 '. Please call get_readers() using the new interface.', DEBUG_DEVELOPER);
140 }
7eaca5a8 141 }
5c73688b 142
7eaca5a8
143 return $return;
144 }
145
f0a0f3c2
AA
146 /**
147 * Get a list of reports that support the given store instance.
148 *
149 * @param string $logstore Name of the store.
150 *
151 * @return array List of supported reports
152 */
153 public function get_supported_reports($logstore) {
154
155 $allstores = self::get_store_plugins();
156 if (empty($allstores[$logstore])) {
157 // Store doesn't exist.
158 return array();
159 }
160
16e59c6a 161 $reports = get_plugin_list_with_function('report', 'supports_logstore', 'lib.php');
f0a0f3c2
AA
162 $enabled = $this->stores;
163
164 if (empty($enabled[$logstore])) {
165 // Store is not enabled, init an instance.
166 $classname = '\\' . $logstore . '\log\store';
167 $instance = new $classname($this);
168 } else {
169 $instance = $enabled[$logstore];
170 }
171
172 $return = array();
173 foreach ($reports as $report => $fulldir) {
16e59c6a
AA
174 if (component_callback($report, 'supports_logstore', array($instance), false)) {
175 $return[$report] = get_string('pluginname', $report);
f0a0f3c2
AA
176 }
177 }
178
179 return $return;
180 }
181
182 /**
183 * For a given report, returns a list of log stores that are supported.
184 *
185 * @param string $component component.
186 *
187 * @return false|array list of logstores that support the given report. It returns false if the given $component doesn't
188 * require logstores.
189 */
190 public function get_supported_logstores($component) {
191
192 $allstores = self::get_store_plugins();
193 $enabled = $this->stores;
194
16e59c6a
AA
195 $function = component_callback_exists($component, 'supports_logstore');
196 if (!$function) {
f0a0f3c2
AA
197 // The report doesn't define the callback, most probably it doesn't need log stores.
198 return false;
199 }
200
201 $return = array();
202 foreach ($allstores as $store => $logclass) {
203 $instance = empty($enabled[$store]) ? new $logclass($this) : $enabled[$store];
204 if ($function($instance)) {
205 $return[$store] = get_string('pluginname', $store);
206 }
207 }
208 return $return;
209 }
210
7eaca5a8
211 /**
212 * Intended for store management, do not use from reports.
213 *
214 * @return store[] Returns list of available store plugins.
215 */
216 public static function get_store_plugins() {
217 return \core_component::get_plugin_list_with_class('logstore', 'log\store');
218 }
219
220 /**
221 * Usually called automatically from shutdown manager,
222 * this allows us to implement buffering of write operations.
223 */
224 public function dispose() {
225 if ($this->stores) {
226 foreach ($this->stores as $store) {
227 $store->dispose();
228 }
229 }
230 $this->stores = null;
231 $this->readers = null;
232 $this->writers = null;
233 }
234
7eaca5a8
235 /**
236 * Legacy add_to_log() redirection.
237 *
238 * To be used only from deprecated add_to_log() function and event trigger() method.
239 *
240 * NOTE: this is hardcoded to legacy log store plugin, hopefully we can get rid of it soon.
241 *
0852f9c6
242 * @param int $courseid The course id
243 * @param string $module The module name e.g. forum, journal, resource, course, user etc
244 * @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify
245 * @param string $url The file and parameters used to see the results of the action
246 * @param string $info Additional description information
247 * @param int $cm The course_module->id if there is one
248 * @param int|\stdClass $user If log regards $user other than $USER
362bc070
MN
249 * @param string $ip Override the IP, should only be used for restore.
250 * @param int $time Override the log time, should only be used for restore.
7eaca5a8 251 */
7cd112df
MN
252 public function legacy_add_to_log($courseid, $module, $action, $url = '', $info = '',
253 $cm = 0, $user = 0, $ip = null, $time = null) {
7eaca5a8 254 $this->init();
53dd210a 255 if (isset($this->stores['logstore_legacy'])) {
362bc070 256 $this->stores['logstore_legacy']->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user, $ip, $time);
7eaca5a8
257 }
258 }
259}