Complex classes like ProductContext 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 ProductContext, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
49 | final class ProductContext implements Context |
||
50 | { |
||
51 | /** |
||
52 | * @var SharedStorageInterface |
||
53 | */ |
||
54 | private $sharedStorage; |
||
55 | |||
56 | /** |
||
57 | * @var ProductRepositoryInterface |
||
58 | */ |
||
59 | private $productRepository; |
||
60 | |||
61 | /** |
||
62 | * @var ProductFactoryInterface |
||
63 | */ |
||
64 | private $productFactory; |
||
65 | |||
66 | /** |
||
67 | * @var FactoryInterface |
||
68 | */ |
||
69 | private $productTranslationFactory; |
||
70 | |||
71 | /** |
||
72 | * @var FactoryInterface |
||
73 | */ |
||
74 | private $productVariantFactory; |
||
75 | |||
76 | /** |
||
77 | * @var FactoryInterface |
||
78 | */ |
||
79 | private $productVariantTranslationFactory; |
||
80 | |||
81 | /** |
||
82 | * @var FactoryInterface |
||
83 | */ |
||
84 | private $channelPricingFactory; |
||
85 | |||
86 | /** |
||
87 | * @var FactoryInterface |
||
88 | */ |
||
89 | private $productOptionFactory; |
||
90 | |||
91 | /** |
||
92 | * @var FactoryInterface |
||
93 | */ |
||
94 | private $productOptionValueFactory; |
||
95 | |||
96 | /** |
||
97 | * @var FactoryInterface |
||
98 | */ |
||
99 | private $productImageFactory; |
||
100 | |||
101 | /** |
||
102 | * @var ObjectManager |
||
103 | */ |
||
104 | private $objectManager; |
||
105 | |||
106 | /** |
||
107 | * @var ProductVariantGeneratorInterface |
||
108 | */ |
||
109 | private $productVariantGenerator; |
||
110 | |||
111 | /** |
||
112 | * @var ProductVariantResolverInterface |
||
113 | */ |
||
114 | private $defaultVariantResolver; |
||
115 | |||
116 | /** |
||
117 | * @var ImageUploaderInterface |
||
118 | */ |
||
119 | private $imageUploader; |
||
120 | |||
121 | /** |
||
122 | * @var SlugGeneratorInterface |
||
123 | */ |
||
124 | private $slugGenerator; |
||
125 | |||
126 | /** |
||
127 | * @var array |
||
128 | */ |
||
129 | private $minkParameters; |
||
130 | |||
131 | /** |
||
132 | * @param SharedStorageInterface $sharedStorage |
||
133 | * @param ProductRepositoryInterface $productRepository |
||
134 | * @param ProductFactoryInterface $productFactory |
||
135 | * @param FactoryInterface $productTranslationFactory |
||
136 | * @param FactoryInterface $productVariantFactory |
||
137 | * @param FactoryInterface $productVariantTranslationFactory |
||
138 | * @param FactoryInterface $channelPricingFactory |
||
139 | * @param FactoryInterface $productOptionFactory |
||
140 | * @param FactoryInterface $productOptionValueFactory |
||
141 | * @param FactoryInterface $productImageFactory |
||
142 | * @param ObjectManager $objectManager |
||
143 | * @param ProductVariantGeneratorInterface $productVariantGenerator |
||
144 | * @param ProductVariantResolverInterface $defaultVariantResolver |
||
145 | * @param ImageUploaderInterface $imageUploader |
||
146 | * @param SlugGeneratorInterface $slugGenerator |
||
147 | * @param array $minkParameters |
||
148 | */ |
||
149 | public function __construct( |
||
184 | |||
185 | /** |
||
186 | * @Given the store has a product :productName |
||
187 | * @Given the store has a :productName product |
||
188 | * @Given I added a product :productName |
||
189 | * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+")$/ |
||
190 | * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") in ("[^"]+" channel)$/ |
||
191 | */ |
||
192 | public function storeHasAProductPricedAt($productName, $price = 100, ChannelInterface $channel = null) |
||
198 | |||
199 | /** |
||
200 | * @Given /^(this product) is(?:| also) priced at ("[^"]+") in ("[^"]+" channel)$/ |
||
201 | */ |
||
202 | public function thisProductIsAlsoPricedAtInChannel(ProductInterface $product, $price, ChannelInterface $channel) |
||
212 | |||
213 | /** |
||
214 | * @Given /^(this product) is(?:| also) available in ("[^"]+" channel)$/ |
||
215 | */ |
||
216 | public function thisProductIsAlsoAvailableInChannel(ProductInterface $product, ChannelInterface $channel): void |
||
220 | |||
221 | /** |
||
222 | * @Given the store( also) has a product :productName with code :code |
||
223 | * @Given the store( also) has a product :productName with code :code, created at :date |
||
224 | */ |
||
225 | public function storeHasProductWithCode($productName, $code, $date = 'now') |
||
233 | |||
234 | /** |
||
235 | * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") available in (channel "[^"]+") and (channel "[^"]+")$/ |
||
236 | */ |
||
237 | public function storeHasAProductPricedAtAvailableInChannels($productName, $price = 100, ...$channels) |
||
252 | |||
253 | /** |
||
254 | * @Given /^(this product) is named "([^"]+)" (in the "([^"]+)" locale)$/ |
||
255 | * @Given /^the (product "[^"]+") is named "([^"]+)" (in the "([^"]+)" locale)$/ |
||
256 | */ |
||
257 | public function thisProductIsNamedIn(ProductInterface $product, $name, $locale) |
||
263 | |||
264 | /** |
||
265 | * @Given /^the store has a product named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/ |
||
266 | */ |
||
267 | public function theStoreHasProductNamedInAndIn($firstName, $firstLocale, $secondName, $secondLocale) |
||
278 | |||
279 | /** |
||
280 | * @Given /^the store has(?:| a| an) "([^"]+)" configurable product$/ |
||
281 | * @Given /^the store has(?:| a| an) "([^"]+)" configurable product with "([^"]+)" slug$/ |
||
282 | */ |
||
283 | public function storeHasAConfigurableProduct($productName, $slug = null) |
||
309 | |||
310 | /** |
||
311 | * @Given the store has( also) :firstProductName and :secondProductName products |
||
312 | * @Given the store has( also) :firstProductName, :secondProductName and :thirdProductName products |
||
313 | * @Given the store has( also) :firstProductName, :secondProductName, :thirdProductName and :fourthProductName products |
||
314 | */ |
||
315 | public function theStoreHasProducts(...$productsNames) |
||
321 | |||
322 | /** |
||
323 | * @Given /^(this channel) has "([^"]+)", "([^"]+)", "([^"]+)" and "([^"]+)" products$/ |
||
324 | */ |
||
325 | public function thisChannelHasProducts(ChannelInterface $channel, ...$productsNames) |
||
333 | |||
334 | /** |
||
335 | * @Given /^the (product "[^"]+") has(?:| a) "([^"]+)" variant priced at ("[^"]+")$/ |
||
336 | * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+")$/ |
||
337 | * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") in ("([^"]+)" channel)$/ |
||
338 | */ |
||
339 | public function theProductHasVariantPricedAt( |
||
353 | |||
354 | /** |
||
355 | * @Given /^the (product "[^"]+") has(?:| a| an) "([^"]+)" variant$/ |
||
356 | * @Given /^(this product) has(?:| a| an) "([^"]+)" variant$/ |
||
357 | * @Given /^(this product) has "([^"]+)", "([^"]+)" and "([^"]+)" variants$/ |
||
358 | */ |
||
359 | public function theProductHasVariants(ProductInterface $product, ...$variantNames) |
||
373 | |||
374 | /** |
||
375 | * @Given /^the (product "[^"]+")(?:| also) has a nameless variant with code "([^"]+)"$/ |
||
376 | * @Given /^(this product)(?:| also) has a nameless variant with code "([^"]+)"$/ |
||
377 | * @Given /^(it)(?:| also) has a nameless variant with code "([^"]+)"$/ |
||
378 | */ |
||
379 | public function theProductHasNamelessVariantWithCode(ProductInterface $product, $variantCode) |
||
385 | |||
386 | /** |
||
387 | * @Given /^the (product "[^"]+")(?:| also) has(?:| a| an) "([^"]+)" variant with code "([^"]+)"$/ |
||
388 | * @Given /^(this product)(?:| also) has(?:| a| an) "([^"]+)" variant with code "([^"]+)"$/ |
||
389 | * @Given /^(it)(?:| also) has(?:| a| an) "([^"]+)" variant with code "([^"]+)"$/ |
||
390 | */ |
||
391 | public function theProductHasVariantWithCode(ProductInterface $product, $variantName, $variantCode) |
||
397 | |||
398 | /** |
||
399 | * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") which does not require shipping$/ |
||
400 | */ |
||
401 | public function theProductHasVariantWhichDoesNotRequireShipping( |
||
416 | |||
417 | /** |
||
418 | * @Given /^the (product "[^"]+") has(?:| also)(?:| a| an) "([^"]+)" variant$/ |
||
419 | * @Given /^the (product "[^"]+") has(?:| also)(?:| a| an) "([^"]+)" variant at position ([^"]+)$/ |
||
420 | * @Given /^(this product) has(?:| also)(?:| a| an) "([^"]+)" variant at position ([^"]+)$/ |
||
421 | */ |
||
422 | public function theProductHasVariantAtPosition( |
||
436 | |||
437 | /** |
||
438 | * @Given /^(this variant) is also priced at ("[^"]+") in ("([^"]+)" channel)$/ |
||
439 | */ |
||
440 | public function thisVariantIsAlsoPricedAtInChannel(ProductVariantInterface $productVariant, $price, ChannelInterface $channel) |
||
449 | |||
450 | /** |
||
451 | * @Given /^(it|this product) has(?:| also) variant named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/ |
||
452 | */ |
||
453 | public function itHasVariantNamedInAndIn(ProductInterface $product, $firstName, $firstLocale, $secondName, $secondLocale) |
||
470 | |||
471 | /** |
||
472 | * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") identified by "([^"]+)"$/ |
||
473 | */ |
||
474 | public function theProductHasVariantPricedAtIdentifiedBy( |
||
482 | |||
483 | /** |
||
484 | * @Given /^(this product) only variant was renamed to "([^"]+)"$/ |
||
485 | */ |
||
486 | public function productOnlyVariantWasRenamed(ProductInterface $product, $variantName) |
||
496 | |||
497 | /** |
||
498 | * @Given /^there is product "([^"]+)" available in ((?:this|that|"[^"]+") channel)$/ |
||
499 | * @Given /^the store has a product "([^"]+)" available in ("([^"]+)" channel)$/ |
||
500 | */ |
||
501 | public function thereIsProductAvailableInGivenChannel($productName, ChannelInterface $channel) |
||
507 | |||
508 | /** |
||
509 | * @Given /^([^"]+) belongs to ("[^"]+" tax category)$/ |
||
510 | */ |
||
511 | public function productBelongsToTaxCategory(ProductInterface $product, TaxCategoryInterface $taxCategory) |
||
519 | |||
520 | /** |
||
521 | * @Given /^(it) comes in the following variations:$/ |
||
522 | */ |
||
523 | public function itComesInTheFollowingVariations(ProductInterface $product, TableNode $table) |
||
544 | |||
545 | /** |
||
546 | * @Given /^("[^"]+" variant of product "[^"]+") belongs to ("[^"]+" tax category)$/ |
||
547 | */ |
||
548 | public function productVariantBelongsToTaxCategory( |
||
557 | |||
558 | /** |
||
559 | * @Given /^(this product) has option "([^"]+)" with values "([^"]+)" and "([^"]+)"$/ |
||
560 | * @Given /^(this product) has option "([^"]+)" with values "([^"]+)", "([^"]+)" and "([^"]+)"$/ |
||
561 | */ |
||
562 | public function thisProductHasOptionWithValues(ProductInterface $product, $optionName, ...$values) |
||
583 | |||
584 | /** |
||
585 | * @Given /^there (?:is|are) (\d+) unit(?:|s) of (product "([^"]+)") available in the inventory$/ |
||
586 | */ |
||
587 | public function thereIsQuantityOfProducts($quantity, ProductInterface $product) |
||
595 | |||
596 | /** |
||
597 | * @Given /^the (product "([^"]+)") is out of stock$/ |
||
598 | */ |
||
599 | public function theProductIsOutOfStock(ProductInterface $product) |
||
608 | |||
609 | /** |
||
610 | * @When other customer has bought :quantity :product products by this time |
||
611 | */ |
||
612 | public function otherCustomerHasBoughtProductsByThisTime($quantity, ProductInterface $product) |
||
620 | |||
621 | /** |
||
622 | * @Given /^(this product) is tracked by the inventory$/ |
||
623 | * @Given /^(?:|the )("[^"]+" product) is(?:| also) tracked by the inventory$/ |
||
624 | */ |
||
625 | public function thisProductIsTrackedByTheInventory(ProductInterface $product) |
||
633 | |||
634 | /** |
||
635 | * @Given /^(this product) is available in "([^"]+)" ([^"]+) priced at ("[^"]+")$/ |
||
636 | */ |
||
637 | public function thisProductIsAvailableInSize(ProductInterface $product, $optionValueName, $optionName, $price) |
||
652 | |||
653 | /** |
||
654 | * @Given the :product product's :optionValueName size belongs to :shippingCategory shipping category |
||
655 | */ |
||
656 | public function thisProductSizeBelongsToShippingCategory(ProductInterface $product, $optionValueName, ShippingCategoryInterface $shippingCategory) |
||
669 | |||
670 | /** |
||
671 | * @Given /^(this product) has (this product option)$/ |
||
672 | * @Given /^(this product) has (?:a|an) ("[^"]+" option)$/ |
||
673 | */ |
||
674 | public function thisProductHasThisProductOption(ProductInterface $product, ProductOptionInterface $option) |
||
680 | |||
681 | /** |
||
682 | * @Given /^(this product) has all possible variants$/ |
||
683 | */ |
||
684 | public function thisProductHasAllPossibleVariants(ProductInterface $product) |
||
713 | |||
714 | /** |
||
715 | * @Given /^there are ([^"]+) units of ("[^"]+" variant of product "[^"]+") available in the inventory$/ |
||
716 | */ |
||
717 | public function thereAreItemsOfProductInVariantAvailableInTheInventory($quantity, ProductVariantInterface $productVariant) |
||
724 | |||
725 | /** |
||
726 | * @Given /^the ("[^"]+" product variant) is tracked by the inventory$/ |
||
727 | */ |
||
728 | public function theProductVariantIsTrackedByTheInventory(ProductVariantInterface $productVariant) |
||
734 | |||
735 | /** |
||
736 | * @Given /^(this product)'s price is ("[^"]+")$/ |
||
737 | * @Given /^the (product "[^"]+") changed its price to ("[^"]+")$/ |
||
738 | * @Given /^(this product) price has been changed to ("[^"]+")$/ |
||
739 | */ |
||
740 | public function theProductChangedItsPriceTo(ProductInterface $product, $price) |
||
749 | |||
750 | /** |
||
751 | * @Given /^(this product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/ |
||
752 | * @Given /^the ("[^"]+" product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/ |
||
753 | * @Given /^(it)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/ |
||
754 | */ |
||
755 | public function thisProductHasAnImageWithType(ProductInterface $product, $imagePath, $imageType) |
||
770 | |||
771 | /** |
||
772 | * @Given /^(this product) belongs to ("([^"]+)" shipping category)$/ |
||
773 | * @Given product :product shipping category has been changed to :shippingCategory |
||
774 | */ |
||
775 | public function thisProductBelongsToShippingCategory(ProductInterface $product, ShippingCategoryInterface $shippingCategory) |
||
780 | |||
781 | /** |
||
782 | * @Given /^(this product) has been disabled$/ |
||
783 | */ |
||
784 | public function thisProductHasBeenDisabled(ProductInterface $product) |
||
789 | |||
790 | /** |
||
791 | * @param string $price |
||
792 | * |
||
793 | * @return int |
||
794 | */ |
||
795 | private function getPriceFromString($price) |
||
799 | |||
800 | /** |
||
801 | * @param string $productName |
||
802 | * @param int $price |
||
803 | * @param ChannelInterface|null $channel |
||
804 | * |
||
805 | * @return ProductInterface |
||
806 | */ |
||
807 | private function createProduct($productName, $price = 100, ChannelInterface $channel = null) |
||
844 | |||
845 | /** |
||
846 | * @param ProductOptionInterface $option |
||
847 | * @param string $value |
||
848 | * @param string $code |
||
849 | * |
||
850 | * @return ProductOptionValueInterface |
||
851 | */ |
||
852 | private function addProductOption(ProductOptionInterface $option, $value, $code) |
||
865 | |||
866 | /** |
||
867 | * @param ProductInterface $product |
||
868 | */ |
||
869 | private function saveProduct(ProductInterface $product) |
||
874 | |||
875 | /** |
||
876 | * @param string $name |
||
877 | * |
||
878 | * @return NodeElement |
||
879 | */ |
||
880 | private function getParameter($name) |
||
884 | |||
885 | /** |
||
886 | * @param ProductInterface $product |
||
887 | * @param $productVariantName |
||
888 | * @param int $price |
||
889 | * @param string $code |
||
890 | * @param ChannelInterface $channel |
||
|
|||
891 | * @param int $position |
||
892 | * @param bool $shippingRequired |
||
893 | * |
||
894 | * @return ProductVariantInterface |
||
895 | */ |
||
896 | private function createProductVariant( |
||
924 | |||
925 | /** |
||
926 | * @param ProductInterface $product |
||
927 | * @param string $name |
||
928 | * @param string $locale |
||
929 | */ |
||
930 | private function addProductTranslation(ProductInterface $product, $name, $locale) |
||
944 | |||
945 | /** |
||
946 | * @param ProductVariantInterface $productVariant |
||
947 | * @param string $name |
||
948 | * @param string $locale |
||
949 | */ |
||
950 | private function addProductVariantTranslation(ProductVariantInterface $productVariant, $name, $locale) |
||
959 | |||
960 | /** |
||
961 | * @param int $price |
||
962 | * @param ChannelInterface|null $channel |
||
963 | * |
||
964 | * @return ChannelPricingInterface |
||
965 | */ |
||
966 | private function createChannelPricingForChannel($price, ChannelInterface $channel = null) |
||
975 | } |
||
976 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.