123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\CatalogSearch\Model\ResourceModel\Search;
- /**
- * Search collection
- *
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- * @api
- * @since 100.0.2
- */
- class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection implements
- \Magento\Search\Model\SearchCollectionInterface
- {
- /**
- * Attribute collection
- *
- * @var array
- */
- protected $_attributesCollection;
- /**
- * Search query
- *
- * @var string
- */
- protected $_searchQuery;
- /**
- * Attribute collection factory
- *
- * @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory
- */
- protected $_attributeCollectionFactory;
- /**
- * Collection constructor.
- * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
- * @param \Psr\Log\LoggerInterface $logger
- * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
- * @param \Magento\Framework\Event\ManagerInterface $eventManager
- * @param \Magento\Eav\Model\Config $eavConfig
- * @param \Magento\Framework\App\ResourceConnection $resource
- * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory
- * @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper
- * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
- * @param \Magento\Store\Model\StoreManagerInterface $storeManager
- * @param \Magento\Framework\Module\Manager $moduleManager
- * @param \Magento\Catalog\Model\Indexer\Product\Flat\State $catalogProductFlatState
- * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
- * @param \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory
- * @param \Magento\Catalog\Model\ResourceModel\Url $catalogUrl
- * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
- * @param \Magento\Customer\Model\Session $customerSession
- * @param \Magento\Framework\Stdlib\DateTime $dateTime
- * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement
- * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeCollectionFactory
- * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
- *
- * @SuppressWarnings(PHPMD.ExcessiveParameterList)
- */
- public function __construct(
- \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
- \Psr\Log\LoggerInterface $logger,
- \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
- \Magento\Framework\Event\ManagerInterface $eventManager,
- \Magento\Eav\Model\Config $eavConfig,
- \Magento\Framework\App\ResourceConnection $resource,
- \Magento\Eav\Model\EntityFactory $eavEntityFactory,
- \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper,
- \Magento\Framework\Validator\UniversalFactory $universalFactory,
- \Magento\Store\Model\StoreManagerInterface $storeManager,
- \Magento\Framework\Module\Manager $moduleManager,
- \Magento\Catalog\Model\Indexer\Product\Flat\State $catalogProductFlatState,
- \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
- \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory,
- \Magento\Catalog\Model\ResourceModel\Url $catalogUrl,
- \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
- \Magento\Customer\Model\Session $customerSession,
- \Magento\Framework\Stdlib\DateTime $dateTime,
- \Magento\Customer\Api\GroupManagementInterface $groupManagement,
- \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeCollectionFactory,
- \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
- ) {
- $this->_attributeCollectionFactory = $attributeCollectionFactory;
- parent::__construct(
- $entityFactory,
- $logger,
- $fetchStrategy,
- $eventManager,
- $eavConfig,
- $resource,
- $eavEntityFactory,
- $resourceHelper,
- $universalFactory,
- $storeManager,
- $moduleManager,
- $catalogProductFlatState,
- $scopeConfig,
- $productOptionFactory,
- $catalogUrl,
- $localeDate,
- $customerSession,
- $dateTime,
- $groupManagement,
- $connection
- );
- }
- /**
- * Add search query filter
- *
- * @param string $query
- * @return $this
- */
- public function addSearchFilter($query)
- {
- $this->_searchQuery = $query;
- $this->addFieldToFilter(
- $this->getEntity()->getLinkField(),
- ['in' => new \Zend_Db_Expr($this->_getSearchEntityIdsSql($query))]
- );
- return $this;
- }
- /**
- * Add backend search query filter (search by all stores)
- *
- * @param string $query
- * @return $this
- */
- public function addBackendSearchFilter($query)
- {
- $this->_searchQuery = $query;
- $this->addFieldToFilter(
- $this->getEntity()->getLinkField(),
- ['in' => new \Zend_Db_Expr($this->_getSearchEntityIdsSql($query, false))]
- );
- return $this;
- }
- /**
- * Retrieve collection of all attributes
- *
- * @return \Magento\Framework\Data\Collection\AbstractDb
- */
- protected function _getAttributesCollection()
- {
- if (!$this->_attributesCollection) {
- $this->_attributesCollection = $this->_attributeCollectionFactory->create()->load();
- foreach ($this->_attributesCollection as $attribute) {
- $attribute->setEntity($this->getEntity());
- }
- }
- return $this->_attributesCollection;
- }
- /**
- * Check attribute is Text and is Searchable
- *
- * @param \Magento\Catalog\Model\Entity\Attribute $attribute
- * @return boolean
- */
- protected function _isAttributeTextAndSearchable($attribute)
- {
- if ($attribute->getIsSearchable() && !in_array(
- $attribute->getFrontendInput(),
- ['select', 'multiselect']
- ) && (in_array(
- $attribute->getBackendType(),
- ['varchar', 'text']
- ) || $attribute->getBackendType() == 'static')
- ) {
- return true;
- }
- return false;
- }
- /**
- * Check attributes has options and searchable
- *
- * @param \Magento\Catalog\Model\Entity\Attribute $attribute
- * @return boolean
- */
- protected function _hasAttributeOptionsAndSearchable($attribute)
- {
- if ($attribute->getIsSearchable() && in_array($attribute->getFrontendInput(), ['select', 'multiselect'])
- ) {
- return true;
- }
- return false;
- }
- /**
- * Retrieve SQL for search entities
- *
- * @param mixed $query
- * @param bool $searchOnlyInCurrentStore Search only in current store or in all stores
- * @return string
- */
- protected function _getSearchEntityIdsSql($query, $searchOnlyInCurrentStore = true)
- {
- $tables = [];
- $selects = [];
- $likeOptions = ['position' => 'any'];
- $linkField = $this->getEntity()->getLinkField();
- /**
- * Collect tables and attribute ids of attributes with string values
- */
- foreach ($this->_getAttributesCollection() as $attribute) {
- /** @var \Magento\Catalog\Model\Entity\Attribute $attribute */
- $attributeCode = $attribute->getAttributeCode();
- if ($this->_isAttributeTextAndSearchable($attribute)) {
- $table = $attribute->getBackendTable();
- if (!isset($tables[$table]) && $attribute->getBackendType() != 'static') {
- $tables[$table] = [];
- }
- if ($attribute->getBackendType() == 'static') {
- $selects[] = $this->getConnection()->select()->from(
- $table,
- $linkField
- )->where(
- $this->_resourceHelper->getCILike($attributeCode, $this->_searchQuery, $likeOptions)
- );
- } else {
- $tables[$table][] = $attribute->getId();
- }
- }
- }
- if ($searchOnlyInCurrentStore) {
- $joinCondition = $this->getConnection()->quoteInto(
- "t1.{$linkField} = t2.{$linkField} AND t1.attribute_id = t2.attribute_id AND t2.store_id = ?",
- $this->getStoreId()
- );
- } else {
- $joinCondition = "t1.{$linkField} = t2.{$linkField} AND t1.attribute_id = t2.attribute_id";
- }
- $ifValueId = $this->getConnection()->getIfNullSql('t2.value', 't1.value');
- foreach ($tables as $table => $attributeIds) {
- $selects[] = $this->getConnection()->select()->from(
- ['t1' => $table],
- $linkField
- )->joinLeft(
- ['t2' => $table],
- $joinCondition,
- []
- )->where(
- 't1.attribute_id IN (?)',
- $attributeIds
- )->where(
- 't1.store_id = ?',
- 0
- )->where(
- $this->_resourceHelper->getCILike($ifValueId, $this->_searchQuery, $likeOptions)
- );
- }
- $sql = $this->_getSearchInOptionSql($query);
- if ($sql) {
- $selects[] = "SELECT * FROM ({$sql}) AS inoptionsql"; // inherent unions may be inside
- }
- $sql = $this->getConnection()->select()->union($selects, \Magento\Framework\DB\Select::SQL_UNION_ALL);
- return $sql;
- }
- /**
- * Retrieve SQL for search entities by option
- *
- * @param mixed $query
- * @return string
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- */
- protected function _getSearchInOptionSql($query)
- {
- $attributeIds = [];
- $attributeTables = [];
- $storeId = (int)$this->getStoreId();
- /**
- * Collect attributes with options
- */
- foreach ($this->_getAttributesCollection() as $attribute) {
- if ($this->_hasAttributeOptionsAndSearchable($attribute)) {
- $attributeTables[$attribute->getFrontendInput()] = $attribute->getBackend()->getTable();
- $attributeIds[] = $attribute->getId();
- }
- }
- if (empty($attributeIds)) {
- return false;
- }
- $optionTable = $this->_resource->getTableName('eav_attribute_option');
- $optionValueTable = $this->_resource->getTableName('eav_attribute_option_value');
- $attributesTable = $this->_resource->getTableName('eav_attribute');
- /**
- * Select option Ids
- */
- $ifStoreId = $this->getConnection()->getIfNullSql('s.store_id', 'd.store_id');
- $ifValue = $this->getConnection()->getCheckSql('s.value_id > 0', 's.value', 'd.value');
- $select = $this->getConnection()->select()->from(
- ['d' => $optionValueTable],
- ['option_id', 'o.attribute_id', 'store_id' => $ifStoreId, 'a.frontend_input']
- )->joinLeft(
- ['s' => $optionValueTable],
- $this->getConnection()->quoteInto('s.option_id = d.option_id AND s.store_id=?', $storeId),
- []
- )->join(
- ['o' => $optionTable],
- 'o.option_id=d.option_id',
- []
- )->join(
- ['a' => $attributesTable],
- 'o.attribute_id=a.attribute_id',
- []
- )->where(
- 'd.store_id=0'
- )->where(
- 'o.attribute_id IN (?)',
- $attributeIds
- )->where(
- $this->_resourceHelper->getCILike($ifValue, $this->_searchQuery, ['position' => 'any'])
- );
- $options = $this->getConnection()->fetchAll($select);
- if (empty($options)) {
- return false;
- }
- // build selects of entity ids for specified options ids by frontend input
- $selects = [];
- foreach (['select' => 'eq', 'multiselect' => 'finset'] as $frontendInput => $condition) {
- if (isset($attributeTables[$frontendInput])) {
- $where = [];
- foreach ($options as $option) {
- if ($frontendInput === $option['frontend_input']) {
- $findSet = $this->getConnection()->prepareSqlCondition(
- 'value',
- [$condition => $option['option_id']]
- );
- $whereCond = "(attribute_id=%d AND store_id=%d AND {$findSet})";
- $where[] = sprintf($whereCond, $option['attribute_id'], $option['store_id']);
- }
- }
- if ($where) {
- $selects[$frontendInput] = (string)$this->getConnection()->select()->from(
- $attributeTables[$frontendInput],
- $this->getEntity()->getLinkField()
- )->where(
- implode(' OR ', $where)
- );
- }
- }
- }
- $sql = $this->getConnection()->select()->union($selects, \Magento\Framework\DB\Select::SQL_UNION_ALL);
- return (string)$sql;
- }
- }
|