]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Updater/AbstractUpdater.php
9a2d9dab22a045ee19c6605dd6bbcc50f633d44c
[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 * @version SVN: $Id$
34 * @link http://galette.tuxfamily.org
35 * @since Available since 0.7.6dev - 2013-07-21
36 */
37
38 namespace Galette\Updater;
39
40 use \Analog\Analog;
41 use Galette\Core\Db;
42
43 /**
44 * Galette abstract updater script
45 *
46 * @category Updater
47 * @name AbstractUpdater
48 * @package Galette
49 * @author Johan Cwiklinski <johan@x-tnd.be>
50 * @copyright 2013 The Galette Team
51 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
52 * @link http://galette.tuxfamily.org
53 * @since Available since 0.7.6dev - 2013-07-21
54 */
55 abstract class AbstractUpdater
56 {
57 const REPORT_SUCCESS = 0;
58 const REPORT_ERROR = 1;
59 const REPORT_WARNING = 2;
60
61 protected $sql_scripts = null;
62 protected $db_version = null;
63 private $engines = array(
64 Db::MYSQL => Db::MYSQL,
65 Db::PGSQL => Db::PGSQL,
66 );
67 protected $zdb;
68 protected $installer;
69 private $report = array();
70
71 /**
72 * Main constructor
73 */
74 public function __construct()
75 {
76 if ($this->db_version === null) {
77 Analog::log(
78 'Upgrade version can not be empty!',
79 Analog::ERROR
80 );
81 throw new \RuntimeException('Upgrade version can not be empty!');
82 }
83 }
84
85 /**
86 * Does upgrade have a SQL script to run
87 *
88 * @return boolean
89 */
90 private function hasSql()
91 {
92 return !($this->sql_scripts === null);
93 }
94
95 /**
96 * Runs the update.
97 * Update will take the following order:
98 * - preUpdate
99 * - update
100 * - sql (if any)
101 * - postUpdate
102 *
103 * If one function fails, an Exception will be thrown
104 * and next function will not be called.
105 *
106 * @param Db $zdb Database instance
107 * @param Install $installer Installer instance
108 *
109 * @return Boolean|Exception
110 */
111 final public function run($zdb, $installer)
112 {
113 $this->zdb = $zdb;
114 $this->installer = $installer;
115
116 $res = $this->preUpdate();
117 if ($res !== true) {
118 throw new \RuntimeException(
119 'Fail executing pre-update instructions'
120 );
121 }
122
123 $res = $this->update();
124 if ($res !== true) {
125 throw new \RuntimeException(
126 'Fail executing update instructions'
127 );
128 }
129
130 if ($this->hasSql()) {
131 $res = $this->sql($zdb, $installer);
132 if ($res !== true) {
133 throw new \RuntimeException(
134 'Fail executing SQL instructions'
135 );
136 }
137 }
138
139 $res = $this->postUpdate();
140 if ($res !== true) {
141 throw new \RuntimeException(
142 'Fail executing post-update instructions'
143 );
144 }
145
146 $this->updateDbVersion();
147 }
148
149 /**
150 * Update instructions
151 *
152 * @return boolean
153 */
154 abstract protected function update();
155
156 /**
157 * Pre stuff, if any.
158 * Will be extecuted first.
159 *
160 * @return boolean
161 */
162 protected function preUpdate()
163 {
164 return true;
165 }
166
167 /**
168 * Executes SQL instructions, if any.
169 *
170 * @param Db $zdb Database instance
171 * @param Install $installer Installer instance
172 *
173 * @return boolean
174 */
175 private function sql($zdb, $installer)
176 {
177 $script = $this->sql_scripts[TYPE_DB];
178
179 $sql_query = @fread(
180 @fopen($script, 'r'),
181 @filesize($script)
182 ) . "\n";
183
184 if ($sql_query !== '') {
185 return $installer->executeSql($zdb, $sql_query);
186 }
187 }
188
189 /**
190 * Post stuff, if any.
191 * Will be executed at the end.
192 *
193 * @return boolean
194 */
195 protected function postUpdate()
196 {
197 return true;
198 }
199
200 /**
201 * Set SQL files instructions for all supported databases
202 *
203 * @param string $version Version for scripts
204 *
205 * @return boolean
206 */
207 protected function setSqlScripts($version)
208 {
209 $scripts = $this->getSqlScripts($version);
210 if (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 }