diff --git a/src/Config/Index.php b/src/Config/Index.php index 23bcc50..bb82981 100644 --- a/src/Config/Index.php +++ b/src/Config/Index.php @@ -7,8 +7,11 @@ use Psr\Container\ContainerInterface; use Setono\SyliusMeilisearchPlugin\DataProvider\IndexableDataProviderInterface; use Setono\SyliusMeilisearchPlugin\Document\Document; +use Setono\SyliusMeilisearchPlugin\Document\Metadata\MetadataFactoryInterface; +use Setono\SyliusMeilisearchPlugin\Document\Metadata\MetadataInterface; use Setono\SyliusMeilisearchPlugin\Indexer\IndexerInterface; use Setono\SyliusMeilisearchPlugin\Model\IndexableInterface; +use Setono\SyliusMeilisearchPlugin\Resolver\IndexName\IndexNameResolverInterface; final class Index implements \Stringable { @@ -90,6 +93,26 @@ public function dataProvider(): IndexableDataProviderInterface return $this->locator->get(IndexableDataProviderInterface::class); } + /** + * Will return the index uid in Meilisearch based on the current context. + * This means you should not call this when you're not in a request/response context + */ + public function uid(): string + { + /** @var IndexNameResolverInterface $indexNameResolver */ + $indexNameResolver = $this->locator->get(IndexNameResolverInterface::class); + + return $indexNameResolver->resolve($this); + } + + public function metadata(): MetadataInterface + { + /** @var MetadataFactoryInterface $metadataFactory */ + $metadataFactory = $this->locator->get(MetadataFactoryInterface::class); + + return $metadataFactory->getMetadataFor($this->document); + } + public function __toString(): string { return $this->name; diff --git a/src/DependencyInjection/SetonoSyliusMeilisearchExtension.php b/src/DependencyInjection/SetonoSyliusMeilisearchExtension.php index a16be4b..8bfe2eb 100644 --- a/src/DependencyInjection/SetonoSyliusMeilisearchExtension.php +++ b/src/DependencyInjection/SetonoSyliusMeilisearchExtension.php @@ -20,6 +20,7 @@ use Setono\SyliusMeilisearchPlugin\Indexer\DefaultIndexer; use Setono\SyliusMeilisearchPlugin\Indexer\IndexerInterface; use Setono\SyliusMeilisearchPlugin\Provider\IndexScope\IndexScopeProviderInterface; +use Setono\SyliusMeilisearchPlugin\Resolver\IndexName\IndexNameResolverInterface; use Setono\SyliusMeilisearchPlugin\Twig\AutocompleteRuntime; use Setono\SyliusMeilisearchPlugin\UrlGenerator\EntityUrlGeneratorInterface; use Sylius\Bundle\ResourceBundle\DependencyInjection\Extension\AbstractResourceExtension; @@ -279,6 +280,8 @@ private static function registerIndexesConfiguration(array $config, ContainerBui ServiceLocatorTagPass::register($container, [ IndexableDataProviderInterface::class => new Reference($index['data_provider']), IndexerInterface::class => new Reference($indexerServiceId), + IndexNameResolverInterface::class => new Reference('setono_sylius_meilisearch.resolver.index_name'), + MetadataFactoryInterface::class => new Reference(MetadataFactoryInterface::class), ]), $index['prefix'], ])); diff --git a/src/Engine/SearchEngine.php b/src/Engine/SearchEngine.php index 808474d..8065ea7 100644 --- a/src/Engine/SearchEngine.php +++ b/src/Engine/SearchEngine.php @@ -5,52 +5,22 @@ namespace Setono\SyliusMeilisearchPlugin\Engine; use Meilisearch\Client; -use Meilisearch\Contracts\SearchQuery; use Meilisearch\Search\SearchResult; use Setono\SyliusMeilisearchPlugin\Config\Index; -use Setono\SyliusMeilisearchPlugin\Document\Metadata\MetadataFactoryInterface; -use Setono\SyliusMeilisearchPlugin\Meilisearch\Filter\FilterBuilderInterface; -use Setono\SyliusMeilisearchPlugin\Meilisearch\Query\MainQueryBuilderInterface; -use Setono\SyliusMeilisearchPlugin\Meilisearch\Query\SubQueriesBuilderInterface; -use Setono\SyliusMeilisearchPlugin\Resolver\IndexName\IndexNameResolverInterface; +use Setono\SyliusMeilisearchPlugin\Meilisearch\Query\MultiSearchBuilderInterface; final class SearchEngine implements SearchEngineInterface { public function __construct( - private readonly MetadataFactoryInterface $metadataFactory, - private readonly FilterBuilderInterface $filterBuilder, private readonly Index $index, - private readonly IndexNameResolverInterface $indexNameResolver, private readonly Client $client, - private readonly MainQueryBuilderInterface $mainQueryBuilder, - private readonly SubQueriesBuilderInterface $subQueriesBuilder, + private readonly MultiSearchBuilderInterface $multiSearchBuilder, ) { } public function execute(SearchRequest $searchRequest): SearchResult { - $indexName = $this->indexNameResolver->resolve($this->index); - $metadata = $this->metadataFactory->getMetadataFor($this->index->document); - $facetsNames = $metadata->getFacetableAttributeNames(); - $facets = $metadata->getFacetableAttributes(); - - /** @var array $filters */ - $filters = $this->filterBuilder->build($facets, $searchRequest->filters); - - $mainQuery = $this->mainQueryBuilder->build( - $indexName, - $searchRequest->query ?? '', - $facetsNames, - $filters, - $searchRequest->page, - $searchRequest->sort ?? '', - ); - - /** @var list $queries */ - $queries = array_merge( - [$mainQuery], - $this->subQueriesBuilder->build($indexName, $searchRequest->query ?? '', $facets, $searchRequest->filters), - ); + $queries = $this->multiSearchBuilder->build($this->index, $searchRequest); /** @var array $results */ $results = $this->client->multiSearch($queries)['results'] ?? []; @@ -62,6 +32,7 @@ private function provideSearchResult(array $results): SearchResult { /** @var array{facetDistribution: array} $firstResult */ $firstResult = current($results); + /** @psalm-suppress MixedArgument (just for now) */ $firstResult['facetDistribution'] = array_merge(...array_column($results, 'facetDistribution')); diff --git a/src/Engine/SearchRequest.php b/src/Engine/SearchRequest.php index 736b3e4..13682fb 100644 --- a/src/Engine/SearchRequest.php +++ b/src/Engine/SearchRequest.php @@ -8,6 +8,7 @@ final class SearchRequest { + // todo we need the hits per page here public function __construct( public readonly ?string $query, /** @var array $filters */ diff --git a/src/Meilisearch/Filter/FilterBuilderInterface.php b/src/Meilisearch/Filter/FilterBuilderInterface.php index 9a3c30d..788bb47 100644 --- a/src/Meilisearch/Filter/FilterBuilderInterface.php +++ b/src/Meilisearch/Filter/FilterBuilderInterface.php @@ -12,7 +12,7 @@ interface FilterBuilderInterface * @param array $facets * @param array $facetsValues * - * @return array + * @return list */ public function build(array $facets, array $facetsValues): array; } diff --git a/src/Meilisearch/Query/MainQueryBuilder.php b/src/Meilisearch/Query/MainQueryBuilder.php deleted file mode 100644 index 2a79068..0000000 --- a/src/Meilisearch/Query/MainQueryBuilder.php +++ /dev/null @@ -1,41 +0,0 @@ - $facetsNames - * @param array $filters - */ - public function build( - string $indexName, - string $query, - array $facetsNames, - array $filters, - int $pageNumber, - string $sort, - ): SearchQuery { - $mainQuery = $this->searchQueryBuilder - ->build($indexName, $query, $facetsNames, $filters) - ->setHitsPerPage($this->hitsPerPage) - ->setPage($pageNumber) - ; - - if ('' !== $sort) { - $mainQuery->setSort([$sort]); - } - - return $mainQuery; - } -} diff --git a/src/Meilisearch/Query/MainQueryBuilderInterface.php b/src/Meilisearch/Query/MainQueryBuilderInterface.php deleted file mode 100644 index 78172d0..0000000 --- a/src/Meilisearch/Query/MainQueryBuilderInterface.php +++ /dev/null @@ -1,23 +0,0 @@ - $facetsNames - * @param array $filters - */ - public function build( - string $indexName, - string $query, - array $facetsNames, - array $filters, - int $pageNumber, - string $sort, - ): SearchQuery; -} diff --git a/src/Meilisearch/Query/MultiSearchBuilder.php b/src/Meilisearch/Query/MultiSearchBuilder.php new file mode 100644 index 0000000..0fb5b8f --- /dev/null +++ b/src/Meilisearch/Query/MultiSearchBuilder.php @@ -0,0 +1,81 @@ +metadata(); + $facetsNames = $metadata->getFacetableAttributeNames(); + $facets = $metadata->getFacetableAttributes(); + + $filters = $this->filterBuilder->build($facets, $searchRequest->filters); + + return array_merge( + [$this->buildSearchQuery($index, $searchRequest, $facetsNames, $filters)], + $this->buildFacetQueries($index, $searchRequest, $facets, $searchRequest->filters), + ); + } + + /** + * @param list $facetNames + * @param list $filters + */ + private function buildSearchQuery(Index $index, SearchRequest $searchRequest, array $facetNames, array $filters): SearchQuery + { + $query = $this->searchQueryBuilder + ->build($index->uid(), $searchRequest->query, $facetNames, $filters) + ->setHitsPerPage($this->hitsPerPage) + ->setPage($searchRequest->page) + ; + + if (null !== $searchRequest->sort) { + $query->setSort([$searchRequest->sort]); + } + + return $query; + } + + /** + * @param array $facets + * @param array $filters + * + * @return list + */ + private function buildFacetQueries(Index $index, SearchRequest $searchRequest, array $facets, array $filters): array + { + $searchQueries = []; + + foreach ($facets as $facet) { + /** @var array $filteredFacets */ + $filteredFacets = array_filter($filters, static fn ($value) => $value !== $facet->name, \ARRAY_FILTER_USE_KEY); + + $searchQueries[] = $this->searchQueryBuilder->build( + indexName: $index->uid(), + query: $searchRequest->query, + facets: [$facet->name], + filter: $this->filterBuilder->build($facets, $filteredFacets), + ) + ->setLimit(1) + ; + } + + return $searchQueries; + } +} diff --git a/src/Meilisearch/Query/MultiSearchBuilderInterface.php b/src/Meilisearch/Query/MultiSearchBuilderInterface.php new file mode 100644 index 0000000..726f049 --- /dev/null +++ b/src/Meilisearch/Query/MultiSearchBuilderInterface.php @@ -0,0 +1,21 @@ + + */ + public function build(Index $index, SearchRequest $searchRequest): array; +} diff --git a/src/Meilisearch/Query/SearchQueryBuilder.php b/src/Meilisearch/Query/SearchQueryBuilder.php index fbb366d..88e418f 100644 --- a/src/Meilisearch/Query/SearchQueryBuilder.php +++ b/src/Meilisearch/Query/SearchQueryBuilder.php @@ -8,13 +8,19 @@ final class SearchQueryBuilder implements SearchQueryBuilderInterface { - public function build(string $indexName, string $query, array $facets, array $filter): SearchQuery + public function build(string $indexName, ?string $query, array $facets, array $filter): SearchQuery { - return (new SearchQuery()) + $searchQuery = new SearchQuery(); + $searchQuery ->setIndexUid($indexName) - ->setQuery($query) ->setFacets($facets) ->setFilter($filter) ; + + if (null !== $query) { + $searchQuery->setQuery($query); + } + + return $searchQuery; } } diff --git a/src/Meilisearch/Query/SearchQueryBuilderInterface.php b/src/Meilisearch/Query/SearchQueryBuilderInterface.php index 842d314..530eb11 100644 --- a/src/Meilisearch/Query/SearchQueryBuilderInterface.php +++ b/src/Meilisearch/Query/SearchQueryBuilderInterface.php @@ -10,7 +10,7 @@ interface SearchQueryBuilderInterface { /** * @param array $facets - * @param array $filter + * @param list $filter */ - public function build(string $indexName, string $query, array $facets, array $filter): SearchQuery; + public function build(string $indexName, ?string $query, array $facets, array $filter): SearchQuery; } diff --git a/src/Meilisearch/Query/SubQueriesBuilder.php b/src/Meilisearch/Query/SubQueriesBuilder.php deleted file mode 100644 index 14e9c57..0000000 --- a/src/Meilisearch/Query/SubQueriesBuilder.php +++ /dev/null @@ -1,33 +0,0 @@ -name]; - /** @var array $filteredFacets */ - $filteredFacets = array_filter($filters, static fn ($value) => $value !== $facet->name, \ARRAY_FILTER_USE_KEY); - /** @var array $filter */ - $filter = $this->filterBuilder->build($facets, $filteredFacets); - - $searchQueries[] = $this->searchQueryBuilder->build($indexName, $query, $facetsNames, $filter)->setLimit(1); - } - - return $searchQueries; - } -} diff --git a/src/Meilisearch/Query/SubQueriesBuilderInterface.php b/src/Meilisearch/Query/SubQueriesBuilderInterface.php deleted file mode 100644 index 26212fd..0000000 --- a/src/Meilisearch/Query/SubQueriesBuilderInterface.php +++ /dev/null @@ -1,23 +0,0 @@ - $facets - * - * @return array - */ - public function build( - string $indexName, - string $query, - array $facets, - array $filters, - ): array; -} diff --git a/src/Resources/config/services/conditional/search.xml b/src/Resources/config/services/conditional/search.xml index e018f08..6b07cd4 100644 --- a/src/Resources/config/services/conditional/search.xml +++ b/src/Resources/config/services/conditional/search.xml @@ -11,19 +11,16 @@ - + - - - - - + - + diff --git a/src/Resources/config/services/meilisearch.xml b/src/Resources/config/services/meilisearch.xml index 6d0ab0f..f75b636 100644 --- a/src/Resources/config/services/meilisearch.xml +++ b/src/Resources/config/services/meilisearch.xml @@ -8,27 +8,20 @@ alias="Setono\SyliusMeilisearchPlugin\Meilisearch\Filter\CompositeFilterBuilder" /> - + - - %setono_sylius_meilisearch.search.hits_per_page% - - + - - - + + + + %setono_sylius_meilisearch.search.hits_per_page%