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 |
||
48 | final class ProductContext implements Context |
||
49 | { |
||
50 | /** |
||
51 | * @var SharedStorageInterface |
||
52 | */ |
||
53 | private $sharedStorage; |
||
54 | |||
55 | /** |
||
56 | * @var ProductRepositoryInterface |
||
57 | */ |
||
58 | private $productRepository; |
||
59 | |||
60 | /** |
||
61 | * @var ProductFactoryInterface |
||
62 | */ |
||
63 | private $productFactory; |
||
64 | |||
65 | /** |
||
66 | * @var FactoryInterface |
||
67 | */ |
||
68 | private $productTranslationFactory; |
||
69 | |||
70 | /** |
||
71 | * @var FactoryInterface |
||
72 | */ |
||
73 | private $productVariantFactory; |
||
74 | |||
75 | /** |
||
76 | * @var FactoryInterface |
||
77 | */ |
||
78 | private $productVariantTranslationFactory; |
||
79 | |||
80 | /** |
||
81 | * @var FactoryInterface |
||
82 | */ |
||
83 | private $channelPricingFactory; |
||
84 | |||
85 | /** |
||
86 | * @var FactoryInterface |
||
87 | */ |
||
88 | private $productOptionFactory; |
||
89 | |||
90 | /** |
||
91 | * @var FactoryInterface |
||
92 | */ |
||
93 | private $productOptionValueFactory; |
||
94 | |||
95 | /** |
||
96 | * @var FactoryInterface |
||
97 | */ |
||
98 | private $productImageFactory; |
||
99 | |||
100 | /** |
||
101 | * @var ObjectManager |
||
102 | */ |
||
103 | private $objectManager; |
||
104 | |||
105 | /** |
||
106 | * @var ProductVariantResolverInterface |
||
107 | */ |
||
108 | private $defaultVariantResolver; |
||
109 | |||
110 | /** |
||
111 | * @var ImageUploaderInterface |
||
112 | */ |
||
113 | private $imageUploader; |
||
114 | |||
115 | /** |
||
116 | * @var SlugGeneratorInterface |
||
117 | */ |
||
118 | private $slugGenerator; |
||
119 | |||
120 | /** |
||
121 | * @var array |
||
122 | */ |
||
123 | private $minkParameters; |
||
124 | |||
125 | /** |
||
126 | * @param SharedStorageInterface $sharedStorage |
||
127 | * @param ProductRepositoryInterface $productRepository |
||
128 | * @param ProductFactoryInterface $productFactory |
||
129 | * @param FactoryInterface $productTranslationFactory |
||
130 | * @param FactoryInterface $productVariantFactory |
||
131 | * @param FactoryInterface $productVariantTranslationFactory |
||
132 | * @param FactoryInterface $channelPricingFactory |
||
133 | * @param FactoryInterface $productOptionFactory |
||
134 | * @param FactoryInterface $productOptionValueFactory |
||
135 | * @param FactoryInterface $productImageFactory |
||
136 | * @param ObjectManager $objectManager |
||
137 | * @param ProductVariantResolverInterface $defaultVariantResolver |
||
138 | * @param ImageUploaderInterface $imageUploader |
||
139 | * @param SlugGeneratorInterface $slugGenerator |
||
140 | * @param array $minkParameters |
||
141 | */ |
||
142 | public function __construct( |
||
175 | |||
176 | /** |
||
177 | * @Given the store has a product :productName |
||
178 | * @Given the store has a :productName product |
||
179 | * @Given I added a product :productName |
||
180 | * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+")$/ |
||
181 | * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") in ("[^"]+" channel)$/ |
||
182 | */ |
||
183 | public function storeHasAProductPricedAt($productName, $price = 100, ChannelInterface $channel = null) |
||
189 | |||
190 | /** |
||
191 | * @Given /^(this product) is also priced at ("[^"]+") in ("[^"]+" channel)$/ |
||
192 | */ |
||
193 | public function thisProductIsAlsoPricedAtInChannel(ProductInterface $product, $price, ChannelInterface $channel) |
||
209 | |||
210 | /** |
||
211 | * @Given the store( also) has a product :productName with code :code |
||
212 | * @Given the store( also) has a product :productName with code :code, created at :date |
||
213 | */ |
||
214 | public function storeHasProductWithCode($productName, $code, $date = null) |
||
222 | |||
223 | /** |
||
224 | * @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+") available in (channel "[^"]+") and (channel "[^"]+")$/ |
||
225 | */ |
||
226 | public function storeHasAProductPricedAtAvailableInChannels($productName, $price = 100, ...$channels) |
||
241 | |||
242 | /** |
||
243 | * @Given /^(this product) is named "([^"]+)" (in the "([^"]+)" locale)$/ |
||
244 | * @Given /^the (product "[^"]+") is named "([^"]+)" (in the "([^"]+)" locale)$/ |
||
245 | */ |
||
246 | public function thisProductIsNamedIn(ProductInterface $product, $name, $locale) |
||
252 | |||
253 | /** |
||
254 | * @Given /^the store has a product named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/ |
||
255 | */ |
||
256 | public function theStoreHasProductNamedInAndIn($firstName, $firstLocale, $secondName, $secondLocale) |
||
267 | |||
268 | /** |
||
269 | * @Given /^the store has(?:| a| an) "([^"]+)" configurable product$/ |
||
270 | * @Given /^the store has(?:| a| an) "([^"]+)" configurable product with "([^"]+)" slug$/ |
||
271 | */ |
||
272 | public function storeHasAConfigurableProduct($productName, $slug = null) |
||
298 | |||
299 | /** |
||
300 | * @Given the store has( also) :firstProductName and :secondProductName products |
||
301 | * @Given the store has( also) :firstProductName, :secondProductName and :thirdProductName products |
||
302 | * @Given the store has( also) :firstProductName, :secondProductName, :thirdProductName and :fourthProductName products |
||
303 | */ |
||
304 | public function theStoreHasProducts(...$productsNames) |
||
310 | |||
311 | /** |
||
312 | * @Given /^(this channel) has "([^"]+)", "([^"]+)", "([^"]+)" and "([^"]+)" products$/ |
||
313 | */ |
||
314 | public function thisChannelHasProducts(ChannelInterface $channel, ...$productsNames) |
||
322 | |||
323 | /** |
||
324 | * @Given /^the (product "[^"]+") has(?:| a) "([^"]+)" variant priced at ("[^"]+")$/ |
||
325 | * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+")$/ |
||
326 | * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") in ("([^"]+)" channel)$/ |
||
327 | */ |
||
328 | public function theProductHasVariantPricedAt( |
||
342 | |||
343 | /** |
||
344 | * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") which does not require shipping$/ |
||
345 | */ |
||
346 | public function theProductHasVariantWhichDoesNotRequireShipping( |
||
361 | |||
362 | /** |
||
363 | * @Given /^the (product "[^"]+") has(?:| also)(?:| a| an) "([^"]+)" variant$/ |
||
364 | * @Given /^the (product "[^"]+") has(?:| also)(?:| a| an) "([^"]+)" variant at position ([^"]+)$/ |
||
365 | * @Given /^(this product) has(?:| also)(?:| a| an) "([^"]+)" variant at position ([^"]+)$/ |
||
366 | */ |
||
367 | public function theProductHasVariantAtPosition( |
||
381 | |||
382 | /** |
||
383 | * @Given /^(this variant) is also priced at ("[^"]+") in ("([^"]+)" channel)$/ |
||
384 | */ |
||
385 | public function thisVariantIsAlsoPricedAtInChannel(ProductVariantInterface $productVariant, $price, ChannelInterface $channel) |
||
394 | |||
395 | /** |
||
396 | * @Given /^(it|this product) has(?:| also) variant named "([^"]+)" in ("[^"]+" locale) and "([^"]+)" in ("[^"]+" locale)$/ |
||
397 | */ |
||
398 | public function itHasVariantNamedInAndIn(ProductInterface $product, $firstName, $firstLocale, $secondName, $secondLocale) |
||
415 | |||
416 | /** |
||
417 | * @Given /^(this product) has "([^"]+)" variant priced at ("[^"]+") identified by "([^"]+)"$/ |
||
418 | */ |
||
419 | public function theProductHasVariantPricedAtIdentifiedBy( |
||
427 | |||
428 | /** |
||
429 | * @Given /^there is product "([^"]+)" available in ((?:this|that|"[^"]+") channel)$/ |
||
430 | * @Given /^the store has a product "([^"]+)" available in ("([^"]+)" channel)$/ |
||
431 | */ |
||
432 | public function thereIsProductAvailableInGivenChannel($productName, ChannelInterface $channel) |
||
438 | |||
439 | /** |
||
440 | * @Given /^([^"]+) belongs to ("[^"]+" tax category)$/ |
||
441 | */ |
||
442 | public function productBelongsToTaxCategory(ProductInterface $product, TaxCategoryInterface $taxCategory) |
||
450 | |||
451 | /** |
||
452 | * @Given /^(it) comes in the following variations:$/ |
||
453 | */ |
||
454 | public function itComesInTheFollowingVariations(ProductInterface $product, TableNode $table) |
||
472 | |||
473 | /** |
||
474 | * @Given /^("[^"]+" variant of product "[^"]+") belongs to ("[^"]+" tax category)$/ |
||
475 | */ |
||
476 | public function productVariantBelongsToTaxCategory( |
||
483 | |||
484 | /** |
||
485 | * @Given /^(this product) has option "([^"]+)" with values "([^"]+)" and "([^"]+)"$/ |
||
486 | * @Given /^(this product) has option "([^"]+)" with values "([^"]+)", "([^"]+)" and "([^"]+)"$/ |
||
487 | */ |
||
488 | public function thisProductHasOptionWithValues(ProductInterface $product, $optionName, ...$values) |
||
509 | |||
510 | /** |
||
511 | * @Given /^there (?:is|are) (\d+) unit(?:|s) of (product "([^"]+)") available in the inventory$/ |
||
512 | */ |
||
513 | public function thereIsQuantityOfProducts($quantity, ProductInterface $product) |
||
521 | |||
522 | /** |
||
523 | * @Given /^the (product "([^"]+)") is out of stock$/ |
||
524 | */ |
||
525 | public function theProductIsOutOfStock(ProductInterface $product) |
||
534 | |||
535 | /** |
||
536 | * @When other customer has bought :quantity :product products by this time |
||
537 | */ |
||
538 | public function otherCustomerHasBoughtProductsByThisTime($quantity, ProductInterface $product) |
||
546 | |||
547 | /** |
||
548 | * @Given /^(this product) is tracked by the inventory$/ |
||
549 | * @Given /^(?:|the )("[^"]+" product) is(?:| also) tracked by the inventory$/ |
||
550 | */ |
||
551 | public function thisProductIsTrackedByTheInventory(ProductInterface $product) |
||
559 | |||
560 | /** |
||
561 | * @Given /^(this product) is available in "([^"]+)" ([^"]+) priced at ("[^"]+")$/ |
||
562 | */ |
||
563 | public function thisProductIsAvailableInSize(ProductInterface $product, $optionValueName, $optionName, $price) |
||
578 | |||
579 | /** |
||
580 | * @Given the :product product's :optionValueName size belongs to :shippingCategory shipping category |
||
581 | */ |
||
582 | public function thisProductSizeBelongsToShippingCategory(ProductInterface $product, $optionValueName, ShippingCategoryInterface $shippingCategory) |
||
595 | |||
596 | /** |
||
597 | * @Given /^(this product) has (this product option)$/ |
||
598 | * @Given /^(this product) has (?:a|an) ("[^"]+" option)$/ |
||
599 | */ |
||
600 | public function thisProductHasThisProductOption(ProductInterface $product, ProductOptionInterface $option) |
||
606 | |||
607 | /** |
||
608 | * @Given /^there are ([^"]+) units of ("[^"]+" variant of product "[^"]+") available in the inventory$/ |
||
609 | */ |
||
610 | public function thereAreItemsOfProductInVariantAvailableInTheInventory($quantity, ProductVariantInterface $productVariant) |
||
617 | |||
618 | /** |
||
619 | * @Given /^the ("[^"]+" product variant) is tracked by the inventory$/ |
||
620 | */ |
||
621 | public function theProductVariantIsTrackedByTheInventory(ProductVariantInterface $productVariant) |
||
627 | |||
628 | /** |
||
629 | * @Given /^(this product)'s price is ("[^"]+")$/ |
||
630 | * @Given /^the (product "[^"]+") changed its price to ("[^"]+")$/ |
||
631 | * @Given /^(this product) price has been changed to ("[^"]+")$/ |
||
632 | */ |
||
633 | public function theProductChangedItsPriceTo(ProductInterface $product, $price) |
||
642 | |||
643 | /** |
||
644 | * @Given /^(this product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/ |
||
645 | * @Given /^the ("[^"]+" product)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/ |
||
646 | * @Given /^(it)(?:| also) has an image "([^"]+)" with "([^"]+)" type$/ |
||
647 | */ |
||
648 | public function thisProductHasAnImageWithType(ProductInterface $product, $imagePath, $imageType) |
||
662 | |||
663 | /** |
||
664 | * @Given /^(this product) belongs to ("([^"]+)" shipping category)$/ |
||
665 | * @Given product :product shipping category has been changed to :shippingCategory |
||
666 | */ |
||
667 | public function thisProductBelongsToShippingCategory(ProductInterface $product, ShippingCategoryInterface $shippingCategory) |
||
672 | |||
673 | /** |
||
674 | * @Given /^(this product) has been disabled$/ |
||
675 | */ |
||
676 | public function thisProductHasBeenDisabled(ProductInterface $product) |
||
681 | |||
682 | /** |
||
683 | * @param string $price |
||
684 | * |
||
685 | * @return int |
||
686 | */ |
||
687 | private function getPriceFromString($price) |
||
691 | |||
692 | /** |
||
693 | * @param string $productName |
||
694 | * @param int $price |
||
695 | * @param ChannelInterface|null $channel |
||
696 | * |
||
697 | * @return ProductInterface |
||
698 | */ |
||
699 | private function createProduct($productName, $price = 100, ChannelInterface $channel = null) |
||
736 | |||
737 | /** |
||
738 | * @param ProductOptionInterface $option |
||
739 | * @param string $value |
||
740 | * @param string $code |
||
741 | * |
||
742 | * @return ProductOptionValueInterface |
||
743 | */ |
||
744 | private function addProductOption(ProductOptionInterface $option, $value, $code) |
||
757 | |||
758 | /** |
||
759 | * @param ProductInterface $product |
||
760 | */ |
||
761 | private function saveProduct(ProductInterface $product) |
||
766 | |||
767 | /** |
||
768 | * @param string $name |
||
769 | * |
||
770 | * @return NodeElement |
||
771 | */ |
||
772 | private function getParameter($name) |
||
776 | |||
777 | /** |
||
778 | * @param ProductInterface $product |
||
779 | * @param $productVariantName |
||
780 | * @param int $price |
||
781 | * @param string $code |
||
782 | * @param ChannelInterface $channel |
||
|
|||
783 | * @param int $position |
||
784 | * @param bool $shippingRequired |
||
785 | * |
||
786 | * @return ProductVariantInterface |
||
787 | */ |
||
788 | private function createProductVariant( |
||
816 | |||
817 | /** |
||
818 | * @param ProductInterface $product |
||
819 | * @param string $name |
||
820 | * @param string $locale |
||
821 | */ |
||
822 | private function addProductTranslation(ProductInterface $product, $name, $locale) |
||
836 | |||
837 | /** |
||
838 | * @param ProductVariantInterface $productVariant |
||
839 | * @param string $name |
||
840 | * @param string $locale |
||
841 | */ |
||
842 | private function addProductVariantTranslation(ProductVariantInterface $productVariant, $name, $locale) |
||
851 | |||
852 | /** |
||
853 | * @param int $price |
||
854 | * @param ChannelInterface|null $channel |
||
855 | * |
||
856 | * @return ChannelPricingInterface |
||
857 | */ |
||
858 | private function createChannelPricingForChannel($price, ChannelInterface $channel = null) |
||
867 | } |
||
868 |
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.