Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
UrlRewriteHandler.php
Go to the documentation of this file.
1 <?php
6 declare(strict_types=1);
7 
9 
13 use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
22 use Magento\UrlRewrite\Model\MergeDataProviderFactory;
25 
30 {
35 
40 
45 
49  protected $urlPersist;
50 
54  protected $isSkippedProduct;
55 
60 
64  private $categoryBasedProductRewriteGenerator;
65 
69  private $mergeDataProviderPrototype;
70 
74  private $serializer;
75 
79  private $productScopeRewriteGenerator;
80 
92  public function __construct(
97  CollectionFactory $productCollectionFactory,
98  CategoryProductUrlPathGenerator $categoryBasedProductRewriteGenerator,
99  MergeDataProviderFactory $mergeDataProviderFactory = null,
100  Json $serializer = null,
101  ProductScopeRewriteGenerator $productScopeRewriteGenerator = null
102  ) {
103  $this->childrenCategoriesProvider = $childrenCategoriesProvider;
104  $this->categoryUrlRewriteGenerator = $categoryUrlRewriteGenerator;
105  $this->productUrlRewriteGenerator = $productUrlRewriteGenerator;
106  $this->urlPersist = $urlPersist;
107  $this->productCollectionFactory = $productCollectionFactory;
108  $this->categoryBasedProductRewriteGenerator = $categoryBasedProductRewriteGenerator;
109 
111  $mergeDataProviderFactory = $mergeDataProviderFactory ?: $objectManager->get(MergeDataProviderFactory::class);
112  $this->mergeDataProviderPrototype = $mergeDataProviderFactory->create();
113  $this->serializer = $serializer ?: $objectManager->get(Json::class);
114  $this->productScopeRewriteGenerator = $productScopeRewriteGenerator
115  ?: $objectManager->get(ProductScopeRewriteGenerator::class);
116  }
117 
125  {
126  $mergeDataProvider = clone $this->mergeDataProviderPrototype;
127  $this->isSkippedProduct[$category->getEntityId()] = [];
128  $saveRewriteHistory = (bool)$category->getData('save_rewrites_history');
129  $storeId = (int)$category->getStoreId();
130 
131  if ($category->getChangedProductIds()) {
132  $this->generateChangedProductUrls($mergeDataProvider, $category, $storeId, $saveRewriteHistory);
133  } else {
134  $mergeDataProvider->merge(
135  $this->getCategoryProductsUrlRewrites(
136  $category,
137  $storeId,
138  $saveRewriteHistory,
139  $category->getEntityId()
140  )
141  );
142  }
143 
144  foreach ($this->childrenCategoriesProvider->getChildren($category, true) as $childCategory) {
145  $mergeDataProvider->merge(
146  $this->getCategoryProductsUrlRewrites(
147  $childCategory,
148  $storeId,
149  $saveRewriteHistory,
150  $category->getEntityId()
151  )
152  );
153  }
154 
155  return $mergeDataProvider->getData();
156  }
157 
163  {
164  $categoryIds = $this->childrenCategoriesProvider->getChildrenIds($category, true);
165  $categoryIds[] = $category->getId();
166  foreach ($categoryIds as $categoryId) {
167  $this->urlPersist->deleteByData(
168  [
170  $categoryId,
173  ]
174  );
175  $this->urlPersist->deleteByData(
176  [
178  $this->serializer->serialize(['category_id' => $categoryId]),
181  ]
182  );
183  }
184  }
185 
193  private function getCategoryProductsUrlRewrites(
195  $storeId,
196  $saveRewriteHistory,
197  $rootCategoryId = null
198  ) {
199  $mergeDataProvider = clone $this->mergeDataProviderPrototype;
200 
202  $productCollection = $this->productCollectionFactory->create();
203 
204  $productCollection->addCategoriesFilter(['eq' => [$category->getEntityId()]])
205  ->setStoreId($storeId)
206  ->addAttributeToSelect('name')
207  ->addAttributeToSelect('visibility')
208  ->addAttributeToSelect('url_key')
209  ->addAttributeToSelect('url_path');
210 
211  foreach ($productCollection as $product) {
212  if (isset($this->isSkippedProduct[$category->getEntityId()]) &&
213  in_array($product->getId(), $this->isSkippedProduct[$category->getEntityId()])
214  ) {
215  continue;
216  }
217  $this->isSkippedProduct[$category->getEntityId()][] = $product->getId();
218  $product->setStoreId($storeId);
219  $product->setData('save_rewrites_history', $saveRewriteHistory);
220  $mergeDataProvider->merge(
221  $this->categoryBasedProductRewriteGenerator->generate($product, $rootCategoryId)
222  );
223  }
224 
225  return $mergeDataProvider->getData();
226  }
227 
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  }
276  }
277  }
278 
285  private function getCategoryStoreIds(Category $category): array
286  {
287  $ids = $category->getStoreIds();
288  return array_filter($ids);
289  }
290 }
$objectManager
Definition: bootstrap.php:17
__construct(ChildrenCategoriesProvider $childrenCategoriesProvider, CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator, ProductUrlRewriteGenerator $productUrlRewriteGenerator, UrlPersistInterface $urlPersist, CollectionFactory $productCollectionFactory, CategoryProductUrlPathGenerator $categoryBasedProductRewriteGenerator, MergeDataProviderFactory $mergeDataProviderFactory=null, Json $serializer=null, ProductScopeRewriteGenerator $productScopeRewriteGenerator=null)