diff --git a/src/module-elasticsuite-catalog/Model/Autocomplete/Category/DataProvider.php b/src/module-elasticsuite-catalog/Model/Autocomplete/Category/DataProvider.php index 9d6bb4580..b8689df36 100644 --- a/src/module-elasticsuite-catalog/Model/Autocomplete/Category/DataProvider.php +++ b/src/module-elasticsuite-catalog/Model/Autocomplete/Category/DataProvider.php @@ -18,7 +18,7 @@ use Magento\Search\Model\QueryFactory; use Smile\ElasticsuiteCatalog\Helper\Autocomplete as ConfigurationHelper; use Smile\ElasticsuiteCatalog\Model\ResourceModel\Category\Fulltext\CollectionFactory as CategoryCollectionFactory; -use Smile\ElasticsuiteCore\Model\Autocomplete\Terms\DataProvider as TermDataProvider; +use Smile\ElasticsuiteCore\Model\Autocomplete\SuggestedTermsProvider; /** * Catalog category autocomplete data provider. @@ -49,7 +49,7 @@ class DataProvider implements DataProviderInterface protected $queryFactory; /** - * @var TermDataProvider + * @var SuggestedTermsProvider */ protected $termDataProvider; @@ -73,7 +73,7 @@ class DataProvider implements DataProviderInterface * * @param ItemFactory $itemFactory Suggest item factory. * @param QueryFactory $queryFactory Search query factory. - * @param TermDataProvider $termDataProvider Search terms suggester. + * @param SuggestedTermsProvider $termDataProvider Search terms suggester. * @param CategoryCollectionFactory $categoryCollectionFactory Category collection factory. * @param ConfigurationHelper $configurationHelper Autocomplete configuration helper. * @param string $type Autocomplete provider type. @@ -81,7 +81,7 @@ class DataProvider implements DataProviderInterface public function __construct( ItemFactory $itemFactory, QueryFactory $queryFactory, - TermDataProvider $termDataProvider, + SuggestedTermsProvider $termDataProvider, CategoryCollectionFactory $categoryCollectionFactory, ConfigurationHelper $configurationHelper, $type = self::AUTOCOMPLETE_TYPE @@ -143,23 +143,6 @@ private function isCategoryAvailable(Category $category): bool ; } - /** - * List of search terms suggested by the search terms data provider. - * - * @return array - */ - private function getSuggestedTerms() - { - $terms = array_map( - function (\Magento\Search\Model\Autocomplete\Item $termItem) { - return $termItem->getTitle(); - }, - $this->termDataProvider->getItems() - ); - - return $terms; - } - /** * Suggested categories collection. * Returns null if no suggested search terms. @@ -171,7 +154,7 @@ private function getCategoryCollection() { $categoryCollection = null; - $suggestedTerms = $this->getSuggestedTerms(); + $suggestedTerms = $this->termDataProvider->getSuggestedTerms(); $terms = [$this->queryFactory->get()->getQueryText()]; if (!empty($suggestedTerms)) { diff --git a/src/module-elasticsuite-catalog/Model/Autocomplete/Product/Collection/Filter.php b/src/module-elasticsuite-catalog/Model/Autocomplete/Product/Collection/Filter.php index b2ad5e9c1..02c18d840 100644 --- a/src/module-elasticsuite-catalog/Model/Autocomplete/Product/Collection/Filter.php +++ b/src/module-elasticsuite-catalog/Model/Autocomplete/Product/Collection/Filter.php @@ -13,10 +13,8 @@ */ namespace Smile\ElasticsuiteCatalog\Model\Autocomplete\Product\Collection; -use Magento\Search\Model\QueryFactory; -use Smile\ElasticsuiteCore\Model\Autocomplete\Terms\DataProvider as TermDataProvider; -use Magento\Search\Model\Autocomplete\Item as TermItem; use Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection as ProductCollection; +use Smile\ElasticsuiteCore\Model\Autocomplete\SuggestedTermsProvider; /** * Catalog autocomplete product collection filter. @@ -27,13 +25,6 @@ */ class Filter implements PreProcessorInterface { - /** - * Query factory - * - * @var QueryFactory - */ - private $queryFactory; - /** * @var TermDataProvider */ @@ -42,12 +33,10 @@ class Filter implements PreProcessorInterface /** * Constructor. * - * @param QueryFactory $queryFactory Search term query factory. - * @param TermDataProvider $termDataProvider Popular search terms provider. + * @param SuggestedTermsProvider $termDataProvider Suggested search terms provider. */ - public function __construct(QueryFactory $queryFactory, TermDataProvider $termDataProvider) + public function __construct(SuggestedTermsProvider $termDataProvider) { - $this->queryFactory = $queryFactory; $this->termDataProvider = $termDataProvider; } @@ -61,31 +50,8 @@ public function __construct(QueryFactory $queryFactory, TermDataProvider $termDa */ public function prepareCollection(ProductCollection $collection) { - $terms = $this->getQueryText(); - - $collection->setSearchQuery($terms); + $collection->setSearchQuery($this->termDataProvider->getSuggestedTerms()); return $collection; } - - /** - * List of search terms suggested by the search terms data provider. - * - * @return array - */ - private function getQueryText() - { - $terms = array_map( - function (TermItem $termItem) { - return $termItem->getTitle(); - }, - $this->termDataProvider->getItems() - ); - - if (empty($terms)) { - $terms = [$this->queryFactory->get()->getQueryText()]; - } - - return $terms; - } } diff --git a/src/module-elasticsuite-core/Helper/Autocomplete.php b/src/module-elasticsuite-core/Helper/Autocomplete.php index 34f3f0123..2078c0a82 100644 --- a/src/module-elasticsuite-core/Helper/Autocomplete.php +++ b/src/module-elasticsuite-core/Helper/Autocomplete.php @@ -51,6 +51,68 @@ public function isEnabled($type) return $this->getMaxSize($type) > 0; } + /** + * Check if Autocomplete "extension" system is enabled. + * + * @return bool + */ + public function isExtensionEnabled() + { + return (bool) $this->scopeConfig->isSetFlag( + self::AUTOCOMPLETE_SETTINGS_CONFIG_XML_PREFIX . "/advanced/extension_enabled", + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + } + + /** + * Check if Autocomplete "extension" system is limited. + * + * @return bool + */ + public function isExtensionLimited() + { + return (bool) ($this->scopeConfig->isSetFlag( + self::AUTOCOMPLETE_SETTINGS_CONFIG_XML_PREFIX . "/advanced/extension_limited", + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + )) && ($this->getExtensionSize() > 0); + } + + /** + * Get the maximum number of popular search terms to use when the "extension" is limited. + * + * @return int + */ + public function getExtensionSize() + { + return (int) $this->getConfigValue("advanced/extension_size"); + } + + /** + * Check if Autocomplete "extension" system is stopped when having matches. + * + * @return bool + */ + public function isExtensionStoppedOnMatch() + { + return (bool) $this->scopeConfig->isSetFlag( + self::AUTOCOMPLETE_SETTINGS_CONFIG_XML_PREFIX . "/advanced/stop_extension_on_match", + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + } + + /** + * Check if Autocomplete is supposed to always use the user raw query or not. + * + * @return bool + */ + public function isPreservingBaseQuery() + { + return (bool) $this->scopeConfig->isSetFlag( + self::AUTOCOMPLETE_SETTINGS_CONFIG_XML_PREFIX . "/advanced/preserve_base_query", + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + } + /** * Retrieve a configuration value by its key * diff --git a/src/module-elasticsuite-core/Model/Autocomplete/SuggestedTermsProvider.php b/src/module-elasticsuite-core/Model/Autocomplete/SuggestedTermsProvider.php new file mode 100644 index 000000000..4f7fc703d --- /dev/null +++ b/src/module-elasticsuite-core/Model/Autocomplete/SuggestedTermsProvider.php @@ -0,0 +1,132 @@ + + * @copyright 2024 Smile + * @license Open Software License ("OSL") v. 3.0 + */ + +namespace Smile\ElasticsuiteCore\Model\Autocomplete; + +use Magento\Search\Model\Autocomplete\Item as TermItem; +use Smile\ElasticsuiteCore\Helper\Autocomplete; +use Smile\ElasticsuiteCore\Model\Autocomplete\Terms\DataProvider as TermDataProvider; +use Smile\ElasticsuiteCore\Model\Search\QueryStringProviderFactory; + +/** + * Suggested Terms Provider. + * Based on the Term provider but will manipulate it according to configuration. + * + * @category Smile + * @package Smile\ElasticsuiteCore + * @author Romain Ruaud + */ +class SuggestedTermsProvider +{ + /** + * @var \Smile\ElasticsuiteCore\Model\Autocomplete\Terms\DataProvider + */ + private $termDataProvider; + + /** + * @var \Smile\ElasticsuiteCatalog\Helper\Autocomplete + */ + private $helper; + + /** + * @var \Smile\ElasticsuiteCore\Model\Search\QueryStringProviderFactory + */ + private $queryStringProviderFactory; + + /** + * @var null|string + */ + private $queryString = null; + + /** + * @var null + */ + private $terms = null; + + /** + * @param Autocomplete $helper Autocomplete helper + * @param TermDataProvider $termDataProvider Term data provider + * @param QueryStringProviderFactory $queryStringProviderFactory Search Query Factory + */ + public function __construct( + Autocomplete $helper, + TermDataProvider $termDataProvider, + QueryStringProviderFactory $queryStringProviderFactory + ) { + $this->helper = $helper; + $this->termDataProvider = $termDataProvider; + $this->queryStringProviderFactory = $queryStringProviderFactory; + } + + /** + * List of search terms suggested by the search terms data provider, and reworked according to configuration. + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * + * @return array|string[] + */ + public function getSuggestedTerms() + { + if (null === $this->terms) { + $terms = []; + + if ($this->helper->isExtensionEnabled()) { + $terms = array_map( + function (TermItem $termItem) { + return trim($termItem->getTitle()); + }, + $this->termDataProvider->getItems() + ); + + $hasAlreadyStoppedExtending = false; + if ($this->helper->isExtensionStoppedOnMatch()) { + if (array_search(trim($this->getQueryString()), $terms) !== false) { + $terms = [$this->getQueryString()]; + $hasAlreadyStoppedExtending = true; + } + } + + if ($this->helper->isExtensionLimited() && !$hasAlreadyStoppedExtending) { + $terms = array_slice($terms, 0, (int) $this->helper->getExtensionSize()); + } + + if ($this->helper->isPreservingBaseQuery() && !$hasAlreadyStoppedExtending) { + array_unshift($terms, $this->getQueryString()); + } + } + + if (empty($terms)) { + $terms = [$this->getQueryString()]; + } + + $this->terms = array_values(array_unique($terms)); + } + + return $this->terms; + } + + /** + * Retrieve current query string + * + * @return string + */ + private function getQueryString() + { + if ($this->queryString === null) { + $this->queryString = $this->queryStringProviderFactory->create()->get(); + } + + return $this->queryString; + } +} diff --git a/src/module-elasticsuite-core/Model/Search/QueryStringProvider.php b/src/module-elasticsuite-core/Model/Search/QueryStringProvider.php new file mode 100644 index 000000000..e3ac30a29 --- /dev/null +++ b/src/module-elasticsuite-core/Model/Search/QueryStringProvider.php @@ -0,0 +1,70 @@ + + * @copyright 2024 Smile + * @license Open Software License ("OSL") v. 3.0 + */ + +namespace Smile\ElasticsuiteCore\Model\Search; + +use Magento\Framework\Stdlib\StringUtils; +use Magento\Framework\App\RequestInterface; +use Magento\Search\Model\QueryFactory; + +/** + * Query String provider : will fetch current search query from current request. + * + * @category Smile + * @package Smile\ElasticsuiteCore + * @author Romain Ruaud + */ +class QueryStringProvider +{ + /** + * @var RequestInterface + */ + private $request; + + /** @var StringUtils */ + private $string; + + /** + * @var null|string + */ + private $currentQuery = null; + + /** + * QueryStringProvider constructor. + * + * @param RequestInterface $request HTTP Request + * @param StringUtils $string String utils + */ + public function __construct(RequestInterface $request, StringUtils $string) + { + $this->request = $request; + $this->string = $string; + } + + /** + * Get current query string. + * + * @return string + */ + public function get() + { + if ($this->currentQuery === null) { + $queryText = $this->request->getParam(QueryFactory::QUERY_VAR_NAME); + + $this->currentQuery = ($queryText === null || is_array($queryText)) ? '' : $this->string->cleanString(trim($queryText)); + } + + return $this->currentQuery; + } +} diff --git a/src/module-elasticsuite-core/Test/Unit/Model/SuggestedTermsProviderTest.php b/src/module-elasticsuite-core/Test/Unit/Model/SuggestedTermsProviderTest.php new file mode 100644 index 000000000..3e1b19c64 --- /dev/null +++ b/src/module-elasticsuite-core/Test/Unit/Model/SuggestedTermsProviderTest.php @@ -0,0 +1,347 @@ + + * @copyright 2024 Smile + * @license Open Software License ("OSL") v. 3.0 + */ +namespace Smile\ElasticsuiteCore\Test\Unit\Model; + +use PHPUnit\Framework\TestCase; +use Smile\ElasticsuiteCore\Model\Autocomplete\SuggestedTermsProvider; +use Smile\ElasticsuiteCore\Helper\Autocomplete; +use Smile\ElasticsuiteCore\Model\Autocomplete\Terms\DataProvider as TermDataProvider; +use Smile\ElasticsuiteCore\Model\Search\QueryStringProvider; +use Magento\Search\Model\Autocomplete\Item as TermItem; + +/** + * Search API unit testing. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * @category Smile + * @package Smile\ElasticsuiteCore + * @author Romain Ruaud + */ +class SuggestedTermsProviderTest extends TestCase +{ + /** + * @var (\object&\PHPUnit\Framework\MockObject\MockObject) + */ + private $helperMock; + + /** + * @var (\object&\PHPUnit\Framework\MockObject\MockObject) + */ + private $termDataProviderMock; + + /** + * @var (\object&\PHPUnit\Framework\MockObject\MockObject) + */ + private $queryStringProviderFactoryMock; + + /** + * @var (\object&\PHPUnit\Framework\MockObject\MockObject) + */ + private $suggestedTermsProvider; + + /** + * Test setup + * + * @return void + */ + protected function setUp(): void + { + $this->helperMock = $this->createMock(Autocomplete::class); + $this->termDataProviderMock = $this->createMock(TermDataProvider::class); + $this->queryStringProviderFactoryMock = $this->getMockBuilder(QueryStringProvider::class. 'Factory') + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->suggestedTermsProvider = new SuggestedTermsProvider( + $this->helperMock, + $this->termDataProviderMock, + $this->queryStringProviderFactoryMock + ); + } + + /** + * Test case when extension is enabled and no limit on the number of suggested terms. + * It should return all available terms. + */ + public function testGetSuggestedTermsWithExtensionEnabledAndNoLimit() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(true); + $this->helperMock->method('isExtensionStoppedOnMatch')->willReturn(false); + $this->helperMock->method('isExtensionLimited')->willReturn(false); + + // Create mock TermItems with terms starting with 'top'. + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $termItem3 = $this->createMock(TermItem::class); + $termItem3->method('getTitle')->willReturn('top tank'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2, $termItem3]); + + $expectedTerms = ['top', 'top blouse', 'top tank']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } + + /** + * Test case when extension is enabled, and results are limited to one term. + * It should return only the first term. + */ + public function testGetSuggestedTermsWithLimitedResultsOneTerm() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(true); + $this->helperMock->method('isExtensionStoppedOnMatch')->willReturn(false); + $this->helperMock->method('isExtensionLimited')->willReturn(true); + $this->helperMock->method('getExtensionSize')->willReturn(1); + + // Create mock TermItems with terms starting with 'top'. + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $termItem3 = $this->createMock(TermItem::class); + $termItem3->method('getTitle')->willReturn('top tank'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2, $termItem3]); + + // Expect the terms to be limited to only one item. + $expectedTerms = ['top']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } + + /** + * Test case when extension is enabled, and results are limited to two terms. + * It should return the first two terms. + */ + public function testGetSuggestedTermsWithLimitedResultsTwoTerms() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(true); + $this->helperMock->method('isExtensionStoppedOnMatch')->willReturn(false); + $this->helperMock->method('isExtensionLimited')->willReturn(true); + $this->helperMock->method('getExtensionSize')->willReturn(2); + + // Create mock TermItems with terms starting with 'top'. + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $termItem3 = $this->createMock(TermItem::class); + $termItem3->method('getTitle')->willReturn('top tank'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2, $termItem3]); + + $expectedTerms = ['top', 'top blouse']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } + + /** + * Test case when extension is enabled, and results are limited to three terms. + * It should return the first three terms. + */ + public function testGetSuggestedTermsWithLimitedResultsThreeTerms() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(true); + $this->helperMock->method('isExtensionStoppedOnMatch')->willReturn(false); + $this->helperMock->method('isExtensionLimited')->willReturn(true); + $this->helperMock->method('getExtensionSize')->willReturn(3); + + // Create mock TermItems with terms starting with 'top'. + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $termItem3 = $this->createMock(TermItem::class); + $termItem3->method('getTitle')->willReturn('top tank'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2, $termItem3]); + + $expectedTerms = ['top', 'top blouse', 'top tank']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } + + /** + * Test case when extension is enabled, and limit is greater than the number of available terms. + * It should return all available terms. + */ + public function testGetSuggestedTermsWithLimitedResultsLessThanSize() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(true); + $this->helperMock->method('isExtensionStoppedOnMatch')->willReturn(false); + $this->helperMock->method('isExtensionLimited')->willReturn(true); + // Limit set to 5, but only 3 items are available. + $this->helperMock->method('getExtensionSize')->willReturn(5); + + // Create mock TermItems with terms starting with 'top'. + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $termItem3 = $this->createMock(TermItem::class); + $termItem3->method('getTitle')->willReturn('top tank'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2, $termItem3]); + + $expectedTerms = ['top', 'top blouse', 'top tank']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } + + /** + * Test case when extension is disabled. + * It should return the query string as the term. + */ + public function testGetSuggestedTermsWhenExtensionDisabled() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(false); + + $queryStringProviderMock = $this->createMock(\Smile\ElasticsuiteCore\Model\Search\QueryStringProvider::class); + $queryStringProviderMock->method('get')->willReturn('top'); + $this->queryStringProviderFactoryMock->method('create')->willReturn($queryStringProviderMock); + + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $termItem3 = $this->createMock(TermItem::class); + $termItem3->method('getTitle')->willReturn('top tank'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2, $termItem3]); + + // Expect the terms to be the query string since the extension is disabled. + $expectedTerms = ['top']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } + + /** + * Test case when extension is enabled and stopped on match. + * It should return only the term that matches the query string. + */ + public function testGetSuggestedTermsWithExtensionStoppedOnMatch() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(true); + $this->helperMock->method('isExtensionStoppedOnMatch')->willReturn(true); + $this->helperMock->method('isExtensionLimited')->willReturn(false); + + $queryStringProviderMock = $this->createMock(\Smile\ElasticsuiteCore\Model\Search\QueryStringProvider::class); + $queryStringProviderMock->method('get')->willReturn('top'); + $this->queryStringProviderFactoryMock->method('create')->willReturn($queryStringProviderMock); + + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2]); + + // Expect the terms to be only 'top' because of the stop on match logic. + $expectedTerms = ['top']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } + + /** + * Tests the scenario where the base query is preserved and added to the suggestions. + * + * @return void + */ + public function testGetSuggestedTermsWithBaseQueryPreserved() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(true); + $this->helperMock->method('isExtensionStoppedOnMatch')->willReturn(false); + $this->helperMock->method('isExtensionLimited')->willReturn(false); + $this->helperMock->method('isPreservingBaseQuery')->willReturn(true); + + $queryStringProviderMock = $this->createMock(QueryStringProvider::class); + $queryStringProviderMock->method('get')->willReturn('to'); + $this->queryStringProviderFactoryMock->method('create')->willReturn($queryStringProviderMock); + + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2]); + + $expectedTerms = ['to', 'top', 'top blouse']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } + + /** + * Tests the case where the base query matches one of the suggested terms, ensuring duplicates are removed. + * + * @return void + */ + public function testGetSuggestedTermsWithBaseQueryPreservedAndDuplicate() + { + $this->helperMock->method('isExtensionEnabled')->willReturn(true); + $this->helperMock->method('isExtensionStoppedOnMatch')->willReturn(false); + $this->helperMock->method('isExtensionLimited')->willReturn(false); + $this->helperMock->method('isPreservingBaseQuery')->willReturn(true); + + $queryStringProviderMock = $this->createMock(QueryStringProvider::class); + $queryStringProviderMock->method('get')->willReturn('top'); + $this->queryStringProviderFactoryMock->method('create')->willReturn($queryStringProviderMock); + + $termItem1 = $this->createMock(TermItem::class); + $termItem1->method('getTitle')->willReturn('top'); + + $termItem2 = $this->createMock(TermItem::class); + $termItem2->method('getTitle')->willReturn('top blouse'); + + $this->termDataProviderMock->method('getItems')->willReturn([$termItem1, $termItem2]); + + $expectedTerms = ['top', 'top blouse']; + + $terms = $this->suggestedTermsProvider->getSuggestedTerms(); + + $this->assertEquals($expectedTerms, $terms); + } +} diff --git a/src/module-elasticsuite-core/etc/adminhtml/system.xml b/src/module-elasticsuite-core/etc/adminhtml/system.xml index 9b0d4b8b7..4d879db9a 100644 --- a/src/module-elasticsuite-core/etc/adminhtml/system.xml +++ b/src/module-elasticsuite-core/etc/adminhtml/system.xml @@ -180,6 +180,48 @@ + + + + + + Magento\Config\Model\Config\Source\Yesno + + + + + Magento\Config\Model\Config\Source\Yesno + + 1 + + + + + + Magento\Config\Model\Config\Source\Yesno + + 1 + + + + + + integer validate-greater-than-zero + + 1 + 1 + + + + + + Magento\Config\Model\Config\Source\Yesno + + 1 + + + +
diff --git a/src/module-elasticsuite-core/etc/config.xml b/src/module-elasticsuite-core/etc/config.xml index cef8eaa21..7a50397f7 100644 --- a/src/module-elasticsuite-core/etc/config.xml +++ b/src/module-elasticsuite-core/etc/config.xml @@ -53,6 +53,12 @@ 3 + + 1 + 0 + 0 + 0 + diff --git a/src/module-elasticsuite-core/i18n/de_DE.csv b/src/module-elasticsuite-core/i18n/de_DE.csv index c8a49fe6e..65d1050b9 100644 --- a/src/module-elasticsuite-core/i18n/de_DE.csv +++ b/src/module-elasticsuite-core/i18n/de_DE.csv @@ -130,3 +130,14 @@ "You have %1 ghost indices. Ghost indices have a footprint on your Elasticsearch cluster health. You should consider removing them.","Sie haben %1 Geister-Indizes. Geister-Indizes haben einen Fußabdruck auf Ihrer Elasticsearch Cluster-Gesundheit. Sie sollten in Erwägung ziehen, sie zu entfernen." "Click here to go to the Elasticsuite Indices page to take appropriate actions.","Klicken Sie hier, um zu den Elasticsuite Indizes Seite zu gelangen, um entsprechende Aktionen durchzuführen." "Click here to go to the Elasticsuite Indices page to take appropriate actions.","Klicken Sie hier, um zu den Elasticsuite Indizes Seite zu gelangen, um entsprechende Aktionen durchzuführen." +"Advanced Settings","Erweiterte Einstellungen" +"Use suggested search terms to fetch results","Verwenden Sie vorgeschlagene Suchbegriffe, um Ergebnisse abzurufen" +"Default: Yes. When enabled, autocompletion box results will be computed from the current search term the user is typing, but also with the suggested search terms. This is intended to suggest results when the user is in the process of typing. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, and therefore products or categories matching ""computer"" will be shown.","Standard: Ja. Wenn aktiviert, werden die Ergebnisse der Autovervollständigungsbox basierend auf dem aktuellen Suchbegriff des Benutzers berechnet, aber auch mit den vorgeschlagenen Suchbegriffen. Dies soll Ergebnisse vorschlagen, während der Benutzer tippt. Beispiel: Wenn der Benutzer ""comp"" eingibt, wird der beliebte Suchbegriff ""computer"" vorgeschlagen, und Produkte oder Kategorien, die zu ""computer"" passen, werden angezeigt." +"Limit the amount of suggested search terms used for autocomplete matching","Begrenzen Sie die Anzahl der vorgeschlagenen Suchbegriffe für die Autovervollständigung" +"Default: No. When set to ""No"", this setting will use the maximum number of suggested popular search terms configured in the dedicated section.","Standard: Nein. Wenn auf ""Nein"" gesetzt, verwendet diese Einstellung die maximale Anzahl an vorgeschlagenen beliebten Suchbegriffen, die im entsprechenden Abschnitt konfiguriert sind." +"The number of suggested popular search terms to use for fetching results.","Die Anzahl der vorgeschlagenen beliebten Suchbegriffe, die für das Abrufen von Ergebnissen verwendet werden sollen." +"The number of suggested search terms that will be used for fetching results in the autocompletion box.","Die Anzahl der vorgeschlagenen Suchbegriffe, die in der Autovervollständigungsbox verwendet werden sollen, um Ergebnisse abzurufen." +"Stop the extension mechanism when the current search term of the user is suggested.","Stoppen Sie den Erweiterungsmechanismus, wenn der aktuelle Suchbegriff des Benutzers vorgeschlagen wird." +"Default: No. When set to ""Yes"", this setting will discard the extension mechanism as soon as the exact search term entered by the user is part of the suggestions. Eg : When the user has finished to type ""computer"", if the list of suggested search terms is ""computer"", ""apple computer"", ""computer for kids"", only ""computer"" will be considered as it's exactly what the user has written.","Standard: Nein. Wenn auf ""Ja"" gesetzt, wird dieser Mechanismus deaktiviert, sobald der genaue Suchbegriff, den der Benutzer eingegeben hat, Teil der Vorschläge ist. Beispiel: Wenn der Benutzer ""computer"" fertig eingegeben hat und die Liste der vorgeschlagenen Suchbegriffe ""computer"", ""apple computer"", ""computer für Kinder"" enthält, wird nur ""computer"" berücksichtigt, da es genau das ist, was der Benutzer eingegeben hat." +"Always use the user raw input for suggestions.","Immer die Rohdaten des Benutzers für Vorschläge verwenden." +"Default: No. When set to ""Yes"", this setting will always proceed to fetch suggestions on the query typed by the user in addition to the extended terms. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, but products or categories matching either ""comp"" or ""computer"" will be shown.","Standard: Nein. Wenn diese Option auf ""Ja"" gesetzt ist, werden immer Vorschläge basierend auf der eingegebenen Benutzereingabe sowie den erweiterten Begriffen abgerufen. Beispiel: Wenn der Benutzer ""comp"" eingibt, wird der beliebte Suchbegriff ""computer"" vorgeschlagen, aber Produkte oder Kategorien, die entweder ""comp"" oder ""computer"" entsprechen, werden angezeigt." diff --git a/src/module-elasticsuite-core/i18n/en_US.csv b/src/module-elasticsuite-core/i18n/en_US.csv index cb1c0cc10..75a50117e 100644 --- a/src/module-elasticsuite-core/i18n/en_US.csv +++ b/src/module-elasticsuite-core/i18n/en_US.csv @@ -140,3 +140,14 @@ Autocomplete,Autocomplete "You have %1 ghost indices. Ghost indices have a footprint on your Elasticsearch cluster health. You should consider removing them.","You have %1 ghost indices. Ghost indices have a footprint on your Elasticsearch cluster health. You should consider removing them." "Click here to go to the Elasticsuite Indices page to take appropriate actions.","Click here to go to the Elasticsuite Indices page to take appropriate actions." "Click here to go to the Elasticsuite Indices page to take appropriate actions.","Click here to go to the Elasticsuite Indices page to take appropriate actions." +"Advanced Settings","Advanced Settings" +"Use suggested search terms to fetch results","Use suggested search terms to fetch results" +"Default: Yes. When enabled, autocompletion box results will be computed from the current search term the user is typing, but also with the suggested search terms. This is intended to suggest results when the user is in the process of typing. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, and therefore products or categories matching ""computer"" will be shown.","Default: Yes. When enabled, autocompletion box results will be computed from the current search term the user is typing, but also with the suggested search terms. This is intended to suggest results when the user is in the process of typing. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, and therefore products or categories matching ""computer"" will be shown." +"Limit the amount of suggested search terms used for autocomplete matching","Limit the amount of suggested search terms used for autocomplete matching" +"Default: No. When set to ""No"", this setting will use the maximum number of suggested popular search terms configured in the dedicated section.","Default: No. When set to ""No"", this setting will use the maximum number of suggested popular search terms configured in the dedicated section." +"The number of suggested popular search terms to use for fetching results.","The number of suggested popular search terms to use for fetching results." +"The number of suggested search terms that will be used for fetching results in the autocompletion box.","The number of suggested search terms that will be used for fetching results in the autocompletion box." +"Stop the extension mechanism when the current search term of the user is suggested.","Stop the extension mechanism when the current search term of the user is suggested." +"Default: No. When set to ""Yes"", this setting will discard the extension mechanism as soon as the exact search term entered by the user is part of the suggestions. Eg : When the user has finished to type ""computer"", if the list of suggested search terms is ""computer"", ""apple computer"", ""computer for kids"", only ""computer"" will be considered as it's exactly what the user has written.","Default: No. When set to ""Yes"", this setting will discard the extension mechanism as soon as the exact search term entered by the user is part of the suggestions. Eg : When the user has finished to type ""computer"", if the list of suggested search terms is ""computer"", ""apple computer"", ""computer for kids"", only ""computer"" will be considered as it's exactly what the user has written." +"Always use the user raw input for suggestions.","Always use the user raw input for suggestions." +"Default: No. When set to ""Yes"", this setting will always proceed to fetch suggestions on the query typed by the user in addition to the extended terms. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, but products or categories matching either ""comp"" or ""computer"" will be shown.","Default: No. When set to ""Yes"", this setting will always proceed to fetch suggestions on the query typed by the user in addition to the extended terms. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, but products or categories matching either ""comp"" or ""computer"" will be shown." diff --git a/src/module-elasticsuite-core/i18n/fr_FR.csv b/src/module-elasticsuite-core/i18n/fr_FR.csv index f2177dc7e..a716645c0 100644 --- a/src/module-elasticsuite-core/i18n/fr_FR.csv +++ b/src/module-elasticsuite-core/i18n/fr_FR.csv @@ -140,3 +140,14 @@ General,Général "You have %1 ghost indices. Ghost indices have a footprint on your Elasticsearch cluster health. You should consider removing them.","Vous avez %1 index fantômes. Les indexs fantômes consomment inutilement des ressources de votre cluster Elasticsearch. Vous devriez envisager de les supprimer." "Click here to go to the Elasticsuite Indices page to take appropriate actions.","Cliquez ici pour accéder à la liste des indexs Elasticsuite et prendre les actions appropriées." "Click here to go to the Elasticsuite Indices page to take appropriate actions.","Cliquez ici pour accéder à la liste des indexs Elasticsuite et prendre les actions appropriées." +"Advanced Settings","Paramètres avancés" +"Use suggested search terms to fetch results","Utiliser les termes de recherche suggérés pour étendre des résultats" +"Default: Yes. When enabled, autocompletion box results will be computed from the current search term the user is typing, but also with the suggested search terms. This is intended to suggest results when the user is in the process of typing. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, and therefore products or categories matching ""computer"" will be shown.","Par défaut : Oui. Lorsqu'activé, les résultats affichés dans l'autocomplétion seront calculés à partir du terme de recherche actuel que l'utilisateur est en train de taper, mais aussi avec les termes de recherche suggérés. Cela vise à suggérer des résultats pendant la saisie de l'utilisateur. Exemple : lorsque l'utilisateur tape ""ord"", le terme de recherche populaire ""ordinateur"" sera suggéré, et donc les produits ou catégories correspondant à ""ordinateur"" seront affichés." +"Limit the amount of suggested search terms used for autocomplete matching","Limiter le nombre de termes de recherche suggérés utilisés pour étendre l'autocomplétion" +"Default: No. When set to ""No"", this setting will use the maximum number of suggested popular search terms configured in the dedicated section.","Par défaut : Non. Lorsque cette option est définie sur ""Non"", ce paramètre utilisera le nombre maximum de termes de recherche populaires suggérés configurés dans la section dédiée." +"The number of suggested popular search terms to use for fetching results.","Le nombre de termes de recherche populaires suggérés à utiliser pour obtenir des résultats." +"The number of suggested search terms that will be used for fetching results in the autocompletion box.","Le nombre de termes de recherche suggérés qui seront utilisés pour obtenir des résultats dans l'autocomplétion'." +"Stop the extension mechanism when the current search term of the user is suggested.","Arrêter le mécanisme d'extension lorsque le terme de recherche actuel de l'utilisateur fait partie des suggestions." +"Default: No. When set to ""Yes"", this setting will discard the extension mechanism as soon as the exact search term entered by the user is part of the suggestions. Eg : When the user has finished to type ""computer"", if the list of suggested search terms is ""computer"", ""apple computer"", ""computer for kids"", only ""computer"" will be considered as it's exactly what the user has written.","Par défaut : Non. Lorsqu'il est défini sur ""Oui"", ce paramètre arrêtera le mécanisme d'extension dès que le terme de recherche exact saisi par l'utilisateur fait partie des suggestions. Exemple : lorsque l'utilisateur a terminé de taper ""ordinateur"", si la liste des termes de recherche suggérés est ""ordinateur"", ""ordinateur Apple"", ""ordinateur pour enfants"", seul ""ordinateur"" sera pris en compte car c'est exactement ce que l'utilisateur a écrit." +"Always use the user raw input for suggestions.","Toujours utiliser la saisie brute de l'utilisateur pour les suggestions." +"Default: No. When set to ""Yes"", this setting will always proceed to fetch suggestions on the query typed by the user in addition to the extended terms. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, but products or categories matching either ""comp"" or ""computer"" will be shown.","Par défaut : Non. Lorsqu'il est défini sur ""Oui"", ce paramètre permettra toujours d'obtenir des suggestions basées sur la saisie utilisateur brute en plus des termes étendus. Par exemple : Lorsque l'utilisateur tape ""ord"", le terme populaire ""ordinateur"" sera suggéré, mais les produits ou catégories correspondant à ""ord"" ou ""ordinateur"" seront affichés." diff --git a/src/module-elasticsuite-core/i18n/nl_NL.csv b/src/module-elasticsuite-core/i18n/nl_NL.csv index 220a5af5b..6f14b90bc 100644 --- a/src/module-elasticsuite-core/i18n/nl_NL.csv +++ b/src/module-elasticsuite-core/i18n/nl_NL.csv @@ -130,3 +130,14 @@ "You have %1 ghost indices. Ghost indices have a footprint on your Elasticsearch cluster health. You should consider removing them.","Je hebt %1 spookindexen. Spook indices hebben een voetafdruk op je Elasticsearch cluster gezondheid. Je zou moeten overwegen om ze te verwijderen." "Click here to go to the Elasticsuite Indices page to take appropriate actions.","Klik hier om naar de Elasticsuite Indices pagina te gaan om de juiste acties te ondernemen." "Click here to go to the Elasticsuite Indices page to take appropriate actions.","Klik hier om naar de Elasticsuite Indices pagina te gaan om de juiste acties te ondernemen." +"Advanced Settings","Geavanceerde instellingen" +"Use suggested search terms to fetch results","Gebruik voorgestelde zoektermen om resultaten op te halen" +"Default: Yes. When enabled, autocompletion box results will be computed from the current search term the user is typing, but also with the suggested search terms. This is intended to suggest results when the user is in the process of typing. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, and therefore products or categories matching ""computer"" will be shown.","Standaard: Ja. Wanneer ingeschakeld, worden de resultaten in het autocompletie-venster berekend op basis van de huidige zoekterm die de gebruiker typt, maar ook met de voorgestelde zoektermen. Dit is bedoeld om resultaten voor te stellen terwijl de gebruiker aan het typen is. Bijv.: Wanneer de gebruiker ""comp"" typt, wordt de populaire zoekterm ""computer"" voorgesteld en worden producten of categorieën die overeenkomen met ""computer"" weergegeven." +"Limit the amount of suggested search terms used for autocomplete matching","Beperk het aantal voorgestelde zoektermen dat wordt gebruikt voor autocompletie" +"Default: No. When set to ""No"", this setting will use the maximum number of suggested popular search terms configured in the dedicated section.","Standaard: Nee. Als ingesteld op ""Nee"", gebruikt deze instelling het maximale aantal voorgestelde populaire zoektermen dat is geconfigureerd in het specifieke gedeelte." +"The number of suggested popular search terms to use for fetching results.","Het aantal voorgestelde populaire zoektermen dat wordt gebruikt om resultaten op te halen." +"The number of suggested search terms that will be used for fetching results in the autocompletion box.","Het aantal voorgestelde zoektermen dat zal worden gebruikt om resultaten in het autocompletie-venster op te halen." +"Stop the extension mechanism when the current search term of the user is suggested.","Stop het uitbreidingsmechanisme wanneer de huidige zoekterm van de gebruiker wordt voorgesteld." +"Default: No. When set to ""Yes"", this setting will discard the extension mechanism as soon as the exact search term entered by the user is part of the suggestions. Eg : When the user has finished to type ""computer"", if the list of suggested search terms is ""computer"", ""apple computer"", ""computer for kids"", only ""computer"" will be considered as it's exactly what the user has written.","Standaard: Nee. Als ingesteld op ""Ja"", zal deze instelling het uitbreidingsmechanisme negeren zodra de exacte zoekterm die door de gebruiker is ingevoerd, deel uitmaakt van de suggesties. Bijv.: Wanneer de gebruiker klaar is met typen van ""computer"", en de lijst met voorgestelde zoektermen is ""computer"", ""apple computer"", ""computer voor kinderen"", wordt alleen ""computer"" overwogen omdat dat precies is wat de gebruiker heeft geschreven." +"Always use the user raw input for suggestions.","Altijd de ruwe invoer van de gebruiker gebruiken voor suggesties." +"Default: No. When set to ""Yes"", this setting will always proceed to fetch suggestions on the query typed by the user in addition to the extended terms. Eg : When the user is typing ""comp"", the popular search term ""computer"" will be suggested, but products or categories matching either ""comp"" or ""computer"" will be shown.","Standaard: Nee. Wanneer deze instelling op ""Ja"" is ingesteld, worden altijd suggesties opgehaald op basis van de ingevoerde zoekopdracht van de gebruiker naast de uitgebreide termen. Bijvoorbeeld: Wanneer de gebruiker ""comp"" typt, wordt de populaire zoekterm ""computer"" voorgesteld, maar producten of categorieën die overeenkomen met ""comp"" of ""computer"" worden weergegeven."