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 | $ExistsProductClass->copyProperties($pc, [ |
||
| 313 | 'id', |
||
| 314 | 'price01_inc_tax', |
||
| 315 | 'price02_inc_tax', |
||
| 316 | 'create_date', |
||
| 317 | 'update_date', |
||
| 318 | 'Creator', |
||
| 319 | ]); |
||
| 320 | $pc = $ExistsProductClass; |
||
| 321 | } |
||
| 322 | } |
||
| 323 | |||
| 324 | // 更新時, チェックを外した場合はPOST内容を破棄してvisibleのみ更新する. |
||
| 325 | 8 | if ($pc->getId() && !$pc->isVisible()) { |
|
| 326 | 1 | $this->entityManager->refresh($pc); |
|
| 327 | 1 | $pc->setVisible(false); |
|
| 328 | 1 | 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 |