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 Plugins 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 Plugins, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
24 | class Plugins { |
||
25 | |||
26 | /** |
||
27 | * @var string[] Active plugin IDs with IDs as the array keys. Missing keys imply inactive plugins. |
||
28 | */ |
||
29 | protected $active_ids = array(); |
||
30 | |||
31 | /** |
||
32 | * @var bool Has $active_ids been populated? |
||
33 | */ |
||
34 | protected $active_ids_known = false; |
||
35 | |||
36 | /** |
||
37 | * @var \Elgg\Cache\MemoryPool |
||
38 | */ |
||
39 | protected $plugins_by_id; |
||
40 | |||
41 | /** |
||
42 | * Constructor |
||
43 | * |
||
44 | * @param \Elgg\EventsService $events Events service |
||
45 | * @param \Elgg\Cache\MemoryPool $pool Cache for referencing plugins by ID |
||
46 | */ |
||
47 | 1 | public function __construct(\Elgg\EventsService $events, \Elgg\Cache\MemoryPool $pool) { |
|
50 | |||
51 | /** |
||
52 | * Returns a list of plugin directory names from a base directory. |
||
53 | * |
||
54 | * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path. |
||
55 | * Must have a trailing slash. |
||
56 | * |
||
57 | * @return array Array of directory names (not full paths) |
||
58 | * @access private |
||
59 | */ |
||
60 | function getDirsInDir($dir = null) { |
||
81 | |||
82 | /** |
||
83 | * Discovers plugins in the plugins_path setting and creates \ElggPlugin |
||
84 | * entities for them if they don't exist. If there are plugins with entities |
||
85 | * but not actual files, will disable the \ElggPlugin entities and mark as inactive. |
||
86 | * The \ElggPlugin object holds config data, so don't delete. |
||
87 | * |
||
88 | * @return bool |
||
89 | * @access private |
||
90 | */ |
||
91 | function generateEntities() { |
||
181 | |||
182 | /** |
||
183 | * Cache a reference to this plugin by its ID |
||
184 | * |
||
185 | * @param \ElggPlugin $plugin |
||
186 | * |
||
187 | * @access private |
||
188 | */ |
||
189 | function cache(\ElggPlugin $plugin) { |
||
192 | |||
193 | /** |
||
194 | * Returns an \ElggPlugin object with the path $path. |
||
195 | * |
||
196 | * @param string $plugin_id The id (dir name) of the plugin. NOT the guid. |
||
197 | * @return \ElggPlugin|null |
||
198 | */ |
||
199 | function get($plugin_id) { |
||
223 | |||
224 | /** |
||
225 | * Returns if a plugin exists in the system. |
||
226 | * |
||
227 | * @warning This checks only plugins that are registered in the system! |
||
228 | * If the plugin cache is outdated, be sure to regenerate it with |
||
229 | * {@link _elgg_generate_plugin_objects()} first. |
||
230 | * |
||
231 | * @param string $id The plugin ID. |
||
232 | * @return bool |
||
233 | */ |
||
234 | function exists($id) { |
||
239 | |||
240 | /** |
||
241 | * Returns the highest priority of the plugins |
||
242 | * |
||
243 | * @return int |
||
244 | * @access private |
||
245 | */ |
||
246 | function getMaxPriority() { |
||
267 | |||
268 | /** |
||
269 | * Returns if a plugin is active for a current site. |
||
270 | * |
||
271 | * @param string $plugin_id The plugin ID |
||
272 | * @param int $site_guid The site guid |
||
273 | * @return bool |
||
274 | */ |
||
275 | function isActive($plugin_id, $site_guid = null) { |
||
301 | |||
302 | /** |
||
303 | * Loads all active plugins in the order specified in the tool admin panel. |
||
304 | * |
||
305 | * @note This is called on every page load. If a plugin is active and problematic, it |
||
306 | * will be disabled and a visible error emitted. This does not check the deps system because |
||
307 | * that was too slow. |
||
308 | * |
||
309 | * @return bool |
||
310 | * @access private |
||
311 | */ |
||
312 | function load() { |
||
362 | |||
363 | /** |
||
364 | * Returns an ordered list of plugins |
||
365 | * |
||
366 | * @param string $status The status of the plugins. active, inactive, or all. |
||
367 | * @param mixed $site_guid Optional site guid |
||
368 | * @return \ElggPlugin[] |
||
369 | */ |
||
370 | function find($status = 'active', $site_guid = null) { |
||
420 | |||
421 | /** |
||
422 | * Reorder plugins to an order specified by the array. |
||
423 | * Plugins not included in this array will be appended to the end. |
||
424 | * |
||
425 | * @note This doesn't use the \ElggPlugin->setPriority() method because |
||
426 | * all plugins are being changed and we don't want it to automatically |
||
427 | * reorder plugins. |
||
428 | * |
||
429 | * @param array $order An array of plugin ids in the order to set them |
||
430 | * @return bool |
||
431 | * @access private |
||
432 | */ |
||
433 | function setPriorities(array $order) { |
||
482 | |||
483 | /** |
||
484 | * Reindexes all plugin priorities starting at 1. |
||
485 | * |
||
486 | * @todo Can this be done in a single sql command? |
||
487 | * @return bool |
||
488 | * @access private |
||
489 | */ |
||
490 | function reindexPriorities() { |
||
493 | |||
494 | /** |
||
495 | * Namespaces a string to be used as a private setting name for a plugin. |
||
496 | * |
||
497 | * For user_settings, two namespaces are added: a user setting namespace and the |
||
498 | * plugin id. |
||
499 | * |
||
500 | * For internal (plugin priority), there is a single internal namespace added. |
||
501 | * |
||
502 | * @param string $type The type of setting: user_setting or internal. |
||
503 | * @param string $name The name to namespace. |
||
504 | * @param string $id The plugin's ID to namespace with. Required for user_setting. |
||
505 | * @return string |
||
506 | * @access private |
||
507 | */ |
||
508 | function namespacePrivateSetting($type, $name, $id = null) { |
||
530 | |||
531 | |||
532 | /** |
||
533 | * Returns an array of all provides from all active plugins. |
||
534 | * |
||
535 | * Array in the form array( |
||
536 | * 'provide_type' => array( |
||
537 | * 'provided_name' => array( |
||
538 | * 'version' => '1.8', |
||
539 | * 'provided_by' => 'provider_plugin_id' |
||
540 | * ) |
||
541 | * ) |
||
542 | * ) |
||
543 | * |
||
544 | * @param string $type The type of provides to return |
||
545 | * @param string $name A specific provided name to return. Requires $provide_type. |
||
546 | * |
||
547 | * @return array |
||
548 | * @access private |
||
549 | */ |
||
550 | function getProvides($type = null, $name = null) { |
||
592 | |||
593 | /** |
||
594 | * Deletes all cached data on plugins being provided. |
||
595 | * |
||
596 | * @return boolean |
||
597 | * @access private |
||
598 | */ |
||
599 | function invalidateProvidesCache() { |
||
604 | |||
605 | /** |
||
606 | * Delete the cache holding whether plugins are active or not |
||
607 | * |
||
608 | * @return void |
||
609 | * @access private |
||
610 | */ |
||
611 | public function invalidateIsActiveCache() { |
||
615 | |||
616 | /** |
||
617 | * Checks if a plugin is currently providing $type and $name, and optionally |
||
618 | * checking a version. |
||
619 | * |
||
620 | * @param string $type The type of the provide |
||
621 | * @param string $name The name of the provide |
||
622 | * @param string $version A version to check against |
||
623 | * @param string $comparison The comparison operator to use in version_compare() |
||
624 | * |
||
625 | * @return array An array in the form array( |
||
626 | * 'status' => bool Does the provide exist?, |
||
627 | * 'value' => string The version provided |
||
628 | * ) |
||
629 | * @access private |
||
630 | */ |
||
631 | function checkProvides($type, $name, $version = null, $comparison = 'ge') { |
||
651 | |||
652 | /** |
||
653 | * Returns an array of parsed strings for a dependency in the |
||
654 | * format: array( |
||
655 | * 'type' => requires, conflicts, or provides. |
||
656 | * 'name' => The name of the requirement / conflict |
||
657 | * 'value' => A string representing the expected value: <1, >=3, !=enabled |
||
658 | * 'local_value' => The current value, ("Not installed") |
||
659 | * 'comment' => Free form text to help resovle the problem ("Enable / Search for plugin <link>") |
||
660 | * ) |
||
661 | * |
||
662 | * @param array $dep An \ElggPluginPackage dependency array |
||
663 | * @return array |
||
664 | * @access private |
||
665 | */ |
||
666 | function getDependencyStrings($dep) { |
||
779 | |||
780 | /** |
||
781 | * Returns an array of all plugin user settings for a user. |
||
782 | * |
||
783 | * @param int $user_guid The user GUID or 0 for the currently logged in user. |
||
784 | * @param string $plugin_id The plugin ID (Required) |
||
785 | * @param bool $return_obj Return settings as an object? This can be used to in reusable |
||
786 | * views where the settings are passed as $vars['entity']. |
||
787 | * @return array |
||
788 | * @see \ElggPlugin::getAllUserSettings() |
||
789 | */ |
||
790 | function getAllUserSettings($user_guid = 0, $plugin_id = null, $return_obj = false) { |
||
816 | |||
817 | /** |
||
818 | * Set a user specific setting for a plugin. |
||
819 | * |
||
820 | * @param string $name The name. Note: cannot be "title". |
||
821 | * @param mixed $value The value. |
||
822 | * @param int $user_guid The user GUID or 0 for the currently logged in user. |
||
823 | * @param string $plugin_id The plugin ID (Required) |
||
824 | * |
||
825 | * @return bool |
||
826 | * @see \ElggPlugin::setUserSetting() |
||
827 | */ |
||
828 | View Code Duplication | function setUserSetting($name, $value, $user_guid = 0, $plugin_id = null) { |
|
842 | |||
843 | /** |
||
844 | * Unsets a user-specific plugin setting |
||
845 | * |
||
846 | * @param string $name Name of the setting |
||
847 | * @param int $user_guid The user GUID or 0 for the currently logged in user. |
||
848 | * @param string $plugin_id The plugin ID (Required) |
||
849 | * |
||
850 | * @return bool |
||
851 | * @see \ElggPlugin::unsetUserSetting() |
||
852 | */ |
||
853 | View Code Duplication | function unsetUserSetting($name, $user_guid = 0, $plugin_id = null) { |
|
867 | |||
868 | /** |
||
869 | * Get a user specific setting for a plugin. |
||
870 | * |
||
871 | * @param string $name The name of the setting. |
||
872 | * @param int $user_guid The user GUID or 0 for the currently logged in user. |
||
873 | * @param string $plugin_id The plugin ID (Required) |
||
874 | * @param mixed $default The default value to return if none is set |
||
875 | * |
||
876 | * @return mixed |
||
877 | * @see \ElggPlugin::getUserSetting() |
||
878 | */ |
||
879 | View Code Duplication | function getUserSetting($name, $user_guid = 0, $plugin_id = null, $default = null) { |
|
893 | |||
894 | /** |
||
895 | * Set a setting for a plugin. |
||
896 | * |
||
897 | * @param string $name The name of the setting - note, can't be "title". |
||
898 | * @param mixed $value The value. |
||
899 | * @param string $plugin_id The plugin ID (Required) |
||
900 | * |
||
901 | * @return bool |
||
902 | * @see \ElggPlugin::setSetting() |
||
903 | */ |
||
904 | function setSetting($name, $value, $plugin_id = null) { |
||
918 | |||
919 | /** |
||
920 | * Get setting for a plugin. |
||
921 | * |
||
922 | * @param string $name The name of the setting. |
||
923 | * @param string $plugin_id The plugin ID (Required) |
||
924 | * @param mixed $default The default value to return if none is set |
||
925 | * |
||
926 | * @return mixed |
||
927 | * @see \ElggPlugin::getSetting() |
||
928 | */ |
||
929 | View Code Duplication | function getSetting($name, $plugin_id = null, $default = null) { |
|
943 | |||
944 | /** |
||
945 | * Unsets a plugin setting. |
||
946 | * |
||
947 | * @param string $name The name of the setting. |
||
948 | * @param string $plugin_id The plugin ID (Required) |
||
949 | * |
||
950 | * @return bool |
||
951 | * @see \ElggPlugin::unsetSetting() |
||
952 | */ |
||
953 | function unsetSetting($name, $plugin_id = null) { |
||
967 | |||
968 | /** |
||
969 | * Unsets all plugin settings for a plugin. |
||
970 | * |
||
971 | * @param string $plugin_id The plugin ID (Required) |
||
972 | * |
||
973 | * @return bool |
||
974 | * @see \ElggPlugin::unsetAllSettings() |
||
975 | */ |
||
976 | function unsetAllSettings($plugin_id = null) { |
||
990 | |||
991 | /** |
||
992 | * Returns entities based upon plugin user settings. |
||
993 | * Takes all the options for {@link elgg_get_entities_from_private_settings()} |
||
994 | * in addition to the ones below. |
||
995 | * |
||
996 | * @param array $options Array in the format: |
||
997 | * |
||
998 | * plugin_id => STR The plugin id. Required. |
||
999 | * |
||
1000 | * plugin_user_setting_names => null|ARR private setting names |
||
1001 | * |
||
1002 | * plugin_user_setting_values => null|ARR metadata values |
||
1003 | * |
||
1004 | * plugin_user_setting_name_value_pairs => null|ARR ( |
||
1005 | * name => 'name', |
||
1006 | * value => 'value', |
||
1007 | * 'operand' => '=', |
||
1008 | * ) |
||
1009 | * Currently if multiple values are sent via |
||
1010 | * an array (value => array('value1', 'value2') |
||
1011 | * the pair's operand will be forced to "IN". |
||
1012 | * |
||
1013 | * plugin_user_setting_name_value_pairs_operator => null|STR The operator to use for combining |
||
1014 | * (name = value) OPERATOR (name = value); default AND |
||
1015 | * |
||
1016 | * @return mixed int If count, int. If not count, array. false on errors. |
||
1017 | */ |
||
1018 | function getEntitiesFromUserSettings(array $options = array()) { |
||
1058 | } |
||
1059 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: