src/module-elasticsuite-catalog/Model/ResourceModel/Product/Search/Position.php
<?php
/**
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Smile ElasticSuite to newer
* versions in the future.
*
* @category Smile
* @package Smile\ElasticsuiteCatalog
* @author Aurelien FOUCRET <aurelien.foucret@smile.fr>
* @copyright 2020 Smile
* @license Open Software License ("OSL") v. 3.0
*/
namespace Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Search;
use Magento\Search\Model\Query;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
/**
* Product search position resource model.
*
* @category Smile
* @package Smile\ElasticsuiteCatalog
* @author Aurelien FOUCRET <aurelien.foucret@smile.fr>
*/
class Position extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
/**
* @var string
*/
const TABLE_NAME = 'smile_elasticsuitecatalog_search_query_product_position';
/**
* @var \Magento\Framework\Indexer\IndexerRegistry
*/
private $indexerRegistry;
/**
* Constructor.
*
* @param \Magento\Framework\Model\ResourceModel\Db\Context $context Context.
* @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry Indexer registry.
* @param string $connectionName Connection name.
*/
public function __construct(
\Magento\Framework\Model\ResourceModel\Db\Context $context,
\Magento\Framework\Indexer\IndexerRegistry $indexerRegistry,
$connectionName = null
) {
$this->indexerRegistry = $indexerRegistry;
parent::__construct($context, $connectionName);
}
/**
* Get query position for a product list.
*
* @param array $productIds Product ids.
* @param int $storeId Store ids.
*
* @return array
*/
public function getByProductIds(array $productIds, $storeId)
{
$searchQueryTable = $this->getTable('search_query');
$select = $this->getBaseSelect()
->joinInner($searchQueryTable, "main_table.query_id = {$searchQueryTable}.query_id", [])
->where('product_id IN(?)', $productIds)
->where('store_id = ?', $storeId)
->columns(['product_id', 'query_id', 'position', 'is_blacklisted']);
return $this->getConnection()->fetchAll($select);
}
/**
* Load product positions for the given query.
*
* @param Query|int $query Query.
*
* @return array
*/
public function getProductPositionsByQuery($query)
{
if (is_object($query)) {
$query = $query->getId();
}
$select = $this->getBaseSelect()
->where('query_id = ?', (int) $query)
->where('position IS NOT NULL')
->columns(['product_id', 'position'])
->order('position');
return $this->getConnection()->fetchPairs($select);
}
/**
* Load blacklisted products for the given query.
*
* @param Query|int $query Query.
*
* @return array
*/
public function getProductBlacklistByQuery($query)
{
if (is_object($query)) {
$query = $query->getId();
}
$select = $this->getBaseSelect()
->columns(['product_id'])
->where('query_id = ?', (int) $query)
->where('is_blacklisted = ?', (int) true);
return $this->getConnection()->fetchCol($select);
}
/**
* Save the product positions.
*
* @param int $queryId Query id.
* @param array $newProductPositions Product positions.
* @param array $blacklistedProducts Blacklisted product ids.
*
* @return \Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Search\Position
*/
public function saveProductPositions($queryId, $newProductPositions, $blacklistedProducts = [])
{
$reindexedProductIds = array_merge(
array_keys($newProductPositions),
array_keys($this->getProductPositionsByQuery($queryId)),
$blacklistedProducts
);
$deleteConditions = [
$this->getConnection()->quoteInto('query_id = ?', (int) $queryId),
];
if (!empty($newProductPositions) || !empty($blacklistedProducts)) {
$insertData = [];
$updatedProductIds = array_merge(array_keys($newProductPositions), $blacklistedProducts);
foreach ($updatedProductIds as $productId) {
$insertData[] = [
'query_id' => $queryId,
'product_id' => $productId,
'position' => $newProductPositions[$productId] ?? null,
'is_blacklisted' => in_array($productId, $blacklistedProducts),
];
}
$deleteConditions[] = $this->getConnection()->quoteInto('product_id NOT IN (?)', $updatedProductIds);
$this->getConnection()->insertOnDuplicate($this->getMainTable(), $insertData, array_keys(current($insertData)));
}
$this->getConnection()->delete($this->getMainTable(), implode(' AND ', $deleteConditions));
$this->reindex(array_unique($reindexedProductIds));
return $this;
}
/**
* @SuppressWarnings(PHPMD.CamelCaseMethodName)
* {@inheritDoc}
*/
protected function _construct()
{
$this->_setMainTable(self::TABLE_NAME);
}
/**
* Reindex product on position change.
*
* @param array $productIds Product ids to be reindexed.
*
* @return void
*/
private function reindex($productIds)
{
$this->indexerRegistry->get(\Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID)->reindexList($productIds);
}
/**
* Init a base select with the main table.
*
* @return \Zend_Db_Select
*/
private function getBaseSelect()
{
$select = $this->getConnection()->select();
$select->from(['main_table' => $this->getMainTable()], []);
return $select;
}
}