Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like ExtensionManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ExtensionManager, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class ExtensionManager implements FileResource |
||
1 ignored issue
–
show
|
|||
17 | { |
||
18 | /** |
||
19 | * An array of all the objects that the Manager is responsible for. |
||
20 | * Defaults to an empty array. |
||
21 | * @var array |
||
22 | */ |
||
23 | protected static $_pool = array(); |
||
24 | |||
25 | /** |
||
26 | * An array of all extensions whose status is enabled |
||
27 | * @var array |
||
28 | */ |
||
29 | private static $_enabled_extensions = array(); |
||
30 | |||
31 | /** |
||
32 | * An array of all the subscriptions to Symphony delegates made by extensions. |
||
33 | * @var array |
||
34 | */ |
||
35 | private static $_subscriptions = array(); |
||
36 | |||
37 | /** |
||
38 | * An associative array of all the extensions in `tbl_extensions` where |
||
39 | * the key is the extension name and the value is an array |
||
40 | * representation of it's accompanying database row. |
||
41 | * @var array |
||
42 | */ |
||
43 | private static $_extensions = array(); |
||
44 | |||
45 | /** |
||
46 | * An associative array of all the providers from the enabled extensions. |
||
47 | * The key is the type of object, with the value being an associative array |
||
48 | * with the name, classname and path to the object |
||
49 | * |
||
50 | * @since Symphony 2.3 |
||
51 | * @var array |
||
52 | */ |
||
53 | private static $_providers = array(); |
||
54 | |||
55 | /** |
||
56 | * The constructor will populate the `$_subscriptions` variable from |
||
57 | * the `tbl_extension` and `tbl_extensions_delegates` tables. |
||
58 | */ |
||
59 | public function __construct() |
||
74 | |||
75 | public static function __getHandleFromFilename($filename) |
||
79 | |||
80 | /** |
||
81 | * Given a name, returns the full class name of an Extension. |
||
82 | * Extension use an 'extension' prefix. |
||
83 | * |
||
84 | * @param string $name |
||
85 | * The extension handle |
||
86 | * @return string |
||
87 | */ |
||
88 | public static function __getClassName($name) |
||
92 | |||
93 | /** |
||
94 | * Finds an Extension by name by searching the `EXTENSIONS` folder and |
||
95 | * returns the path to the folder. |
||
96 | * |
||
97 | * @param string $name |
||
98 | * The extension folder |
||
99 | * @return string |
||
100 | */ |
||
101 | public static function __getClassPath($name) |
||
105 | |||
106 | /** |
||
107 | * Given a name, return the path to the driver of the Extension. |
||
108 | * |
||
109 | * @see toolkit.ExtensionManager#__getClassPath() |
||
110 | * @param string $name |
||
111 | * The extension folder |
||
112 | * @return string |
||
113 | */ |
||
114 | public static function __getDriverPath($name) |
||
118 | |||
119 | /** |
||
120 | * This function returns an instance of an extension from it's name |
||
121 | * |
||
122 | * @param string $name |
||
123 | * The name of the Extension Class minus the extension prefix. |
||
124 | * @throws SymphonyErrorPage |
||
125 | * @throws Exception |
||
126 | * @return Extension |
||
127 | */ |
||
128 | public static function getInstance($name) |
||
132 | |||
133 | /** |
||
134 | * Populates the `ExtensionManager::$_extensions` array with all the |
||
135 | * extensions stored in `tbl_extensions`. If `ExtensionManager::$_extensions` |
||
136 | * isn't empty, passing true as a parameter will force the array to update |
||
137 | * |
||
138 | * @param boolean $update |
||
139 | * Updates the `ExtensionManager::$_extensions` array even if it was |
||
140 | * populated, defaults to false. |
||
141 | * @throws DatabaseException |
||
142 | */ |
||
143 | private static function __buildExtensionList($update = false) |
||
149 | |||
150 | /** |
||
151 | * Returns the status of an Extension given an associative array containing |
||
152 | * the Extension `handle` and `version` where the `version` is the file |
||
153 | * version, not the installed version. This function returns an array |
||
154 | * which may include a maximum of two statuses. |
||
155 | * |
||
156 | * @param array $about |
||
157 | * An associative array of the extension meta data, typically returned |
||
158 | * by `ExtensionManager::about()`. At the very least this array needs |
||
159 | * `handle` and `version` keys. |
||
160 | * @return array |
||
161 | * An array of extension statuses, with the possible values being |
||
162 | * `EXTENSION_ENABLED`, `EXTENSION_DISABLED`, `EXTENSION_REQUIRES_UPDATE` |
||
163 | * or `EXTENSION_NOT_INSTALLED`. If an extension doesn't exist, |
||
164 | * `EXTENSION_NOT_INSTALLED` will be returned. |
||
165 | */ |
||
166 | public static function fetchStatus($about) |
||
187 | |||
188 | /** |
||
189 | * A convenience method that returns an extension version from it's name. |
||
190 | * |
||
191 | * @param string $name |
||
192 | * The name of the Extension Class minus the extension prefix. |
||
193 | * @return string |
||
194 | */ |
||
195 | public static function fetchInstalledVersion($name) |
||
201 | |||
202 | /** |
||
203 | * A convenience method that returns an extension ID from it's name. |
||
204 | * |
||
205 | * @param string $name |
||
206 | * The name of the Extension Class minus the extension prefix. |
||
207 | * @return integer |
||
208 | */ |
||
209 | public static function fetchExtensionID($name) |
||
215 | |||
216 | /** |
||
217 | * Return an array all the Provider objects supplied by extensions, |
||
218 | * optionally filtered by a given `$type`. |
||
219 | * |
||
220 | * @since Symphony 2.3 |
||
221 | * @todo Add information about the possible types |
||
222 | * @param string $type |
||
223 | * This will only return Providers of this type. If null, which is |
||
224 | * default, all providers will be returned. |
||
225 | * @throws Exception |
||
226 | * @throws SymphonyErrorPage |
||
227 | * @return array |
||
228 | * An array of objects |
||
229 | */ |
||
230 | public static function getProvidersOf($type = null) |
||
265 | |||
266 | /** |
||
267 | * This function will return the `Cacheable` object with the appropriate |
||
268 | * caching layer for the given `$key`. This `$key` should be stored in |
||
269 | * the Symphony configuration in the caching group with a reference |
||
270 | * to the class of the caching object. If the key is not found, this |
||
271 | * will return a default `Cacheable` object created with the MySQL driver. |
||
272 | * |
||
273 | * @since Symphony 2.4 |
||
274 | * @param string $key |
||
275 | * Should be a reference in the Configuration file to the Caching class |
||
276 | * @param boolean $reuse |
||
277 | * By default true, which will reuse an existing Cacheable object of `$key` |
||
278 | * if it exists. If false, a new instance will be generated. |
||
279 | * @return Cacheable |
||
280 | */ |
||
281 | public static function getCacheProvider($key = null, $reuse = true) |
||
300 | |||
301 | /** |
||
302 | * Determines whether the current extension is installed or not by checking |
||
303 | * for an id in `tbl_extensions` |
||
304 | * |
||
305 | * @param string $name |
||
306 | * The name of the Extension Class minus the extension prefix. |
||
307 | * @return boolean |
||
308 | */ |
||
309 | private static function __requiresInstallation($name) |
||
316 | |||
317 | /** |
||
318 | * Determines whether an extension needs to be updated or not using |
||
319 | * PHP's `version_compare` function. This function will return the |
||
320 | * installed version if the extension requires an update, or |
||
321 | * false otherwise. |
||
322 | * |
||
323 | * @param string $name |
||
324 | * The name of the Extension Class minus the extension prefix. |
||
325 | * @param string $file_version |
||
326 | * The version of the extension from the **file**, not the Database. |
||
327 | * @return string|boolean |
||
328 | * If the given extension (by $name) requires updating, the installed |
||
329 | * version is returned, otherwise, if the extension doesn't require |
||
330 | * updating, false. |
||
331 | */ |
||
332 | private static function __requiresUpdate($name, $file_version) |
||
342 | |||
343 | /** |
||
344 | * Enabling an extension will re-register all it's delegates with Symphony. |
||
345 | * It will also install or update the extension if needs be by calling the |
||
346 | * extensions respective install and update methods. The enable method is |
||
347 | * of the extension object is finally called. |
||
348 | * |
||
349 | * @see toolkit.ExtensionManager#registerDelegates() |
||
350 | * @see toolkit.ExtensionManager#__canUninstallOrDisable() |
||
351 | * @param string $name |
||
352 | * The name of the Extension Class minus the extension prefix. |
||
353 | * @throws SymphonyErrorPage |
||
354 | * @throws Exception |
||
355 | * @return boolean |
||
356 | */ |
||
357 | public static function enable($name) |
||
402 | |||
403 | /** |
||
404 | * Disabling an extension will prevent it from executing but retain all it's |
||
405 | * settings in the relevant tables. Symphony checks that an extension can |
||
406 | * be disabled using the `canUninstallorDisable()` before removing |
||
407 | * all delegate subscriptions from the database and calling the extension's |
||
408 | * `disable()` function. |
||
409 | * |
||
410 | * @see toolkit.ExtensionManager#removeDelegates() |
||
411 | * @see toolkit.ExtensionManager#__canUninstallOrDisable() |
||
412 | * @param string $name |
||
413 | * The name of the Extension Class minus the extension prefix. |
||
414 | * @throws DatabaseException |
||
415 | * @throws SymphonyErrorPage |
||
416 | * @throws Exception |
||
417 | * @return boolean |
||
418 | */ |
||
419 | public static function disable($name) |
||
444 | |||
445 | /** |
||
446 | * Uninstalling an extension will unregister all delegate subscriptions and |
||
447 | * remove all extension settings. Symphony checks that an extension can |
||
448 | * be uninstalled using the `canUninstallorDisable()` before calling |
||
449 | * the extension's `uninstall()` function. Alternatively, if this function |
||
450 | * is called because the extension described by `$name` cannot be found |
||
451 | * it's delegates and extension meta information will just be removed from the |
||
452 | * database. |
||
453 | * |
||
454 | * @see toolkit.ExtensionManager#removeDelegates() |
||
455 | * @see toolkit.ExtensionManager#__canUninstallOrDisable() |
||
456 | * @param string $name |
||
457 | * The name of the Extension Class minus the extension prefix. |
||
458 | * @throws Exception |
||
459 | * @throws SymphonyErrorPage |
||
460 | * @throws DatabaseException |
||
461 | * @throws Exception |
||
462 | * @return boolean |
||
463 | */ |
||
464 | public static function uninstall($name) |
||
488 | |||
489 | /** |
||
490 | * This functions registers an extensions delegates in `tbl_extensions_delegates`. |
||
491 | * |
||
492 | * @param string $name |
||
493 | * The name of the Extension Class minus the extension prefix. |
||
494 | * @throws Exception |
||
495 | * @throws SymphonyErrorPage |
||
496 | * @return integer |
||
497 | * The Extension ID |
||
498 | */ |
||
499 | public static function registerDelegates($name) |
||
533 | |||
534 | /** |
||
535 | * This function will remove all delegate subscriptions for an extension |
||
536 | * given an extension's name. This triggers `cleanupDatabase()` |
||
537 | * |
||
538 | * @see toolkit.ExtensionManager#cleanupDatabase() |
||
539 | * @param string $name |
||
540 | * The name of the Extension Class minus the extension prefix. |
||
541 | * @return boolean |
||
542 | */ |
||
543 | public static function removeDelegates($name) |
||
563 | |||
564 | /** |
||
565 | * This function checks that if the given extension has provided Fields, |
||
566 | * Data Sources or Events, that they aren't in use before the extension |
||
567 | * is uninstalled or disabled. This prevents exceptions from occurring when |
||
568 | * accessing an object that was using something provided by this Extension |
||
569 | * can't anymore because it has been removed. |
||
570 | * |
||
571 | * @param Extension $obj |
||
572 | * An extension object |
||
573 | * @throws SymphonyErrorPage |
||
574 | * @throws Exception |
||
575 | * @return boolean |
||
576 | */ |
||
577 | private static function __canUninstallOrDisable(Extension $obj) |
||
638 | |||
639 | /** |
||
640 | * Given a delegate name, notify all extensions that have registered to that |
||
641 | * delegate to executing their callbacks with a `$context` array parameter |
||
642 | * that contains information about the current Symphony state. |
||
643 | * |
||
644 | * @param string $delegate |
||
645 | * The delegate name |
||
646 | * @param string $page |
||
647 | * The current page namespace that this delegate operates in |
||
648 | * @param array $context |
||
649 | * The `$context` param is an associative array that at minimum will contain |
||
650 | * the current Administration class, the current page object and the delegate |
||
651 | * name. Other context information may be passed to this function when it is |
||
652 | * called. eg. |
||
653 | * |
||
654 | * array( |
||
655 | * 'parent' =>& $this->Parent, |
||
656 | * 'page' => $page, |
||
657 | * 'delegate' => $delegate |
||
658 | * ); |
||
659 | * @throws Exception |
||
660 | * @throws SymphonyErrorPage |
||
661 | * @return null|void |
||
662 | */ |
||
663 | public static function notifyMembers($delegate, $page, array $context = array()) |
||
716 | |||
717 | /** |
||
718 | * Returns an array of all the enabled extensions available |
||
719 | * |
||
720 | * @return array |
||
721 | */ |
||
722 | public static function listInstalledHandles() |
||
732 | |||
733 | /** |
||
734 | * Will return an associative array of all extensions and their about information |
||
735 | * |
||
736 | * @param string $filter |
||
737 | * Allows a regular expression to be passed to return only extensions whose |
||
738 | * folders match the filter. |
||
739 | * @throws SymphonyErrorPage |
||
740 | * @throws Exception |
||
741 | * @return array |
||
742 | * An associative array with the key being the extension folder and the value |
||
743 | * being the extension's about information |
||
744 | */ |
||
745 | public static function listAll($filter = '/^((?![-^?%:*|"<>]).)*$/') |
||
762 | |||
763 | /** |
||
764 | * Custom user sorting function used inside `fetch` to recursively sort authors |
||
765 | * by their names. |
||
766 | * |
||
767 | * @param array $a |
||
768 | * @param array $b |
||
769 | * @param integer $i |
||
770 | * @return integer |
||
771 | */ |
||
772 | private static function sortByAuthor($a, $b, $i = 0) |
||
793 | |||
794 | /** |
||
795 | * This function will return an associative array of Extension information. The |
||
796 | * information returned is defined by the `$select` parameter, which will allow |
||
797 | * a developer to restrict what information is returned about the Extension. |
||
798 | * Optionally, `$where` (not implemented) and `$order_by` parameters allow a developer to |
||
799 | * further refine their query. |
||
800 | * |
||
801 | * @param array $select (optional) |
||
802 | * Accepts an array of keys to return from the listAll() method. If omitted, all keys |
||
803 | * will be returned. |
||
804 | * @param array $where (optional) |
||
805 | * Not implemented. |
||
806 | * @param string $order_by (optional) |
||
807 | * Allows a developer to return the extensions in a particular order. The syntax is the |
||
808 | * same as other `fetch` methods. If omitted this will return resources ordered by `name`. |
||
809 | * @throws Exception |
||
810 | * @throws SymphonyErrorPage |
||
811 | * @return array |
||
812 | * An associative array of Extension information, formatted in the same way as the |
||
813 | * listAll() method. |
||
814 | */ |
||
815 | public static function fetch(array $select = array(), array $where = array(), $order_by = null) |
||
872 | |||
873 | /** |
||
874 | * This function will load an extension's meta information given the extension |
||
875 | * `$name`. Since Symphony 2.3, this function will look for an `extension.meta.xml` |
||
876 | * file inside the extension's folder. If this is not found, it will initialise |
||
877 | * the extension and invoke the `about()` function. By default this extension will |
||
878 | * return an associative array display the basic meta data about the given extension. |
||
879 | * If the `$rawXML` parameter is passed true, and the extension has a `extension.meta.xml` |
||
880 | * file, this function will return `DOMDocument` of the file. |
||
881 | * |
||
882 | * @param string $name |
||
883 | * The name of the Extension Class minus the extension prefix. |
||
884 | * @param boolean $rawXML |
||
885 | * If passed as true, and is available, this function will return the |
||
886 | * DOMDocument of representation of the given extension's `extension.meta.xml` |
||
887 | * file. If the file is not available, the extension will return the normal |
||
888 | * `about()` results. By default this is false. |
||
889 | * @throws Exception |
||
890 | * @throws SymphonyErrorPage |
||
891 | * @return array |
||
892 | * An associative array describing this extension |
||
893 | */ |
||
894 | public static function about($name, $rawXML = false) |
||
1010 | |||
1011 | /** |
||
1012 | * Creates an instance of a given class and returns it |
||
1013 | * |
||
1014 | * @param string $name |
||
1015 | * The name of the Extension Class minus the extension prefix. |
||
1016 | * @throws Exception |
||
1017 | * @throws SymphonyErrorPage |
||
1018 | * @return Extension |
||
1019 | */ |
||
1020 | public static function create($name) |
||
1052 | |||
1053 | /** |
||
1054 | * A utility function that is used by the ExtensionManager to ensure |
||
1055 | * stray delegates are not in `tbl_extensions_delegates`. It is called when |
||
1056 | * a new Delegate is added or removed. |
||
1057 | */ |
||
1058 | public static function cleanupDatabase() |
||
1083 | } |
||
1084 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.