9c286f0f4d7277e09b8a2e2fb7bd25f349fbb49f
[moodle.git] / admin / tool / log / classes / log / manager.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  * 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  */
25 namespace tool_log\log;
27 defined('MOODLE_INTERNAL') || die();
29 class manager implements \core\log\manager {
30     /** @var \core\log\reader[] $readers list of initialised log readers */
31     protected $readers;
33     /** @var \tool_log\log\writer[] $writers list of initialised log writers */
34     protected $writers;
36     /** @var \tool_log\log\store[] $stores list of all enabled stores */
37     protected $stores;
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();
52         // Register shutdown handler - this may be useful for buffering, file handle closing, etc.
53         \core_shutdown_manager::register_function(array($this, 'dispose'));
55         $plugins = get_config('tool_log', 'enabled_stores');
56         if (empty($plugins)) {
57             return;
58         }
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     }
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) {
87                 debugging('Exception detected when logging event ' . $event->eventname . ' in ' . $plugin . ': ' .
88                     $e->getMessage(), DEBUG_NORMAL, $e->getTrace());
89             }
90         }
91     }
93     /**
94      * Returns list of available log readers.
95      *
96      * This way the reports find out available sources of data.
97      *
98      * @param string $interface Returned stores must implement this interface.
99      *
100      * @return \core\log\reader[] list of available log data readers
101      */
102     public function get_readers($interface = null) {
103         $this->init();
104         $return = array();
105         foreach ($this->readers as $plugin => $reader) {
106             if (empty($interface) || ($reader instanceof $interface)) {
107                 $return[$plugin] = $reader;
108             }
109         }
110         return $return;
111     }
113     /**
114      * Get a list of reports that support the given store instance.
115      *
116      * @param string $logstore Name of the store.
117      *
118      * @return array List of supported reports
119      */
120     public function get_supported_reports($logstore) {
122         $allstores = self::get_store_plugins();
123         if (empty($allstores[$logstore])) {
124             // Store doesn't exist.
125             return array();
126         }
128         $reports = get_plugin_list_with_function('report', 'supports_logstore', 'lib.php');
129         $enabled = $this->stores;
131         if (empty($enabled[$logstore])) {
132             // Store is not enabled, init an instance.
133             $classname = '\\' . $logstore . '\log\store';
134             $instance = new $classname($this);
135         } else {
136             $instance = $enabled[$logstore];
137         }
139         $return = array();
140         foreach ($reports as $report => $fulldir) {
141             if (component_callback($report, 'supports_logstore', array($instance), false)) {
142                 $return[$report] = get_string('pluginname', $report);
143             }
144         }
146         return $return;
147     }
149     /**
150      * For a given report, returns a list of log stores that are supported.
151      *
152      * @param string $component component.
153      *
154      * @return false|array list of logstores that support the given report. It returns false if the given $component doesn't
155      *      require logstores.
156      */
157     public function get_supported_logstores($component) {
159         $allstores = self::get_store_plugins();
160         $enabled = $this->stores;
162         $function = component_callback_exists($component, 'supports_logstore');
163         if (!$function) {
164             // The report doesn't define the callback, most probably it doesn't need log stores.
165             return false;
166         }
168         $return = array();
169         foreach ($allstores as $store => $logclass) {
170             $instance = empty($enabled[$store]) ? new $logclass($this) : $enabled[$store];
171             if ($function($instance)) {
172                 $return[$store] = get_string('pluginname', $store);
173             }
174         }
175         return $return;
176     }
178     /**
179      * Intended for store management, do not use from reports.
180      *
181      * @return store[] Returns list of available store plugins.
182      */
183     public static function get_store_plugins() {
184         return \core_component::get_plugin_list_with_class('logstore', 'log\store');
185     }
187     /**
188      * Usually called automatically from shutdown manager,
189      * this allows us to implement buffering of write operations.
190      */
191     public function dispose() {
192         if ($this->stores) {
193             foreach ($this->stores as $store) {
194                 $store->dispose();
195             }
196         }
197         $this->stores = null;
198         $this->readers = null;
199         $this->writers = null;
200     }
202     /**
203      * Legacy add_to_log() redirection.
204      *
205      * To be used only from deprecated add_to_log() function and event trigger() method.
206      *
207      * NOTE: this is hardcoded to legacy log store plugin, hopefully we can get rid of it soon.
208      *
209      * @param int $courseid The course id
210      * @param string $module The module name  e.g. forum, journal, resource, course, user etc
211      * @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify
212      * @param string $url The file and parameters used to see the results of the action
213      * @param string $info Additional description information
214      * @param int $cm The course_module->id if there is one
215      * @param int|\stdClass $user If log regards $user other than $USER
216      * @param string $ip Override the IP, should only be used for restore.
217      * @param int $time Override the log time, should only be used for restore.
218      */
219     public function legacy_add_to_log($courseid, $module, $action, $url = '', $info = '',
220                                       $cm = 0, $user = 0, $ip = null, $time = null) {
221         $this->init();
222         if (isset($this->stores['logstore_legacy'])) {
223             $this->stores['logstore_legacy']->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user, $ip, $time);
224         }
225     }