77
88namespace Magento \CatalogRuleConfigurable \Plugin \CatalogRule \Model \Rule ;
99
10- use Magento \CatalogRule \Model \Rule ;
10+ use Magento \CatalogRuleConfigurable \ Plugin \ CatalogRule \Model \ConfigurableProductsProvider ;
1111use Magento \ConfigurableProduct \Model \ResourceModel \Product \Type \Configurable as ConfigurableProductsResourceModel ;
12- use Magento \Framework \App \ResourceConnection ;
1312
1413/**
1514 * Add configurable sub products to catalog rule indexer on full reindex
@@ -22,174 +21,100 @@ class ConfigurableProductHandler
2221 private ConfigurableProductsResourceModel $ configurable ;
2322
2423 /**
25- * @var ResourceConnection
24+ * @var ConfigurableProductsProvider
2625 */
27- private ResourceConnection $ resourceConnection ;
28-
29- /**
30- * @var array|null
31- */
32- private static ?array $ allConfigurableProductIds = null ;
26+ private ConfigurableProductsProvider $ configurableProductsProvider ;
3327
3428 /**
3529 * @var array
3630 */
37- private static array $ childrenProducts = [];
31+ private array $ childrenProducts = [];
3832
3933 /**
4034 * @param ConfigurableProductsResourceModel $configurable
41- * @param ResourceConnection $resourceConnection
35+ * @param ConfigurableProductsProvider $configurableProductsProvider
4236 */
4337 public function __construct (
4438 ConfigurableProductsResourceModel $ configurable ,
45- ResourceConnection $ resourceConnection
39+ ConfigurableProductsProvider $ configurableProductsProvider
4640 ) {
4741 $ this ->configurable = $ configurable ;
48- $ this ->resourceConnection = $ resourceConnection ;
42+ $ this ->configurableProductsProvider = $ configurableProductsProvider ;
4943 }
5044
5145 /**
52- * Match configurable child products if configurable product matches the condition
46+ * Match configurable child products if configurable product match the condition
5347 *
54- * @param Rule $rule
48+ * @param \Magento\CatalogRule\Model\ Rule $rule
5549 * @param \Closure $proceed
5650 * @return array
5751 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
52+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
53+ * @SuppressWarnings(PHPMD.NPathComplexity)
54+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
5855 */
5956 public function aroundGetMatchingProductIds (
60- Rule $ rule ,
57+ \ Magento \ CatalogRule \ Model \ Rule $ rule ,
6158 \Closure $ proceed
6259 ): array {
6360 $ productsFilter = $ rule ->getProductsFilter () ? (array ) $ rule ->getProductsFilter () : [];
64-
65- $ this ->updateProductsFilter ($ rule , $ productsFilter );
66-
67- $ productIds = $ proceed ();
68-
69- if (self ::$ allConfigurableProductIds === null ) {
70- self ::$ allConfigurableProductIds = $ this ->loadAllConfigurableProductIds ();
71- }
72-
73- return $ this ->processConfigurableProducts ($ productIds , $ productsFilter );
74- }
75-
76- /**
77- * Update products filter to include parent IDs and remove duplicate children
78- *
79- * @param Rule $rule
80- * @param array $productsFilter
81- * @return void
82- */
83- private function updateProductsFilter (
84- Rule $ rule ,
85- array $ productsFilter
86- ): void {
87- if (!$ productsFilter ) {
88- return ;
89- }
90-
91- $ parentIds = $ this ->configurable ->getParentIdsByChild ($ productsFilter );
92- if (!$ parentIds ) {
93- return ;
94- }
95-
96- $ childrenToRemove = $ this ->getChildrenToRemove ($ productsFilter , $ parentIds );
97- $ filteredProducts = array_diff ($ productsFilter , $ childrenToRemove );
98-
99- $ rule ->setProductsFilter (
100- array_unique (
101- array_merge (
102- $ filteredProducts ,
103- $ parentIds
61+ if ($ productsFilter ) {
62+ $ rule ->setProductsFilter (
63+ array_unique (
64+ array_merge (
65+ $ productsFilter ,
66+ $ this ->configurable ->getParentIdsByChild ($ productsFilter )
67+ )
10468 )
105- )
106- );
107- }
108-
109- /**
110- * Get children to remove from filter to avoid redundancy
111- *
112- * @param array $productsFilter
113- * @param array $parentIds
114- * @return array
115- */
116- private function getChildrenToRemove (array $ productsFilter , array $ parentIds ): array
117- {
118- $ childrenToRemove = [];
69+ );
70+ }
11971
120- foreach ($ parentIds as $ parentId ) {
121- if (in_array ($ parentId , $ productsFilter )) {
122- continue ;
72+ $ productIds = $ proceed ();
73+ foreach ($ productIds as $ productId => $ productData ) {
74+ if ($ this ->hasAntecedentRule ((int ) $ productId )) {
75+ $ productIds [$ productId ]['has_antecedent_rule ' ] = true ;
12376 }
77+ }
12478
125- if (!isset (self ::$ childrenProducts [$ parentId ])) {
126- self ::$ childrenProducts [$ parentId ] = $ this ->configurable ->getChildrenIds ($ parentId )[0 ];
79+ foreach ($ this ->configurableProductsProvider ->getIds (array_keys ($ productIds )) as $ configurableProductId ) {
80+ if (!isset ($ this ->childrenProducts [$ configurableProductId ])) {
81+ $ this ->childrenProducts [$ configurableProductId ] =
82+ $ this ->configurable ->getChildrenIds ($ configurableProductId )[0 ];
12783 }
128- $ children = self ::$ childrenProducts [$ parentId ];
12984
130- $ childrenInFilter = array_intersect ($ productsFilter , $ children );
131- if (count ($ childrenInFilter ) > 1 ) {
132- $ childrenInFilterArray = array_values ($ childrenInFilter );
133- $ childrenCount = count ($ childrenInFilterArray );
134- for ($ i = 1 ; $ i < $ childrenCount ; $ i ++) {
135- $ childrenToRemove [] = $ childrenInFilterArray [$ i ];
85+ $ parentValidationResult = isset ($ productIds [$ configurableProductId ])
86+ ? array_filter ($ productIds [$ configurableProductId ])
87+ : [];
88+ $ processAllChildren = !$ productsFilter || in_array ($ configurableProductId , $ productsFilter );
89+ foreach ($ this ->childrenProducts [$ configurableProductId ] as $ childrenProductId ) {
90+ if ($ processAllChildren || in_array ($ childrenProductId , $ productsFilter )) {
91+ $ childValidationResult = isset ($ productIds [$ childrenProductId ])
92+ ? array_filter ($ productIds [$ childrenProductId ])
93+ : [];
94+ $ productIds [$ childrenProductId ] = $ parentValidationResult + $ childValidationResult ;
13695 }
13796 }
97+ unset($ productIds [$ configurableProductId ]);
13898 }
13999
140- return $ childrenToRemove ;
100+ return $ productIds ;
141101 }
142102
143103 /**
144- * Process configurable products and apply parent validation to children
104+ * Check if simple product has previously applied rule.
145105 *
146- * @param array $productIds
147- * @param array $productsFilter
148- * @return array
106+ * @param int $productId
107+ * @return bool
108+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
149109 */
150- private function processConfigurableProducts ( array $ productIds , array $ productsFilter ): array
110+ private function hasAntecedentRule ( int $ productId ): bool
151111 {
152- foreach (array_keys ($ productIds ) as $ productId ) {
153- if (isset (self ::$ allConfigurableProductIds [$ productId ])) {
154- if (!isset (self ::$ childrenProducts [$ productId ])) {
155- self ::$ childrenProducts [$ productId ] = $ this ->configurable ->getChildrenIds ($ productId )[0 ];
156- }
157-
158- $ parentValidationResult = array_filter ($ productIds [$ productId ]);
159- $ processAllChildren = !$ productsFilter || in_array ($ productId , $ productsFilter );
160-
161- foreach (self ::$ childrenProducts [$ productId ] as $ childProductId ) {
162- if ($ processAllChildren || in_array ($ childProductId , $ productsFilter )) {
163- $ childValidationResult = isset ($ productIds [$ childProductId ])
164- ? array_filter ($ productIds [$ childProductId ])
165- : [];
166- $ productIds [$ childProductId ] = $ parentValidationResult + $ childValidationResult ;
167- }
168- }
169- unset($ productIds [$ productId ]);
112+ foreach ($ this ->childrenProducts as $ parent => $ children ) {
113+ if (in_array ($ productId , $ children )) {
114+ return true ;
170115 }
171116 }
172117
173- return $ productIds ;
174- }
175-
176- /**
177- * Load all configurable product IDs at once
178- *
179- * @return array
180- */
181- private function loadAllConfigurableProductIds (): array
182- {
183- $ connection = $ this ->resourceConnection ->getConnection ();
184- $ select = $ connection ->select ()
185- ->from (
186- ['e ' => $ this ->resourceConnection ->getTableName ('catalog_product_entity ' )],
187- ['entity_id ' ]
188- )
189- ->where ('e.type_id = ? ' , 'configurable ' );
190-
191- $ result = $ connection ->fetchCol ($ select );
192-
193- return array_flip ($ result );
118+ return false ;
194119 }
195120}
0 commit comments