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 PluginController 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 PluginController, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
58 | class PluginController extends AbstractController |
||
59 | { |
||
60 | /** |
||
61 | * @Inject("orm.em") |
||
62 | * @var EntityManager |
||
63 | */ |
||
64 | protected $entityManager; |
||
65 | |||
66 | /** |
||
67 | * @Inject("monolog") |
||
68 | * @var Logger |
||
69 | */ |
||
70 | protected $logger; |
||
71 | |||
72 | /** |
||
73 | * @Inject(PluginEventHandlerRepository::class) |
||
74 | * @var PluginEventHandlerRepository |
||
75 | */ |
||
76 | protected $pluginEventHandlerRepository; |
||
77 | |||
78 | /** |
||
79 | * @Inject(PluginService::class) |
||
80 | * @var PluginService |
||
81 | */ |
||
82 | protected $pluginService; |
||
83 | |||
84 | /** |
||
85 | * @Inject("config") |
||
86 | * @var array |
||
87 | */ |
||
88 | protected $appConfig; |
||
89 | |||
90 | /** |
||
91 | * @Inject(BaseInfo::class) |
||
92 | * @var BaseInfo |
||
93 | */ |
||
94 | protected $BaseInfo; |
||
95 | |||
96 | /** |
||
97 | * @Inject("form.factory") |
||
98 | * @var FormFactory |
||
99 | */ |
||
100 | protected $formFactory; |
||
101 | |||
102 | /** |
||
103 | * @Inject(PluginRepository::class) |
||
104 | * @var PluginRepository |
||
105 | */ |
||
106 | protected $pluginRepository; |
||
107 | |||
108 | |||
109 | /** |
||
110 | * インストール済プラグイン画面 |
||
111 | * |
||
112 | * @Route("/{_admin}/store/plugin", name="admin_store_plugin") |
||
113 | * @Template("Store/plugin.twig") |
||
114 | */ |
||
115 | public function index(Application $app, Request $request) |
||
116 | { |
||
117 | $pluginForms = array(); |
||
118 | $configPages = array(); |
||
119 | |||
120 | $Plugins = $this->pluginRepository->findBy(array(), array('code' => 'ASC')); |
||
121 | |||
122 | // ファイル設置プラグインの取得. |
||
123 | $unregisterdPlugins = $this->getUnregisteredPlugins($Plugins, $app); |
||
124 | $unregisterdPluginsConfigPages = array(); |
||
125 | foreach ($unregisterdPlugins as $unregisterdPlugin) { |
||
126 | try { |
||
127 | $code = $unregisterdPlugin['code']; |
||
128 | // プラグイン用設定画面があれば表示(プラグイン用のサービスプロバイダーに定義されているか) |
||
129 | $unregisterdPluginsConfigPages[$code] = $app->url('plugin_'.$code.'_config'); |
||
130 | } catch (RouteNotFoundException $e) { |
||
131 | // プラグインで設定画面のルートが定義されていない場合は無視 |
||
132 | } |
||
133 | } |
||
134 | |||
135 | $officialPlugins = array(); |
||
136 | $unofficialPlugins = array(); |
||
137 | |||
138 | foreach ($Plugins as $Plugin) { |
||
139 | $form = $this->formFactory |
||
140 | ->createNamedBuilder( |
||
141 | 'form'.$Plugin->getId(), |
||
142 | PluginManagementType::class, |
||
143 | null, |
||
144 | array( |
||
145 | 'plugin_id' => $Plugin->getId(), |
||
146 | ) |
||
147 | ) |
||
148 | ->getForm(); |
||
149 | $pluginForms[$Plugin->getId()] = $form->createView(); |
||
150 | |||
151 | try { |
||
152 | // プラグイン用設定画面があれば表示(プラグイン用のサービスプロバイダーに定義されているか) |
||
153 | $configPages[$Plugin->getCode()] = $app->url('plugin_'.$Plugin->getCode().'_config'); |
||
154 | } catch (\Exception $e) { |
||
155 | // プラグインで設定画面のルートが定義されていない場合は無視 |
||
156 | } |
||
157 | |||
158 | if ($Plugin->getSource() == 0) { |
||
159 | // 商品IDが設定されていない場合、非公式プラグイン |
||
160 | $unofficialPlugins[] = $Plugin; |
||
161 | } else { |
||
162 | $officialPlugins[] = $Plugin; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | // Todo: Need new authentication mechanism |
||
167 | // オーナーズストアからダウンロード可能プラグイン情報を取得 |
||
168 | $authKey = $this->BaseInfo->getAuthenticationKey(); |
||
169 | // if (!is_null($authKey)) { |
||
170 | |||
171 | // オーナーズストア通信 |
||
172 | $url = $this->appConfig['owners_store_url'].'?method=list'; |
||
173 | list($json, $info) = $this->getRequestApi($request, $authKey, $url, $app); |
||
174 | |||
175 | $officialPluginsDetail = []; |
||
176 | if ($json) { |
||
177 | // 接続成功時 |
||
178 | $data = json_decode($json, true); |
||
179 | if (isset($data['success'])) { |
||
180 | $success = $data['success']; |
||
181 | if ($success == '1') { |
||
182 | foreach ($data['item'] as $item) { |
||
183 | foreach ($officialPlugins as $key => $plugin) { |
||
184 | if ($plugin->getSource() == $item['product_id']) { |
||
185 | $officialPluginsDetail[$key] = $item; |
||
186 | $officialPluginsDetail[$key]['update_status'] = 0; |
||
187 | if ($plugin->getVersion() != $item['version']) { |
||
188 | $officialPluginsDetail[$key]['update_status'] = 1; |
||
189 | } |
||
190 | } |
||
191 | } |
||
192 | } |
||
193 | } |
||
194 | } |
||
195 | } |
||
196 | |||
197 | return [ |
||
198 | 'plugin_forms' => $pluginForms, |
||
199 | 'officialPlugins' => $officialPlugins, |
||
200 | 'unofficialPlugins' => $unofficialPlugins, |
||
201 | 'configPages' => $configPages, |
||
202 | 'unregisterdPlugins' => $unregisterdPlugins, |
||
203 | 'unregisterdPluginsConfigPages' => $unregisterdPluginsConfigPages, |
||
204 | 'officialPluginsDetail' => $officialPluginsDetail, |
||
205 | ]; |
||
206 | } |
||
207 | |||
208 | /** |
||
209 | * インストール済プラグインからのアップデート |
||
210 | * |
||
211 | * @Method("POST") |
||
212 | * @Route("/{_admin}/store/plugin/{id}/update", requirements={"id" = "\d+"}, name="admin_store_plugin_update") |
||
213 | */ |
||
214 | public function update(Application $app, Request $request, Plugin $Plugin) |
||
215 | { |
||
216 | $form = $this->formFactory |
||
217 | ->createNamedBuilder( |
||
218 | 'form'.$Plugin->getId(), |
||
219 | PluginManagementType::class, |
||
220 | null, |
||
221 | array( |
||
222 | 'plugin_id' => null, // placeHolder |
||
223 | ) |
||
224 | ) |
||
225 | ->getForm(); |
||
226 | |||
227 | $message = ''; |
||
228 | |||
229 | if ('POST' === $request->getMethod()) { |
||
230 | $form->handleRequest($request); |
||
231 | |||
232 | if ($form->isValid()) { |
||
233 | |||
234 | $tmpDir = null; |
||
235 | try { |
||
236 | |||
237 | $formFile = $form['plugin_archive']->getData(); |
||
238 | |||
239 | $tmpDir = $this->pluginService->createTempDir(); |
||
240 | $tmpFile = sha1(Str::random(32)).'.'.$formFile->getClientOriginalExtension(); |
||
241 | |||
242 | $formFile->move($tmpDir, $tmpFile); |
||
243 | $this->pluginService->update($Plugin, $tmpDir.'/'.$tmpFile); |
||
244 | |||
245 | $fs = new Filesystem(); |
||
246 | $fs->remove($tmpDir); |
||
247 | |||
248 | $app->addSuccess('admin.plugin.update.complete', 'admin'); |
||
249 | |||
250 | return $app->redirect($app->url('admin_store_plugin')); |
||
251 | |||
252 | } catch (PluginException $e) { |
||
253 | if (!empty($tmpDir) && file_exists($tmpDir)) { |
||
254 | $fs = new Filesystem(); |
||
255 | $fs->remove($tmpDir); |
||
256 | } |
||
257 | $message = $e->getMessage(); |
||
258 | } |
||
259 | } else { |
||
260 | $errors = $form->getErrors(true); |
||
261 | foreach ($errors as $error) { |
||
262 | $message = $error->getMessage(); |
||
263 | } |
||
264 | |||
265 | } |
||
266 | |||
267 | } |
||
268 | |||
269 | $app->addError($message, 'admin'); |
||
270 | |||
271 | return $app->redirect($app->url('admin_store_plugin')); |
||
272 | } |
||
273 | |||
274 | |||
275 | /** |
||
276 | * 対象のプラグインを有効にします。 |
||
277 | * |
||
278 | * @Method("PUT") |
||
279 | * @Route("/{_admin}/store/plugin/{id}/enable", requirements={"id" = "\d+"}, name="admin_store_plugin_enable") |
||
280 | */ |
||
281 | View Code Duplication | public function enable(Application $app, Plugin $Plugin) |
|
282 | { |
||
283 | $this->isTokenValid($app); |
||
284 | |||
285 | if ($Plugin->getEnable() == Constant::ENABLED) { |
||
286 | $app->addError('admin.plugin.already.enable', 'admin'); |
||
287 | } else { |
||
288 | $this->pluginService->enable($Plugin); |
||
289 | $app->addSuccess('admin.plugin.enable.complete', 'admin'); |
||
290 | } |
||
291 | |||
292 | return $app->redirect($app->url('admin_store_plugin')); |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * 対象のプラグインを無効にします。 |
||
297 | * |
||
298 | * @Method("PUT") |
||
299 | * @Route("/{_admin}/store/plugin/{id}/disable", requirements={"id" = "\d+"}, name="admin_store_plugin_disable") |
||
300 | */ |
||
301 | View Code Duplication | public function disable(Application $app, Plugin $Plugin) |
|
302 | { |
||
303 | $this->isTokenValid($app); |
||
304 | |||
305 | if ($Plugin->getEnable() == Constant::ENABLED) { |
||
306 | $this->pluginService->disable($Plugin); |
||
307 | $app->addSuccess('admin.plugin.disable.complete', 'admin'); |
||
308 | } else { |
||
309 | $app->addError('admin.plugin.already.disable', 'admin'); |
||
310 | } |
||
311 | |||
312 | return $app->redirect($app->url('admin_store_plugin')); |
||
313 | } |
||
314 | |||
315 | |||
316 | /** |
||
317 | * 対象のプラグインを削除します。 |
||
318 | * |
||
319 | * @Method("DELETE") |
||
320 | * @Route("/{_admin}/store/plugin/{id}/uninstall", requirements={"id" = "\d+"}, name="admin_store_plugin_uninstall") |
||
321 | */ |
||
322 | public function uninstall(Application $app, Plugin $Plugin) |
||
323 | { |
||
324 | $this->isTokenValid($app); |
||
325 | |||
326 | $this->pluginService->uninstall($Plugin); |
||
327 | |||
328 | $app->addSuccess('admin.plugin.uninstall.complete', 'admin'); |
||
329 | |||
330 | return $app->redirect($app->url('admin_store_plugin')); |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * @Route("/{_admin}/store/plugin/handler", name="admin_store_plugin_handler") |
||
335 | * @Template("Store/plugin_handler.twig") |
||
336 | */ |
||
337 | public function handler(Application $app) |
||
338 | { |
||
339 | $handlers = $this->pluginEventHandlerRepository->getHandlers(); |
||
340 | |||
341 | // 一次元配列からイベント毎の二次元配列に変換する |
||
342 | $HandlersPerEvent = array(); |
||
343 | foreach ($handlers as $handler) { |
||
344 | $HandlersPerEvent[$handler->getEvent()][$handler->getHandlerType()][] = $handler; |
||
345 | } |
||
346 | |||
347 | return [ |
||
348 | 'handlersPerEvent' => $HandlersPerEvent, |
||
349 | ]; |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * @Route("/{_admin}/store/plugin/handler_up/{id}", requirements={"id" = "\d+"}, name="admin_store_plugin_handler_up") |
||
354 | */ |
||
355 | View Code Duplication | public function handler_up(Application $app, PluginEventHandler $Handler) |
|
362 | |||
363 | /** |
||
364 | * @Route("/{_admin}/store/plugin/handler_down/{id}", requirements={"id" = "\d+"}, name="admin_store_plugin_handler_down") |
||
365 | */ |
||
366 | View Code Duplication | public function handler_down(Application $app, PluginEventHandler $Handler) |
|
367 | { |
||
368 | $repo = $this->pluginEventHandlerRepository; |
||
373 | |||
374 | /** |
||
375 | * プラグインファイルアップロード画面 |
||
376 | * |
||
377 | * @Route("/{_admin}/store/plugin/install", name="admin_store_plugin_install") |
||
378 | * @Template("Store/plugin_install.twig") |
||
379 | */ |
||
380 | public function install(Application $app, Request $request) |
||
440 | |||
441 | /** |
||
442 | * オーナーズストアプラグインインストール画面 |
||
443 | * |
||
444 | * @Route("/{_admin}/store/plugin/owners_install", name="admin_store_plugin_owners_install") |
||
445 | * @Template("Store/plugin_owners_install.twig") |
||
446 | */ |
||
447 | public function ownersInstall(Application $app, Request $request) |
||
448 | { |
||
449 | // オーナーズストアからダウンロード可能プラグイン情報を取得 |
||
450 | $authKey = $this->BaseInfo->getAuthenticationKey(); |
||
451 | $authResult = true; |
||
452 | $success = 0; |
||
453 | $items = array(); |
||
454 | $promotionItems = array(); |
||
455 | $message = ''; |
||
456 | if (!is_null($authKey)) { |
||
457 | |||
458 | // オーナーズストア通信 |
||
459 | $url = $this->appConfig['owners_store_url'].'?method=list'; |
||
460 | list($json, $info) = $this->getRequestApi($request, $authKey, $url, $app); |
||
461 | |||
462 | if ($json === false) { |
||
463 | // 接続失敗時 |
||
464 | $success = 0; |
||
465 | |||
466 | $message = $this->getResponseErrorMessage($info); |
||
467 | |||
468 | } else { |
||
469 | // 接続成功時 |
||
470 | |||
471 | $data = json_decode($json, true); |
||
472 | |||
473 | if (isset($data['success'])) { |
||
474 | $success = $data['success']; |
||
475 | if ($success == '1') { |
||
476 | $items = array(); |
||
477 | |||
478 | // 既にインストールされているかどうか確認 |
||
479 | $Plugins = $this->pluginRepository->findAll(); |
||
480 | $status = false; |
||
481 | // update_status 1 : 未インストール、2 : インストール済、 3 : 更新あり、4 : 有料購入 |
||
482 | foreach ($data['item'] as $item) { |
||
483 | foreach ($Plugins as $plugin) { |
||
484 | if ($plugin->getSource() == $item['product_id']) { |
||
485 | if ($plugin->getVersion() == $item['version']) { |
||
486 | // バージョンが同じ |
||
487 | $item['update_status'] = 2; |
||
488 | } else { |
||
489 | // バージョンが異なる |
||
490 | $item['update_status'] = 3; |
||
491 | } |
||
492 | $items[] = $item; |
||
493 | $status = true; |
||
494 | break; |
||
495 | } |
||
496 | } |
||
497 | if (!$status) { |
||
498 | // 未インストール |
||
499 | $item['update_status'] = 1; |
||
500 | $items[] = $item; |
||
501 | } |
||
502 | $status = false; |
||
503 | } |
||
504 | |||
505 | // EC-CUBEのバージョンチェック |
||
506 | // 参照渡しをして値を追加 |
||
507 | foreach ($items as &$item) { |
||
508 | if (in_array(Constant::VERSION, $item['eccube_version'])) { |
||
509 | // 対象バージョン |
||
510 | $item['version_check'] = 1; |
||
511 | } else { |
||
512 | // 未対象バージョン |
||
513 | $item['version_check'] = 0; |
||
514 | } |
||
515 | if ($item['price'] != '0' && $item['purchased'] == '0') { |
||
516 | // 有料商品で未購入 |
||
517 | $item['update_status'] = 4; |
||
518 | } |
||
519 | } |
||
520 | unset($item); |
||
521 | |||
522 | // promotionアイテム |
||
523 | $i = 0; |
||
524 | View Code Duplication | foreach ($items as $item) { |
|
525 | if ($item['promotion'] == 1) { |
||
526 | $promotionItems[] = $item; |
||
527 | unset($items[$i]); |
||
528 | } |
||
529 | $i++; |
||
530 | } |
||
531 | |||
532 | } else { |
||
533 | $message = $data['error_code'].' : '.$data['error_message']; |
||
534 | } |
||
535 | } else { |
||
536 | $success = 0; |
||
537 | $message = "EC-CUBEオーナーズストアにエラーが発生しています。"; |
||
538 | } |
||
539 | } |
||
540 | |||
541 | } else { |
||
542 | $authResult = false; |
||
543 | } |
||
544 | |||
545 | return [ |
||
546 | 'authResult' => $authResult, |
||
547 | 'success' => $success, |
||
548 | 'items' => $items, |
||
549 | 'promotionItems' => $promotionItems, |
||
550 | 'message' => $message, |
||
551 | ]; |
||
552 | } |
||
553 | |||
554 | /** |
||
555 | * オーナーズブラグインインストール、アップデート |
||
556 | * |
||
557 | * @Route("/{_admin}/store/plugin/upgrade/{action}/{id}/{version}", requirements={"id" = "\d+"}, name="admin_store_plugin_upgrade") |
||
558 | */ |
||
559 | public function upgrade(Application $app, Request $request, $action, $id, $version) |
||
651 | |||
652 | /** |
||
653 | * 認証キー設定画面 |
||
654 | * |
||
655 | * @Route("/{_admin}/store/plugin/authentication_setting", name="admin_store_authentication_setting") |
||
656 | * @Template("Store/authentication_setting.twig") |
||
657 | */ |
||
658 | public function authenticationSetting(Application $app, Request $request) |
||
688 | |||
689 | |||
690 | /** |
||
691 | * APIリクエスト処理 |
||
692 | * |
||
693 | * @param Request $request |
||
694 | * @param $authKey |
||
695 | * @param string $url |
||
696 | * @param Application $app |
||
697 | * @return array |
||
698 | */ |
||
699 | private function getRequestApi(Request $request, $authKey, $url, $app) |
||
729 | |||
730 | /** |
||
731 | * レスポンスのチェック |
||
732 | * |
||
733 | * @param $info |
||
734 | * @return string |
||
735 | */ |
||
736 | View Code Duplication | private function getResponseErrorMessage($info) |
|
750 | |||
751 | |||
752 | /** |
||
753 | * フォルダ設置のみのプラグインを取得する. |
||
754 | * |
||
755 | * @param array $plugins |
||
756 | * @param Application $app |
||
757 | * @return array |
||
758 | */ |
||
759 | protected function getUnregisteredPlugins(array $plugins, \Eccube\Application $app) |
||
795 | } |
||
796 |