]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - application/Updater.php
Replace $GLOBALS configuration with the configuration manager in the whole code base
[github/shaarli/Shaarli.git] / application / Updater.php
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 */
8 class Updater
9 {
10 /**
11 * @var array Updates which are already done.
12 */
13 protected $doneUpdates;
14
15 /**
16 * @var LinkDB instance.
17 */
18 protected $linkDB;
19
20 /**
21 * @var bool True if the user is logged in, false otherwise.
22 */
23 protected $isLoggedIn;
24
25 /**
26 * @var ReflectionMethod[] List of current class methods.
27 */
28 protected $methods;
29
30 /**
31 * Object constructor.
32 *
33 * @param array $doneUpdates Updates which are already done.
34 * @param LinkDB $linkDB LinkDB instance.
35 * @param boolean $isLoggedIn True if the user is logged in.
36 */
37 public function __construct($doneUpdates, $linkDB, $isLoggedIn)
38 {
39 $this->doneUpdates = $doneUpdates;
40 $this->linkDB = $linkDB;
41 $this->isLoggedIn = $isLoggedIn;
42
43 // Retrieve all update methods.
44 $class = new ReflectionClass($this);
45 $this->methods = $class->getMethods();
46 }
47
48 /**
49 * Run all new updates.
50 * Update methods have to start with 'updateMethod' and return true (on success).
51 *
52 * @return array An array containing ran updates.
53 *
54 * @throws UpdaterException If something went wrong.
55 */
56 public function update()
57 {
58 $updatesRan = array();
59
60 // If the user isn't logged in, exit without updating.
61 if ($this->isLoggedIn !== true) {
62 return $updatesRan;
63 }
64
65 if ($this->methods == null) {
66 throw new UpdaterException('Couldn\'t retrieve Updater class methods.');
67 }
68
69 foreach ($this->methods as $method) {
70 // Not an update method or already done, pass.
71 if (! startsWith($method->getName(), 'updateMethod')
72 || in_array($method->getName(), $this->doneUpdates)
73 ) {
74 continue;
75 }
76
77 try {
78 $method->setAccessible(true);
79 $res = $method->invoke($this);
80 // Update method must return true to be considered processed.
81 if ($res === true) {
82 $updatesRan[] = $method->getName();
83 }
84 } catch (Exception $e) {
85 throw new UpdaterException($method, $e);
86 }
87 }
88
89 $this->doneUpdates = array_merge($this->doneUpdates, $updatesRan);
90
91 return $updatesRan;
92 }
93
94 /**
95 * @return array Updates methods already processed.
96 */
97 public function getDoneUpdates()
98 {
99 return $this->doneUpdates;
100 }
101
102 /**
103 * Move deprecated options.php to config.php.
104 *
105 * Milestone 0.9 (old versioning) - shaarli/Shaarli#41:
106 * options.php is not supported anymore.
107 */
108 public function updateMethodMergeDeprecatedConfigFile()
109 {
110 $conf = ConfigManager::getInstance();
111
112 if (is_file($conf->get('config.DATADIR') . '/options.php')) {
113 include $conf->get('config.DATADIR') . '/options.php';
114
115 // Load GLOBALS into config
116 $allowedKeys = array_merge(ConfigPhp::$ROOT_KEYS);
117 $allowedKeys[] = 'config';
118 foreach ($GLOBALS as $key => $value) {
119 if (in_array($key, $allowedKeys)) {
120 $conf->set($key, $value);
121 }
122 }
123 $conf->write($this->isLoggedIn);
124 unlink($conf->get('config.DATADIR').'/options.php');
125 }
126
127 return true;
128 }
129
130 /**
131 * Rename tags starting with a '-' to work with tag exclusion search.
132 */
133 public function updateMethodRenameDashTags()
134 {
135 $conf = ConfigManager::getInstance();
136 $linklist = $this->linkDB->filterSearch();
137 foreach ($linklist as $link) {
138 $link['tags'] = preg_replace('/(^| )\-/', '$1', $link['tags']);
139 $link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true)));
140 $this->linkDB[$link['linkdate']] = $link;
141 }
142 $this->linkDB->savedb($conf->get('config.PAGECACHE'));
143 return true;
144 }
145 }
146
147 /**
148 * Class UpdaterException.
149 */
150 class UpdaterException extends Exception
151 {
152 /**
153 * @var string Method where the error occurred.
154 */
155 protected $method;
156
157 /**
158 * @var Exception The parent exception.
159 */
160 protected $previous;
161
162 /**
163 * Constructor.
164 *
165 * @param string $message Force the error message if set.
166 * @param string $method Method where the error occurred.
167 * @param Exception|bool $previous Parent exception.
168 */
169 public function __construct($message = '', $method = '', $previous = false)
170 {
171 $this->method = $method;
172 $this->previous = $previous;
173 $this->message = $this->buildMessage($message);
174 }
175
176 /**
177 * Build the exception error message.
178 *
179 * @param string $message Optional given error message.
180 *
181 * @return string The built error message.
182 */
183 private function buildMessage($message)
184 {
185 $out = '';
186 if (! empty($message)) {
187 $out .= $message . PHP_EOL;
188 }
189
190 if (! empty($this->method)) {
191 $out .= 'An error occurred while running the update '. $this->method . PHP_EOL;
192 }
193
194 if (! empty($this->previous)) {
195 $out .= ' '. $this->previous->getMessage();
196 }
197
198 return $out;
199 }
200 }
201
202
203 /**
204 * Read the updates file, and return already done updates.
205 *
206 * @param string $updatesFilepath Updates file path.
207 *
208 * @return array Already done update methods.
209 */
210 function read_updates_file($updatesFilepath)
211 {
212 if (! empty($updatesFilepath) && is_file($updatesFilepath)) {
213 $content = file_get_contents($updatesFilepath);
214 if (! empty($content)) {
215 return explode(';', $content);
216 }
217 }
218 return array();
219 }
220
221 /**
222 * Write updates file.
223 *
224 * @param string $updatesFilepath Updates file path.
225 * @param array $updates Updates array to write.
226 *
227 * @throws Exception Couldn't write version number.
228 */
229 function write_updates_file($updatesFilepath, $updates)
230 {
231 if (empty($updatesFilepath)) {
232 throw new Exception('Updates file path is not set, can\'t write updates.');
233 }
234
235 $res = file_put_contents($updatesFilepath, implode(';', $updates));
236 if ($res === false) {
237 throw new Exception('Unable to write updates in '. $updatesFilepath . '.');
238 }
239 }