Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed URL Rewrite addition/removal on product website add/remove #26999

Merged
merged 12 commits into from
Mar 28, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,26 @@
namespace Magento\CatalogUrlRewrite\Observer;

use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ProductRepository;
use Magento\CatalogUrlRewrite\Model\ProductScopeRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator;
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Event\Observer;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException;
use Magento\UrlRewrite\Model\UrlPersistInterface;
use Magento\Framework\Event\ObserverInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Store\Api\StoreWebsiteRelationInterface;
use Magento\UrlRewrite\Model\Storage\DbStorage;
use Magento\Store\Model\Store;

/**
* Class ProductProcessUrlRewriteSavingObserver
*
* Observer to update the Rewrite URLs for a product.
* This observer is triggered on the save function when making changes
* to the products website on the Product Edit page.
*/
class ProductProcessUrlRewriteSavingObserver implements ObserverInterface
{
Expand All @@ -32,30 +44,71 @@ class ProductProcessUrlRewriteSavingObserver implements ObserverInterface
*/
private $productUrlPathGenerator;

/**
* @var StoreManagerInterface $storeManager
*/
private $storeManager;

/**
* @var StoreWebsiteRelationInterface
*/
private $storeWebsiteRelation;

/**
* @var ProductRepository $productRepository
*/
private $productRepository;

/**
* @var ProductScopeRewriteGenerator
*/
private $productScopeRewriteGenerator;

/**
* @var DbStorage
*/
private $dbStorage;

/**
* @param ProductUrlRewriteGenerator $productUrlRewriteGenerator
* @param UrlPersistInterface $urlPersist
* @param ProductUrlPathGenerator|null $productUrlPathGenerator
* @param ProductUrlPathGenerator $productUrlPathGenerator
* @param StoreManagerInterface $storeManager
* @param StoreWebsiteRelationInterface $storeWebsiteRelation
* @param ProductRepository $productRepository
* @param ProductScopeRewriteGenerator $productScopeRewriteGenerator
* @param DbStorage $dbStorage
*/
public function __construct(
ProductUrlRewriteGenerator $productUrlRewriteGenerator,
UrlPersistInterface $urlPersist,
ProductUrlPathGenerator $productUrlPathGenerator = null
ProductUrlPathGenerator $productUrlPathGenerator,
StoreManagerInterface $storeManager,
StoreWebsiteRelationInterface $storeWebsiteRelation,
ProductRepository $productRepository,
ProductScopeRewriteGenerator $productScopeRewriteGenerator,
DbStorage $dbStorage
) {
$this->productUrlRewriteGenerator = $productUrlRewriteGenerator;
$this->urlPersist = $urlPersist;
$this->productUrlPathGenerator = $productUrlPathGenerator ?: ObjectManager::getInstance()
->get(ProductUrlPathGenerator::class);
$this->productUrlPathGenerator = $productUrlPathGenerator;
$this->storeManager = $storeManager;
$this->storeWebsiteRelation = $storeWebsiteRelation;
$this->productRepository = $productRepository;
$this->productScopeRewriteGenerator = $productScopeRewriteGenerator;
$this->dbStorage = $dbStorage;
}

/**
* Generate urls for UrlRewrite and save it in storage
*
* @param \Magento\Framework\Event\Observer $observer
* @param Observer $observer
* @return void
* @throws \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException
* @throws UrlAlreadyExistsException
* @throws NoSuchEntityException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function execute(\Magento\Framework\Event\Observer $observer)
public function execute(Observer $observer)
{
/** @var Product $product */
$product = $observer->getEvent()->getProduct();
Expand All @@ -65,11 +118,46 @@ public function execute(\Magento\Framework\Event\Observer $observer)
|| $product->getIsChangedWebsites()
|| $product->dataHasChangedFor('visibility')
) {
if ($product->isVisibleInSiteVisibility()) {
$product->unsUrlPath();
$product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product));
//Refresh rewrite urls
$product->unsUrlPath();
$product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product));
if (!empty($this->productUrlRewriteGenerator->generate($product))) {
$this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product));
}

$storeIdsToRemove = [];
if ($this->productScopeRewriteGenerator->isGlobalScope($product->getStoreId())) {
//Remove any rewrite URLs for websites the product is not in, or is not visible in. Global Scope.
foreach ($this->storeManager->getWebsites() as $website) {
$websiteId = $website->getWebsiteId();
foreach ($this->storeWebsiteRelation->getStoreByWebsiteId($websiteId) as $storeid) {
//Load the product for the store we are processing so we can see if it is visible
$storeProduct = $this->productRepository->getById(
gwharton marked this conversation as resolved.
Show resolved Hide resolved
$product->getId(),
false,
$storeid,
true
);
if (!$storeProduct->isVisibleInSiteVisibility() ||
!in_array($websiteId, $product->getWebsiteIds())) {
gwharton marked this conversation as resolved.
Show resolved Hide resolved
$storeIdsToRemove[] = $storeid;
};
}
}
} else {
//Only remove rewrite for current scope
if (!$product->isVisibleInSiteVisibility() ||
!in_array($product->getStoreId(), $product->getStoreIds())) {
gwharton marked this conversation as resolved.
Show resolved Hide resolved
$storeIdsToRemove[] = $product->getStoreId();
}
}
if (count($storeIdsToRemove)) {
$this->dbStorage->deleteEntitiesFromStores(
$storeIdsToRemove,
[$product->getId()],
ProductUrlRewriteGenerator::ENTITY_TYPE
);
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogUrlRewrite\Plugin;

use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\Product\Action;
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
use Magento\Store\Api\StoreWebsiteRelationInterface;
use Magento\Store\Model\Store;
use Magento\UrlRewrite\Model\Storage\DbStorage;
use Magento\UrlRewrite\Model\UrlPersistInterface;

/**
* Class ProductProcessUrlRewriteRemovingPlugin
*
* Plugin to update the Rewrite URLs for a product.
* This plugin is triggered by the product_action_attribute.website.update
* consumer in response to Mass Action changes in the Admin Product Grid.
*/
class ProductProcessUrlRewriteRemovingPlugin
{
/**
* @var ProductRepositoryInterface $productRepository
*/
private $productRepository;

/**
* @var StoreWebsiteRelationInterface $storeWebsiteRelation
*/
private $storeWebsiteRelation;

/**
* @var UrlPersistInterface $urlPersist
*/
private $urlPersist;

/**
* @var ProductUrlRewriteGenerator $productUrlRewriteGenerator
*/
private $productUrlRewriteGenerator;

/**
* @var DbStorage $dbStorage
*/
private $dbStorage;

/**
* @param ProductRepositoryInterface $productRepository
* @param StoreWebsiteRelationInterface $storeWebsiteRelation
* @param UrlPersistInterface $urlPersist
* @param ProductUrlRewriteGenerator $productUrlRewriteGenerator
* @param DbStorage $dbStorage
*/
public function __construct(
ProductRepositoryInterface $productRepository,
StoreWebsiteRelationInterface $storeWebsiteRelation,
UrlPersistInterface $urlPersist,
ProductUrlRewriteGenerator $productUrlRewriteGenerator,
DbStorage $dbStorage
) {
$this->productRepository = $productRepository;
$this->storeWebsiteRelation = $storeWebsiteRelation;
$this->urlPersist = $urlPersist;
$this->productUrlRewriteGenerator = $productUrlRewriteGenerator;
$this->dbStorage = $dbStorage;
}

/**
* Function afterUpdateWebsites
*
* @param Action $subject
* @param void $result
* @param array $productIds
* @param array $websiteIds
* @param string $type
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function afterUpdateWebsites(
Action $subject,
$result,
$productIds,
$websiteIds,
$type
) {
foreach ($productIds as $productId) {
/* @var Product $product */
$product = $this->productRepository->getById(
$productId,
false,
Store::DEFAULT_STORE_ID,
true
);

// Refresh all existing URLs for the product
if (!empty($this->productUrlRewriteGenerator->generate($product))) {
if ($product->isVisibleInSiteVisibility()) {
$this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product));
}
}
}

$storeIdsToRemove = [];
// Remove the URLs from websites this product no longer belongs to
if ($type == "remove" && $websiteIds && $productIds) {
gwharton marked this conversation as resolved.
Show resolved Hide resolved
foreach ($websiteIds as $webId) {
foreach ($this->storeWebsiteRelation->getStoreByWebsiteId($webId) as $storeid) {
$storeIdsToRemove[] = $storeid;
}
}
if (count($storeIdsToRemove)) {
$this->dbStorage->deleteEntitiesFromStores(
$storeIdsToRemove,
$productIds,
ProductUrlRewriteGenerator::ENTITY_TYPE
);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<testCaseId value="MC-17515"/>
<useCaseId value="MAGETWO-69825"/>
<group value="CatalogUrlRewrite"/>
<group value="urlRewrite"/>
</annotations>
<before>
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
Expand Down
Loading