Skip to content

Commit 650f254

Browse files
authored
Merge pull request #6444 from magento-tsg/2.4-develop-pr113
[Arrows] Fixes for 2.4 (pr113) (2.4-develop)
2 parents b941603 + a41bd02 commit 650f254

File tree

47 files changed

+1728
-328
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1728
-328
lines changed

app/code/Magento/Catalog/Model/Product/Option/Type/File.php

+21-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66

77
namespace Magento\Catalog\Model\Product\Option\Type;
88

9+
use Magento\Catalog\Model\Product\Exception as ProductException;
10+
use Magento\Catalog\Helper\Product as ProductHelper;
911
use Magento\Framework\App\Filesystem\DirectoryList;
1012
use Magento\Framework\Filesystem;
1113
use Magento\Framework\Exception\LocalizedException;
12-
use Magento\Catalog\Model\Product\Exception as ProductException;
1314
use Magento\Framework\Serialize\Serializer\Json;
1415
use Magento\Framework\App\ObjectManager;
1516

@@ -91,6 +92,11 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
9192
*/
9293
private $filesystem;
9394

95+
/**
96+
* @var ProductHelper
97+
*/
98+
private $productHelper;
99+
94100
/**
95101
* @param \Magento\Checkout\Model\Session $checkoutSession
96102
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
@@ -103,6 +109,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
103109
* @param array $data
104110
* @param Filesystem $filesystem
105111
* @param Json|null $serializer
112+
* @param ProductHelper|null $productHelper
106113
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
107114
*/
108115
public function __construct(
@@ -116,7 +123,8 @@ public function __construct(
116123
\Magento\Framework\Escaper $escaper,
117124
array $data = [],
118125
Filesystem $filesystem = null,
119-
Json $serializer = null
126+
Json $serializer = null,
127+
ProductHelper $productHelper = null
120128
) {
121129
$this->_itemOptionFactory = $itemOptionFactory;
122130
$this->_urlBuilder = $urlBuilder;
@@ -129,6 +137,7 @@ public function __construct(
129137
$this->validatorInfo = $validatorInfo;
130138
$this->validatorFile = $validatorFile;
131139
$this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
140+
$this->productHelper = $productHelper ?: ObjectManager::getInstance()->get(ProductHelper::class);
132141
parent::__construct($checkoutSession, $scopeConfig, $data);
133142
}
134143

@@ -223,12 +232,21 @@ public function validateUserValue($values)
223232
$this->setIsValid(true);
224233
$option = $this->getOption();
225234

235+
if (isset($values['files_prefix'])) {
236+
$processingParams = ['files_prefix' => $values['files_prefix']];
237+
$processingParams = array_merge($this->_getProcessingParams()->getData(), $processingParams);
238+
$this->productHelper->addParamsToBuyRequest($this->getRequest(), $processingParams);
239+
}
240+
226241
/*
227242
* Check whether we receive uploaded file or restore file by: reorder/edit configuration or
228243
* previous configuration with no newly uploaded file
229244
*/
230245
$fileInfo = null;
231-
if (isset($values[$option->getId()]) && is_array($values[$option->getId()])) {
246+
if (isset($values[$option->getId()])) {
247+
if (is_string($values[$option->getId()])) {
248+
$values[$option->getId()] = explode(',', $values[$option->getId()]);
249+
}
232250
// Legacy style, file info comes in array with option id index
233251
$fileInfo = $values[$option->getId()];
234252
} else {

app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml

+4
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,10 @@
586586
<var key="sku" entityType="product" entityKey="sku" />
587587
<requiredEntity type="product_option">ProductOptionValueDropdown</requiredEntity>
588588
</entity>
589+
<entity name="productWithFileOption" type="product">
590+
<var key="sku" entityType="product" entityKey="sku" />
591+
<requiredEntity type="product_option">ProductOptionFile</requiredEntity>
592+
</entity>
589593
<entity name="productWithDropdownAndFieldOptions" type="product">
590594
<var key="sku" entityType="product" entityKey="sku" />
591595
<requiredEntity type="product_option">ProductOptionValueDropdown</requiredEntity>

app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ define([
607607
* @param method can be 'item_confirm', 'item_restore', 'current_confirmed_to_form', 'form_confirmed_to_confirmed'
608608
*/
609609
_processFieldsData: function (method) {
610+
var self = this;
610611

611612
/**
612613
* Internal function for rename fields names of some list type
@@ -616,12 +617,14 @@ define([
616617
* @param blockItem
617618
*/
618619
var _renameFields = function (method, blockItem, listType) {
619-
var pattern = null;
620-
var patternFlat = null;
621-
var replacement = null;
622-
var replacementFlat = null;
623-
var scopeArr = blockItem.id.match(/.*\[\w+\]\[([^\]]+)\]$/);
624-
var itemId = scopeArr[1];
620+
var pattern = null;
621+
var patternFlat = null;
622+
var patternPrefix = RegExp('\\s', 'g');
623+
var replacement = null;
624+
var replacementFlat = null;
625+
var replacementPrefix = '_';
626+
var scopeArr = blockItem.id.match(/.*\[\w+\]\[([^\]]+)\]$/);
627+
var itemId = scopeArr[1];
625628

626629
if (method == 'current_confirmed_to_form') {
627630
pattern = RegExp('(\\w+)(\\[?)');
@@ -651,6 +654,14 @@ define([
651654
var rename = function (elms) {
652655
for (var i = 0; i < elms.length; i++) {
653656
if (elms[i].name && elms[i].type == 'file') {
657+
var prefixName = 'options[files_prefix]',
658+
prefixValue = 'item_' + itemId + '_';
659+
660+
self.blockFormFields.insert(new Element('input', {
661+
type: 'hidden',
662+
name: prefixName.replace(pattern, replacement),
663+
value: prefixValue.replace(patternPrefix, replacementPrefix)
664+
}));
654665
elms[i].name = elms[i].name.replace(patternFlat, replacementFlat);
655666
} else if (elms[i].name) {
656667
elms[i].name = elms[i].name.replace(pattern, replacement);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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\Api\Data\ProductInterface;
11+
use Magento\CatalogUrlRewrite\Model\ResourceModel\Product\GetUrlRewriteData;
12+
use Magento\Store\Model\Store;
13+
14+
/**
15+
* Product data needed for url rewrite generation locator class
16+
*/
17+
class GetProductUrlRewriteDataByStore
18+
{
19+
/**
20+
* @var array
21+
*/
22+
private $urlRewriteData = [];
23+
24+
/**
25+
* @var GetUrlRewriteData
26+
*/
27+
private $getUrlRewriteData;
28+
29+
/**
30+
* @param GetUrlRewriteData $getUrlRewriteData
31+
*/
32+
public function __construct(GetUrlRewriteData $getUrlRewriteData)
33+
{
34+
$this->getUrlRewriteData = $getUrlRewriteData;
35+
}
36+
37+
/**
38+
* Retrieves data for product by store
39+
*
40+
* @param ProductInterface $product
41+
* @param int $storeId
42+
* @return array
43+
*/
44+
public function execute(ProductInterface $product, int $storeId): array
45+
{
46+
$productId = $product->getId();
47+
if (isset($this->urlRewriteData[$productId][$storeId])) {
48+
return $this->urlRewriteData[$productId][$storeId];
49+
}
50+
if (empty($this->urlRewriteData[$productId])) {
51+
$storesData = $this->getUrlRewriteData->execute($product);
52+
foreach ($storesData as $storeData) {
53+
$this->urlRewriteData[$productId][$storeData['store_id']] = [
54+
'visibility' => (int)($storeData['visibility'] ?? $storesData[Store::DEFAULT_STORE_ID]['visibility']),
55+
'url_key' => $storeData['url_key'] ?? $storesData[Store::DEFAULT_STORE_ID]['url_key'],
56+
];
57+
}
58+
}
59+
60+
if (!isset($this->urlRewriteData[$productId][$storeId])) {
61+
$this->urlRewriteData[$productId][$storeId] = $this->urlRewriteData[$productId][Store::DEFAULT_STORE_ID];
62+
}
63+
64+
return $this->urlRewriteData[$productId][$storeId];
65+
}
66+
67+
/**
68+
* Clears product url rewrite data in local cache
69+
*
70+
* @param ProductInterface $product
71+
*/
72+
public function clearProductUrlRewriteDataCache(ProductInterface $product)
73+
{
74+
unset($this->urlRewriteData[$product->getId()]);
75+
}
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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\Products;
9+
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\Catalog\Model\Product\Visibility;
13+
use Magento\CatalogUrlRewrite\Model\Product\GetProductUrlRewriteDataByStore;
14+
use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator;
15+
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
16+
use Magento\CatalogUrlRewrite\Service\V1\StoreViewService;
17+
use Magento\Store\Model\Store;
18+
use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException;
19+
use Magento\UrlRewrite\Model\UrlPersistInterface;
20+
21+
/**
22+
* Update existing url rewrites or create new ones if needed
23+
*/
24+
class AppendUrlRewritesToProducts
25+
{
26+
/**
27+
* @var ProductUrlRewriteGenerator
28+
*/
29+
private $productUrlRewriteGenerator;
30+
31+
/**
32+
* @var StoreViewService
33+
*/
34+
private $storeViewService;
35+
36+
/**
37+
* @var ProductUrlPathGenerator
38+
*/
39+
private $productUrlPathGenerator;
40+
41+
/**
42+
* @var UrlPersistInterface
43+
*/
44+
private $urlPersist;
45+
46+
/**
47+
* @var GetProductUrlRewriteDataByStore
48+
*/
49+
private $getDataByStore;
50+
51+
/**
52+
* @param ProductUrlRewriteGenerator $urlRewriteGenerator
53+
* @param StoreViewService $storeViewService
54+
* @param ProductUrlPathGenerator $urlPathGenerator
55+
* @param UrlPersistInterface $urlPersist
56+
* @param GetProductUrlRewriteDataByStore $getDataByStore
57+
*/
58+
public function __construct(
59+
ProductUrlRewriteGenerator $urlRewriteGenerator,
60+
StoreViewService $storeViewService,
61+
ProductUrlPathGenerator $urlPathGenerator,
62+
UrlPersistInterface $urlPersist,
63+
GetProductUrlRewriteDataByStore $getDataByStore
64+
) {
65+
$this->productUrlRewriteGenerator = $urlRewriteGenerator;
66+
$this->storeViewService = $storeViewService;
67+
$this->productUrlPathGenerator = $urlPathGenerator;
68+
$this->urlPersist = $urlPersist;
69+
$this->getDataByStore = $getDataByStore;
70+
}
71+
72+
/**
73+
* Update existing rewrites and add for specific stores websites
74+
*
75+
* @param ProductInterface[] $products
76+
* @param array $storesToAdd
77+
* @throws UrlAlreadyExistsException
78+
*/
79+
public function execute(array $products, array $storesToAdd): void
80+
{
81+
foreach ($products as $product) {
82+
$forceGenerateDefault = false;
83+
foreach ($storesToAdd as $storeId) {
84+
if ($this->needGenerateUrlForStore($product, (int)$storeId)) {
85+
$urls[] = $this->generateUrls($product, (int)$storeId);
86+
} elseif ((int)$product->getStoreId() !== Store::DEFAULT_STORE_ID) {
87+
$forceGenerateDefault = true;
88+
}
89+
}
90+
if ($product->getStoreId() === Store::DEFAULT_STORE_ID
91+
|| $this->isProductAssignedToStore($product)) {
92+
$product->unsUrlPath();
93+
$product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product));
94+
$urls[] = $this->productUrlRewriteGenerator->generate($product);
95+
}
96+
if ($forceGenerateDefault && $product->getStoreId() !== Store::DEFAULT_STORE_ID) {
97+
$urls[] = $this->generateUrls($product, Store::DEFAULT_STORE_ID);
98+
}
99+
$this->getDataByStore->clearProductUrlRewriteDataCache($product);
100+
}
101+
if (!empty($urls)) {
102+
$this->urlPersist->replace(array_merge(...$urls));
103+
}
104+
}
105+
106+
/**
107+
* Generate urls for specific store
108+
*
109+
* @param ProductInterface $product
110+
* @param int $storeId
111+
* @return array
112+
*/
113+
private function generateUrls(ProductInterface $product, int $storeId): array
114+
{
115+
$storeData = $this->getDataByStore->execute($product, $storeId);
116+
$origStoreId = $product->getStoreId();
117+
$origVisibility = $product->getVisibility();
118+
$origUrlKey = $product->getUrlKey();
119+
$product->setStoreId($storeId);
120+
$product->setVisibility($storeData['visibility'] ?? Visibility::VISIBILITY_NOT_VISIBLE);
121+
$product->setUrlKey($storeData['url_key'] ?? '');
122+
$product->unsUrlPath();
123+
$product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product));
124+
$urls = $this->productUrlRewriteGenerator->generate($product);
125+
$product->setStoreId($origStoreId);
126+
$product->setVisibility($origVisibility);
127+
$product->setUrlKey($origUrlKey);
128+
129+
return $urls;
130+
}
131+
132+
/**
133+
* Does product has scope overridden url key value
134+
*
135+
* @param ProductInterface $product
136+
* @param int $storeId
137+
* @return bool
138+
*/
139+
private function needGenerateUrlForStore(ProductInterface $product, int $storeId): bool
140+
{
141+
return (int)$product->getStoreId() !== $storeId
142+
&& $this->storeViewService->doesEntityHaveOverriddenUrlKeyForStore(
143+
$storeId,
144+
$product->getId(),
145+
Product::ENTITY
146+
);
147+
}
148+
149+
/**
150+
* Is product still assigned to store which request is performed from
151+
*
152+
* @param ProductInterface $product
153+
* @return bool
154+
*/
155+
private function isProductAssignedToStore(ProductInterface $product): bool
156+
{
157+
return in_array($product->getStoreId(), $product->getStoreIds());
158+
}
159+
}

0 commit comments

Comments
 (0)