Skip to content

Commit b784eca

Browse files
Merge branch '2.4-develop' into ACQE-5379
2 parents abe1ae5 + 7f58418 commit b784eca

File tree

42 files changed

+1723
-158
lines changed

Some content is hidden

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

42 files changed

+1723
-158
lines changed

app/code/Magento/AwsS3/Driver/AwsS3.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -893,16 +893,24 @@ public function fileClose($resource): bool
893893
*/
894894
public function fileOpen($path, $mode)
895895
{
896+
$_mode = str_replace(['b', '+'], '', strtolower($mode));
897+
if (!in_array($_mode, ['r', 'w', 'a'], true)) {
898+
throw new FileSystemException(new Phrase('Invalid file open mode "%1".', [$mode]));
899+
}
896900
$path = $this->normalizeRelativePath($path, true);
897901

898902
if (!isset($this->streams[$path])) {
899903
$this->streams[$path] = tmpfile();
900904
try {
901905
if ($this->adapter->fileExists($path)) {
902-
//phpcs:ignore Magento2.Functions.DiscouragedFunction
903-
fwrite($this->streams[$path], $this->adapter->read($path));
904-
//phpcs:ignore Magento2.Functions.DiscouragedFunction
905-
rewind($this->streams[$path]);
906+
if ($_mode !== 'w') {
907+
//phpcs:ignore Magento2.Functions.DiscouragedFunction
908+
fwrite($this->streams[$path], $this->adapter->read($path));
909+
//phpcs:ignore Magento2.Functions.DiscouragedFunction
910+
if ($_mode !== 'a') {
911+
rewind($this->streams[$path]);
912+
}
913+
}
906914
}
907915
} catch (FlysystemFilesystemException $e) {
908916
$this->logger->error($e->getMessage());

app/code/Magento/AwsS3/Test/Unit/Driver/AwsS3Test.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,42 @@ public function testFileCloseShouldReturnFalseIfTheArgumentIsNotAResource(): voi
537537
$this->assertEquals(false, $this->driver->fileClose(null));
538538
$this->assertEquals(false, $this->driver->fileClose(false));
539539
}
540+
541+
/**
542+
* @dataProvider fileOpenModesDataProvider
543+
*/
544+
public function testFileOppenedMode($mode, $expected): void
545+
{
546+
$this->adapterMock->method('fileExists')->willReturn(true);
547+
if ($mode !== 'w') {
548+
$this->adapterMock->expects($this->once())->method('read')->willReturn('aaa');
549+
} else {
550+
$this->adapterMock->expects($this->never())->method('read');
551+
}
552+
$resource = $this->driver->fileOpen('test/path', $mode);
553+
$this->assertEquals($expected, ftell($resource));
554+
}
555+
556+
/**
557+
* Data provider for testFileOppenedMode
558+
*
559+
* @return array[]
560+
*/
561+
public function fileOpenModesDataProvider(): array
562+
{
563+
return [
564+
[
565+
"mode" => "a",
566+
"expected" => 3
567+
],
568+
[
569+
"mode" => "r",
570+
"expected" => 0
571+
],
572+
[
573+
"mode" => "w",
574+
"expected" => 0
575+
]
576+
];
577+
}
540578
}

app/code/Magento/Catalog/Setup/Patch/Data/UpdateMultiselectAttributesBackendTypes.php

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
use Magento\Catalog\Model\Product;
1010
use Magento\Eav\Setup\EavSetup;
1111
use Magento\Eav\Setup\EavSetupFactory;
12-
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Framework\DB\Adapter\AdapterInterface;
1313
use Magento\Framework\Setup\ModuleDataSetupInterface;
1414
use Magento\Framework\Setup\Patch\DataPatchInterface;
15+
use Magento\Framework\Setup\Patch\NonTransactionableInterface;
1516

16-
class UpdateMultiselectAttributesBackendTypes implements DataPatchInterface
17+
class UpdateMultiselectAttributesBackendTypes implements DataPatchInterface, NonTransactionableInterface
1718
{
1819
/**
1920
* @var ModuleDataSetupInterface
@@ -24,6 +25,11 @@ class UpdateMultiselectAttributesBackendTypes implements DataPatchInterface
2425
*/
2526
private $eavSetupFactory;
2627

28+
/**
29+
* @var array
30+
*/
31+
private $triggersRestoreQueries = [];
32+
2733
/**
2834
* MigrateMultiselectAttributesData constructor.
2935
* @param ModuleDataSetupInterface $dataSetup
@@ -61,6 +67,7 @@ public function apply()
6167
$this->dataSetup->startSetup();
6268
$setup = $this->dataSetup;
6369
$connection = $setup->getConnection();
70+
$this->triggersRestoreQueries = [];
6471

6572
$attributeTable = $setup->getTable('eav_attribute');
6673
/** @var EavSetup $eavSetup */
@@ -74,26 +81,31 @@ public function apply()
7481
->where('backend_type = ?', 'varchar')
7582
->where('frontend_input = ?', 'multiselect')
7683
);
84+
$attributesToMigrate = array_map('intval', $attributesToMigrate);
7785

7886
$varcharTable = $setup->getTable('catalog_product_entity_varchar');
7987
$textTable = $setup->getTable('catalog_product_entity_text');
80-
$varcharTableDataSql = $connection
81-
->select()
82-
->from($varcharTable)
83-
->where('attribute_id in (?)', $attributesToMigrate);
8488

8589
$columns = $connection->describeTable($varcharTable);
8690
unset($columns['value_id']);
87-
$connection->query(
88-
$connection->insertFromSelect(
89-
$connection->select()
90-
->from($varcharTable, array_keys($columns))
91-
->where('attribute_id in (?)', $attributesToMigrate),
92-
$textTable,
93-
array_keys($columns)
94-
)
95-
);
96-
$connection->query($connection->deleteFromSelect($varcharTableDataSql, $varcharTable));
91+
$this->dropTriggers($textTable);
92+
$this->dropTriggers($varcharTable);
93+
try {
94+
$connection->query(
95+
$connection->insertFromSelect(
96+
$connection->select()
97+
->from($varcharTable, array_keys($columns))
98+
->where('attribute_id in (?)', $attributesToMigrate, \Zend_Db::INT_TYPE),
99+
$textTable,
100+
array_keys($columns),
101+
AdapterInterface::INSERT_ON_DUPLICATE
102+
)
103+
);
104+
$connection->delete($varcharTable, ['attribute_id IN (?)' => $attributesToMigrate]);
105+
} finally {
106+
$this->restoreTriggers($textTable);
107+
$this->restoreTriggers($varcharTable);
108+
}
97109

98110
foreach ($attributesToMigrate as $attributeId) {
99111
$eavSetup->updateAttribute($entityTypeId, $attributeId, 'backend_type', 'text');
@@ -103,4 +115,48 @@ public function apply()
103115

104116
return $this;
105117
}
118+
119+
/**
120+
* Drop table triggers
121+
*
122+
* @param string $tableName
123+
* @return void
124+
* @throws \Zend_Db_Statement_Exception
125+
*/
126+
private function dropTriggers(string $tableName): void
127+
{
128+
$triggers = $this->dataSetup->getConnection()
129+
->query('SHOW TRIGGERS LIKE \''. $tableName . '\'')
130+
->fetchAll();
131+
132+
if (!$triggers) {
133+
return;
134+
}
135+
136+
foreach ($triggers as $trigger) {
137+
$triggerData = $this->dataSetup->getConnection()
138+
->query('SHOW CREATE TRIGGER '. $trigger['Trigger'])
139+
->fetch();
140+
$this->triggersRestoreQueries[$tableName][] =
141+
preg_replace('/DEFINER=[^\s]*/', '', $triggerData['SQL Original Statement']);
142+
// phpcs:ignore Magento2.SQL.RawQuery.FoundRawSql
143+
$this->dataSetup->getConnection()->query('DROP TRIGGER IF EXISTS ' . $trigger['Trigger']);
144+
}
145+
}
146+
147+
/**
148+
* Restore table triggers.
149+
*
150+
* @param string $tableName
151+
* @return void
152+
* @throws \Zend_Db_Statement_Exception
153+
*/
154+
private function restoreTriggers(string $tableName): void
155+
{
156+
if (array_key_exists($tableName, $this->triggersRestoreQueries)) {
157+
foreach ($this->triggersRestoreQueries[$tableName] as $query) {
158+
$this->dataSetup->getConnection()->multiQuery($query);
159+
}
160+
}
161+
}
106162
}

app/code/Magento/Catalog/Test/Unit/Setup/Patch/Data/UpdateMultiselectAttributesBackendTypesTest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public function testApply(): void
5252
$select1 = $this->createMock(Select::class);
5353
$select2 = $this->createMock(Select::class);
5454
$select3 = $this->createMock(Select::class);
55+
$statement = $this->createMock(\Zend_Db_Statement_Interface::class);
56+
5557
$this->eavSetupFactory->method('create')
5658
->willReturn($eavSetup);
5759
$this->dataSetup->method('getConnection')
@@ -65,7 +67,7 @@ public function testApply(): void
6567
[$entityTypeId, 3, 'backend_type', 'text'],
6668
[$entityTypeId, 7, 'backend_type', 'text']
6769
);
68-
$connection->expects($this->exactly(3))
70+
$connection->expects($this->exactly(2))
6971
->method('select')
7072
->willReturnOnConsecutiveCalls($select1, $select2, $select3);
7173
$connection->method('describeTable')
@@ -78,6 +80,10 @@ public function testApply(): void
7880
'row_id' => [],
7981
]
8082
);
83+
$connection->method('query')
84+
->willReturn($statement);
85+
$connection->method('fetchAll')
86+
->willReturn([]);
8187
$connection->method('fetchCol')
8288
->with($select1)
8389
->willReturn($attributeIds);

app/code/Magento/CatalogGraphQl/DataProvider/Product/SearchCriteriaBuilder.php

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
use Magento\Framework\Api\SortOrderBuilder;
1919
use Magento\Framework\App\Config\ScopeConfigInterface;
2020
use Magento\Framework\App\ObjectManager;
21+
use Magento\Framework\Exception\LocalizedException;
2122
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\Builder;
23+
use Magento\Framework\Search\Request\Config as SearchConfig;
2224

2325
/**
2426
* Build search criteria
@@ -46,6 +48,7 @@ class SearchCriteriaBuilder
4648
* @var Builder
4749
*/
4850
private $builder;
51+
4952
/**
5053
* @var Visibility
5154
*/
@@ -61,14 +64,20 @@ class SearchCriteriaBuilder
6164
*/
6265
private Config $eavConfig;
6366

67+
/**
68+
* @var SearchConfig
69+
*/
70+
private SearchConfig $searchConfig;
71+
6472
/**
6573
* @param Builder $builder
6674
* @param ScopeConfigInterface $scopeConfig
6775
* @param FilterBuilder $filterBuilder
6876
* @param FilterGroupBuilder $filterGroupBuilder
6977
* @param Visibility $visibility
70-
* @param SortOrderBuilder $sortOrderBuilder
71-
* @param Config $eavConfig
78+
* @param SortOrderBuilder|null $sortOrderBuilder
79+
* @param Config|null $eavConfig
80+
* @param SearchConfig|null $searchConfig
7281
*/
7382
public function __construct(
7483
Builder $builder,
@@ -77,7 +86,8 @@ public function __construct(
7786
FilterGroupBuilder $filterGroupBuilder,
7887
Visibility $visibility,
7988
SortOrderBuilder $sortOrderBuilder = null,
80-
Config $eavConfig = null
89+
Config $eavConfig = null,
90+
SearchConfig $searchConfig = null
8191
) {
8292
$this->scopeConfig = $scopeConfig;
8393
$this->filterBuilder = $filterBuilder;
@@ -86,6 +96,7 @@ public function __construct(
8696
$this->visibility = $visibility;
8797
$this->sortOrderBuilder = $sortOrderBuilder ?? ObjectManager::getInstance()->get(SortOrderBuilder::class);
8898
$this->eavConfig = $eavConfig ?? ObjectManager::getInstance()->get(Config::class);
99+
$this->searchConfig = $searchConfig ?? ObjectManager::getInstance()->get(SearchConfig::class);
89100
}
90101

91102
/**
@@ -94,9 +105,15 @@ public function __construct(
94105
* @param array $args
95106
* @param bool $includeAggregation
96107
* @return SearchCriteriaInterface
108+
* @throws LocalizedException
97109
*/
98110
public function build(array $args, bool $includeAggregation): SearchCriteriaInterface
99111
{
112+
$partialMatchFilters = [];
113+
if (isset($args['filter'])) {
114+
$partialMatchFilters = $this->getPartialMatchFilters($args);
115+
$args = $this->removeMatchTypeFromArguments($args);
116+
}
100117
$searchCriteria = $this->builder->build('products', $args);
101118
$isSearch = isset($args['search']);
102119
$this->updateRangeFilters($searchCriteria);
@@ -113,6 +130,10 @@ public function build(array $args, bool $includeAggregation): SearchCriteriaInte
113130
}
114131
$searchCriteria->setRequestName($requestName);
115132

133+
if (count($partialMatchFilters)) {
134+
$this->updateMatchTypeRequestConfig($requestName, $partialMatchFilters);
135+
}
136+
116137
if ($isSearch) {
117138
$this->addFilter($searchCriteria, 'search_term', $args['search']);
118139
}
@@ -130,6 +151,63 @@ public function build(array $args, bool $includeAggregation): SearchCriteriaInte
130151
return $searchCriteria;
131152
}
132153

154+
/**
155+
* Update dynamically the search match type based on requested params
156+
*
157+
* @param string $requestName
158+
* @param array $partialMatchFilters
159+
*
160+
* @return void
161+
*/
162+
private function updateMatchTypeRequestConfig(string $requestName, array $partialMatchFilters): void
163+
{
164+
$data = $this->searchConfig->get($requestName);
165+
foreach ($data['queries'] as $queryName => $query) {
166+
foreach ($query['match'] ?? [] as $index => $matchItem) {
167+
if (in_array($matchItem['field'] ?? null, $partialMatchFilters, true)) {
168+
$data['queries'][$queryName]['match'][$index]['matchCondition'] = 'match_phrase_prefix';
169+
}
170+
}
171+
}
172+
$this->searchConfig->merge([$requestName => $data]);
173+
}
174+
175+
/**
176+
* Check if and what type of match_type value was requested
177+
*
178+
* @param array $args
179+
*
180+
* @return array
181+
*/
182+
private function getPartialMatchFilters(array $args): array
183+
{
184+
$partialMatchFilters = [];
185+
foreach ($args['filter'] as $fieldName => $conditions) {
186+
if (isset($conditions['match_type']) && $conditions['match_type'] === 'PARTIAL') {
187+
$partialMatchFilters[] = $fieldName;
188+
}
189+
}
190+
return $partialMatchFilters;
191+
}
192+
193+
/**
194+
* Remove the match_type to avoid search criteria containing it
195+
*
196+
* @param array $args
197+
*
198+
* @return array
199+
*/
200+
private function removeMatchTypeFromArguments(array $args): array
201+
{
202+
foreach ($args['filter'] as &$conditions) {
203+
if (isset($conditions['match_type'])) {
204+
unset($conditions['match_type']);
205+
}
206+
}
207+
208+
return $args;
209+
}
210+
133211
/**
134212
* Add filter by visibility
135213
*

0 commit comments

Comments
 (0)