3
3
* Copyright © Magento, Inc. All rights reserved.
4
4
* See COPYING.txt for license details.
5
5
*/
6
+ declare (strict_types=1 );
7
+
6
8
namespace Magento \CatalogUrlRewrite \Observer ;
7
9
10
+ use Magento \Catalog \Model \Product ;
11
+ use Magento \Catalog \Model \Category ;
12
+ use Magento \Catalog \Model \ResourceModel \Product \Collection ;
13
+ use Magento \Catalog \Model \ResourceModel \Product \CollectionFactory ;
14
+ use Magento \CatalogUrlRewrite \Model \Category \ChildrenCategoriesProvider ;
15
+ use Magento \CatalogUrlRewrite \Model \CategoryProductUrlPathGenerator ;
16
+ use Magento \CatalogUrlRewrite \Model \CategoryUrlRewriteGenerator ;
17
+ use Magento \CatalogUrlRewrite \Model \ProductScopeRewriteGenerator ;
18
+ use Magento \CatalogUrlRewrite \Model \ProductUrlRewriteGenerator ;
19
+ use Magento \Framework \App \ObjectManager ;
20
+ use Magento \Framework \Serialize \Serializer \Json ;
21
+ use Magento \UrlRewrite \Model \MergeDataProvider ;
22
+ use Magento \UrlRewrite \Model \MergeDataProviderFactory ;
23
+ use Magento \UrlRewrite \Model \UrlPersistInterface ;
24
+ use Magento \UrlRewrite \Service \V1 \Data \UrlRewrite ;
25
+
26
+ /**
27
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
28
+ */
8
29
class UrlRewriteHandler
9
30
{
10
31
/**
11
- * @var \Magento\CatalogUrlRewrite\Model\Category\ ChildrenCategoriesProvider
32
+ * @var ChildrenCategoriesProvider
12
33
*/
13
34
protected $ childrenCategoriesProvider ;
14
35
15
36
/**
16
- * @var \Magento\CatalogUrlRewrite\Model\ CategoryUrlRewriteGenerator
37
+ * @var CategoryUrlRewriteGenerator
17
38
*/
18
39
protected $ categoryUrlRewriteGenerator ;
19
40
20
41
/**
21
- * @var \Magento\CatalogUrlRewrite\Model\ ProductUrlRewriteGenerator
42
+ * @var ProductUrlRewriteGenerator
22
43
*/
23
44
protected $ productUrlRewriteGenerator ;
24
45
25
46
/**
26
- * @var \Magento\UrlRewrite\Model\ UrlPersistInterface
47
+ * @var UrlPersistInterface
27
48
*/
28
49
protected $ urlPersist ;
29
50
@@ -33,44 +54,51 @@ class UrlRewriteHandler
33
54
protected $ isSkippedProduct ;
34
55
35
56
/**
36
- * @var \Magento\Catalog\Model\ResourceModel\Product\ CollectionFactory
57
+ * @var CollectionFactory
37
58
*/
38
59
protected $ productCollectionFactory ;
39
60
40
61
/**
41
- * @var \Magento\CatalogUrlRewrite\Model\ CategoryProductUrlPathGenerator
62
+ * @var CategoryProductUrlPathGenerator
42
63
*/
43
64
private $ categoryBasedProductRewriteGenerator ;
44
65
45
66
/**
46
- * @var \Magento\UrlRewrite\Model\ MergeDataProvider
67
+ * @var MergeDataProvider
47
68
*/
48
69
private $ mergeDataProviderPrototype ;
49
70
50
71
/**
51
- * @var \Magento\Framework\Serialize\Serializer\ Json
72
+ * @var Json
52
73
*/
53
74
private $ serializer ;
54
75
55
76
/**
56
- * @param \Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider $childrenCategoriesProvider
57
- * @param \Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator
58
- * @param \Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator $productUrlRewriteGenerator
59
- * @param \Magento\UrlRewrite\Model\UrlPersistInterface $urlPersist
60
- * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory
61
- * @param \Magento\CatalogUrlRewrite\Model\CategoryProductUrlPathGenerator $categoryBasedProductRewriteGenerator
62
- * @param \Magento\UrlRewrite\Model\MergeDataProviderFactory|null $mergeDataProviderFactory
63
- * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
77
+ * @var ProductScopeRewriteGenerator
78
+ */
79
+ private $ productScopeRewriteGenerator ;
80
+
81
+ /**
82
+ * @param ChildrenCategoriesProvider $childrenCategoriesProvider
83
+ * @param CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator
84
+ * @param ProductUrlRewriteGenerator $productUrlRewriteGenerator
85
+ * @param UrlPersistInterface $urlPersist
86
+ * @param CollectionFactory $productCollectionFactory
87
+ * @param CategoryProductUrlPathGenerator $categoryBasedProductRewriteGenerator
88
+ * @param MergeDataProviderFactory|null $mergeDataProviderFactory
89
+ * @param Json|null $serializer
90
+ * @param ProductScopeRewriteGenerator|null $productScopeRewriteGenerator
64
91
*/
65
92
public function __construct (
66
- \Magento \CatalogUrlRewrite \Model \Category \ChildrenCategoriesProvider $ childrenCategoriesProvider ,
67
- \Magento \CatalogUrlRewrite \Model \CategoryUrlRewriteGenerator $ categoryUrlRewriteGenerator ,
68
- \Magento \CatalogUrlRewrite \Model \ProductUrlRewriteGenerator $ productUrlRewriteGenerator ,
69
- \Magento \UrlRewrite \Model \UrlPersistInterface $ urlPersist ,
70
- \Magento \Catalog \Model \ResourceModel \Product \CollectionFactory $ productCollectionFactory ,
71
- \Magento \CatalogUrlRewrite \Model \CategoryProductUrlPathGenerator $ categoryBasedProductRewriteGenerator ,
72
- \Magento \UrlRewrite \Model \MergeDataProviderFactory $ mergeDataProviderFactory = null ,
73
- \Magento \Framework \Serialize \Serializer \Json $ serializer = null
93
+ ChildrenCategoriesProvider $ childrenCategoriesProvider ,
94
+ CategoryUrlRewriteGenerator $ categoryUrlRewriteGenerator ,
95
+ ProductUrlRewriteGenerator $ productUrlRewriteGenerator ,
96
+ UrlPersistInterface $ urlPersist ,
97
+ CollectionFactory $ productCollectionFactory ,
98
+ CategoryProductUrlPathGenerator $ categoryBasedProductRewriteGenerator ,
99
+ MergeDataProviderFactory $ mergeDataProviderFactory = null ,
100
+ Json $ serializer = null ,
101
+ ProductScopeRewriteGenerator $ productScopeRewriteGenerator = null
74
102
) {
75
103
$ this ->childrenCategoriesProvider = $ childrenCategoriesProvider ;
76
104
$ this ->categoryUrlRewriteGenerator = $ categoryUrlRewriteGenerator ;
@@ -79,58 +107,29 @@ public function __construct(
79
107
$ this ->productCollectionFactory = $ productCollectionFactory ;
80
108
$ this ->categoryBasedProductRewriteGenerator = $ categoryBasedProductRewriteGenerator ;
81
109
82
- if (!isset ($ mergeDataProviderFactory )) {
83
- $ mergeDataProviderFactory = \Magento \Framework \App \ObjectManager::getInstance ()->get (
84
- \Magento \UrlRewrite \Model \MergeDataProviderFactory::class
85
- );
86
- }
87
-
110
+ $ objectManager = ObjectManager::getInstance ();
111
+ $ mergeDataProviderFactory = $ mergeDataProviderFactory ?: $ objectManager ->get (MergeDataProviderFactory::class);
88
112
$ this ->mergeDataProviderPrototype = $ mergeDataProviderFactory ->create ();
89
-
90
- $ this ->serializer = $ serializer ?: \Magento \Framework \App \ObjectManager::getInstance ()->get (
91
- \Magento \Framework \Serialize \Serializer \Json::class
92
- );
113
+ $ this ->serializer = $ serializer ?: $ objectManager ->get (Json::class);
114
+ $ this ->productScopeRewriteGenerator = $ productScopeRewriteGenerator
115
+ ?: $ objectManager ->get (ProductScopeRewriteGenerator::class);
93
116
}
94
117
95
118
/**
96
- * Generate url rewrites for products assigned to category
119
+ * Generates URL rewrites for products assigned to category.
97
120
*
98
- * @param \Magento\Catalog\Model\ Category $category
121
+ * @param Category $category
99
122
* @return array
100
123
*/
101
- public function generateProductUrlRewrites (\ Magento \ Catalog \ Model \ Category $ category )
124
+ public function generateProductUrlRewrites (Category $ category ): array
102
125
{
103
126
$ mergeDataProvider = clone $ this ->mergeDataProviderPrototype ;
104
127
$ this ->isSkippedProduct [$ category ->getEntityId ()] = [];
105
- $ saveRewriteHistory = $ category ->getData ('save_rewrites_history ' );
106
- $ storeId = $ category ->getStoreId ();
128
+ $ saveRewriteHistory = ( bool ) $ category ->getData ('save_rewrites_history ' );
129
+ $ storeId = ( int ) $ category ->getStoreId ();
107
130
108
131
if ($ category ->getChangedProductIds ()) {
109
- $ this ->isSkippedProduct [$ category ->getEntityId ()] = $ category ->getAffectedProductIds ();
110
- /* @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */
111
- $ collection = $ this ->productCollectionFactory ->create ()
112
- ->setStoreId ($ storeId )
113
- ->addIdFilter ($ category ->getAffectedProductIds ())
114
- ->addAttributeToSelect ('visibility ' )
115
- ->addAttributeToSelect ('name ' )
116
- ->addAttributeToSelect ('url_key ' )
117
- ->addAttributeToSelect ('url_path ' );
118
-
119
- $ collection ->setPageSize (1000 );
120
- $ pageCount = $ collection ->getLastPageNumber ();
121
- $ currentPage = 1 ;
122
- while ($ currentPage <= $ pageCount ) {
123
- $ collection ->setCurPage ($ currentPage );
124
- foreach ($ collection as $ product ) {
125
- $ product ->setStoreId ($ storeId );
126
- $ product ->setData ('save_rewrites_history ' , $ saveRewriteHistory );
127
- $ mergeDataProvider ->merge (
128
- $ this ->productUrlRewriteGenerator ->generate ($ product , $ category ->getEntityId ())
129
- );
130
- }
131
- $ collection ->clear ();
132
- $ currentPage ++;
133
- }
132
+ $ this ->generateChangedProductUrls ($ mergeDataProvider , $ category , $ storeId , $ saveRewriteHistory );
134
133
} else {
135
134
$ mergeDataProvider ->merge (
136
135
$ this ->getCategoryProductsUrlRewrites (
@@ -157,21 +156,49 @@ public function generateProductUrlRewrites(\Magento\Catalog\Model\Category $cate
157
156
}
158
157
159
158
/**
160
- * @param \Magento\Catalog\Model\Category $category
159
+ * @param Category $category
160
+ * @return void
161
+ */
162
+ public function deleteCategoryRewritesForChildren (Category $ category )
163
+ {
164
+ $ categoryIds = $ this ->childrenCategoriesProvider ->getChildrenIds ($ category , true );
165
+ $ categoryIds [] = $ category ->getId ();
166
+ foreach ($ categoryIds as $ categoryId ) {
167
+ $ this ->urlPersist ->deleteByData (
168
+ [
169
+ UrlRewrite::ENTITY_ID =>
170
+ $ categoryId ,
171
+ UrlRewrite::ENTITY_TYPE =>
172
+ CategoryUrlRewriteGenerator::ENTITY_TYPE ,
173
+ ]
174
+ );
175
+ $ this ->urlPersist ->deleteByData (
176
+ [
177
+ UrlRewrite::METADATA =>
178
+ $ this ->serializer ->serialize (['category_id ' => $ categoryId ]),
179
+ UrlRewrite::ENTITY_TYPE =>
180
+ ProductUrlRewriteGenerator::ENTITY_TYPE ,
181
+ ]
182
+ );
183
+ }
184
+ }
185
+
186
+ /**
187
+ * @param Category $category
161
188
* @param int $storeId
162
189
* @param bool $saveRewriteHistory
163
190
* @param int|null $rootCategoryId
164
191
* @return array
165
192
*/
166
193
private function getCategoryProductsUrlRewrites (
167
- \ Magento \ Catalog \ Model \ Category $ category ,
194
+ Category $ category ,
168
195
$ storeId ,
169
196
$ saveRewriteHistory ,
170
197
$ rootCategoryId = null
171
198
) {
172
199
$ mergeDataProvider = clone $ this ->mergeDataProviderPrototype ;
173
200
174
- /** @var \Magento\Catalog\Model\ResourceModel\Product\ Collection $productCollection */
201
+ /** @var Collection $productCollection */
175
202
$ productCollection = $ this ->productCollectionFactory ->create ();
176
203
177
204
$ productCollection ->addCategoriesFilter (['eq ' => [$ category ->getEntityId ()]])
@@ -199,30 +226,65 @@ private function getCategoryProductsUrlRewrites(
199
226
}
200
227
201
228
/**
202
- * @param \Magento\Catalog\Model\Category $category
229
+ * Generates product URL rewrites.
230
+ *
231
+ * @param MergeDataProvider $mergeDataProvider
232
+ * @param Category $category
233
+ * @param int $storeId
234
+ * @param bool $saveRewriteHistory
203
235
* @return void
204
236
*/
205
- public function deleteCategoryRewritesForChildren (\Magento \Catalog \Model \Category $ category )
206
- {
207
- $ categoryIds = $ this ->childrenCategoriesProvider ->getChildrenIds ($ category , true );
208
- $ categoryIds [] = $ category ->getId ();
209
- foreach ($ categoryIds as $ categoryId ) {
210
- $ this ->urlPersist ->deleteByData (
211
- [
212
- \Magento \UrlRewrite \Service \V1 \Data \UrlRewrite::ENTITY_ID =>
213
- $ categoryId ,
214
- \Magento \UrlRewrite \Service \V1 \Data \UrlRewrite::ENTITY_TYPE =>
215
- \Magento \CatalogUrlRewrite \Model \CategoryUrlRewriteGenerator::ENTITY_TYPE ,
216
- ]
217
- );
218
- $ this ->urlPersist ->deleteByData (
219
- [
220
- \Magento \UrlRewrite \Service \V1 \Data \UrlRewrite::METADATA =>
221
- $ this ->serializer ->serialize (['category_id ' => $ categoryId ]),
222
- \Magento \UrlRewrite \Service \V1 \Data \UrlRewrite::ENTITY_TYPE =>
223
- \Magento \CatalogUrlRewrite \Model \ProductUrlRewriteGenerator::ENTITY_TYPE ,
224
- ]
225
- );
237
+ private function generateChangedProductUrls (
238
+ MergeDataProvider $ mergeDataProvider ,
239
+ Category $ category ,
240
+ int $ storeId ,
241
+ bool $ saveRewriteHistory
242
+ ) {
243
+ $ this ->isSkippedProduct [$ category ->getEntityId ()] = $ category ->getAffectedProductIds ();
244
+
245
+ $ categoryStoreIds = [$ storeId ];
246
+ // If category is changed in the Global scope when need to regenerate product URL rewrites for all other scopes.
247
+ if ($ this ->productScopeRewriteGenerator ->isGlobalScope ($ storeId )) {
248
+ $ categoryStoreIds = $ this ->getCategoryStoreIds ($ category );
249
+ }
250
+
251
+ foreach ($ categoryStoreIds as $ categoryStoreId ) {
252
+ /* @var Collection $collection */
253
+ $ collection = $ this ->productCollectionFactory ->create ()
254
+ ->setStoreId ($ categoryStoreId )
255
+ ->addIdFilter ($ category ->getAffectedProductIds ())
256
+ ->addAttributeToSelect ('visibility ' )
257
+ ->addAttributeToSelect ('name ' )
258
+ ->addAttributeToSelect ('url_key ' )
259
+ ->addAttributeToSelect ('url_path ' );
260
+
261
+ $ collection ->setPageSize (1000 );
262
+ $ pageCount = $ collection ->getLastPageNumber ();
263
+ $ currentPage = 1 ;
264
+ while ($ currentPage <= $ pageCount ) {
265
+ $ collection ->setCurPage ($ currentPage );
266
+ foreach ($ collection as $ product ) {
267
+ $ product ->setData ('save_rewrites_history ' , $ saveRewriteHistory );
268
+ $ product ->setStoreId ($ categoryStoreId );
269
+ $ mergeDataProvider ->merge (
270
+ $ this ->productUrlRewriteGenerator ->generate ($ product , $ category ->getEntityId ())
271
+ );
272
+ }
273
+ $ collection ->clear ();
274
+ $ currentPage ++;
275
+ }
226
276
}
227
277
}
278
+
279
+ /**
280
+ * Gets category store IDs without Global Store.
281
+ *
282
+ * @param Category $category
283
+ * @return array
284
+ */
285
+ private function getCategoryStoreIds (Category $ category ): array
286
+ {
287
+ $ ids = $ category ->getStoreIds ();
288
+ return array_filter ($ ids );
289
+ }
228
290
}
0 commit comments