1717class Collection extends \Magento \Catalog \Model \ResourceModel \Product \Collection implements
1818 \Magento \Search \Model \SearchCollectionInterface
1919{
20+ /**
21+ * @var array
22+ */
23+ private $ indexUsageEnforcements ;
24+
2025 /**
2126 * Attribute collection
2227 *
@@ -61,6 +66,7 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
6166 * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement
6267 * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeCollectionFactory
6368 * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
69+ * @param array $indexUsageEnforcements
6470 * @SuppressWarnings(PHPMD.ExcessiveParameterList)
6571 */
6672 public function __construct (
@@ -84,7 +90,8 @@ public function __construct(
8490 \Magento \Framework \Stdlib \DateTime $ dateTime ,
8591 \Magento \Customer \Api \GroupManagementInterface $ groupManagement ,
8692 \Magento \Catalog \Model \ResourceModel \Product \Attribute \CollectionFactory $ attributeCollectionFactory ,
87- \Magento \Framework \DB \Adapter \AdapterInterface $ connection = null
93+ \Magento \Framework \DB \Adapter \AdapterInterface $ connection = null ,
94+ array $ indexUsageEnforcements = []
8895 ) {
8996 $ this ->_attributeCollectionFactory = $ attributeCollectionFactory ;
9097 parent ::__construct (
@@ -109,6 +116,7 @@ public function __construct(
109116 $ groupManagement ,
110117 $ connection
111118 );
119+ $ this ->indexUsageEnforcements = $ indexUsageEnforcements ;
112120 }
113121
114122 /**
@@ -197,6 +205,35 @@ protected function _hasAttributeOptionsAndSearchable($attribute)
197205 return false ;
198206 }
199207
208+ /**
209+ * Prepare table names for the index enforcements
210+ *
211+ * @return array
212+ */
213+ private function prepareIndexEnforcements () : array
214+ {
215+ $ result = [];
216+ foreach ($ this ->indexUsageEnforcements as $ table => $ index ) {
217+ $ table = $ this ->getTable ($ table );
218+ if ($ this ->isIndexExists ($ table , $ index )) {
219+ $ result [$ table ] = $ index ;
220+ }
221+ }
222+ return $ result ;
223+ }
224+
225+ /**
226+ * Check if index exists in the table
227+ *
228+ * @param string $table
229+ * @param string $index
230+ * @return bool
231+ */
232+ private function isIndexExists (string $ table , string $ index ) : bool
233+ {
234+ return array_key_exists ($ index , $ this ->_conn ->getIndexList ($ table ));
235+ }
236+
200237 /**
201238 * Retrieve SQL for search entities
202239 *
@@ -208,6 +245,7 @@ protected function _getSearchEntityIdsSql($query, $searchOnlyInCurrentStore = tr
208245 {
209246 $ tables = [];
210247 $ selects = [];
248+ $ preparedIndexEnforcements = $ this ->prepareIndexEnforcements ();
211249
212250 $ likeOptions = ['position ' => 'any ' ];
213251
@@ -249,23 +287,56 @@ protected function _getSearchEntityIdsSql($query, $searchOnlyInCurrentStore = tr
249287
250288 $ ifValueId = $ this ->getConnection ()->getIfNullSql ('t2.value ' , 't1.value ' );
251289 foreach ($ tables as $ table => $ attributeIds ) {
252- $ selects [] = $ this ->getConnection ()->select ()->from (
253- ['t1 ' => $ table ],
254- $ linkField
255- )->joinLeft (
256- ['t2 ' => $ table ],
257- $ joinCondition ,
258- []
259- )->where (
260- 't1.attribute_id IN (?) ' ,
261- $ attributeIds ,
262- \Zend_Db::INT_TYPE
263- )->where (
264- 't1.store_id = ? ' ,
265- 0
266- )->where (
267- $ this ->_resourceHelper ->getCILike ($ ifValueId , $ this ->_searchQuery , $ likeOptions )
268- );
290+ if (!empty ($ preparedIndexEnforcements [$ table ])) {
291+ $ condition1 = $ this ->_conn ->quoteInto (
292+ '`t1`.`attribute_id` IN (?) ' ,
293+ $ attributeIds ,
294+ \Zend_Db::INT_TYPE
295+ );
296+ $ condition2 = '`t1`.`store_id` = 0 ' ;
297+ $ quotedField = $ this ->_conn ->quoteIdentifier ($ ifValueId );
298+ $ condition3 = $ this ->_conn ->quoteInto (
299+ $ quotedField . ' LIKE ? ' ,
300+ $ this ->_resourceHelper ->addLikeEscape ($ this ->_searchQuery , $ likeOptions )
301+ );
302+
303+ //force index statement not implemented in framework
304+ // phpcs:ignore Magento2.SQL.RawQuery
305+ $ select = sprintf (
306+ 'SELECT `t1`.`%s` FROM `%s` AS `t1` FORCE INDEX(%s)
307+ LEFT JOIN `%s` AS `t2` FORCE INDEX(%s)
308+ ON %s WHERE %s AND %s AND (%s) ' ,
309+ $ linkField ,
310+ $ table ,
311+ $ preparedIndexEnforcements [$ table ],
312+ $ table ,
313+ $ preparedIndexEnforcements [$ table ],
314+ $ joinCondition ,
315+ $ condition1 ,
316+ $ condition2 ,
317+ $ condition3
318+ );
319+ } else {
320+ $ select = $ this ->getConnection ()->select ();
321+ $ select ->from (
322+ ['t1 ' => $ table ],
323+ $ linkField
324+ )->joinLeft (
325+ ['t2 ' => $ table ],
326+ $ joinCondition ,
327+ []
328+ )->where (
329+ 't1.attribute_id IN (?) ' ,
330+ $ attributeIds ,
331+ \Zend_Db::INT_TYPE
332+ )->where (
333+ 't1.store_id = ? ' ,
334+ 0
335+ )->where (
336+ $ this ->_resourceHelper ->getCILike ($ ifValueId , $ this ->_searchQuery , $ likeOptions )
337+ );
338+ }
339+ $ selects [] = $ select ;
269340 }
270341
271342 $ sql = $ this ->_getSearchInOptionSql ($ query );
0 commit comments