Recommendations.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\AdvancedSearch\Model\ResourceModel;
  7. /**
  8. * Catalog search recommendations resource model
  9. *
  10. * @author Magento Core Team <core@magentocommerce.com>
  11. * @api
  12. * @since 100.0.2
  13. */
  14. class Recommendations extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
  15. {
  16. /**
  17. * Search query model
  18. *
  19. * @var \Magento\Search\Model\Query
  20. */
  21. protected $_searchQueryModel;
  22. /**
  23. * Construct
  24. *
  25. * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
  26. * @param \Magento\Search\Model\QueryFactory $queryFactory
  27. * @param string $connectionName
  28. */
  29. public function __construct(
  30. \Magento\Framework\Model\ResourceModel\Db\Context $context,
  31. \Magento\Search\Model\QueryFactory $queryFactory,
  32. $connectionName = null
  33. ) {
  34. parent::__construct($context, $connectionName);
  35. $this->_searchQueryModel = $queryFactory->create();
  36. }
  37. /**
  38. * Init main table
  39. *
  40. * @return void
  41. */
  42. protected function _construct()
  43. {
  44. $this->_init('catalogsearch_recommendations', 'id');
  45. }
  46. /**
  47. * Save search relations
  48. *
  49. * @param int $queryId
  50. * @param array $relatedQueries
  51. * @return $this
  52. */
  53. public function saveRelatedQueries($queryId, $relatedQueries = [])
  54. {
  55. $connection = $this->getConnection();
  56. $whereOr = [];
  57. if (count($relatedQueries) > 0) {
  58. $whereOr[] = implode(
  59. ' AND ',
  60. [
  61. $connection->quoteInto('query_id=?', $queryId),
  62. $connection->quoteInto('relation_id NOT IN(?)', $relatedQueries)
  63. ]
  64. );
  65. $whereOr[] = implode(
  66. ' AND ',
  67. [
  68. $connection->quoteInto('relation_id = ?', $queryId),
  69. $connection->quoteInto('query_id NOT IN(?)', $relatedQueries)
  70. ]
  71. );
  72. } else {
  73. $whereOr[] = $connection->quoteInto('query_id = ?', $queryId);
  74. $whereOr[] = $connection->quoteInto('relation_id = ?', $queryId);
  75. }
  76. $whereCond = '(' . implode(') OR (', $whereOr) . ')';
  77. $connection->delete($this->getMainTable(), $whereCond);
  78. $existsRelatedQueries = $this->getRelatedQueries($queryId);
  79. $neededRelatedQueries = array_diff($relatedQueries, $existsRelatedQueries);
  80. foreach ($neededRelatedQueries as $relationId) {
  81. $connection->insert($this->getMainTable(), ["query_id" => $queryId, "relation_id" => $relationId]);
  82. }
  83. return $this;
  84. }
  85. /**
  86. * Retrieve related search queries
  87. *
  88. * @param int|array $queryId
  89. * @param bool $limit
  90. * @param bool $order
  91. * @return array
  92. */
  93. public function getRelatedQueries($queryId, $limit = false, $order = false)
  94. {
  95. $collection = $this->_searchQueryModel->getResourceCollection();
  96. $connection = $this->getConnection();
  97. $queryIdCond = $connection->quoteInto('main_table.query_id IN (?)', $queryId);
  98. $collection->getSelect()->join(
  99. ['sr' => $collection->getTable('catalogsearch_recommendations')],
  100. '(sr.query_id=main_table.query_id OR sr.relation_id=main_table.query_id) AND ' . $queryIdCond
  101. )->reset(
  102. \Magento\Framework\DB\Select::COLUMNS
  103. )->columns(
  104. [
  105. 'rel_id' => $connection->getCheckSql(
  106. 'main_table.query_id=sr.query_id',
  107. 'sr.relation_id',
  108. 'sr.query_id'
  109. ),
  110. ]
  111. );
  112. if (!empty($limit)) {
  113. $collection->getSelect()->limit($limit);
  114. }
  115. if (!empty($order)) {
  116. $collection->getSelect()->order($order);
  117. }
  118. $queryIds = $connection->fetchCol($collection->getSelect());
  119. return $queryIds;
  120. }
  121. /**
  122. * Retrieve related search queries by single query
  123. *
  124. * @param string $query
  125. * @param array $params
  126. * @param int $searchRecommendationsCount
  127. * @return array
  128. */
  129. public function getRecommendationsByQuery($query, $params, $searchRecommendationsCount)
  130. {
  131. $this->_searchQueryModel->loadByQueryText($query);
  132. if (isset($params['store_id'])) {
  133. $this->_searchQueryModel->setStoreId($params['store_id']);
  134. }
  135. $relatedQueriesIds = $this->loadByQuery($query, $searchRecommendationsCount);
  136. $relatedQueries = [];
  137. if (count($relatedQueriesIds)) {
  138. $connection = $this->getConnection();
  139. $mainTable = $this->_searchQueryModel->getResourceCollection()->getMainTable();
  140. $select = $connection->select()->from(
  141. ['main_table' => $mainTable],
  142. ['query_text', 'num_results']
  143. )->where(
  144. 'query_id IN(?)',
  145. $relatedQueriesIds
  146. )->where(
  147. 'num_results > 0'
  148. );
  149. $relatedQueries = $connection->fetchAll($select);
  150. }
  151. return $relatedQueries;
  152. }
  153. /**
  154. * Retrieve search terms which are started with $queryWords
  155. *
  156. * @param string $query
  157. * @param int $searchRecommendationsCount
  158. * @return array
  159. */
  160. protected function loadByQuery($query, $searchRecommendationsCount)
  161. {
  162. $connection = $this->getConnection();
  163. $queryId = $this->_searchQueryModel->getId();
  164. $relatedQueries = $this->getRelatedQueries($queryId, $searchRecommendationsCount, 'num_results DESC');
  165. if ($searchRecommendationsCount - count($relatedQueries) < 1) {
  166. return $relatedQueries;
  167. }
  168. $queryWords = [$query];
  169. if (strpos($query, ' ') !== false) {
  170. $queryWords = array_unique(array_merge($queryWords, explode(' ', $query)));
  171. foreach ($queryWords as $key => $word) {
  172. $queryWords[$key] = trim($word);
  173. if (strlen($word) < 3) {
  174. unset($queryWords[$key]);
  175. }
  176. }
  177. }
  178. $likeCondition = [];
  179. foreach ($queryWords as $word) {
  180. $likeCondition[] = $connection->quoteInto('query_text LIKE ?', $word . '%');
  181. }
  182. $likeCondition = implode(' OR ', $likeCondition);
  183. $select = $connection->select()->from(
  184. $this->_searchQueryModel->getResource()->getMainTable(),
  185. ['query_id']
  186. )->where(
  187. new \Zend_Db_Expr($likeCondition)
  188. )->where(
  189. 'store_id=?',
  190. $this->_searchQueryModel->getStoreId()
  191. )->order(
  192. 'num_results DESC'
  193. )->limit(
  194. $searchRecommendationsCount + 1
  195. );
  196. $ids = $connection->fetchCol($select);
  197. if (!is_array($ids)) {
  198. $ids = [];
  199. }
  200. $key = array_search($queryId, $ids);
  201. if ($key !== false) {
  202. unset($ids[$key]);
  203. }
  204. $ids = array_unique(array_merge($relatedQueries, $ids));
  205. $ids = array_slice($ids, 0, $searchRecommendationsCount);
  206. return $ids;
  207. }
  208. }