Skip to content

Commit 2d6cd7d

Browse files
committed
Merge remote-tracking branch 'origin/AC-14360' into spartans_pr_27102025
2 parents d567457 + d11d7ca commit 2d6cd7d

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Sales\Plugin\SearchCriteria;
9+
10+
use Magento\Framework\Api\Filter;
11+
use Magento\Framework\Data\Collection;
12+
use Magento\Sales\Model\ResourceModel\Order\Grid\Collection as OrderGridCollection;
13+
use Magento\Framework\View\Element\UiComponent\DataProvider\FulltextFilter as UiFulltextFilter;
14+
15+
class FulltextFilterPlugin
16+
{
17+
18+
/**
19+
* Use LIKE instead of MATCH AGAINST in sales order grid to bypass MySQL stopword limitations
20+
*
21+
* @param UiFulltextFilter $subject
22+
* @param \Closure $proceed
23+
* @param Collection $collection
24+
* @param Filter $filter
25+
* @return void
26+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
27+
*/
28+
public function aroundApply(
29+
UiFulltextFilter $subject,
30+
\Closure $proceed,
31+
Collection $collection,
32+
Filter $filter
33+
): void {
34+
if ($collection instanceof OrderGridCollection) {
35+
$raw = trim((string) $filter->getValue());
36+
if ($raw === '') {
37+
return;
38+
}
39+
40+
$normalized = preg_replace('/^\{+|\}+$/', '', $raw);
41+
$normalized = ltrim($normalized);
42+
$normalized = ltrim($normalized, '#');
43+
44+
// Exact increment_id search when normalized is all digits
45+
if ($normalized !== '' && ctype_digit($normalized)) {
46+
$collection->addFieldToFilter('increment_id', ['eq' => $normalized]);
47+
return;
48+
}
49+
50+
// LIKE across key columns (for names, emails, non-digit terms)
51+
$valueForLike = trim($raw, '{}');
52+
$valueForLike = ltrim($valueForLike);
53+
$valueForLike = ltrim($valueForLike, '#');
54+
55+
$like = '%' . str_replace(['%', '_'], ['\\%', '\\_'], $valueForLike) . '%';
56+
57+
$fields = ['increment_id', 'billing_name', 'shipping_name', 'customer_email'];
58+
$conditions = array_fill(0, count($fields), ['like' => $like]);
59+
60+
$collection->addFieldToFilter($fields, $conditions);
61+
return;
62+
}
63+
$proceed($collection, $filter);
64+
}
65+
}

app/code/Magento/Sales/etc/adminhtml/di.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,9 @@
8989
</argument>
9090
</arguments>
9191
</type>
92+
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\FulltextFilter">
93+
<plugin name="ordergrid_fulltext_fallback"
94+
type="Magento\Sales\Plugin\SearchCriteria\FulltextFilterPlugin"
95+
sortOrder="10"/>
96+
</type>
9297
</config>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Sales\Plugin\SearchCriteria;
9+
10+
use Magento\Framework\Api\Filter;
11+
use Magento\Framework\ObjectManagerInterface;
12+
use Magento\Framework\View\Element\UiComponent\DataProvider\FulltextFilter as UiFulltextFilter;
13+
use Magento\Sales\Model\ResourceModel\Order\Grid\Collection as OrderGridCollection;
14+
use Magento\TestFramework\Helper\Bootstrap;
15+
use PHPUnit\Framework\TestCase;
16+
17+
class FulltextFilterPluginTest extends TestCase
18+
{
19+
/** @var ObjectManagerInterface */
20+
private $objectManager;
21+
22+
protected function setUp(): void
23+
{
24+
$this->objectManager = Bootstrap::getObjectManager();
25+
}
26+
27+
/**
28+
* @magentoAppArea adminhtml
29+
*/
30+
public function testApplyOnOrderGridUsesLikeConditionsAndNoMatchAgainst(): void
31+
{
32+
/** @var UiFulltextFilter $fulltextFilter */
33+
$fulltextFilter = $this->objectManager->get(UiFulltextFilter::class);
34+
35+
/** @var OrderGridCollection $collection */
36+
$collection = $this->objectManager->create(OrderGridCollection::class);
37+
38+
/** @var Filter $filter */
39+
$filter = $this->objectManager->create(Filter::class);
40+
$filter->setValue('Will');
41+
42+
$fulltextFilter->apply($collection, $filter);
43+
44+
$sql = $collection->getSelectSql(true);
45+
46+
$this->assertStringContainsString("`main_table`.`increment_id` LIKE '%Will%'", $sql);
47+
$this->assertStringContainsString("`main_table`.`billing_name` LIKE '%Will%'", $sql);
48+
$this->assertStringContainsString("`main_table`.`shipping_name` LIKE '%Will%'", $sql);
49+
$this->assertStringContainsString("`main_table`.`customer_email` LIKE '%Will%'", $sql);
50+
51+
$this->assertStringNotContainsString('MATCH(', $sql);
52+
$this->assertStringNotContainsString('AGAINST(', $sql);
53+
}
54+
55+
/**
56+
* @magentoAppArea adminhtml
57+
*/
58+
public function testApplyOnOrderGridWithEmptyValueDoesNothing(): void
59+
{
60+
/** @var UiFulltextFilter $fulltextFilter */
61+
$fulltextFilter = $this->objectManager->get(UiFulltextFilter::class);
62+
63+
/** @var OrderGridCollection $collection */
64+
$collection = $this->objectManager->create(OrderGridCollection::class);
65+
$initialSql = $collection->getSelectSql(true);
66+
67+
/** @var Filter $filter */
68+
$filter = $this->objectManager->create(Filter::class);
69+
$filter->setValue(' '); // empty after trim
70+
71+
$fulltextFilter->apply($collection, $filter);
72+
73+
$sql = $collection->getSelectSql(true);
74+
75+
// No LIKE or MATCH added
76+
$this->assertSame($initialSql, $sql);
77+
$this->assertStringNotContainsString('LIKE', $sql);
78+
$this->assertStringNotContainsString('MATCH(', $sql);
79+
$this->assertStringNotContainsString('AGAINST(', $sql);
80+
}
81+
}

0 commit comments

Comments
 (0)