Commit | Line | Data |
---|---|---|
69dd0c8c EL |
1 | <?php |
2 | ||
3 | // This file is part of Moodle - http://moodle.org/ | |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
18 | /** | |
19 | * @package moodlecore | |
20 | * @subpackage backup-logger | |
21 | * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} | |
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
23 | */ | |
24 | ||
25 | /** | |
26 | * Base abstract class for all the loggers to be used in backup/restore | |
27 | * | |
28 | * Any message passed will be processed by all the loggers in the defined chain | |
29 | * (note some implementations may be not strictly "loggers" but classes performing | |
30 | * other sort of tasks (avoiding browser/php timeouts, painters...). One simple 1-way | |
31 | * basic chain of commands/responsibility pattern. | |
32 | * | |
33 | * TODO: Finish phpdocs | |
34 | */ | |
35 | abstract class base_logger implements checksumable { | |
36 | ||
37 | protected $level; // minimum level of logging this logger must handle (valid level from @backup class) | |
38 | protected $showdate; // flag to decide if the logger must output the date (true) or no (false) | |
39 | protected $showlevel; // flag to decide if the logger must output the level (true) or no (false) | |
40 | protected $next; // next logger in the chain | |
41 | ||
42 | public function __construct($level, $showdate = false, $showlevel = false) { | |
43 | // TODO: check level is correct | |
44 | $this->level = $level; | |
45 | $this->showdate = $showdate; | |
46 | $this->showlevel = $showlevel; | |
47 | $this->next = null; | |
48 | } | |
49 | ||
50 | public final function set_next($next) { | |
51 | // TODO: Check is a base logger | |
52 | ||
53 | // TODO: Check next hasn't been set already | |
54 | ||
55 | // TODO: Avoid circular dependencies | |
56 | if ($this->is_circular_reference($next)) { | |
57 | $a = new stdclass(); | |
58 | $a->alreadyinchain = get_class($this); | |
59 | $a->main = get_class($next); | |
60 | throw new base_logger_exception('logger_circular_reference', $a); | |
61 | } | |
62 | ||
63 | $this->next = $next; | |
64 | } | |
65 | ||
66 | public function get_next() { | |
67 | return $this->next; | |
68 | } | |
69 | ||
70 | public function get_level() { | |
71 | return $this->level; | |
72 | } | |
73 | ||
53f95c99 EL |
74 | /** |
75 | * Destroy (nullify) the chain of loggers references, also closing resources when needed. | |
76 | * | |
77 | * @since Moodle 3.1 | |
78 | */ | |
79 | public final function destroy() { | |
80 | // Recursively destroy the chain. | |
81 | if ($this->next !== null) { | |
82 | $this->next->destroy(); | |
83 | $this->next = null; | |
84 | } | |
85 | // And close every logger. | |
86 | $this->close(); | |
87 | } | |
88 | ||
89 | /** | |
90 | * Close any resource the logger may have open. | |
91 | * | |
92 | * @since Moodle 3.1 | |
93 | */ | |
94 | public function close() { | |
95 | // Nothing to do by default. Only loggers using resources (files, own connections...) need to override this. | |
96 | } | |
97 | ||
69dd0c8c EL |
98 | // checksumable interface methods |
99 | ||
100 | public function calculate_checksum() { | |
101 | // Checksum is a simple md5 hash of classname, level and | |
102 | // on each specialised logger, its own atrributes | |
103 | // Not following the chain at all. | |
104 | return md5(get_class($this) . '-' . $this->level); | |
105 | } | |
106 | ||
107 | public function is_checksum_correct($checksum) { | |
108 | return $this->calculate_checksum() === $checksum; | |
109 | } | |
110 | ||
111 | // Protected API starts here | |
112 | ||
113 | abstract protected function action($message, $level, $options = null); // To implement | |
114 | ||
115 | public final function process($message, $level, $options = null) { | |
116 | $result = true; | |
117 | if ($this->level != backup::LOG_NONE && $this->level >= $level) { // Perform action conditionally | |
118 | $result = $this->action($message, $level, $options); | |
119 | } | |
120 | if ($result === false) { // Something was wrong, stop the chain | |
121 | return $result; | |
122 | } | |
123 | if ($this->next !== null) { // The chain continues being processed | |
124 | $result = $this->next->process($message, $level, $options); | |
125 | } | |
126 | return $result; | |
127 | } | |
128 | ||
129 | protected function is_circular_reference($obj) { | |
130 | // Get object all nexts recursively and check if $this is already there | |
131 | $nexts = $obj->get_nexts(); | |
132 | if (array_key_exists($this->calculate_checksum(), $nexts) || $obj == $this) { | |
133 | return true; | |
134 | } | |
135 | return false; | |
136 | } | |
137 | ||
138 | protected function get_nexts() { | |
139 | $nexts = array(); | |
140 | if ($this->next !== null) { | |
141 | $nexts[$this->next->calculate_checksum()] = $this->next->calculate_checksum(); | |
142 | $nexts = array_merge($nexts, $this->next->get_nexts()); | |
143 | } | |
144 | return $nexts; | |
145 | } | |
146 | ||
147 | protected function get_datestr() { | |
148 | return userdate(time(), '%c'); | |
149 | } | |
150 | ||
151 | protected function get_levelstr($level) { | |
152 | $result = 'undefined'; | |
153 | switch ($level) { | |
154 | case backup::LOG_ERROR: | |
155 | $result = 'error'; | |
156 | break; | |
157 | case backup::LOG_WARNING: | |
158 | $result = 'warn'; | |
159 | break; | |
160 | case backup::LOG_INFO: | |
161 | $result = 'info'; | |
162 | break; | |
163 | case backup::LOG_DEBUG: | |
164 | $result = 'debug'; | |
165 | break; | |
166 | } | |
167 | return $result; | |
168 | } | |
169 | ||
170 | protected function get_prefix($level, $options) { | |
171 | $prefix = ''; | |
172 | if ($this->showdate) { | |
173 | $prefix .= '[' . $this->get_datestr() . '] '; | |
174 | } | |
175 | if ($this->showlevel) { | |
176 | $prefix .= '[' . $this->get_levelstr($level) . '] '; | |
177 | } | |
178 | return $prefix; | |
179 | } | |
180 | } | |
181 | ||
182 | /* | |
183 | * Exception class used by all the @base_logger stuff | |
184 | */ | |
185 | class base_logger_exception extends backup_exception { | |
186 | ||
187 | public function __construct($errorcode, $a=NULL, $debuginfo=null) { | |
188 | parent::__construct($errorcode, $a, $debuginfo); | |
189 | } | |
190 | } |