1 | <?php |
||||
2 | |||||
3 | /** |
||||
4 | * @package toolkit |
||||
5 | */ |
||||
6 | /** |
||||
7 | * The ExtensionManager class is responsible for managing all extensions |
||||
8 | * in Symphony. Extensions are stored on the file system in the `EXTENSIONS` |
||||
9 | * folder. They are auto-discovered where the Extension class name is the same |
||||
10 | * as it's folder name (excluding the extension prefix). |
||||
11 | */ |
||||
12 | |||||
13 | class ExtensionManager implements FileResource |
||||
14 | { |
||||
15 | /** |
||||
16 | * An array of all the objects that the Manager is responsible for. |
||||
17 | * Defaults to an empty array. |
||||
18 | * @var array |
||||
19 | */ |
||||
20 | protected static $_pool = array(); |
||||
21 | |||||
22 | /** |
||||
23 | * An array of all extensions whose status is enabled |
||||
24 | * @var array |
||||
25 | */ |
||||
26 | private static $_enabled_extensions = array(); |
||||
27 | |||||
28 | /** |
||||
29 | * An array of all the subscriptions to Symphony delegates made by extensions. |
||||
30 | * @var array |
||||
31 | */ |
||||
32 | private static $_subscriptions = array(); |
||||
33 | |||||
34 | /** |
||||
35 | * An associative array of all the extensions in `tbl_extensions` where |
||||
36 | * the key is the extension name and the value is an array |
||||
37 | * representation of it's accompanying database row. |
||||
38 | * @var array |
||||
39 | */ |
||||
40 | private static $_extensions = array(); |
||||
41 | |||||
42 | /** |
||||
43 | * An associative array of all the providers from the enabled extensions. |
||||
44 | * The key is the type of object, with the value being an associative array |
||||
45 | * with the name, classname and path to the object |
||||
46 | * |
||||
47 | * @since Symphony 2.3 |
||||
48 | * @var array |
||||
49 | */ |
||||
50 | private static $_providers = array(); |
||||
51 | |||||
52 | /** |
||||
53 | * The constructor will populate the `$_subscriptions` variable from |
||||
54 | * the `tbl_extension` and `tbl_extensions_delegates` tables. |
||||
55 | */ |
||||
56 | public function __construct() |
||||
57 | { |
||||
58 | if (empty(self::$_subscriptions) && Symphony::Database()->isConnected()) { |
||||
59 | $subscriptions = Symphony::Database()->fetch( |
||||
60 | "SELECT t1.name, t2.page, t2.delegate, t2.callback |
||||
61 | FROM `tbl_extensions` as t1 INNER JOIN `tbl_extensions_delegates` as t2 ON t1.id = t2.extension_id |
||||
62 | WHERE t1.status = 'enabled' |
||||
63 | ORDER BY t2.delegate, t1.name" |
||||
64 | ); |
||||
65 | |||||
66 | foreach ($subscriptions as $subscription) { |
||||
67 | self::$_subscriptions[$subscription['delegate']][] = $subscription; |
||||
68 | } |
||||
69 | } |
||||
70 | } |
||||
71 | |||||
72 | public static function __getHandleFromFilename($filename) |
||||
73 | { |
||||
74 | return false; |
||||
75 | } |
||||
76 | |||||
77 | /** |
||||
78 | * Given a name, returns the full class name of an Extension. |
||||
79 | * Extension use an 'extension' prefix. |
||||
80 | * |
||||
81 | * @param string $name |
||||
82 | * The extension handle |
||||
83 | * @return string |
||||
84 | */ |
||||
85 | public static function __getClassName($name) |
||||
86 | { |
||||
87 | return 'extension_' . $name; |
||||
88 | } |
||||
89 | |||||
90 | /** |
||||
91 | * Finds an Extension by name by searching the `EXTENSIONS` folder and |
||||
92 | * returns the path to the folder. |
||||
93 | * |
||||
94 | * @param string $name |
||||
95 | * The extension folder |
||||
96 | * @return string |
||||
97 | */ |
||||
98 | public static function __getClassPath($name) |
||||
99 | { |
||||
100 | return EXTENSIONS . strtolower("/$name"); |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() As per coding-style, please use concatenation or
sprintf for the variable $name instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
101 | } |
||||
102 | |||||
103 | /** |
||||
104 | * Given a name, return the path to the driver of the Extension. |
||||
105 | * |
||||
106 | * @see toolkit.ExtensionManager#__getClassPath() |
||||
107 | * @param string $name |
||||
108 | * The extension folder |
||||
109 | * @return string |
||||
110 | */ |
||||
111 | public static function __getDriverPath($name) |
||||
112 | { |
||||
113 | return self::__getClassPath($name) . '/extension.driver.php'; |
||||
114 | } |
||||
115 | |||||
116 | /** |
||||
117 | * This function returns an instance of an extension from it's name |
||||
118 | * |
||||
119 | * @param string $name |
||||
120 | * The name of the Extension Class minus the extension prefix. |
||||
121 | * @throws SymphonyErrorPage |
||||
122 | * @throws Exception |
||||
123 | * @return Extension |
||||
124 | */ |
||||
125 | public static function getInstance($name) |
||||
126 | { |
||||
127 | return (isset(self::$_pool[$name]) ? self::$_pool[$name] : self::create($name)); |
||||
128 | } |
||||
129 | |||||
130 | /** |
||||
131 | * Populates the `ExtensionManager::$_extensions` array with all the |
||||
132 | * extensions stored in `tbl_extensions`. If `ExtensionManager::$_extensions` |
||||
133 | * isn't empty, passing true as a parameter will force the array to update |
||||
134 | * |
||||
135 | * @param boolean $update |
||||
136 | * Updates the `ExtensionManager::$_extensions` array even if it was |
||||
137 | * populated, defaults to false. |
||||
138 | * @throws DatabaseException |
||||
139 | */ |
||||
140 | private static function __buildExtensionList($update = false) |
||||
0 ignored issues
–
show
|
|||||
141 | { |
||||
142 | if (empty(self::$_extensions) || $update) { |
||||
143 | self::$_extensions = Symphony::Database()->fetch("SELECT * FROM `tbl_extensions`", 'name'); |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
SELECT * FROM `tbl_extensions` does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
144 | } |
||||
145 | } |
||||
146 | |||||
147 | /** |
||||
148 | * Returns the status of an Extension given an associative array containing |
||||
149 | * the Extension `handle` and `version` where the `version` is the file |
||||
150 | * version, not the installed version. This function returns an array |
||||
151 | * which may include a maximum of two statuses. |
||||
152 | * |
||||
153 | * @param array $about |
||||
154 | * An associative array of the extension meta data, typically returned |
||||
155 | * by `ExtensionManager::about()`. At the very least this array needs |
||||
156 | * `handle` and `version` keys. |
||||
157 | * @return array |
||||
158 | * An array of extension statuses, with the possible values being |
||||
159 | * `EXTENSION_ENABLED`, `EXTENSION_DISABLED`, `EXTENSION_REQUIRES_UPDATE` |
||||
160 | * or `EXTENSION_NOT_INSTALLED`. If an extension doesn't exist, |
||||
161 | * `EXTENSION_NOT_INSTALLED` will be returned. |
||||
162 | */ |
||||
163 | public static function fetchStatus($about) |
||||
164 | { |
||||
165 | $return = array(); |
||||
166 | self::__buildExtensionList(); |
||||
167 | |||||
168 | if (isset($about['handle']) && array_key_exists($about['handle'], self::$_extensions)) { |
||||
169 | if (self::$_extensions[$about['handle']]['status'] == 'enabled') { |
||||
170 | $return[] = Extension::EXTENSION_ENABLED; |
||||
171 | } else { |
||||
172 | $return[] = Extension::EXTENSION_DISABLED; |
||||
173 | } |
||||
174 | } else { |
||||
175 | $return[] = Extension::EXTENSION_NOT_INSTALLED; |
||||
176 | } |
||||
177 | |||||
178 | if (isset($about['handle'], $about['version']) && self::__requiresUpdate($about['handle'], $about['version'])) { |
||||
179 | $return[] = Extension::EXTENSION_REQUIRES_UPDATE; |
||||
180 | } |
||||
181 | |||||
182 | return $return; |
||||
183 | } |
||||
184 | |||||
185 | /** |
||||
186 | * A convenience method that returns an extension version from it's name. |
||||
187 | * |
||||
188 | * @param string $name |
||||
189 | * The name of the Extension Class minus the extension prefix. |
||||
190 | * @return string |
||||
191 | */ |
||||
192 | public static function fetchInstalledVersion($name) |
||||
193 | { |
||||
194 | self::__buildExtensionList(); |
||||
195 | |||||
196 | return (isset(self::$_extensions[$name]) ? self::$_extensions[$name]['version'] : null); |
||||
197 | } |
||||
198 | |||||
199 | /** |
||||
200 | * A convenience method that returns an extension ID from it's name. |
||||
201 | * |
||||
202 | * @param string $name |
||||
203 | * The name of the Extension Class minus the extension prefix. |
||||
204 | * @return integer |
||||
205 | */ |
||||
206 | public static function fetchExtensionID($name) |
||||
207 | { |
||||
208 | self::__buildExtensionList(); |
||||
209 | |||||
210 | return self::$_extensions[$name]['id']; |
||||
211 | } |
||||
212 | |||||
213 | /** |
||||
214 | * Return an array all the Provider objects supplied by extensions, |
||||
215 | * optionally filtered by a given `$type`. |
||||
216 | * |
||||
217 | * @since Symphony 2.3 |
||||
218 | * @todo Add information about the possible types |
||||
219 | * @param string $type |
||||
220 | * This will only return Providers of this type. If null, which is |
||||
221 | * default, all providers will be returned. |
||||
222 | * @throws Exception |
||||
223 | * @throws SymphonyErrorPage |
||||
224 | * @return array |
||||
225 | * An array of objects |
||||
226 | */ |
||||
227 | public static function getProvidersOf($type = null) |
||||
0 ignored issues
–
show
|
|||||
228 | { |
||||
229 | // Loop over all extensions and build an array of providable objects |
||||
230 | if (empty(self::$_providers)) { |
||||
231 | self::$_providers = array(); |
||||
232 | |||||
233 | foreach (self::listInstalledHandles() as $handle) { |
||||
234 | $obj = self::getInstance($handle); |
||||
235 | |||||
236 | if (!method_exists($obj, 'providerOf')) { |
||||
237 | continue; |
||||
238 | } |
||||
239 | |||||
240 | $providers = $obj->providerOf(); |
||||
241 | |||||
242 | if (empty($providers)) { |
||||
243 | continue; |
||||
244 | } |
||||
245 | |||||
246 | // For each of the matching objects (by $type), resolve the object path |
||||
247 | self::$_providers = array_merge_recursive(self::$_providers, $obj->providerOf()); |
||||
248 | } |
||||
249 | } |
||||
250 | |||||
251 | // Return an array of objects |
||||
252 | if (is_null($type)) { |
||||
253 | return self::$_providers; |
||||
254 | } |
||||
255 | |||||
256 | if (!isset(self::$_providers[$type])) { |
||||
257 | return array(); |
||||
258 | } |
||||
259 | |||||
260 | return self::$_providers[$type]; |
||||
261 | } |
||||
262 | |||||
263 | /** |
||||
264 | * This function will return the `Cacheable` object with the appropriate |
||||
265 | * caching layer for the given `$key`. This `$key` should be stored in |
||||
266 | * the Symphony configuration in the caching group with a reference |
||||
267 | * to the class of the caching object. If the key is not found, this |
||||
268 | * will return a default `Cacheable` object created with the MySQL driver. |
||||
269 | * |
||||
270 | * @since Symphony 2.4 |
||||
271 | * @param string $key |
||||
272 | * Should be a reference in the Configuration file to the Caching class |
||||
273 | * @param boolean $reuse |
||||
274 | * By default true, which will reuse an existing Cacheable object of `$key` |
||||
275 | * if it exists. If false, a new instance will be generated. |
||||
276 | * @return Cacheable |
||||
277 | */ |
||||
278 | public static function getCacheProvider($key = null, $reuse = true) |
||||
0 ignored issues
–
show
|
|||||
279 | { |
||||
280 | $cacheDriver = Symphony::Configuration()->get($key, 'caching'); |
||||
281 | |||||
282 | if (in_array($cacheDriver, array_keys(Symphony::ExtensionManager()->getProvidersOf('cache')))) { |
||||
283 | $cacheable = new $cacheDriver; |
||||
284 | } else { |
||||
285 | $cacheable = Symphony::Database(); |
||||
286 | $cacheDriver = 'CacheDatabase'; |
||||
287 | } |
||||
288 | |||||
289 | if ($reuse === false) { |
||||
290 | return new Cacheable($cacheable); |
||||
0 ignored issues
–
show
It seems like
$cacheable can also be of type MySQL ; however, parameter $cacheProvider of Cacheable::__construct() does only seem to accept iCache , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
291 | } elseif (!isset(self::$_pool[$cacheDriver])) { |
||||
292 | self::$_pool[$cacheDriver] = new Cacheable($cacheable); |
||||
293 | } |
||||
294 | |||||
295 | return self::$_pool[$cacheDriver]; |
||||
296 | } |
||||
297 | |||||
298 | /** |
||||
299 | * Determines whether the current extension is installed or not by checking |
||||
300 | * for an id in `tbl_extensions` |
||||
301 | * |
||||
302 | * @param string $name |
||||
303 | * The name of the Extension Class minus the extension prefix. |
||||
304 | * @return boolean |
||||
305 | */ |
||||
306 | private static function __requiresInstallation($name) |
||||
307 | { |
||||
308 | self::__buildExtensionList(); |
||||
309 | $id = self::$_extensions[$name]['id']; |
||||
310 | |||||
311 | return (is_numeric($id) ? false : true); |
||||
312 | } |
||||
313 | |||||
314 | /** |
||||
315 | * Determines whether an extension needs to be updated or not using |
||||
316 | * PHP's `version_compare` function. This function will return the |
||||
317 | * installed version if the extension requires an update, or |
||||
318 | * false otherwise. |
||||
319 | * |
||||
320 | * @param string $name |
||||
321 | * The name of the Extension Class minus the extension prefix. |
||||
322 | * @param string $file_version |
||||
323 | * The version of the extension from the **file**, not the Database. |
||||
324 | * @return string|boolean |
||||
325 | * If the given extension (by $name) requires updating, the installed |
||||
326 | * version is returned, otherwise, if the extension doesn't require |
||||
327 | * updating, false. |
||||
328 | */ |
||||
329 | private static function __requiresUpdate($name, $file_version) |
||||
330 | { |
||||
331 | $installed_version = self::fetchInstalledVersion($name); |
||||
332 | |||||
333 | if (is_null($installed_version)) { |
||||
0 ignored issues
–
show
|
|||||
334 | return false; |
||||
335 | } |
||||
336 | |||||
337 | return (version_compare($installed_version, $file_version, '<') ? $installed_version : false); |
||||
338 | } |
||||
339 | |||||
340 | /** |
||||
341 | * Enabling an extension will re-register all it's delegates with Symphony. |
||||
342 | * It will also install or update the extension if needs be by calling the |
||||
343 | * extensions respective install and update methods. The enable method is |
||||
344 | * of the extension object is finally called. |
||||
345 | * |
||||
346 | * @see toolkit.ExtensionManager#registerDelegates() |
||||
347 | * @see toolkit.ExtensionManager#__canUninstallOrDisable() |
||||
348 | * @param string $name |
||||
349 | * The name of the Extension Class minus the extension prefix. |
||||
350 | * @throws SymphonyErrorPage |
||||
351 | * @throws Exception |
||||
352 | * @return boolean |
||||
353 | */ |
||||
354 | public static function enable($name) |
||||
355 | { |
||||
356 | $obj = self::getInstance($name); |
||||
357 | |||||
358 | // If not installed, install it |
||||
359 | if (self::__requiresInstallation($name) && $obj->install() === false) { |
||||
0 ignored issues
–
show
|
|||||
360 | // If the installation failed, run the uninstall method which |
||||
361 | // should rollback the install method. #1326 |
||||
362 | $obj->uninstall(); |
||||
363 | return false; |
||||
364 | |||||
365 | // If the extension requires updating before enabling, then update it |
||||
366 | } elseif (($about = self::about($name)) && ($previousVersion = self::__requiresUpdate($name, $about['version'])) !== false) { |
||||
367 | $obj->update($previousVersion); |
||||
368 | } |
||||
369 | |||||
370 | if (!isset($about)) { |
||||
371 | $about = self::about($name); |
||||
372 | } |
||||
373 | |||||
374 | $id = self::fetchExtensionID($name); |
||||
375 | |||||
376 | $fields = array( |
||||
377 | 'name' => $name, |
||||
378 | 'status' => 'enabled', |
||||
379 | 'version' => $about['version'] |
||||
380 | ); |
||||
381 | |||||
382 | // If there's no $id, the extension needs to be installed |
||||
383 | if (is_null($id)) { |
||||
0 ignored issues
–
show
|
|||||
384 | Symphony::Database()->insert($fields, 'tbl_extensions'); |
||||
385 | self::__buildExtensionList(true); |
||||
386 | |||||
387 | // Extension is installed, so update! |
||||
388 | } else { |
||||
389 | Symphony::Database()->update($fields, 'tbl_extensions', sprintf(" `id` = %d ", $id)); |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
`id` = %d does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
390 | } |
||||
391 | |||||
392 | self::registerDelegates($name); |
||||
393 | |||||
394 | // Now enable the extension |
||||
395 | $obj->enable(); |
||||
396 | |||||
397 | return true; |
||||
398 | } |
||||
399 | |||||
400 | /** |
||||
401 | * Disabling an extension will prevent it from executing but retain all it's |
||||
402 | * settings in the relevant tables. Symphony checks that an extension can |
||||
403 | * be disabled using the `canUninstallorDisable()` before removing |
||||
404 | * all delegate subscriptions from the database and calling the extension's |
||||
405 | * `disable()` function. |
||||
406 | * |
||||
407 | * @see toolkit.ExtensionManager#removeDelegates() |
||||
408 | * @see toolkit.ExtensionManager#__canUninstallOrDisable() |
||||
409 | * @param string $name |
||||
410 | * The name of the Extension Class minus the extension prefix. |
||||
411 | * @throws DatabaseException |
||||
412 | * @throws SymphonyErrorPage |
||||
413 | * @throws Exception |
||||
414 | * @return boolean |
||||
415 | */ |
||||
416 | public static function disable($name) |
||||
417 | { |
||||
418 | $obj = self::getInstance($name); |
||||
419 | |||||
420 | self::__canUninstallOrDisable($obj); |
||||
421 | |||||
422 | $info = self::about($name); |
||||
423 | $id = self::fetchExtensionID($name); |
||||
424 | |||||
425 | Symphony::Database()->update( |
||||
426 | array( |
||||
427 | 'name' => $name, |
||||
428 | 'status' => 'disabled', |
||||
429 | 'version' => $info['version'] |
||||
430 | ), |
||||
431 | 'tbl_extensions', |
||||
432 | sprintf(" `id` = %d ", $id) |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
`id` = %d does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
433 | ); |
||||
434 | |||||
435 | $obj->disable(); |
||||
436 | |||||
437 | self::removeDelegates($name); |
||||
438 | |||||
439 | return true; |
||||
440 | } |
||||
441 | |||||
442 | /** |
||||
443 | * Uninstalling an extension will unregister all delegate subscriptions and |
||||
444 | * remove all extension settings. Symphony checks that an extension can |
||||
445 | * be uninstalled using the `canUninstallorDisable()` before calling |
||||
446 | * the extension's `uninstall()` function. Alternatively, if this function |
||||
447 | * is called because the extension described by `$name` cannot be found |
||||
448 | * it's delegates and extension meta information will just be removed from the |
||||
449 | * database. |
||||
450 | * |
||||
451 | * @see toolkit.ExtensionManager#removeDelegates() |
||||
452 | * @see toolkit.ExtensionManager#__canUninstallOrDisable() |
||||
453 | * @param string $name |
||||
454 | * The name of the Extension Class minus the extension prefix. |
||||
455 | * @throws Exception |
||||
456 | * @throws SymphonyErrorPage |
||||
457 | * @throws DatabaseException |
||||
458 | * @throws Exception |
||||
459 | * @return boolean |
||||
460 | */ |
||||
461 | public static function uninstall($name) |
||||
462 | { |
||||
463 | // If this function is called because the extension doesn't exist, |
||||
464 | // then catch the error and just remove from the database. This |
||||
465 | // means that the uninstall() function will not run on the extension, |
||||
466 | // which may be a blessing in disguise as no entry data will be removed |
||||
467 | try { |
||||
468 | $obj = self::getInstance($name); |
||||
469 | self::__canUninstallOrDisable($obj); |
||||
470 | $obj->uninstall(); |
||||
471 | } catch (SymphonyErrorPage $ex) { |
||||
472 | // Create a consistant key |
||||
473 | $key = str_replace('-', '_', $ex->getTemplateName()); |
||||
474 | |||||
475 | if ($key !== 'missing_extension') { |
||||
476 | throw $ex; |
||||
477 | } |
||||
478 | } |
||||
479 | |||||
480 | self::removeDelegates($name); |
||||
481 | Symphony::Database()->delete('tbl_extensions', sprintf(" `name` = '%s' ", $name)); |
||||
482 | |||||
483 | return true; |
||||
484 | } |
||||
485 | |||||
486 | /** |
||||
487 | * This functions registers an extensions delegates in `tbl_extensions_delegates`. |
||||
488 | * |
||||
489 | * @param string $name |
||||
490 | * The name of the Extension Class minus the extension prefix. |
||||
491 | * @throws Exception |
||||
492 | * @throws SymphonyErrorPage |
||||
493 | * @return integer |
||||
494 | * The Extension ID |
||||
495 | */ |
||||
496 | public static function registerDelegates($name) |
||||
497 | { |
||||
498 | $obj = self::getInstance($name); |
||||
499 | $id = self::fetchExtensionID($name); |
||||
500 | |||||
501 | if (!$id) { |
||||
502 | return false; |
||||
0 ignored issues
–
show
|
|||||
503 | } |
||||
504 | |||||
505 | Symphony::Database()->delete('tbl_extensions_delegates', sprintf(" |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
\n `extension_id` = %d does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
506 | `extension_id` = %d ", $id |
||||
507 | )); |
||||
508 | |||||
509 | $delegates = $obj->getSubscribedDelegates(); |
||||
510 | |||||
511 | if (is_array($delegates) && !empty($delegates)) { |
||||
512 | foreach ($delegates as $delegate) { |
||||
513 | Symphony::Database()->insert( |
||||
514 | array( |
||||
515 | 'extension_id' => $id, |
||||
516 | 'page' => $delegate['page'], |
||||
517 | 'delegate' => $delegate['delegate'], |
||||
518 | 'callback' => $delegate['callback'] |
||||
519 | ), |
||||
520 | 'tbl_extensions_delegates' |
||||
521 | ); |
||||
522 | } |
||||
523 | } |
||||
524 | |||||
525 | // Remove the unused DB records |
||||
526 | self::cleanupDatabase(); |
||||
527 | |||||
528 | return $id; |
||||
529 | } |
||||
530 | |||||
531 | /** |
||||
532 | * This function will remove all delegate subscriptions for an extension |
||||
533 | * given an extension's name. This triggers `cleanupDatabase()` |
||||
534 | * |
||||
535 | * @see toolkit.ExtensionManager#cleanupDatabase() |
||||
536 | * @param string $name |
||||
537 | * The name of the Extension Class minus the extension prefix. |
||||
538 | * @return boolean |
||||
539 | */ |
||||
540 | public static function removeDelegates($name) |
||||
541 | { |
||||
542 | $delegates = Symphony::Database()->fetchCol('id', sprintf(" |
||||
543 | SELECT tbl_extensions_delegates.`id` |
||||
544 | FROM `tbl_extensions_delegates` |
||||
545 | LEFT JOIN `tbl_extensions` |
||||
546 | ON (`tbl_extensions`.id = `tbl_extensions_delegates`.extension_id) |
||||
547 | WHERE `tbl_extensions`.name = '%s'", |
||||
548 | $name |
||||
549 | )); |
||||
550 | |||||
551 | if (!empty($delegates)) { |
||||
552 | Symphony::Database()->delete('tbl_extensions_delegates', " `id` IN ('". implode("', '", $delegates). "') "); |
||||
553 | } |
||||
554 | |||||
555 | // Remove the unused DB records |
||||
556 | self::cleanupDatabase(); |
||||
557 | |||||
558 | return true; |
||||
559 | } |
||||
560 | |||||
561 | /** |
||||
562 | * This function checks that if the given extension has provided Fields, |
||||
563 | * Data Sources or Events, that they aren't in use before the extension |
||||
564 | * is uninstalled or disabled. This prevents exceptions from occurring when |
||||
565 | * accessing an object that was using something provided by this Extension |
||||
566 | * can't anymore because it has been removed. |
||||
567 | * |
||||
568 | * @param Extension $obj |
||||
569 | * An extension object |
||||
570 | * @throws SymphonyErrorPage |
||||
571 | * @throws Exception |
||||
572 | */ |
||||
573 | private static function __canUninstallOrDisable(Extension $obj) |
||||
574 | { |
||||
575 | $extension_handle = strtolower(preg_replace('/^extension_/i', null, get_class($obj))); |
||||
576 | $about = self::about($extension_handle); |
||||
577 | |||||
578 | // Fields: |
||||
579 | if (is_dir(EXTENSIONS . "/{$extension_handle}/fields")) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $extension_handle instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
580 | foreach (glob(EXTENSIONS . "/{$extension_handle}/fields/field.*.php") as $file) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $extension_handle instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
581 | $type = preg_replace(array('/^field\./i', '/\.php$/i'), null, basename($file)); |
||||
582 | |||||
583 | if (FieldManager::isFieldUsed($type)) { |
||||
584 | throw new Exception( |
||||
585 | __('The field ‘%s’, provided by the Extension ‘%s’, is currently in use.', array(basename($file), $about['name'])) |
||||
586 | . ' ' . __("Please remove it from your sections prior to uninstalling or disabling.") |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
Please remove it from yo...nstalling or disabling. does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
587 | ); |
||||
588 | } |
||||
589 | } |
||||
590 | } |
||||
591 | |||||
592 | // Data Sources: |
||||
593 | if (is_dir(EXTENSIONS . "/{$extension_handle}/data-sources")) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $extension_handle instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
594 | foreach (glob(EXTENSIONS . "/{$extension_handle}/data-sources/data.*.php") as $file) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $extension_handle instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
595 | $handle = preg_replace(array('/^data\./i', '/\.php$/i'), null, basename($file)); |
||||
596 | |||||
597 | if (PageManager::isDataSourceUsed($handle)) { |
||||
598 | throw new Exception( |
||||
599 | __('The Data Source ‘%s’, provided by the Extension ‘%s’, is currently in use.', array(basename($file), $about['name'])) |
||||
600 | . ' ' . __("Please remove it from your pages prior to uninstalling or disabling.") |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
Please remove it from yo...nstalling or disabling. does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
601 | ); |
||||
602 | } |
||||
603 | } |
||||
604 | } |
||||
605 | |||||
606 | // Events |
||||
607 | if (is_dir(EXTENSIONS . "/{$extension_handle}/events")) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $extension_handle instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
608 | foreach (glob(EXTENSIONS . "/{$extension_handle}/events/event.*.php") as $file) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $extension_handle instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
609 | $handle = preg_replace(array('/^event\./i', '/\.php$/i'), null, basename($file)); |
||||
610 | |||||
611 | if (PageManager::isEventUsed($handle)) { |
||||
612 | throw new Exception( |
||||
613 | __('The Event ‘%s’, provided by the Extension ‘%s’, is currently in use.', array(basename($file), $about['name'])) |
||||
614 | . ' ' . __("Please remove it from your pages prior to uninstalling or disabling.") |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
Please remove it from yo...nstalling or disabling. does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
615 | ); |
||||
616 | } |
||||
617 | } |
||||
618 | } |
||||
619 | |||||
620 | // Text Formatters |
||||
621 | if (is_dir(EXTENSIONS . "/{$extension_handle}/text-formatters")) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $extension_handle instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
622 | foreach (glob(EXTENSIONS . "/{$extension_handle}/text-formatters/formatter.*.php") as $file) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $extension_handle instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
623 | $handle = preg_replace(array('/^formatter\./i', '/\.php$/i'), null, basename($file)); |
||||
624 | |||||
625 | if (FieldManager::isTextFormatterUsed($handle)) { |
||||
626 | throw new Exception( |
||||
627 | __('The Text Formatter ‘%s’, provided by the Extension ‘%s’, is currently in use.', array(basename($file), $about['name'])) |
||||
628 | . ' ' . __("Please remove it from your fields prior to uninstalling or disabling.") |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
Please remove it from yo...nstalling or disabling. does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
629 | ); |
||||
630 | } |
||||
631 | } |
||||
632 | } |
||||
633 | } |
||||
634 | |||||
635 | /** |
||||
636 | * Given a delegate name, notify all extensions that have registered to that |
||||
637 | * delegate to executing their callbacks with a `$context` array parameter |
||||
638 | * that contains information about the current Symphony state. |
||||
639 | * |
||||
640 | * @param string $delegate |
||||
641 | * The delegate name |
||||
642 | * @param string $page |
||||
643 | * The current page namespace that this delegate operates in |
||||
644 | * @param array $context |
||||
645 | * The `$context` param is an associative array that at minimum will contain |
||||
646 | * the current Administration class, the current page object and the delegate |
||||
647 | * name. Other context information may be passed to this function when it is |
||||
648 | * called. eg. |
||||
649 | * |
||||
650 | * array( |
||||
651 | * 'parent' =>& $this->Parent, |
||||
652 | * 'page' => $page, |
||||
653 | * 'delegate' => $delegate |
||||
654 | * ); |
||||
655 | * @throws Exception |
||||
656 | * @throws SymphonyErrorPage |
||||
657 | * @return null|void |
||||
658 | */ |
||||
659 | public static function notifyMembers($delegate, $page, array $context = array()) |
||||
0 ignored issues
–
show
|
|||||
660 | { |
||||
661 | // Make sure $page is an array |
||||
662 | if (!is_array($page)) { |
||||
0 ignored issues
–
show
|
|||||
663 | $page = array($page); |
||||
664 | } |
||||
665 | |||||
666 | // Support for global delegate subscription |
||||
667 | if (!in_array('*', $page)) { |
||||
668 | $page[] = '*'; |
||||
669 | } |
||||
670 | |||||
671 | $services = array(); |
||||
672 | |||||
673 | if (isset(self::$_subscriptions[$delegate])) { |
||||
674 | foreach (self::$_subscriptions[$delegate] as $subscription) { |
||||
675 | if (!in_array($subscription['page'], $page)) { |
||||
676 | continue; |
||||
677 | } |
||||
678 | |||||
679 | $services[] = $subscription; |
||||
680 | } |
||||
681 | } |
||||
682 | |||||
683 | if (empty($services)) { |
||||
684 | return null; |
||||
685 | } |
||||
686 | |||||
687 | $context += array('page' => $page, 'delegate' => $delegate); |
||||
688 | $profiling = Symphony::Profiler() instanceof Profiler; |
||||
689 | |||||
690 | foreach ($services as $s) { |
||||
691 | if ($profiling) { |
||||
692 | // Initial seeding and query count |
||||
693 | Symphony::Profiler()->seed(); |
||||
694 | $queries = Symphony::Database()->queryCount(); |
||||
695 | } |
||||
696 | |||||
697 | // Get instance of extension and execute the callback passing |
||||
698 | // the `$context` along |
||||
699 | $obj = self::getInstance($s['name']); |
||||
700 | |||||
701 | if (is_object($obj) && method_exists($obj, $s['callback'])) { |
||||
702 | $obj->{$s['callback']}($context); |
||||
703 | } |
||||
704 | |||||
705 | // Complete the Profiling sample |
||||
706 | if ($profiling) { |
||||
707 | $queries = Symphony::Database()->queryCount() - $queries; |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
708 | Symphony::Profiler()->sample($delegate . '|' . $s['name'], PROFILE_LAP, 'Delegate', $queries); |
||||
0 ignored issues
–
show
|
|||||
709 | } |
||||
710 | } |
||||
711 | } |
||||
712 | |||||
713 | /** |
||||
714 | * Returns an array of all the enabled extensions available |
||||
715 | * |
||||
716 | * @return array |
||||
717 | */ |
||||
718 | public static function listInstalledHandles() |
||||
719 | { |
||||
720 | if (empty(self::$_enabled_extensions) && Symphony::Database()->isConnected()) { |
||||
721 | self::$_enabled_extensions = Symphony::Database()->fetchCol( |
||||
722 | 'name', |
||||
723 | "SELECT `name` FROM `tbl_extensions` WHERE `status` = 'enabled'" |
||||
724 | ); |
||||
725 | } |
||||
0 ignored issues
–
show
|
|||||
726 | return self::$_enabled_extensions; |
||||
727 | } |
||||
728 | |||||
729 | /** |
||||
730 | * Will return an associative array of all extensions and their about information |
||||
731 | * |
||||
732 | * @param string $filter |
||||
733 | * Allows a regular expression to be passed to return only extensions whose |
||||
734 | * folders match the filter. |
||||
735 | * @throws SymphonyErrorPage |
||||
736 | * @throws Exception |
||||
737 | * @return array |
||||
738 | * An associative array with the key being the extension folder and the value |
||||
739 | * being the extension's about information |
||||
740 | */ |
||||
741 | public static function listAll($filter = '/^((?![-^?%:*|"<>]).)*$/') |
||||
0 ignored issues
–
show
|
|||||
742 | { |
||||
743 | $result = array(); |
||||
744 | $extensions = General::listDirStructure(EXTENSIONS, $filter, false, EXTENSIONS); |
||||
0 ignored issues
–
show
Are you sure the assignment to
$extensions is correct as General::listDirStructur...ter, false, EXTENSIONS) targeting General::listDirStructure() seems to always return null.
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||
745 | |||||
746 | if (is_array($extensions) && !empty($extensions)) { |
||||
0 ignored issues
–
show
|
|||||
747 | foreach ($extensions as $extension) { |
||||
748 | $e = trim($extension, '/'); |
||||
749 | |||||
750 | if ($about = self::about($e)) { |
||||
751 | $result[$e] = $about; |
||||
752 | } |
||||
753 | } |
||||
754 | } |
||||
755 | |||||
756 | return $result; |
||||
757 | } |
||||
758 | |||||
759 | /** |
||||
760 | * Custom user sorting function used inside `fetch` to recursively sort authors |
||||
761 | * by their names. |
||||
762 | * |
||||
763 | * @param array $a |
||||
764 | * @param array $b |
||||
765 | * @param integer $i |
||||
766 | * @return integer |
||||
767 | */ |
||||
768 | private static function sortByAuthor($a, $b, $i = 0) |
||||
0 ignored issues
–
show
|
|||||
769 | { |
||||
770 | $first = $a; |
||||
771 | $second = $b; |
||||
772 | |||||
773 | if (isset($a[$i])) { |
||||
774 | $first = $a[$i]; |
||||
775 | } |
||||
776 | |||||
777 | if (isset($b[$i])) { |
||||
778 | $second = $b[$i]; |
||||
779 | } |
||||
780 | |||||
781 | if ($first == $a && $second == $b && $first['name'] == $second['name']) { |
||||
782 | return 1; |
||||
783 | } elseif ($first['name'] == $second['name']) { |
||||
784 | return self::sortByAuthor($a, $b, $i + 1); |
||||
785 | } else { |
||||
786 | return ($first['name'] < $second['name']) ? -1 : 1; |
||||
787 | } |
||||
788 | } |
||||
789 | |||||
790 | /** |
||||
791 | * This function will return an associative array of Extension information. The |
||||
792 | * information returned is defined by the `$select` parameter, which will allow |
||||
793 | * a developer to restrict what information is returned about the Extension. |
||||
794 | * Optionally, `$where` (not implemented) and `$order_by` parameters allow a developer to |
||||
795 | * further refine their query. |
||||
796 | * |
||||
797 | * @param array $select (optional) |
||||
798 | * Accepts an array of keys to return from the listAll() method. If omitted, all keys |
||||
799 | * will be returned. |
||||
800 | * @param array $where (optional) |
||||
801 | * Not implemented. |
||||
802 | * @param string $order_by (optional) |
||||
803 | * Allows a developer to return the extensions in a particular order. The syntax is the |
||||
804 | * same as other `fetch` methods. If omitted this will return resources ordered by `name`. |
||||
805 | * @throws Exception |
||||
806 | * @throws SymphonyErrorPage |
||||
807 | * @return array |
||||
808 | * An associative array of Extension information, formatted in the same way as the |
||||
809 | * listAll() method. |
||||
810 | */ |
||||
811 | public static function fetch(array $select = array(), array $where = array(), $order_by = null) |
||||
0 ignored issues
–
show
|
|||||
812 | { |
||||
813 | $extensions = self::listAll(); |
||||
814 | $data = array(); |
||||
815 | |||||
816 | if (empty($select) && empty($where) && is_null($order_by)) { |
||||
817 | return $extensions; |
||||
818 | } |
||||
819 | |||||
820 | if (empty($extensions)) { |
||||
821 | return array(); |
||||
822 | } |
||||
823 | |||||
824 | if (!is_null($order_by)) { |
||||
825 | $author = $name = $label = array(); |
||||
826 | $order_by = array_map('strtolower', explode(' ', $order_by)); |
||||
827 | $order = ($order_by[1] == 'desc') ? SORT_DESC : SORT_ASC; |
||||
828 | $sort = $order_by[0]; |
||||
829 | |||||
830 | if ($sort == 'author') { |
||||
831 | foreach ($extensions as $key => $about) { |
||||
832 | $author[$key] = $about['author']; |
||||
833 | } |
||||
834 | |||||
835 | uasort($author, array('self', 'sortByAuthor')); |
||||
836 | |||||
837 | if ($order == SORT_DESC) { |
||||
838 | $author = array_reverse($author); |
||||
839 | } |
||||
840 | |||||
841 | foreach ($author as $key => $value) { |
||||
842 | $data[$key] = $extensions[$key]; |
||||
843 | } |
||||
844 | |||||
845 | $extensions = $data; |
||||
846 | } elseif ($sort == 'name') { |
||||
847 | foreach ($extensions as $key => $about) { |
||||
848 | $name[$key] = strtolower($about['name']); |
||||
849 | $label[$key] = $key; |
||||
850 | } |
||||
851 | |||||
852 | array_multisort($name, $order, $label, $order, $extensions); |
||||
853 | } |
||||
854 | } |
||||
855 | |||||
856 | foreach ($extensions as $i => $e) { |
||||
857 | $data[$i] = array(); |
||||
858 | foreach ($e as $key => $value) { |
||||
859 | // If $select is empty, we assume every field is requested |
||||
860 | if (in_array($key, $select) || empty($select)) { |
||||
861 | $data[$i][$key] = $value; |
||||
862 | } |
||||
863 | } |
||||
864 | } |
||||
865 | |||||
866 | return $data; |
||||
867 | } |
||||
868 | |||||
869 | /** |
||||
870 | * This function will load an extension's meta information given the extension |
||||
871 | * `$name`. Since Symphony 2.3, this function will look for an `extension.meta.xml` |
||||
872 | * file inside the extension's folder. If this is not found, it will initialise |
||||
873 | * the extension and invoke the `about()` function. By default this extension will |
||||
874 | * return an associative array display the basic meta data about the given extension. |
||||
875 | * If the `$rawXML` parameter is passed true, and the extension has a `extension.meta.xml` |
||||
876 | * file, this function will return `DOMDocument` of the file. |
||||
877 | * |
||||
878 | * @param string $name |
||||
879 | * The name of the Extension Class minus the extension prefix. |
||||
880 | * @param boolean $rawXML |
||||
881 | * If passed as true, and is available, this function will return the |
||||
882 | * DOMDocument of representation of the given extension's `extension.meta.xml` |
||||
883 | * file. If the file is not available, the extension will return the normal |
||||
884 | * `about()` results. By default this is false. |
||||
885 | * @throws Exception |
||||
886 | * @throws SymphonyErrorPage |
||||
887 | * @return array |
||||
888 | * An associative array describing this extension |
||||
889 | */ |
||||
890 | public static function about($name, $rawXML = false) |
||||
0 ignored issues
–
show
|
|||||
891 | { |
||||
892 | // See if the extension has the new meta format |
||||
893 | if (file_exists(self::__getClassPath($name) . '/extension.meta.xml')) { |
||||
894 | try { |
||||
895 | $meta = new DOMDocument; |
||||
896 | $meta->load(self::__getClassPath($name) . '/extension.meta.xml'); |
||||
897 | $xpath = new DOMXPath($meta); |
||||
898 | $rootNamespace = $meta->lookupNamespaceUri($meta->namespaceURI); |
||||
899 | |||||
900 | if (is_null($rootNamespace)) { |
||||
0 ignored issues
–
show
|
|||||
901 | throw new Exception(__('Missing default namespace definition.')); |
||||
902 | } else { |
||||
903 | $xpath->registerNamespace('ext', $rootNamespace); |
||||
904 | } |
||||
905 | } catch (Exception $ex) { |
||||
906 | Symphony::Engine()->throwCustomError( |
||||
907 | __('The %1$s file for the %2$s extension is not valid XML: %3$s', array( |
||||
908 | '<code>extension.meta.xml</code>', |
||||
909 | '<code>' . $name . '</code>', |
||||
910 | '<br /><code>' . $ex->getMessage() . '</code>' |
||||
911 | )) |
||||
912 | ); |
||||
913 | } |
||||
914 | |||||
915 | // Load <extension> |
||||
916 | $extension = $xpath->query('/ext:extension')->item(0); |
||||
917 | |||||
918 | // Check to see that the extension is named correctly, if it is |
||||
919 | // not, then return nothing |
||||
920 | if (self::__getClassName($name) !== self::__getClassName($xpath->evaluate('string(@id)', $extension))) { |
||||
921 | return array(); |
||||
922 | } |
||||
923 | |||||
924 | // If `$rawXML` is set, just return our DOMDocument instance |
||||
925 | if ($rawXML) { |
||||
926 | return $meta; |
||||
0 ignored issues
–
show
|
|||||
927 | } |
||||
928 | |||||
929 | $about = array( |
||||
930 | 'name' => $xpath->evaluate('string(ext:name)', $extension), |
||||
931 | 'handle' => $name, |
||||
932 | 'github' => $xpath->evaluate('string(ext:repo)', $extension), |
||||
933 | 'discuss' => $xpath->evaluate('string(ext:url[@type="discuss"])', $extension), |
||||
934 | 'homepage' => $xpath->evaluate('string(ext:url[@type="homepage"])', $extension), |
||||
935 | 'wiki' => $xpath->evaluate('string(ext:url[@type="wiki"])', $extension), |
||||
936 | 'issues' => $xpath->evaluate('string(ext:url[@type="issues"])', $extension), |
||||
937 | 'status' => array() |
||||
938 | ); |
||||
939 | |||||
940 | // find the latest <release> (largest version number) |
||||
941 | $latest_release_version = '0.0.0'; |
||||
942 | foreach ($xpath->query('//ext:release', $extension) as $release) { |
||||
943 | $version = $xpath->evaluate('string(@version)', $release); |
||||
944 | |||||
945 | if (version_compare($version, $latest_release_version, '>')) { |
||||
946 | $latest_release_version = $version; |
||||
947 | } |
||||
948 | } |
||||
949 | |||||
950 | // Load the latest <release> information |
||||
951 | if ($release = $xpath->query("//ext:release[@version='$latest_release_version']", $extension)->item(0)) { |
||||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $latest_release_version instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||||
952 | $about += array( |
||||
953 | 'version' => $xpath->evaluate('string(@version)', $release), |
||||
954 | 'release-date' => $xpath->evaluate('string(@date)', $release) |
||||
955 | ); |
||||
956 | |||||
957 | // If it exists, load in the 'min/max' version data for this release |
||||
958 | $required_min_version = $xpath->evaluate('string(@min)', $release); |
||||
959 | $required_max_version = $xpath->evaluate('string(@max)', $release); |
||||
960 | $current_symphony_version = Symphony::Configuration()->get('version', 'symphony'); |
||||
961 | |||||
962 | // Remove pre-release notes from the current Symphony version so that |
||||
963 | // we don't get false erros in the backend |
||||
964 | $current_symphony_version = preg_replace(array('/dev/i', '/-?beta\.?\d/i', '/-?rc\.?\d/i', '/\.0(?:\.0)?$/'), '', $current_symphony_version); |
||||
965 | |||||
966 | // Munge the version number so that it makes sense in the backend. |
||||
967 | // Consider, 2.3.x. As the min version, this means 2.3 onwards, |
||||
968 | // for the max it implies any 2.3 release. RE: #1019 |
||||
969 | // Also remove any .0 when doing the comparison to prevent extensions |
||||
970 | // that don't use semver yet. RE: #2146 |
||||
971 | $required_min_version = preg_replace(array('/\.x/', '/\.0$/'), '', $required_min_version); |
||||
972 | $required_max_version = preg_replace(array('/\.x/', '/\.0$/'), 'p', $required_max_version); |
||||
973 | |||||
974 | // Min version |
||||
975 | if (!empty($required_min_version) && version_compare($current_symphony_version, $required_min_version, '<')) { |
||||
976 | $about['status'][] = Extension::EXTENSION_NOT_COMPATIBLE; |
||||
977 | $about['required_version'] = $required_min_version; |
||||
978 | |||||
979 | // Max version |
||||
980 | } elseif (!empty($required_max_version) && version_compare($current_symphony_version, $required_max_version, '>')) { |
||||
981 | $about['status'][] = Extension::EXTENSION_NOT_COMPATIBLE; |
||||
982 | $about['required_version'] = str_replace('p', '.x', $required_max_version); |
||||
983 | } |
||||
984 | } |
||||
985 | |||||
986 | // Add the <author> information |
||||
987 | foreach ($xpath->query('//ext:author', $extension) as $author) { |
||||
988 | $a = array( |
||||
989 | 'name' => $xpath->evaluate('string(ext:name)', $author), |
||||
990 | 'website' => $xpath->evaluate('string(ext:website)', $author), |
||||
991 | 'github' => $xpath->evaluate('string(ext:name/@github)', $author), |
||||
992 | 'email' => $xpath->evaluate('string(ext:email)', $author) |
||||
993 | ); |
||||
994 | |||||
995 | $about['author'][] = array_filter($a); |
||||
996 | } |
||||
997 | |||||
998 | $about['status'] = array_merge($about['status'], self::fetchStatus($about)); |
||||
999 | return $about; |
||||
1000 | } else { |
||||
1001 | Symphony::Log()->pushToLog(sprintf('%s does not have an extension.meta.xml file', $name), E_DEPRECATED, true); |
||||
1002 | |||||
1003 | return array(); |
||||
1004 | } |
||||
1005 | } |
||||
1006 | |||||
1007 | /** |
||||
1008 | * Creates an instance of a given class and returns it |
||||
1009 | * |
||||
1010 | * @param string $name |
||||
1011 | * The name of the Extension Class minus the extension prefix. |
||||
1012 | * @throws Exception |
||||
1013 | * @throws SymphonyErrorPage |
||||
1014 | * @return Extension |
||||
1015 | */ |
||||
1016 | public static function create($name) |
||||
1017 | { |
||||
1018 | if (!isset(self::$_pool[$name])) { |
||||
1019 | $classname = self::__getClassName($name); |
||||
1020 | $path = self::__getDriverPath($name); |
||||
1021 | |||||
1022 | if (!is_file($path)) { |
||||
1023 | $errMsg = __('Could not find extension %s at location %s.', array( |
||||
1024 | '<code>' . $name . '</code>', |
||||
1025 | '<code>' . str_replace(DOCROOT . '/', '', $path) . '</code>' |
||||
1026 | )); |
||||
1027 | try { |
||||
1028 | Symphony::Engine()->throwCustomError( |
||||
1029 | $errMsg, |
||||
1030 | __('Symphony Extension Missing Error'), |
||||
1031 | Page::HTTP_STATUS_ERROR, |
||||
1032 | 'missing_extension', |
||||
1033 | array( |
||||
1034 | 'name' => $name, |
||||
1035 | 'path' => $path |
||||
1036 | ) |
||||
1037 | ); |
||||
1038 | } catch (Exception $ex) { |
||||
1039 | throw new Exception($errMsg, 0, $ex); |
||||
1040 | } |
||||
1041 | } |
||||
1042 | |||||
1043 | if (!class_exists($classname)) { |
||||
1044 | require_once($path); |
||||
1045 | } |
||||
1046 | |||||
1047 | // Create the extension object |
||||
1048 | self::$_pool[$name] = new $classname(array()); |
||||
1049 | } |
||||
1050 | |||||
1051 | return self::$_pool[$name]; |
||||
1052 | } |
||||
1053 | |||||
1054 | /** |
||||
1055 | * A utility function that is used by the ExtensionManager to ensure |
||||
1056 | * stray delegates are not in `tbl_extensions_delegates`. It is called when |
||||
1057 | * a new Delegate is added or removed. |
||||
1058 | */ |
||||
1059 | public static function cleanupDatabase() |
||||
1060 | { |
||||
1061 | // Grab any extensions sitting in the database |
||||
1062 | $rows = Symphony::Database()->fetch("SELECT `name` FROM `tbl_extensions`"); |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
SELECT `name` FROM `tbl_extensions` does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
1063 | |||||
1064 | // Iterate over each row |
||||
1065 | if (is_array($rows) && !empty($rows)) { |
||||
1066 | foreach ($rows as $r) { |
||||
1067 | $name = $r['name']; |
||||
1068 | $status = isset($r['status']) ? $r['status'] : null; |
||||
1069 | |||||
1070 | // Grab the install location |
||||
1071 | $path = self::__getClassPath($name); |
||||
1072 | $existing_id = self::fetchExtensionID($name); |
||||
1073 | |||||
1074 | // If it doesnt exist, remove the DB rows |
||||
1075 | if (!@is_dir($path)) { |
||||
1076 | Symphony::Database()->delete("tbl_extensions_delegates", sprintf(" `extension_id` = %d ", $existing_id)); |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
tbl_extensions_delegates does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() Coding Style
Comprehensibility
introduced
by
The string literal
`extension_id` = %d does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
1077 | Symphony::Database()->delete('tbl_extensions', sprintf(" `id` = %d LIMIT 1", $existing_id)); |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
`id` = %d LIMIT 1 does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
1078 | } elseif ($status == 'disabled') { |
||||
1079 | Symphony::Database()->delete("tbl_extensions_delegates", sprintf(" `extension_id` = %d ", $existing_id)); |
||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
tbl_extensions_delegates does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() Coding Style
Comprehensibility
introduced
by
The string literal
`extension_id` = %d does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||||
1080 | } |
||||
1081 | } |
||||
1082 | } |
||||
1083 | } |
||||
1084 | } |
||||
1085 |