aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/Updater.php
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2016-01-12 19:50:48 +0100
committerArthurHoaro <arthur@hoa.ro>2016-02-15 20:30:24 +0100
commit510377d2cb4b12d1a421e8a88bd7edb86f223451 (patch)
tree6cea29c199fc1b29ccfb78f902313019f6f9d95e /application/Updater.php
parent268a2e52659964fb7d033a1bb4d1490bf8cc49bf (diff)
downloadShaarli-510377d2cb4b12d1a421e8a88bd7edb86f223451.tar.gz
Shaarli-510377d2cb4b12d1a421e8a88bd7edb86f223451.tar.zst
Shaarli-510377d2cb4b12d1a421e8a88bd7edb86f223451.zip
Introduce the Updater class which
* contains methods designed to be run once. * is able to upgrade the datastore or the configuration. * is based on methods names, stored in a text file with ';' separator (updates.txt). * begins with existing function 'mergeDeprecatedConfigFile()' (options.php).
Diffstat (limited to 'application/Updater.php')
-rw-r--r--application/Updater.php228
1 files changed, 228 insertions, 0 deletions
diff --git a/application/Updater.php b/application/Updater.php
new file mode 100644
index 00000000..20ae0c4d
--- /dev/null
+++ b/application/Updater.php
@@ -0,0 +1,228 @@
1<?php
2
3/**
4 * Class Updater.
5 * Used to update stuff when a new Shaarli's version is reached.
6 * Update methods are ran only once, and the stored in a JSON file.
7 */
8class Updater
9{
10 /**
11 * @var array Updates which are already done.
12 */
13 protected $doneUpdates;
14
15 /**
16 * @var array Shaarli's configuration array.
17 */
18 protected $config;
19
20 /**
21 * @var LinkDB instance.
22 */
23 protected $linkDB;
24
25 /**
26 * @var bool True if the user is logged in, false otherwise.
27 */
28 protected $isLoggedIn;
29
30 /**
31 * @var ReflectionMethod[] List of current class methods.
32 */
33 protected $methods;
34
35 /**
36 * Object constructor.
37 *
38 * @param array $doneUpdates Updates which are already done.
39 * @param array $config Shaarli's configuration array.
40 * @param LinkDB $linkDB LinkDB instance.
41 * @param boolean $isLoggedIn True if the user is logged in.
42 */
43 public function __construct($doneUpdates, $config, $linkDB, $isLoggedIn)
44 {
45 $this->doneUpdates = $doneUpdates;
46 $this->config = $config;
47 $this->linkDB = $linkDB;
48 $this->isLoggedIn = $isLoggedIn;
49
50 // Retrieve all update methods.
51 $class = new ReflectionClass($this);
52 $this->methods = $class->getMethods();
53 }
54
55 /**
56 * Run all new updates.
57 * Update methods have to start with 'updateMethod' and return true (on success).
58 *
59 * @return array An array containing ran updates.
60 *
61 * @throws UpdaterException If something went wrong.
62 */
63 public function update()
64 {
65 $updatesRan = array();
66
67 // If the user isn't logged in, exit without updating.
68 if ($this->isLoggedIn !== true) {
69 return $updatesRan;
70 }
71
72 if ($this->methods == null) {
73 throw new UpdaterException('Couldn\'t retrieve Updater class methods.');
74 }
75
76 foreach ($this->methods as $method) {
77 // Not an update method or already done, pass.
78 if (! startsWith($method->getName(), 'updateMethod')
79 || in_array($method->getName(), $this->doneUpdates)
80 ) {
81 continue;
82 }
83
84 try {
85 $method->setAccessible(true);
86 $res = $method->invoke($this);
87 // Update method must return true to be considered processed.
88 if ($res === true) {
89 $updatesRan[] = $method->getName();
90 }
91 } catch (Exception $e) {
92 throw new UpdaterException($method, $e);
93 }
94 }
95
96 $this->doneUpdates = array_merge($this->doneUpdates, $updatesRan);
97
98 return $updatesRan;
99 }
100
101 /**
102 * @return array Updates methods already processed.
103 */
104 public function getDoneUpdates()
105 {
106 return $this->doneUpdates;
107 }
108
109 /**
110 * Move deprecated options.php to config.php.
111 *
112 * Milestone 0.9 (old versioning) - shaarli/Shaarli#41:
113 * options.php is not supported anymore.
114 */
115 public function updateMethodMergeDeprecatedConfigFile()
116 {
117 $config_file = $this->config['config']['CONFIG_FILE'];
118
119 if (is_file($this->config['config']['DATADIR'].'/options.php')) {
120 include $this->config['config']['DATADIR'].'/options.php';
121
122 // Load GLOBALS into config
123 foreach ($GLOBALS as $key => $value) {
124 $this->config[$key] = $value;
125 }
126 $this->config['config']['CONFIG_FILE'] = $config_file;
127 writeConfig($this->config, $this->isLoggedIn);
128
129 unlink($this->config['config']['DATADIR'].'/options.php');
130 }
131
132 return true;
133 }
134}
135
136/**
137 * Class UpdaterException.
138 */
139class UpdaterException extends Exception
140{
141 /**
142 * @var string Method where the error occurred.
143 */
144 protected $method;
145
146 /**
147 * @var Exception The parent exception.
148 */
149 protected $previous;
150
151 /**
152 * Constructor.
153 *
154 * @param string $message Force the error message if set.
155 * @param string $method Method where the error occurred.
156 * @param Exception|bool $previous Parent exception.
157 */
158 public function __construct($message = '', $method = '', $previous = false)
159 {
160 $this->method = $method;
161 $this->previous = $previous;
162 $this->message = $this->buildMessage($message);
163 }
164
165 /**
166 * Build the exception error message.
167 *
168 * @param string $message Optional given error message.
169 *
170 * @return string The built error message.
171 */
172 private function buildMessage($message)
173 {
174 $out = '';
175 if (! empty($message)) {
176 $out .= $message . PHP_EOL;
177 }
178
179 if (! empty($this->method)) {
180 $out .= 'An error occurred while running the update '. $this->method . PHP_EOL;
181 }
182
183 if (! empty($this->previous)) {
184 $out .= ' '. $this->previous->getMessage();
185 }
186
187 return $out;
188 }
189}
190
191
192/**
193 * Read the updates file, and return already done updates.
194 *
195 * @param string $updatesFilepath Updates file path.
196 *
197 * @return array Already done update methods.
198 */
199function read_updates_file($updatesFilepath)
200{
201 if (! empty($updatesFilepath) && is_file($updatesFilepath)) {
202 $content = file_get_contents($updatesFilepath);
203 if (! empty($content)) {
204 return explode(';', $content);
205 }
206 }
207 return array();
208}
209
210/**
211 * Write updates file.
212 *
213 * @param string $updatesFilepath Updates file path.
214 * @param array $updates Updates array to write.
215 *
216 * @throws Exception Couldn't write version number.
217 */
218function write_updates_file($updatesFilepath, $updates)
219{
220 if (empty($updatesFilepath)) {
221 throw new Exception('Updates file path is not set, can\'t write updates.');
222 }
223
224 $res = file_put_contents($updatesFilepath, implode(';', $updates));
225 if ($res === false) {
226 throw new Exception('Unable to write updates in '. $updatesFilepath . '.');
227 }
228}