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:
| 1 | <?php | ||
| 18 | class PluginManager | ||
| 19 | { | ||
| 20 | /** @var PluginDescription[] List of all the plugins adescriptions. */ | ||
| 21 | protected $plugins = []; | ||
| 22 | |||
| 23 | /** @var PluginDescription[] Current List of enabled plugins */ | ||
| 24 | protected $enabledPlugins = []; | ||
| 25 | |||
| 26 | /** @var PluginDescriptionFactory */ | ||
| 27 | protected $pluginDescriptionFactory; | ||
| 28 | |||
| 29 | /** @var ContainerInterface */ | ||
| 30 | protected $container; | ||
| 31 | |||
| 32 | /** @var DataProviderManager */ | ||
| 33 | protected $dataProviderManager; | ||
| 34 | |||
| 35 | /** @var GameDataStorage */ | ||
| 36 | protected $gameDataStorage; | ||
| 37 | |||
| 38 | /** @var Console */ | ||
| 39 | protected $console; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * PluginManager constructor. | ||
| 43 | * | ||
| 44 | * @param ContainerInterface $container | ||
| 45 | * @param PluginDescriptionFactory $pluginDescriptionFactory | ||
| 46 | * @param DataProviderManager $dataProviderManager | ||
| 47 | * @param GameDataStorage $gameDataStorage | ||
| 48 | * @param Console $console | ||
| 49 | */ | ||
| 50 | 46 | public function __construct( | |
| 64 | |||
| 65 | /** | ||
| 66 | * Initialize plugins. | ||
| 67 | */ | ||
| 68 | public function init() | ||
| 72 | |||
| 73 | public function reset() | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Enable all possible plugins. | ||
| 83 | * | ||
| 84 | * @param string $title | ||
| 85 | * @param string $mode | ||
| 86 | * @param string $script | ||
| 87 | */ | ||
| 88 | protected function enableDisablePlugins($title, $mode, $script) | ||
| 89 |     { | ||
| 90 | $pluginsToEnable = []; | ||
| 91 | $pluginsToProcess = $this->plugins; | ||
| 92 | |||
| 93 |         do { | ||
| 94 | $lastEnabledPluginCount = count($pluginsToEnable); | ||
| 95 | $pluginsToProcessNew = []; | ||
| 96 | |||
| 97 | foreach ($pluginsToProcess | ||
| 98 | |||
| 99 |                      as $pluginId => $plugin) { | ||
| 100 |                 if ($this->isPluginCompatible($plugin, $pluginsToEnable, $title, $mode, $script)) { | ||
| 101 | $pluginsToEnable[$pluginId] = $plugin; | ||
| 102 |                 } else { | ||
| 103 | $pluginsToProcessNew[$pluginId] = $plugin; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | $pluginsToProcess = $pluginsToProcessNew; | ||
| 108 | } while ($lastEnabledPluginCount != count($pluginsToEnable) && !empty($pluginsToProcess)); | ||
| 109 | |||
| 110 |         foreach ($pluginsToEnable as $plugin) { | ||
| 111 | $this->enablePlugin($plugin, $title, $mode, $script); | ||
| 112 | } | ||
| 113 | |||
| 114 |         foreach ($pluginsToProcess as $plugin) { | ||
| 115 | $this->disablePlugin($plugin); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Check if a plugin is compatible or not. | ||
| 121 | * | ||
| 122 | * @param PluginDescription $plugin | ||
| 123 | * @param $enabledPlugins | ||
| 124 | * @param $title | ||
| 125 | * @param $mode | ||
| 126 | * @param $script | ||
| 127 | * | ||
| 128 | * @return bool | ||
| 129 | */ | ||
| 130 |     protected function isPluginCompatible(PluginDescription $plugin, $enabledPlugins, $title, $mode, $script) { | ||
| 131 | |||
| 132 | // first check for other plugins. | ||
| 133 |         foreach ($plugin->getParents() as $parentPluginId) { | ||
| 134 |             if (!isset($enabledPlugins[$parentPluginId])) { | ||
| 135 | // A parent plugin is missing. Can't enable plugin. | ||
| 136 | return false; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | // Now check for data providers. | ||
| 141 |         foreach ($plugin->getDataProviders() as $dataProvider) { | ||
| 142 | $providerId = $this->dataProviderManager->getCompatibleProviderId($dataProvider, $title, $mode, $script); | ||
| 143 | |||
| 144 |             if (is_null($providerId) || !isset($enabledPlugins[$providerId])) { | ||
| 145 | // Either there are no data providers compatible or the only one compatible | ||
| 146 | return false; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | // If data provider need to check if it was "the chosen one". | ||
| 151 |         if ($plugin->isIsDataProvider()) { | ||
| 152 | $selectedProvider = $this->dataProviderManager->getCompatibleProviderId($plugin->getDataProviderName(), $title, $mode, $script); | ||
| 153 | |||
| 154 |             if ($plugin->getPluginId() != $selectedProvider) { | ||
| 155 | // This data provider wasn't the one selected and therefore the plugin isn't compatible. | ||
| 156 | return false; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | return true; | ||
| 161 | } | ||
| 162 | |||
| 163 | |||
| 164 | /** | ||
| 165 | * Enable a plugin for a certain game mode. | ||
| 166 | * | ||
| 167 | * @param PluginDescription $plugin | ||
| 168 | * @param $title | ||
| 169 | * @param $mode | ||
| 170 | * @param $script | ||
| 171 | */ | ||
| 172 |     protected function enablePlugin(PluginDescription $plugin, $title, $mode, $script) { | ||
| 173 | $plugin->setIsEnabled(true); | ||
| 174 | $pluginService = $this->container->get($plugin->getPluginId()); | ||
| 175 | |||
| 176 | View Code Duplication |         if ($pluginService instanceof StatusAwarePluginInterface && !isset($this->enabledPlugins[$plugin->getPluginId()])) { | |
|  | |||
| 177 | $pluginService->setStatus(true); | ||
| 178 | } | ||
| 179 | |||
| 180 | $this->console->getConsoleOutput() | ||
| 181 |             ->writeln("<info>Plugin <comment>'{$plugin->getPluginId()}'</comment> is enabled with providers :</info>"); | ||
| 182 |         foreach ($plugin->getDataProviders() as $provider) { | ||
| 183 | $this->dataProviderManager->registerPlugin($provider, $plugin->getPluginId(), $title, $mode, $script); | ||
| 184 | } | ||
| 185 | |||
| 186 | $this->enabledPlugins[$plugin->getPluginId()] = $plugin; | ||
| 187 | } | ||
| 188 | |||
| 189 | /** | ||
| 190 | * Disable a plugin. | ||
| 191 | * | ||
| 192 | * @param PluginDescription $plugin | ||
| 193 | * | ||
| 194 | */ | ||
| 195 |     protected function disablePlugin(PluginDescription $plugin) { | ||
| 196 | $plugin->setIsEnabled(false); | ||
| 197 | $pluginService = $this->container->get($plugin->getPluginId()); | ||
| 198 | |||
| 199 |         foreach ($plugin->getDataProviders() as $provider) { | ||
| 200 | $this->dataProviderManager->deletePlugin($provider, $plugin->getPluginId()); | ||
| 201 | } | ||
| 202 | |||
| 203 | View Code Duplication |         if (isset($this->enabledPlugins[$plugin->getPluginId()])) { | |
| 204 | unset($this->enabledPlugins[$plugin->getPluginId()]); | ||
| 205 | |||
| 206 |             if ($pluginService instanceof StatusAwarePluginInterface) { | ||
| 207 | $pluginService->setStatus(true); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | /** | ||
| 213 | * Check if a plugin is enabled or not. | ||
| 214 | * | ||
| 215 | * @param $pluginId | ||
| 216 | * | ||
| 217 | * @return bool | ||
| 218 | */ | ||
| 219 |     public function isPluginEnabled($pluginId) { | ||
| 222 | |||
| 223 | /** | ||
| 224 | * Register a plugin. | ||
| 225 | * | ||
| 226 | * @param string $id The service id of the plugin to register. | ||
| 227 | * @param string[] $dataProviders The data providers it needs to work. | ||
| 228 | * @param string[] $parents The parent plugins. | ||
| 229 | */ | ||
| 230 | 46 |     public function registerPlugin($id, $dataProviders, $parents, $dataProviderName = null) { | |
| 239 | } | ||
| 240 | 
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.