]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Updater/AbstractUpdater.php
CS: declare visibility for constants
[galette.git] / galette / lib / Galette / Updater / AbstractUpdater.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Galette abstract script updater
7 *
8 * PHP version 5
9 *
10 * Copyright © 2013 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Updater
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2013 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link http://galette.tuxfamily.org
34 * @since Available since 0.7.6dev - 2013-07-21
35 */
36
37 namespace Galette\Updater;
38
39 use Analog\Analog;
40 use Galette\Core\Db;
41
42 /**
43 * Galette abstract updater script
44 *
45 * @category Updater
46 * @name AbstractUpdater
47 * @package Galette
48 * @author Johan Cwiklinski <johan@x-tnd.be>
49 * @copyright 2013 The Galette Team
50 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
51 * @link http://galette.tuxfamily.org
52 * @since Available since 0.7.6dev - 2013-07-21
53 */
54 abstract class AbstractUpdater
55 {
56 public const REPORT_SUCCESS = 0;
57 public const REPORT_ERROR = 1;
58 public const REPORT_WARNING = 2;
59
60 protected $sql_scripts = null;
61 protected $db_version = null;
62 private $engines = array(
63 Db::MYSQL => Db::MYSQL,
64 Db::PGSQL => Db::PGSQL,
65 );
66 protected $zdb;
67 protected $installer;
68 private $report = array();
69
70 /**
71 * Main constructor
72 */
73 public function __construct()
74 {
75 if ($this->db_version === null) {
76 Analog::log(
77 'Upgrade version can not be empty!',
78 Analog::ERROR
79 );
80 throw new \RuntimeException('Upgrade version can not be empty!');
81 }
82 }
83
84 /**
85 * Does upgrade have a SQL script to run
86 *
87 * @return boolean
88 */
89 private function hasSql()
90 {
91 return !($this->sql_scripts === null);
92 }
93
94 /**
95 * Runs the update.
96 * Update will take the following order:
97 * - preUpdate
98 * - update
99 * - sql (if any)
100 * - postUpdate
101 *
102 * If one function fails, an Exception will be thrown
103 * and next function will not be called.
104 *
105 * @param Db $zdb Database instance
106 * @param Install $installer Installer instance
107 *
108 * @return Boolean|Exception
109 */
110 final public function run($zdb, $installer)
111 {
112 $this->zdb = $zdb;
113 $this->installer = $installer;
114
115 $res = $this->preUpdate();
116 if ($res !== true) {
117 throw new \RuntimeException(
118 'Fail executing pre-update instructions'
119 );
120 }
121
122 $res = $this->update();
123 if ($res !== true) {
124 throw new \RuntimeException(
125 'Fail executing update instructions'
126 );
127 }
128
129 if ($this->hasSql()) {
130 $res = $this->sql($zdb, $installer);
131 if ($res !== true) {
132 throw new \RuntimeException(
133 'Fail executing SQL instructions'
134 );
135 }
136 }
137
138 $res = $this->postUpdate();
139 if ($res !== true) {
140 throw new \RuntimeException(
141 'Fail executing post-update instructions'
142 );
143 }
144
145 $this->updateDbVersion();
146 }
147
148 /**
149 * Update instructions
150 *
151 * @return boolean
152 */
153 abstract protected function update();
154
155 /**
156 * Pre stuff, if any.
157 * Will be extecuted first.
158 *
159 * @return boolean
160 */
161 protected function preUpdate()
162 {
163 return true;
164 }
165
166 /**
167 * Executes SQL instructions, if any.
168 *
169 * @param Db $zdb Database instance
170 * @param Install $installer Installer instance
171 *
172 * @return boolean
173 */
174 private function sql($zdb, $installer)
175 {
176 $script = $this->sql_scripts[TYPE_DB];
177
178 $sql_query = @fread(
179 @fopen($script, 'r'),
180 @filesize($script)
181 ) . "\n";
182
183 if ($sql_query !== '') {
184 return $installer->executeSql($zdb, $sql_query);
185 }
186 }
187
188 /**
189 * Post stuff, if any.
190 * Will be executed at the end.
191 *
192 * @return boolean
193 */
194 protected function postUpdate()
195 {
196 return true;
197 }
198
199 /**
200 * Set SQL files instructions for all supported databases
201 *
202 * @param string $version Version for scripts
203 *
204 * @return boolean
205 */
206 protected function setSqlScripts($version)
207 {
208 $scripts = $this->getSqlScripts($version);
209 if (
210 is_array($scripts)
211 && count($scripts) === count($this->engines)
212 && count(array_diff(array_keys($scripts), $this->engines)) == 0
213 ) {
214 $checked = false;
215 foreach ($scripts as $file) {
216 if (file_exists($file)) {
217 $checked = true;
218 } else {
219 $checked = false;
220 break;
221 }
222 }
223
224 if ($checked === true) {
225 $this->sql_scripts = $scripts;
226 }
227 return $checked;
228 } else {
229 Analog::log(
230 'Unable to see SQL scripts. Please check that scripts exists ' .
231 'in scripts/sql directory, for all supported SQL engines.',
232 Analog::ERROR
233 );
234 return false;
235 }
236 }
237
238 /**
239 * Get SQL scripts for specified version
240 *
241 * @param string $version Scripts version
242 *
243 * @return array
244 */
245 private function getSqlScripts($version)
246 {
247 $dh = opendir(GALETTE_ROOT . '/install/scripts/sql');
248 $scripts = array();
249
250 if ($dh !== false) {
251 while (($file = readdir($dh)) !== false) {
252 if (preg_match('/upgrade-to-(.*)-(.+)\.sql/', $file, $ver)) {
253 if ($ver[1] == $version) {
254 $scripts[$ver[2]] = GALETTE_ROOT . '/install/scripts/sql/' . $file;
255 }
256 }
257 }
258 closedir($dh);
259 }
260
261 return $scripts;
262 }
263
264 /**
265 * Add report entry in array
266 *
267 * @param string $msg Report message
268 * @param int $type Entry type
269 *
270 * @return void
271 */
272 public function addReportEntry($msg, $type)
273 {
274 $res = true;
275 if ($type === self::REPORT_ERROR) {
276 $res = false;
277 }
278 $this->report[] = array(
279 'message' => $msg,
280 'type' => $type,
281 'res' => $res
282 );
283 }
284
285 /**
286 * Add an error in array
287 *
288 * @param string $msg Error message
289 *
290 * @return void
291 */
292 public function addError($msg)
293 {
294 $this->addReportEntry($msg, self::REPORT_ERROR);
295 }
296
297 /**
298 * Has current update errors?
299 *
300 * @return boolean
301 */
302 public function hasErrors()
303 {
304 foreach ($this->report as $report) {
305 if ($report['type'] === self::REPORT_ERROR) {
306 return true;
307 }
308 }
309 }
310
311 /**
312 * Get upgrade report
313 *
314 * @return array
315 */
316 public function getReport()
317 {
318 return $this->report;
319 }
320
321 /**
322 * Update database version
323 *
324 * @return void
325 */
326 private function updateDbVersion()
327 {
328 $update = $this->zdb->update('database');
329 $update->set(
330 array('version' => $this->db_version)
331 );
332 $this->zdb->execute($update);
333 }
334 }