diff --git a/vendor/magento/module-sales/Plugin/SearchCriteria/FulltextFilterPlugin.php b/vendor/magento/module-sales/Plugin/SearchCriteria/FulltextFilterPlugin.php deleted file mode 100644 index fa3127361aa02..0000000000000 --- a/vendor/magento/module-sales/Plugin/SearchCriteria/FulltextFilterPlugin.php +++ /dev/null @@ -1,65 +0,0 @@ -getValue()); - if ($raw === '') { - return; - } - - $normalized = preg_replace('/^\{+|\}+$/', '', $raw); - $normalized = ltrim($normalized); - $normalized = ltrim($normalized, '#'); - - // Exact increment_id search when normalized is all digits - if ($normalized !== '' && ctype_digit($normalized)) { - $collection->addFieldToFilter('increment_id', ['eq' => $normalized]); - return; - } - - // LIKE across key columns (for names, emails, non-digit terms) - $valueForLike = trim($raw, '{}'); - $valueForLike = ltrim($valueForLike); - $valueForLike = ltrim($valueForLike, '#'); - - $like = '%' . str_replace(['%', '_'], ['\\%', '\\_'], $valueForLike) . '%'; - - $fields = ['increment_id', 'billing_name', 'shipping_name', 'customer_email']; - $conditions = array_fill(0, count($fields), ['like' => $like]); - - $collection->addFieldToFilter($fields, $conditions); - return; - } - $proceed($collection, $filter); - } -} diff --git a/vendor/magento/module-sales/Ui/Component/Listing/FulltextFilter.php b/vendor/magento/module-sales/Ui/Component/Listing/FulltextFilter.php new file mode 100644 index 0000000000000..754a19ae73a88 --- /dev/null +++ b/vendor/magento/module-sales/Ui/Component/Listing/FulltextFilter.php @@ -0,0 +1,146 @@ +getValue()); + if ($raw === '') { + return; + } + + $tokens = preg_split('/[\s,]+/', $raw, -1, PREG_SPLIT_NO_EMPTY); + $ignoredTokens = array_filter($tokens, fn (string $token): bool => $this->isTokenIgnored($token)); + + if (!$ignoredTokens) { + // nothing InnoDB's fulltext index would drop, so no LIKE fallback + parent::apply($collection, $filter); + return; + } + + $select = $collection->getSelect(); + $baseline = $select->getPart(Select::WHERE); + + parent::apply($collection, $filter); + + $addedParts = array_map( + fn (string $part): string => $this->stripLeadingBoolean($part), + array_diff($select->getPart(Select::WHERE), $baseline) + ); + $select->reset(Select::WHERE); + $select->setPart(Select::WHERE, $baseline); + + $addedParts = array_merge($addedParts, $this->buildLikeConditions($collection, $ignoredTokens)); + + if ($addedParts) { + $select->where('(' . implode(') ' . Select::SQL_OR . ' (', $addedParts) . ')'); + } + } + + /** + * Build a LIKE condition per ignored token, per fulltext-indexed column. + * + * @param AbstractDb $collection + * @param string[] $tokens + * @return string[] + */ + private function buildLikeConditions(AbstractDb $collection, array $tokens): array + { + $mainTable = $collection->getMainTable(); + $columns = $this->getFulltextIndexColumns($collection, $mainTable); + if (!$columns) { + return []; + } + $columns = $this->addTableAliasToColumns($columns, $collection, $mainTable); + + $connection = $collection->getConnection(); + $conditions = array_map( + fn (string $token) => array_map( + fn (string $column) => $connection->prepareSqlCondition( + $column, + ['like' => $this->dbHelper->escapeLikeValue($token, ['position' => 'any'])] + ), + $columns + ), + $tokens + ); + + return array_merge(...$conditions); + } + + /** + * Whether a search term would be silently dropped by InnoDB's fulltext index (stopword or too short). + * + * @param string $token + * @return bool + */ + private function isTokenIgnored(string $token): bool + { + return mb_strlen($token) < $this->minTokenSize || in_array(mb_strtolower($token), $this->stopwords, true); + } + + /** + * Strip a leading boolean keyword (AND/OR) Zend_Db_Select prefixes WHERE parts with. + * + * @param string $part + * @return string + */ + private function stripLeadingBoolean(string $part): string + { + return preg_replace('/^(' . Select::SQL_OR . '|' . Select::SQL_AND . ')\s+/i', '', trim($part), 1); + } +} diff --git a/vendor/magento/module-sales/etc/adminhtml/di.xml b/vendor/magento/module-sales/etc/adminhtml/di.xml index 3a25a8386e839..33e311302929b 100644 --- a/vendor/magento/module-sales/etc/adminhtml/di.xml +++ b/vendor/magento/module-sales/etc/adminhtml/di.xml @@ -86,14 +86,27 @@ - - - + + + + Magento\Framework\View\Element\UiComponent\DataProvider\RegularFilter + Magento\Sales\Ui\Component\Listing\FulltextFilter + + + + + + SalesOrderGridFilterPool + + + + + SalesOrderGridReporting + + diff --git a/vendor/magento/module-sales/view/adminhtml/ui_component/sales_order_grid.xml b/vendor/magento/module-sales/view/adminhtml/ui_component/sales_order_grid.xml index 7485c8ac0af26..74302917065cb 100644 --- a/vendor/magento/module-sales/view/adminhtml/ui_component/sales_order_grid.xml +++ b/vendor/magento/module-sales/view/adminhtml/ui_component/sales_order_grid.xml @@ -30,7 +30,7 @@ Magento_Sales::sales_order - + id main_table.entity_id