Complex classes like ProductClassController 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 ProductClassController, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
35 | class ProductClassController extends AbstractController |
||
36 | { |
||
37 | /** |
||
38 | * @var ProductRepository |
||
39 | */ |
||
40 | protected $productRepository; |
||
41 | |||
42 | /** |
||
43 | * @var ProductClassRepository |
||
44 | */ |
||
45 | protected $productClassRepository; |
||
46 | |||
47 | /** |
||
48 | * @var ClassCategoryRepository |
||
49 | */ |
||
50 | protected $classCategoryRepository; |
||
51 | |||
52 | /** |
||
53 | * @var BaseInfoRepository |
||
54 | */ |
||
55 | protected $baseInfoRepository; |
||
56 | |||
57 | /** |
||
58 | * @var TaxRuleRepository |
||
59 | */ |
||
60 | protected $taxRuleRepository; |
||
61 | |||
62 | /** |
||
63 | * ProductClassController constructor. |
||
64 | * |
||
65 | * @param ProductClassRepository $productClassRepository |
||
66 | * @param ClassCategoryRepository $classCategoryRepository |
||
67 | */ |
||
68 | 13 | public function __construct( |
|
81 | |||
82 | /** |
||
83 | * 商品規格が登録されていなければ新規登録, 登録されていれば更新画面を表示する |
||
84 | * |
||
85 | * @Route("/%eccube_admin_route%/product/product/class/{id}", requirements={"id" = "\d+"}, name="admin_product_product_class") |
||
86 | * @Template("@admin/Product/product_class.twig") |
||
87 | */ |
||
88 | 13 | public function index(Request $request, $id) |
|
176 | |||
177 | /** |
||
178 | * 商品規格を初期化する. |
||
179 | * |
||
180 | * @Route("/%eccube_admin_route%/product/product/class/{id}/clear", requirements={"id" = "\d+"}, name="admin_product_product_class_clear") |
||
181 | */ |
||
182 | public function clearProductClasses(Request $request, Product $Product) |
||
214 | |||
215 | /** |
||
216 | * 規格名1/2から, 商品規格の組み合わせを生成する. |
||
217 | * |
||
218 | * @param ClassName $ClassName1 |
||
219 | * @param ClassName|null $ClassName2 |
||
220 | * |
||
221 | * @return array|ProductClass[] |
||
222 | */ |
||
223 | 12 | protected function createProductClasses(ClassName $ClassName1, ClassName $ClassName2 = null) |
|
251 | |||
252 | /** |
||
253 | * 商品規格の配列をマージする. |
||
254 | * |
||
255 | * @param $ProductClassessForMatrix |
||
256 | * @param $ProductClasses |
||
257 | * |
||
258 | * @return array|ProductClass[] |
||
259 | */ |
||
260 | 11 | protected function mergeProductClassess($ProductClassessForMatrix, $ProductClasses) |
|
286 | |||
287 | /** |
||
288 | * 商品規格を登録, 更新する. |
||
289 | * |
||
290 | * @param Product $Product |
||
291 | * @param array|ProductClass[] $ProductClasses |
||
292 | */ |
||
293 | 8 | protected function saveProductClasses(Product $Product, $ProductClasses = []) |
|
294 | { |
||
295 | 8 | foreach ($ProductClasses as $pc) { |
|
296 | // 新規登録時、チェックを入れていなければ更新しない |
||
297 | 8 | if (!$pc->getId() && !$pc->isVisible()) { |
|
298 | 4 | continue; |
|
299 | } |
||
300 | |||
301 | // 無効から有効にした場合は, 過去の登録情報を検索. |
||
302 | 8 | if (!$pc->getId()) { |
|
303 | /** @var ProductClass $ExistsProductClass */ |
||
304 | 4 | $ExistsProductClass = $this->productClassRepository->findOneBy([ |
|
305 | 4 | 'Product' => $Product, |
|
306 | 4 | 'ClassCategory1' => $pc->getClassCategory1(), |
|
307 | 4 | 'ClassCategory2' => $pc->getClassCategory2(), |
|
308 | ]); |
||
309 | |||
310 | // 過去の登録情報があればその情報を復旧する. |
||
311 | 4 | if ($ExistsProductClass) { |
|
312 | 1 | $ExistsProductClass->copyProperties($pc, [ |
|
313 | 1 | 'id', |
|
314 | 'price01_inc_tax', |
||
315 | 'price02_inc_tax', |
||
316 | 'create_date', |
||
317 | 'update_date', |
||
318 | 'Creator', |
||
319 | ]); |
||
320 | 1 | $pc = $ExistsProductClass; |
|
321 | } |
||
322 | } |
||
323 | |||
324 | // 更新時, チェックを外した場合はPOST内容を破棄してvisibleのみ更新する. |
||
325 | 8 | if ($pc->getId() && !$pc->isVisible()) { |
|
326 | 2 | $this->entityManager->refresh($pc); |
|
327 | 2 | $pc->setVisible(false); |
|
328 | 2 | continue; |
|
329 | } |
||
330 | |||
331 | 8 | $pc->setProduct($Product); |
|
332 | 8 | $this->entityManager->persist($pc); |
|
333 | |||
334 | // 在庫の更新 |
||
335 | 8 | $ProductStock = $pc->getProductStock(); |
|
336 | 8 | if (!$ProductStock) { |
|
337 | 4 | $ProductStock = new ProductStock(); |
|
338 | 4 | $ProductStock->setProductClass($pc); |
|
339 | 4 | $this->entityManager->persist($ProductStock); |
|
340 | } |
||
341 | 8 | $ProductStock->setStock($pc->isStockUnlimited() ? null : $pc->getStock()); |
|
342 | |||
343 | 8 | if ($this->baseInfoRepository->get()->isOptionProductTaxRule()) { |
|
344 | 6 | $rate = $pc->getTaxRate(); |
|
345 | 6 | $TaxRule = $pc->getTaxRule(); |
|
346 | 6 | if (is_numeric($rate)) { |
|
347 | 5 | if ($TaxRule) { |
|
348 | $TaxRule->setTaxRate($rate); |
||
349 | } else { |
||
350 | // 初期税率設定の計算方法を設定する |
||
351 | 5 | $RoundingType = $this->taxRuleRepository->find(TaxRule::DEFAULT_TAX_RULE_ID) |
|
352 | 5 | ->getRoundingType(); |
|
353 | |||
354 | 5 | $TaxRule = new TaxRule(); |
|
355 | 5 | $TaxRule->setProduct($Product); |
|
356 | 5 | $TaxRule->setProductClass($pc); |
|
357 | 5 | $TaxRule->setTaxRate($rate); |
|
358 | 5 | $TaxRule->setRoundingType($RoundingType); |
|
359 | 5 | $TaxRule->setTaxAdjust(0); |
|
360 | 5 | $TaxRule->setApplyDate(new \DateTime()); |
|
361 | 5 | $this->entityManager->persist($TaxRule); |
|
362 | } |
||
363 | } else { |
||
364 | 4 | if ($TaxRule) { |
|
365 | $this->taxRuleRepository->delete($TaxRule); |
||
366 | 8 | $pc->setTaxRule(null); |
|
367 | } |
||
368 | } |
||
369 | } |
||
370 | } |
||
371 | |||
372 | // デフォルト規格を非表示にする. |
||
373 | 8 | $DefaultProductClass = $this->productClassRepository->findOneBy([ |
|
374 | 8 | 'Product' => $Product, |
|
375 | 'ClassCategory1' => null, |
||
376 | 'ClassCategory2' => null, |
||
377 | ]); |
||
378 | 8 | $DefaultProductClass->setVisible(false); |
|
379 | |||
380 | 8 | $this->entityManager->flush(); |
|
381 | } |
||
382 | |||
383 | /** |
||
384 | * 商品規格登録フォームを生成する. |
||
385 | * |
||
386 | * @param array $ProductClasses |
||
387 | * @param ClassName|null $ClassName1 |
||
388 | * @param ClassName|null $ClassName2 |
||
389 | * @param array $options |
||
390 | * |
||
391 | * @return \Symfony\Component\Form\FormInterface |
||
392 | */ |
||
393 | 13 | protected function createMatrixForm( |
|
408 | |||
409 | /** |
||
410 | * 商品を取得する. |
||
411 | * 商品規格はvisible=trueのものだけを取得し, 規格分類はsort_no=DESCでソートされている. |
||
412 | * |
||
413 | * @param $id |
||
414 | * |
||
415 | * @return Product|null |
||
416 | * |
||
417 | * @throws \Doctrine\ORM\NonUniqueResultException |
||
418 | */ |
||
419 | 13 | protected function findProduct($id) |
|
439 | } |
||
440 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.