Skip to content

Commit 0b36bd2

Browse files
committed
Merge remote-tracking branch 'origin/imported-magento-magento2-32194' into 2.4-develop-pr138
2 parents 8137771 + 89c122d commit 0b36bd2

File tree

3 files changed

+192
-1
lines changed

3 files changed

+192
-1
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Product/Validate.php

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
use Magento\Catalog\Controller\Adminhtml\Product;
1313
use Magento\Framework\App\ObjectManager;
1414
use Magento\Store\Model\StoreManagerInterface;
15+
use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException;
16+
use Magento\CatalogUrlRewrite\Model\Product\Validator as ProductUrlRewriteValidator;
17+
use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator;
1518

1619
/**
1720
* Product validate
@@ -57,6 +60,16 @@ class Validate extends Product implements HttpPostActionInterface, HttpGetAction
5760
*/
5861
private $storeManager;
5962

63+
/**
64+
* @var ProductUrlPathGenerator
65+
*/
66+
private $productUrlPathGenerator;
67+
68+
/**
69+
* @var ProductUrlRewriteValidator
70+
*/
71+
private $productUrlRewriteValidator;
72+
6073
/**
6174
* @param Action\Context $context
6275
* @param Builder $productBuilder
@@ -65,6 +78,8 @@ class Validate extends Product implements HttpPostActionInterface, HttpGetAction
6578
* @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
6679
* @param \Magento\Framework\View\LayoutFactory $layoutFactory
6780
* @param \Magento\Catalog\Model\ProductFactory $productFactory
81+
* @param ProductUrlRewriteValidator $productUrlRewriteValidator
82+
* @param ProductUrlPathGenerator $productUrlPathGenerator
6883
*/
6984
public function __construct(
7085
\Magento\Backend\App\Action\Context $context,
@@ -73,14 +88,18 @@ public function __construct(
7388
\Magento\Catalog\Model\Product\Validator $productValidator,
7489
\Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
7590
\Magento\Framework\View\LayoutFactory $layoutFactory,
76-
\Magento\Catalog\Model\ProductFactory $productFactory
91+
\Magento\Catalog\Model\ProductFactory $productFactory,
92+
ProductUrlRewriteValidator $productUrlRewriteValidator,
93+
ProductUrlPathGenerator $productUrlPathGenerator
7794
) {
7895
$this->_dateFilter = $dateFilter;
7996
$this->productValidator = $productValidator;
8097
parent::__construct($context, $productBuilder);
8198
$this->resultJsonFactory = $resultJsonFactory;
8299
$this->layoutFactory = $layoutFactory;
83100
$this->productFactory = $productFactory;
101+
$this->productUrlRewriteValidator = $productUrlRewriteValidator;
102+
$this->productUrlPathGenerator = $productUrlPathGenerator;
84103
}
85104

86105
/**
@@ -130,11 +149,22 @@ public function execute()
130149
$resource->getAttribute('news_from_date')->setMaxValue($product->getNewsToDate());
131150
$resource->getAttribute('custom_design_from')->setMaxValue($product->getCustomDesignTo());
132151

152+
if (!$product->getUrlKey()) {
153+
$urlKey = $this->productUrlPathGenerator->getUrlKey($product);
154+
$product->setUrlKey($urlKey);
155+
}
156+
$this->productUrlRewriteValidator->validateUrlKeyConflicts($product);
133157
$this->productValidator->validate($product, $this->getRequest(), $response);
134158
} catch (\Magento\Eav\Model\Entity\Attribute\Exception $e) {
135159
$response->setError(true);
136160
$response->setAttribute($e->getAttributeCode());
137161
$response->setMessages([$e->getMessage()]);
162+
} catch (UrlAlreadyExistsException $e) {
163+
$this->messageManager->addExceptionMessage($e);
164+
$layout = $this->layoutFactory->create();
165+
$layout->initMessages();
166+
$response->setError(true);
167+
$response->setHtmlMessage($layout->getMessagesBlock()->getGroupedHtml());
138168
} catch (\Magento\Framework\Exception\LocalizedException $e) {
139169
$response->setError(true);
140170
$response->setMessages([$e->getMessage()]);
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogUrlRewrite\Model\Product;
9+
10+
use Magento\Catalog\Model\Product;
11+
use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator;
12+
use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException;
13+
use Magento\UrlRewrite\Model\UrlFinderInterface;
14+
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
15+
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
16+
use Magento\Store\Model\StoreManagerInterface;
17+
18+
/**
19+
* Url Rewrites Product validator.
20+
*/
21+
class Validator
22+
{
23+
/**
24+
* @var ProductUrlPathGenerator
25+
*/
26+
private $productUrlPathGenerator;
27+
28+
/**
29+
* @var UrlFinderInterface
30+
*/
31+
private $urlFinder;
32+
33+
/**
34+
* @var StoreManagerInterface
35+
*/
36+
private $storeManager;
37+
38+
/**
39+
* @param ProductUrlPathGenerator $productUrlPathGenerator
40+
* @param UrlFinderInterface $urlFinder
41+
* @param StoreManagerInterface $storeManager
42+
*/
43+
public function __construct(
44+
ProductUrlPathGenerator $productUrlPathGenerator,
45+
UrlFinderInterface $urlFinder,
46+
StoreManagerInterface $storeManager
47+
) {
48+
$this->productUrlPathGenerator = $productUrlPathGenerator;
49+
$this->urlFinder = $urlFinder;
50+
$this->storeManager = $storeManager;
51+
}
52+
53+
/**
54+
* Validate Url Key of a Product has no conflicts.
55+
*
56+
* @param Product $product
57+
* @throws UrlAlreadyExistsException
58+
*/
59+
public function validateUrlKeyConflicts(Product $product): void
60+
{
61+
$stores = $this->storeManager->getStores();
62+
63+
$storeIdsToPathForSave = [];
64+
$searchData = [
65+
UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE,
66+
UrlRewrite::REQUEST_PATH => [],
67+
];
68+
69+
foreach ($stores as $store) {
70+
if (!in_array($store->getWebsiteId(), $product->getWebsiteIds())) {
71+
continue;
72+
}
73+
74+
$urlPath = $this->productUrlPathGenerator->getUrlPathWithSuffix($product, $store->getId());
75+
$storeIdsToPathForSave[$store->getId()] = $urlPath;
76+
$searchData[UrlRewrite::REQUEST_PATH][] = $urlPath;
77+
}
78+
79+
$urlRewrites = $this->urlFinder->findAllByData($searchData);
80+
$exceptionData = [];
81+
82+
foreach ($urlRewrites as $urlRewrite) {
83+
if (in_array($urlRewrite->getRequestPath(), $storeIdsToPathForSave)
84+
&& isset($storeIdsToPathForSave[$urlRewrite->getStoreId()])
85+
&& $storeIdsToPathForSave[$urlRewrite->getStoreId()] === $urlRewrite->getRequestPath()
86+
&& $product->getId() !== $urlRewrite->getEntityId()
87+
) {
88+
$exceptionData[$urlRewrite->getUrlRewriteId()] = $urlRewrite->toArray();
89+
}
90+
}
91+
92+
if ($exceptionData) {
93+
throw new UrlAlreadyExistsException(
94+
__('URL key for specified store already exists.'),
95+
null,
96+
0,
97+
$exceptionData
98+
);
99+
}
100+
}
101+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Controller\Adminhtml\Product;
9+
10+
use Magento\TestFramework\TestCase\AbstractBackendController;
11+
use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException;
12+
use Magento\Framework\App\Request\Http as HttpRequest;
13+
use Magento\Catalog\Model\Product\Type;
14+
15+
/**
16+
* @magentoAppArea adminhtml
17+
*/
18+
class ValidateTest extends AbstractBackendController
19+
{
20+
/**
21+
* @magentoDataFixture Magento/Catalog/_files/product_simple.php
22+
*/
23+
public function testNotUniqueUrlKey()
24+
{
25+
$this->getRequest()
26+
->setMethod(HttpRequest::METHOD_POST);
27+
28+
$postData = [
29+
'product' => [
30+
'attribute_set_id' => '4',
31+
'status' => '1',
32+
'name' => 'Simple product',
33+
'sku' => 'simple',
34+
'type_id' => Type::TYPE_SIMPLE,
35+
'quantity_and_stock_status' => [
36+
'qty' => '10',
37+
'is_in_stock' => '1',
38+
],
39+
'website_ids' => [
40+
1 => '1',
41+
],
42+
'price' => '100',
43+
],
44+
];
45+
46+
$this->getRequest()
47+
->setPostValue($postData);
48+
$this->dispatch('backend/catalog/product/validate/');
49+
$responseBody = $this->getResponse()
50+
->getBody();
51+
52+
$message = __('The value specified in the URL Key field would generate a URL that already exists.');
53+
$additionalInfo = __('To resolve this conflict, you can either change the value of the URL Key field '
54+
. '(located in the Search Engine Optimization section) to a unique value, or change the Request Path fields'
55+
. ' in all locations listed below:');
56+
57+
$this->assertStringContainsString((string)$message, $responseBody);
58+
$this->assertStringContainsString((string)$additionalInfo, $responseBody);
59+
}
60+
}

0 commit comments

Comments
 (0)