Skip to content

Commit c1fbef5

Browse files
authored
Merge branch '2.4-develop' into fix-26976
2 parents d231549 + c36db34 commit c1fbef5

File tree

104 files changed

+1980
-253
lines changed

Some content is hidden

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

104 files changed

+1980
-253
lines changed

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
<p align="center">
2-
<a href="https://magento.com">
3-
<img src="https://static.magento.com/sites/all/themes/magento/logo.svg" width="300px" alt="Magento" />
4-
</a>
5-
</p>
6-
<p align="center">
7-
<br /><br />
2+
<a href="https://magento.com">
3+
<img src="https://static.magento.com/sites/all/themes/magento/logo.svg" width="300px" alt="Magento Commerce" />
4+
</a>
5+
<br />
6+
<br />
87
<a href="https://www.codetriage.com/magento/magento2">
98
<img src="https://www.codetriage.com/magento/magento2/badges/users.svg" alt="Open Source Helpers" />
109
</a>

app/code/Magento/Analytics/Model/ReportWriter.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\Analytics\Model;
79

810
use Magento\Analytics\ReportXml\DB\ReportValidator;
911
use Magento\Framework\Filesystem\Directory\WriteInterface;
1012

1113
/**
1214
* Writes reports in files in csv format
13-
* @inheritdoc
1415
*/
1516
class ReportWriter implements ReportWriterInterface
1617
{
@@ -54,7 +55,7 @@ public function __construct(
5455
}
5556

5657
/**
57-
* {@inheritdoc}
58+
* @inheritdoc
5859
*/
5960
public function write(WriteInterface $directory, $path)
6061
{
@@ -81,7 +82,7 @@ public function write(WriteInterface $directory, $path)
8182
$headers = array_keys($row);
8283
$stream->writeCsv($headers);
8384
}
84-
$stream->writeCsv($row);
85+
$stream->writeCsv($this->prepareRow($row));
8586
}
8687
$stream->unlock();
8788
$stream->close();
@@ -98,4 +99,18 @@ public function write(WriteInterface $directory, $path)
9899

99100
return true;
100101
}
102+
103+
/**
104+
* Replace wrong symbols in row
105+
*
106+
* @param array $row
107+
* @return array
108+
*/
109+
private function prepareRow(array $row): array
110+
{
111+
$row = preg_replace('/(?<!\\\\)"/', '\\"', $row);
112+
$row = preg_replace('/[\\\\]+/', '\\', $row);
113+
114+
return $row;
115+
}
101116
}

app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
use Magento\Analytics\Model\ReportWriter;
1313
use Magento\Analytics\ReportXml\DB\ReportValidator;
1414
use Magento\Analytics\ReportXml\ReportProvider;
15-
use Magento\Framework\Filesystem\Directory\WriteInterface;
15+
use Magento\Framework\Filesystem\Directory\WriteInterface as DirectoryWriteInterface;
16+
use Magento\Framework\Filesystem\File\WriteInterface as FileWriteInterface;
1617
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
1718
use PHPUnit\Framework\MockObject\MockObject;
1819
use PHPUnit\Framework\TestCase;
@@ -48,7 +49,7 @@ class ReportWriterTest extends TestCase
4849
private $objectManagerHelper;
4950

5051
/**
51-
* @var WriteInterface|MockObject
52+
* @var DirectoryWriteInterface|MockObject
5253
*/
5354
private $directoryMock;
5455

@@ -82,7 +83,7 @@ protected function setUp(): void
8283
$this->reportValidatorMock = $this->createMock(ReportValidator::class);
8384
$this->providerFactoryMock = $this->createMock(ProviderFactory::class);
8485
$this->reportProviderMock = $this->createMock(ReportProvider::class);
85-
$this->directoryMock = $this->getMockBuilder(WriteInterface::class)
86+
$this->directoryMock = $this->getMockBuilder(DirectoryWriteInterface::class)
8687
->getMockForAbstractClass();
8788
$this->objectManagerHelper = new ObjectManagerHelper($this);
8889

@@ -98,16 +99,15 @@ protected function setUp(): void
9899

99100
/**
100101
* @param array $configData
102+
* @param array $fileData
103+
* @param array $expectedFileData
101104
* @return void
102105
*
103106
* @dataProvider configDataProvider
104107
*/
105-
public function testWrite(array $configData)
108+
public function testWrite(array $configData, array $fileData, array $expectedFileData): void
106109
{
107110
$errors = [];
108-
$fileData = [
109-
['number' => 1, 'type' => 'Shoes Usual']
110-
];
111111
$this->configInterfaceMock
112112
->expects($this->once())
113113
->method('get')
@@ -126,7 +126,7 @@ public function testWrite(array $configData)
126126
->with($parameterName ?: null)
127127
->willReturn($fileData);
128128
$errorStreamMock = $this->getMockBuilder(
129-
\Magento\Framework\Filesystem\File\WriteInterface::class
129+
FileWriteInterface::class
130130
)->getMockForAbstractClass();
131131
$errorStreamMock
132132
->expects($this->once())
@@ -136,8 +136,8 @@ public function testWrite(array $configData)
136136
->expects($this->exactly(2))
137137
->method('writeCsv')
138138
->withConsecutive(
139-
[array_keys($fileData[0])],
140-
[$fileData[0]]
139+
[array_keys($expectedFileData[0])],
140+
[$expectedFileData[0]]
141141
);
142142
$errorStreamMock->expects($this->once())->method('unlock');
143143
$errorStreamMock->expects($this->once())->method('close');
@@ -164,12 +164,12 @@ public function testWrite(array $configData)
164164
*
165165
* @dataProvider configDataProvider
166166
*/
167-
public function testWriteErrorFile($configData)
167+
public function testWriteErrorFile(array $configData): void
168168
{
169169
$errors = ['orders', 'SQL Error: test'];
170170
$this->configInterfaceMock->expects($this->once())->method('get')->willReturn([$configData]);
171171
$errorStreamMock = $this->getMockBuilder(
172-
\Magento\Framework\Filesystem\File\WriteInterface::class
172+
FileWriteInterface::class
173173
)->getMockForAbstractClass();
174174
$errorStreamMock->expects($this->once())->method('lock');
175175
$errorStreamMock->expects($this->once())->method('writeCsv')->with($errors);
@@ -184,7 +184,7 @@ public function testWriteErrorFile($configData)
184184
/**
185185
* @return void
186186
*/
187-
public function testWriteEmptyReports()
187+
public function testWriteEmptyReports(): void
188188
{
189189
$this->configInterfaceMock->expects($this->once())->method('get')->willReturn([]);
190190
$this->reportValidatorMock->expects($this->never())->method('validate');
@@ -195,11 +195,11 @@ public function testWriteEmptyReports()
195195
/**
196196
* @return array
197197
*/
198-
public function configDataProvider()
198+
public function configDataProvider(): array
199199
{
200200
return [
201201
'reportProvider' => [
202-
[
202+
'configData' => [
203203
'providers' => [
204204
[
205205
'name' => $this->providerName,
@@ -209,6 +209,12 @@ public function configDataProvider()
209209
],
210210
]
211211
]
212+
],
213+
'fileData' => [
214+
['number' => 1, 'type' => 'Shoes\"" Usual\\\\"']
215+
],
216+
'expectedFileData' => [
217+
['number' => 1, 'type' => 'Shoes\"\" Usual\\"']
212218
]
213219
],
214220
];

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

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,27 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

78
namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute;
89

10+
use Magento\Backend\App\Action\Context;
911
use Magento\Catalog\Controller\Adminhtml\Product\Attribute as AttributeAction;
12+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
13+
use Magento\Eav\Model\Entity\Attribute\Set;
1014
use Magento\Eav\Model\Validator\Attribute\Code as AttributeCodeValidator;
1115
use Magento\Framework\App\Action\HttpGetActionInterface;
1216
use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
1317
use Magento\Framework\App\ObjectManager;
18+
use Magento\Framework\Cache\FrontendInterface;
19+
use Magento\Framework\Controller\Result\JsonFactory;
20+
use Magento\Framework\Controller\ResultInterface;
1421
use Magento\Framework\DataObject;
1522
use Magento\Framework\Escaper;
23+
use Magento\Framework\Registry;
1624
use Magento\Framework\Serialize\Serializer\FormData;
25+
use Magento\Framework\View\LayoutFactory;
26+
use Magento\Framework\View\Result\PageFactory;
1727

1828
/**
1929
* Product attribute validate controller.
@@ -25,12 +35,12 @@ class Validate extends AttributeAction implements HttpGetActionInterface, HttpPo
2535
const DEFAULT_MESSAGE_KEY = 'message';
2636

2737
/**
28-
* @var \Magento\Framework\Controller\Result\JsonFactory
38+
* @var JsonFactory
2939
*/
3040
protected $resultJsonFactory;
3141

3242
/**
33-
* @var \Magento\Framework\View\LayoutFactory
43+
* @var LayoutFactory
3444
*/
3545
protected $layoutFactory;
3646

@@ -57,25 +67,25 @@ class Validate extends AttributeAction implements HttpGetActionInterface, HttpPo
5767
/**
5868
* Constructor
5969
*
60-
* @param \Magento\Backend\App\Action\Context $context
61-
* @param \Magento\Framework\Cache\FrontendInterface $attributeLabelCache
62-
* @param \Magento\Framework\Registry $coreRegistry
63-
* @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
64-
* @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
65-
* @param \Magento\Framework\View\LayoutFactory $layoutFactory
70+
* @param Context $context
71+
* @param FrontendInterface $attributeLabelCache
72+
* @param Registry $coreRegistry
73+
* @param PageFactory $resultPageFactory
74+
* @param JsonFactory $resultJsonFactory
75+
* @param LayoutFactory $layoutFactory
6676
* @param array $multipleAttributeList
6777
* @param FormData|null $formDataSerializer
6878
* @param AttributeCodeValidator|null $attributeCodeValidator
6979
* @param Escaper $escaper
7080
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
7181
*/
7282
public function __construct(
73-
\Magento\Backend\App\Action\Context $context,
74-
\Magento\Framework\Cache\FrontendInterface $attributeLabelCache,
75-
\Magento\Framework\Registry $coreRegistry,
76-
\Magento\Framework\View\Result\PageFactory $resultPageFactory,
77-
\Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
78-
\Magento\Framework\View\LayoutFactory $layoutFactory,
83+
Context $context,
84+
FrontendInterface $attributeLabelCache,
85+
Registry $coreRegistry,
86+
PageFactory $resultPageFactory,
87+
JsonFactory $resultJsonFactory,
88+
LayoutFactory $layoutFactory,
7989
array $multipleAttributeList = [],
8090
FormData $formDataSerializer = null,
8191
AttributeCodeValidator $attributeCodeValidator = null,
@@ -96,7 +106,7 @@ public function __construct(
96106
/**
97107
* @inheritdoc
98108
*
99-
* @return \Magento\Framework\Controller\ResultInterface
109+
* @return ResultInterface
100110
* @SuppressWarnings(PHPMD.NPathComplexity)
101111
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
102112
*/
@@ -118,14 +128,22 @@ public function execute()
118128

119129
$attributeCode = $this->getRequest()->getParam('attribute_code');
120130
$frontendLabel = $this->getRequest()->getParam('frontend_label');
121-
$attributeCode = $attributeCode ?: $this->generateCode($frontendLabel[0]);
122131
$attributeId = $this->getRequest()->getParam('attribute_id');
123-
$attribute = $this->_objectManager->create(
124-
\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class
125-
)->loadByCode(
126-
$this->_entityTypeId,
127-
$attributeCode
128-
);
132+
133+
if ($attributeId) {
134+
$attribute = $this->_objectManager->create(
135+
Attribute::class
136+
)->load($attributeId);
137+
$attributeCode = $attribute->getAttributeCode();
138+
} else {
139+
$attributeCode = $attributeCode ?: $this->generateCode($frontendLabel[0]);
140+
$attribute = $this->_objectManager->create(
141+
Attribute::class
142+
)->loadByCode(
143+
$this->_entityTypeId,
144+
$attributeCode
145+
);
146+
}
129147

130148
if ($attribute->getId() && !$attributeId || $attributeCode === 'product_type' || $attributeCode === 'type_id') {
131149
$message = strlen($this->getRequest()->getParam('attribute_code'))
@@ -145,8 +163,8 @@ public function execute()
145163

146164
if ($this->getRequest()->has('new_attribute_set_name')) {
147165
$setName = $this->getRequest()->getParam('new_attribute_set_name');
148-
/** @var $attributeSet \Magento\Eav\Model\Entity\Attribute\Set */
149-
$attributeSet = $this->_objectManager->create(\Magento\Eav\Model\Entity\Attribute\Set::class);
166+
/** @var $attributeSet Set */
167+
$attributeSet = $this->_objectManager->create(Set::class);
150168
$attributeSet->setEntityTypeId($this->_entityTypeId)->load($setName, 'attribute_set_name');
151169
if ($attributeSet->getId()) {
152170
$setName = $this->escaper->escapeHtml($setName);
@@ -252,7 +270,7 @@ private function checkUniqueOption(DataObject $response, array $options = null)
252270
private function checkEmptyOption(DataObject $response, array $optionsForCheck = null)
253271
{
254272
foreach ($optionsForCheck as $optionValues) {
255-
if (isset($optionValues[0]) && trim($optionValues[0]) == '') {
273+
if (isset($optionValues[0]) && trim((string)$optionValues[0]) == '') {
256274
$this->setMessageToResponse($response, [__("The value of Admin scope can't be empty.")]);
257275
$response->setError(true);
258276
}

app/code/Magento/Catalog/Model/Category/Attribute/Backend/Sortby.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ public function beforeSave($object)
102102
}
103103
$object->setData($attributeCode, implode(',', $data) ?: null);
104104
}
105+
if ($attributeCode == 'default_sort_by') {
106+
$data = $object->getData($attributeCode);
107+
$attributeValue = (is_array($data) ? reset($data) : (!empty($data))) ? $data : null;
108+
$object->setData($attributeCode, $attributeValue);
109+
}
105110
if (!$object->hasData($attributeCode)) {
106111
$object->setData($attributeCode, null);
107112
}

app/code/Magento/Catalog/Model/Plugin/SetPageLayoutDefaultValue.php

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
namespace Magento\Catalog\Model\Plugin;
1212

1313
use Magento\Catalog\Model\Category\DataProvider;
14+
use Magento\Framework\App\Config\ScopeConfigInterface;
1415
use Magento\Framework\Exception\NoSuchEntityException;
16+
use Magento\Store\Model\ScopeInterface;
17+
use Magento\Store\Model\StoreManagerInterface;
1518

1619
/**
1720
* Sets the default value for Category Design Layout if provided
@@ -21,11 +24,28 @@ class SetPageLayoutDefaultValue
2124
private $defaultValue;
2225

2326
/**
27+
* @var StoreManagerInterface
28+
*/
29+
private $storeManager;
30+
31+
/**
32+
* @var ScopeConfigInterface
33+
*/
34+
private $scopeConfig;
35+
36+
/**
37+
* @param ScopeConfigInterface $scopeConfig
38+
* @param StoreManagerInterface $storeManager
2439
* @param string $defaultValue
2540
*/
26-
public function __construct(string $defaultValue = "")
27-
{
41+
public function __construct(
42+
ScopeConfigInterface $scopeConfig,
43+
StoreManagerInterface $storeManager,
44+
string $defaultValue = ""
45+
) {
2846
$this->defaultValue = $defaultValue;
47+
$this->scopeConfig = $scopeConfig;
48+
$this->storeManager = $storeManager;
2949
}
3050

3151
/**
@@ -42,7 +62,15 @@ public function afterGetDefaultMetaData(DataProvider $subject, array $result): a
4262
$currentCategory = $subject->getCurrentCategory();
4363

4464
if ($currentCategory && !$currentCategory->getId() && array_key_exists('page_layout', $result)) {
45-
$result['page_layout']['default'] = $this->defaultValue ?: null;
65+
$defaultAdminValue = $this->scopeConfig->getValue(
66+
'web/default_layouts/default_category_layout',
67+
ScopeInterface::SCOPE_STORE,
68+
$this->storeManager->getStore()->getId()
69+
);
70+
71+
$defaultValue = $defaultAdminValue ?: $this->defaultValue;
72+
73+
$result['page_layout']['default'] = $defaultValue ?: null;
4674
}
4775

4876
return $result;

0 commit comments

Comments
 (0)