Skip to content

Commit 3ef845f

Browse files
committed
Merge branch 'ACP2E-3449' of https://github.com/adobe-commerce-tier-4/magento2ce into PR-03-17-2025
2 parents 505b541 + e4de0fb commit 3ef845f

File tree

2 files changed

+165
-53
lines changed
  • app/code/Magento/Rule/Model/Condition/Sql
  • dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql

2 files changed

+165
-53
lines changed

app/code/Magento/Rule/Model/Condition/Sql/Builder.php

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2014 Adobe
4+
* All Rights Reserved.
55
*/
66

77
namespace Magento\Rule\Model\Condition\Sql;
@@ -166,42 +166,38 @@ protected function _getMappedSqlCondition(
166166
throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator'));
167167
}
168168

169-
$defaultValue = 0;
170169
//operator 'contains {}' is mapped to 'IN()' query that cannot work with substrings
171170
// adding mapping to 'LIKE %%'
172171
if ($condition->getInputType() === 'string'
173172
&& in_array($conditionOperator, array_keys($this->stringConditionOperatorMap), true)
174173
) {
175174
$sql = str_replace(
176175
':field',
177-
(string) $this->_connection->getIfNullSql(
178-
$this->_connection->quoteIdentifier($argument),
179-
$defaultValue
180-
),
176+
(string)$this->_connection->quoteIdentifier($argument),
181177
$this->stringConditionOperatorMap[$conditionOperator]
182178
);
183179
$bindValue = $condition->getBindArgumentValue();
184180
$expression = $value . $this->_connection->quoteInto($sql, "%$bindValue%");
185181
} else {
186182
$sql = str_replace(
187183
':field',
188-
(string) $this->_connection->getIfNullSql(
189-
$this->_connection->quoteIdentifier($argument),
190-
$defaultValue
191-
),
184+
(string)$this->_connection->quoteIdentifier($argument),
192185
$this->_conditionOperatorMap[$conditionOperator]
193186
);
194187
$bindValue = $condition->getBindArgumentValue();
195188
$expression = $value . $this->_connection->quoteInto($sql, $bindValue);
196189
}
197190
// values for multiselect attributes can be saved in comma-separated format
198191
// below is a solution for matching such conditions with selected values
199-
if (is_array($bindValue) && \in_array($conditionOperator, ['()', '{}'], true)) {
200-
foreach ($bindValue as $item) {
201-
$expression .= $this->_connection->quoteInto(
202-
" OR (FIND_IN_SET (?, {$this->_connection->quoteIdentifier($argument)}) > 0)",
203-
$item
204-
);
192+
$attribute = $condition->getAttributeObject();
193+
if ($attribute && $attribute->getFrontendInput() === 'multiselect') {
194+
if (is_array($bindValue) && \in_array($conditionOperator, ['()', '{}'], true)) {
195+
foreach ($bindValue as $item) {
196+
$expression .= $this->_connection->quoteInto(
197+
" OR (FIND_IN_SET (?, {$this->_connection->quoteIdentifier($argument)}) > 0)",
198+
$item
199+
);
200+
}
205201
}
206202
}
207203
return $this->_expressionFactory->create(
Lines changed: 152 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,195 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2017 Adobe
4+
* All Rights Reserved.
55
*/
66

77
namespace Magento\Rule\Model\Condition\Sql;
88

9+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
10+
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation;
11+
use Magento\Catalog\Setup\CategorySetup;
12+
use Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend;
13+
use Magento\Framework\DB\Select;
14+
use Magento\Framework\Exception\LocalizedException;
15+
use Magento\TestFramework\Fixture\DataFixtureStorage;
16+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
917
use Magento\TestFramework\Helper\Bootstrap;
18+
use Magento\TestFramework\Fixture\DataFixture;
19+
use Magento\Catalog\Test\Fixture\MultiselectAttribute;
1020
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
1121
use Magento\CatalogWidget\Model\RuleFactory;
1222
use Magento\CatalogWidget\Model\Rule\Condition\Combine as CombineCondition;
1323
use Magento\CatalogWidget\Model\Rule\Condition\Product as ProductCondition;
24+
use Magento\Catalog\Model\ResourceModel\Product\Collection;
25+
use Magento\TestFramework\Helper\Bootstrap as BootstrapHelper;
26+
use PHPUnit\Framework\TestCase;
1427

1528
/**
1629
* Test for Magento\Rule\Model\Condition\Sql\Builder
1730
*/
18-
class BuilderTest extends \PHPUnit\Framework\TestCase
31+
class BuilderTest extends TestCase
1932
{
2033
/**
21-
* @var Builder
34+
* @var Builder|null
2235
*/
23-
private $model;
36+
private ?Builder $model;
2437

38+
/**
39+
* @var DataFixtureStorage|null
40+
*/
41+
private ?DataFixtureStorage $fixtures;
42+
43+
/**
44+
* @inheritDoc
45+
*/
2546
protected function setUp(): void
2647
{
2748
$this->model = Bootstrap::getObjectManager()->create(Builder::class);
49+
$this->fixtures = BootstrapHelper::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
2850
}
2951

3052
/**
53+
* @param array $conditions
54+
* @param string $expectedWhere
55+
* @param string $expectedOrder
3156
* @return void
57+
* @throws LocalizedException|\PHPUnit\Framework\MockObject\Exception
58+
* @dataProvider attachConditionToCollectionDataProvider
3259
*/
33-
public function testAttachConditionToCollection(): void
34-
{
60+
#[
61+
DataFixture(
62+
MultiselectAttribute::class,
63+
[
64+
'entity_type_id' => CategorySetup::CATALOG_PRODUCT_ENTITY_TYPE_ID,
65+
'source_model' => null,
66+
'backend_model' => ArrayBackend::class,
67+
'attribute_code' => 'multi_select_attr',
68+
'is_visible_on_front' => true,
69+
'frontend_input' => 'multiselect',
70+
'backend_type' => 'text',
71+
'attribute_model' => Attribute::class,
72+
'options' => ['red', 'white']
73+
],
74+
'multiselect'
75+
)
76+
]
77+
public function testAttachConditionToCollection(
78+
array $conditions,
79+
string $expectedWhere,
80+
string $expectedOrder
81+
): void {
3582
/** @var ProductCollectionFactory $collectionFactory */
3683
$collectionFactory = Bootstrap::getObjectManager()->create(ProductCollectionFactory::class);
3784
$collection = $collectionFactory->create();
85+
foreach ($conditions as $key => $condition) {
86+
if (isset($condition['attribute']) && $condition['attribute'] === 'multi_select_attr') {
87+
$multiselectAttributeOptionIds = [
88+
$this->fixtures->get('multiselect')->getData('red'),
89+
$this->fixtures->get('multiselect')->getData('white')
90+
];
91+
$expectedWhere = str_replace(["red", "white"], $multiselectAttributeOptionIds, $expectedWhere);
92+
93+
$conditions[$key]['value'] = $multiselectAttributeOptionIds;
94+
}
95+
}
3896

3997
/** @var RuleFactory $ruleFactory */
4098
$ruleFactory = Bootstrap::getObjectManager()->create(RuleFactory::class);
4199
$rule = $ruleFactory->create();
42100

43101
$ruleConditionArray = [
44-
'conditions' => [
45-
'1' => [
46-
'type' => CombineCondition::class,
47-
'aggregator' => 'all',
48-
'value' => '1',
49-
'new_child' => '',
50-
],
51-
'1--1' => [
52-
'type' => ProductCondition::class,
53-
'attribute' => 'category_ids',
54-
'operator' => '==',
55-
'value' => '3',
56-
],
57-
'1--2' => [
58-
'type' => ProductCondition::class,
59-
'attribute' => 'special_to_date',
60-
'operator' => '==',
61-
'value' => '2017-09-15',
62-
],
63-
'1--3' => [
64-
'type' => ProductCondition::class,
65-
'attribute' => 'sku',
66-
'operator' => '()',
67-
'value' => ' :( , :) ',
68-
]
69-
],
102+
'conditions' => $conditions,
70103
];
71104

72105
$rule->loadPost($ruleConditionArray);
106+
foreach ($rule->getConditions()->getConditions() as $condition) {
107+
$condition->addToCollection($collection);
108+
if ($condition->getAttribute() === 'multi_select_attr') {
109+
$from = array_keys($collection->getSelectSql()->getPart('from'));
110+
$expectedWhere = str_replace('multi_select_attr', end($from), $expectedWhere);
111+
}
112+
}
73113
$this->model->attachConditionToCollection($collection, $rule->getConditions());
74114

75-
$whereString = "/\(category_id IN \('3'\).+\(IFNULL\(`e`\.`entity_id`,.+\) = '2017-09-15 00:00:00'\)"
76-
. ".+ORDER BY \(FIELD\(`e`.`sku`, ':\(', ':\)'\)\)/";
77-
$this->assertEquals(1, preg_match($whereString, $collection->getSelectSql(true)));
115+
$this->assertStringContainsString($expectedWhere, $collection->getSelectSql(true));
116+
$this->assertStringContainsString($expectedOrder, $collection->getSelectSql(true));
117+
}
118+
119+
/**
120+
* @return array
121+
*/
122+
public static function attachConditionToCollectionDataProvider(): array
123+
{
124+
return [
125+
[
126+
[
127+
'1' => [
128+
'type' => CombineCondition::class,
129+
'aggregator' => 'all',
130+
'value' => '1',
131+
'new_child' => '',
132+
],
133+
'1--1' => [
134+
'type' => ProductCondition::class,
135+
'attribute' => 'category_ids',
136+
'operator' => '==',
137+
'value' => '3',
138+
],
139+
'1--2' => [
140+
'type' => ProductCondition::class,
141+
'attribute' => 'special_to_date',
142+
'operator' => '==',
143+
'value' => '2017-09-15',
144+
],
145+
'1--3' => [
146+
'type' => ProductCondition::class,
147+
'attribute' => 'sku',
148+
'operator' => '()',
149+
'value' => 'sku1,sku2,sku3,sku4,sku5',
150+
]
151+
],
152+
"(((`e`.`entity_id` IN (SELECT `catalog_category_product`.`product_id` FROM " .
153+
"`catalog_category_product` WHERE (category_id IN ('3')))) " .
154+
"AND(IF(`at_special_to_date`.`value_id` > 0, `at_special_to_date`.`value`, " .
155+
"`at_special_to_date_default`.`value`) = '2017-09-15 00:00:00') " .
156+
"AND(`e`.`sku` IN ('sku1', 'sku2', 'sku3', 'sku4', 'sku5'))",
157+
"ORDER BY (FIELD(`e`.`sku`, 'sku1', 'sku2', 'sku3', 'sku4', 'sku5'))"
158+
],
159+
[
160+
[
161+
'1' => [
162+
'type' => CombineCondition::class,
163+
'aggregator' => 'all',
164+
'value' => '1',
165+
'new_child' => '',
166+
],
167+
'1--1' => [
168+
'type' => ProductCondition::class,
169+
'attribute' => 'category_ids',
170+
'operator' => '==',
171+
'value' => '3',
172+
],
173+
'1--2' => [
174+
'type' => ProductCondition::class,
175+
'attribute' => 'sku',
176+
'operator' => '()',
177+
'value' => 'sku1,sku2,sku3',
178+
],
179+
'1--3' => [
180+
'type' => ProductCondition::class,
181+
'attribute' => 'multi_select_attr',
182+
'operator' => '{}',
183+
'collected_attributes' => ['multiselect_attribute' => true],
184+
]
185+
],
186+
"(((`e`.`entity_id` IN (SELECT `catalog_category_product`.`product_id` FROM " .
187+
"`catalog_category_product` WHERE (category_id IN ('3')))) " .
188+
"AND(`e`.`sku` IN ('sku1', 'sku2', 'sku3')) AND(`multi_select_attr`.`value` IN ('red', 'white') OR " .
189+
"(FIND_IN_SET ('red', `multi_select_attr`.`value`) > 0) OR " .
190+
"(FIND_IN_SET ('white', `multi_select_attr`.`value`) > 0))",
191+
"ORDER BY (FIELD(`e`.`sku`, 'sku1', 'sku2', 'sku3'))"
192+
]
193+
];
78194
}
79195
}

0 commit comments

Comments
 (0)