Download Fee Magento 2 Get One Search Result By Sku Extension
By default when you enter sku reference in quick bar search of Magento 2 , It displays all the product whose sku is having prefix of entered sku , By example if you enter 'BHSHIRT-F' for searching specific proudtc which have this reference as value , you will get more than one for example ' BHSHIRT-FX1 and BHSHIRT-FX2' .
Why ?
Now in Magento 2 we have in database catalogsearch_fulltext_scope1 and catalogsearch_fulltext_scope2 , is related to how many scope you have , let's imagine you have 2 store one for English and other for Arabic , the system create 2 scope . And stock the map of search inside this tables , but how ? Yeah let's go and see the structure of table ,this table have 3 columns entity_id and atrribute_id and data_index :
entity_id : id of entity or product that mapped with this infos
atrribute_id : id of attribute related to attribute set of product by default title and short description and description attribute used in map
data_index: the work used for map taking from attribute like title or description
When you create an attribute (for Example Sku) with option of search-able option (use in search) , the system add automatically this attribute to catalogsearch_fulltext_scope for indexation
Full course : http://www.ibnab.com/en/blog/magento-2/magento-2-for-developer-some-ideas-about-frontend-search
When you search from the small field text in the top with reference of sku the type of query is 'quick_search_container' , the system take the query like 'BHSHIRT-F' nad create sql query based on it , but the fulltext query have custom strategie to create this query sql , te field data_index is used in matching proccess but Match responsible will add the filter based on data_index filed and text and add to query sql :
public function build( ScoreBuilder $scoreBuilder, Select $select, RequestQueryInterface $query, $conditionType ) { /** @var $query \Magento\Framework\Search\Request\Query\Match */ $queryValue = $this->prepareQuery($query->getValue(), $conditionType); $fieldList = []; foreach ($query->getMatches() as $match) { $fieldList[] = $match['field']; } $resolvedFieldList = $this->resolver->resolve($fieldList); $fieldIds = []; $columns = []; foreach ($resolvedFieldList as $field) { $fieldIds[] = $field->getAttributeId(); } $column = $field->getColumn(); $columns[$column] = $column; } $matchQuery = $this->fulltextHelper->getMatchQuery( $columns, $queryValue, $this->fulltextSearchMode ); $scoreBuilder->addCondition($matchQuery, true); if ($fieldIds) { } $select->where($matchQuery); return $select; }
The important line here for us is $this->prepareQuery($query->getValue(), $conditionType);
/** * @param string $queryValue * @param string $conditionType * @return string */ protected function prepareQuery($queryValue, $conditionType) { foreach ($this->preprocessors as $preprocessor) { $queryValue = $preprocessor->process($queryValue); } $stringPrefix = ''; if ($conditionType === BoolExpression::QUERY_CONDITION_MUST) { $stringPrefix = ''; } elseif ($conditionType === BoolExpression::QUERY_CONDITION_NOT) { $stringPrefix = '-'; } foreach ($queryValues as $queryKey => $queryValue) { } else { $queryValues[$queryKey] = $stringPrefix . $queryValue . $stringSuffix; } } return $queryValue; }
But how you can only fetch whose sku is 'BHSHIRT-F' ?
Just create Plugin the customize and change the match strategie Magento\Framework\Search\Adapter\Mysql\Query\Builder\Match
and use around Plugin Function technique :
<p><?php namespace Ibnab\OneSku\Plugin; use Magento\Framework\DB\Select; use Magento\Framework\Search\Request\Query\BoolExpression; use Magento\Framework\Search\Request\QueryInterface as RequestQueryInterface; use Magento\Framework\Search\Adapter\Preprocessor\PreprocessorInterface; use Magento\CatalogSearch\Model\ResourceModel\Fulltext as FulltextResource; use Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection as AttributeCollection; use Magento\Store\Model\StoreManagerInterface; use Magento\Framework\App\ResourceConnection; use Ibnab\OneSku\Helper\Data as OneSkuData; const SPECIAL_CHARACTERS = '-+~/\\<>\'":*$#@()!,.?`=%&^'; const MINIMAL_CHARACTER_LENGTH = 3; /** * @var string[] */ private $replaceSymbols = []; /** * @var ResolverInterface */ private $resolver; /** * @var Fulltext */ private $fulltextHelper; /** * @var string */ private $fulltextSearchMode; /** * @var PreprocessorInterface[] * @since 100.1.0 */ protected $preprocessors; /** * @var AttributeCollection */ private $attributeCollection; /** * @var FulltextResource */ private $fulltextResource; private $storeManager; private $_resource;</p> <p> /** * @var \Ibnab\PaymentFee\Helper\Data */ protected $dataHelper; /** * @param ResolverInterface $resolver * @param Fulltext $fulltextHelper * @param string $fulltextSearchMode * @param PreprocessorInterface[] $preprocessors */ public function __construct( OneSkuData $dataHelper,AttributeCollection $attributeCollection, FulltextResource $fulltextResource, StoreManagerInterface $storeManage, ResourceConnection $resource, ResolverInterface $resolver, Fulltext $fulltextHelper, $fulltextSearchMode = Fulltext::FULLTEXT_MODE_BOOLEAN, array $preprocessors = [] ) { $this->resolver = $resolver; $this->fulltextHelper = $fulltextHelper; $this->fulltextSearchMode = $fulltextSearchMode; $this->preprocessors = $preprocessors; $this->attributeCollection = $attributeCollection; $this->fulltextResource = $fulltextResource; $this->storeManager = $storeManage; $this->_resource = $resource; $this->dataHelper = $dataHelper; parent::__construct($resolver,$fulltextHelper, $fulltextSearchMode, $preprocessors); } public function aroundBuild($matcher, $build, $scoreBuilder, $select, $query, $conditionType ) { /** @var $query \Magento\Framework\Search\Request\Query\Match */ $resultSku = 0; $queryValue = $this->prepareQuery($query->getValue(), $conditionType); $fieldList = []; foreach ($query->getMatches() as $match) { $fieldList[] = $match['field']; } $resolvedFieldList = $this->resolver->resolve($fieldList); $fieldIds = []; $columns = []; foreach ($resolvedFieldList as $field) { $fieldIds[] = $field->getAttributeId(); } $column = $field->getColumn(); $columns[$column] = $column; } if ($this->dataHelper->allowExtension()) { $attribute = $this->attributeCollection->getItemByColumnValue('attribute_code', 'sku'); $attributeId = $attribute ? $attribute->getId() : 0; if ($attributeId != 0) { $connection = $this->_resource->getConnection(\Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION); $mainFullTextScope = $this->fulltextResource->getMainTable() . "_scope" . $this->storeManager->getStore()->getId(); $tblFullTextScope = $connection->getTableName($mainFullTextScope); $resultSku = $connection->fetchOne('SELECT count(entity_id) FROM `' . $tblFullTextScope . '` WHERE attribute_id=' . $attributeId . ' And data_index=\'' . $query->getValue() . '\''); } } if ($resultSku == 1) { $matchQuery = 'data_index=\'' . $query->getValue() . '\''; }else{ $matchQuery = $this->fulltextHelper->getMatchQuery( $columns, $queryValue, $this->fulltextSearchMode ); } $matchQuery = $this->fulltextHelper->getMatchQuery( $columns, $queryValue, $this->fulltextSearchMode ); $scoreBuilder->addCondition($matchQuery, true); if ($fieldIds) { } $select->where($matchQuery); return $select; } }
in this class we have added some line to test of sku with some reference is exist by example in table catalogsearch_fulltext_scope1 (related to store id 1)
$attribute = $this->attributeCollection->getItemByColumnValue('attribute_code', 'sku'); $attributeId = $attribute ? $attribute->getId() : 0; if ($attributeId != 0) { $connection = $this->_resource->getConnection(\Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION); $mainFullTextScope = $this->fulltextResource->getMainTable() . "_scope" . $this->storeManager->getStore()->getId(); $tblFullTextScope = $connection->getTableName($mainFullTextScope); $resultSku = $connection->fetchOne('SELECT count(entity_id) FROM `' . $tblFullTextScope . '` WHERE attribute_id=' . $attributeId . ' And data_index=\'' . $query->getValue() . '\''); }
if yes we change the clause where to be strict equal without Boolean match or like .
if ($resultSku == 1) { $matchQuery = 'data_index=\'' . $query->getValue() . '\''; }else{ $matchQuery = $this->fulltextHelper->getMatchQuery( $columns, $queryValue, $this->fulltextSearchMode ); }
Is done you can download the free ibnab extension get One result Search by Sku
Download Fee Magento 2 Get One Search Result By Sku Extension
Download Fee Magento 2 Get One Search Result By Sku Extension
Comments