Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Controller/Action/SearchAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function __invoke(Request $request): Response

$items = [];
/** @var array{entityClass: class-string<IndexableInterface>, entityId: mixed} $hit */
foreach ($searchResult->getHits() as $hit) {
foreach ($searchResult->hits as $hit) {
$item = $this->getManager($hit['entityClass'])->find($hit['entityClass'], $hit['entityId']);
if (null === $item) {
continue;
Expand Down
12 changes: 7 additions & 5 deletions src/Engine/SearchEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Setono\SyliusMeilisearchPlugin\Engine;

use Meilisearch\Client;
use Meilisearch\Search\SearchResult;
use Meilisearch\Search\SearchResult as MeilisearchSearchResult;
use Setono\SyliusMeilisearchPlugin\Config\Index;
use Setono\SyliusMeilisearchPlugin\Meilisearch\Query\MultiSearchBuilderInterface;

Expand All @@ -18,24 +18,26 @@
) {
}

public function execute(SearchRequest $searchRequest): SearchResult

Check failure on line 21 in src/Engine/SearchEngine.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The return type of Setono\SyliusMeilisearchPlugin\Engine\SearchEngine#execute() changed from Meilisearch\Search\SearchResult to the non-covariant Setono\SyliusMeilisearchPlugin\Engine\SearchResult
{
$queries = $this->multiSearchBuilder->build($this->index, $searchRequest);

/** @var array<SearchResult> $results */
/** @var array<MeilisearchSearchResult> $results */
$results = $this->client->multiSearch($queries)['results'] ?? [];

return $this->provideSearchResult($results);
$result = $this->provideSearchResult($results);

return SearchResult::fromMeilisearchSearchResult($this->index, $result);
}

private function provideSearchResult(array $results): SearchResult
private function provideSearchResult(array $results): MeilisearchSearchResult
{
/** @var array{facetDistribution: array<string, int>} $firstResult */
$firstResult = current($results);

/** @psalm-suppress MixedArgument (just for now) */
$firstResult['facetDistribution'] = array_merge(...array_column($results, 'facetDistribution'));

return new SearchResult($firstResult);
return new MeilisearchSearchResult($firstResult);
}
}
2 changes: 0 additions & 2 deletions src/Engine/SearchEngineInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

namespace Setono\SyliusMeilisearchPlugin\Engine;

use Meilisearch\Search\SearchResult;

interface SearchEngineInterface
{
public function execute(SearchRequest $searchRequest): SearchResult;

Check failure on line 9 in src/Engine/SearchEngineInterface.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The return type of Setono\SyliusMeilisearchPlugin\Engine\SearchEngineInterface#execute() changed from Meilisearch\Search\SearchResult to the non-covariant Setono\SyliusMeilisearchPlugin\Engine\SearchResult

Check failure on line 9 in src/Engine/SearchEngineInterface.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The return type of Setono\SyliusMeilisearchPlugin\Engine\SearchEngineInterface#execute() changed from Meilisearch\Search\SearchResult to Setono\SyliusMeilisearchPlugin\Engine\SearchResult
}
61 changes: 61 additions & 0 deletions src/Engine/SearchResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusMeilisearchPlugin\Engine;

use Meilisearch\Search\SearchResult as MeilisearchSearchResult;
use Setono\SyliusMeilisearchPlugin\Config\Index;
use Webmozart\Assert\Assert;

final class SearchResult
{
public function __construct(
/** The index that was queried */
public readonly Index $index,

/** @var array<int, array> $hits */
public readonly array $hits,
public readonly int $totalHits,
public readonly int $page,
public readonly int $pageSize,
public readonly int $totalPages,

/** @var array<string, mixed> $facetStats */
public readonly array $facetStats,

/** @var array<string, mixed> $facetDistribution */
public readonly array $facetDistribution,
) {
}

/**
* @throws \InvalidArgumentException
*/
public static function fromMeilisearchSearchResult(Index $index, MeilisearchSearchResult $meilisearchSearchResult): self
{
// TODO support estimated total number of search results. See https://www.meilisearch.com/docs/reference/api/search#exhaustive-and-estimated-total-number-of-search-results
$page = $meilisearchSearchResult->getPage();
Assert::notNull($page);

$totalPages = $meilisearchSearchResult->getTotalPages();
Assert::notNull($totalPages);

$totalHits = $meilisearchSearchResult->getTotalHits();
Assert::notNull($totalHits);

$pageSize = $meilisearchSearchResult->getHitsPerPage();
Assert::notNull($pageSize);

return new self(
$index,
$meilisearchSearchResult->getHits(),
$totalHits,
$page,
$pageSize,
$totalPages,
$meilisearchSearchResult->getFacetStats(),
$meilisearchSearchResult->getFacetDistribution(),
);
}
}
2 changes: 1 addition & 1 deletion src/Event/Search/SearchResultReceived.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

namespace Setono\SyliusMeilisearchPlugin\Event\Search;

use Meilisearch\Search\SearchResult;
use Setono\SyliusMeilisearchPlugin\Engine\SearchResult;

final class SearchResultReceived
{
public function __construct(public readonly SearchResult $searchResult)

Check failure on line 11 in src/Event/Search/SearchResultReceived.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

Type of property Setono\SyliusMeilisearchPlugin\Event\Search\SearchResultReceived#$searchResult changed from Meilisearch\Search\SearchResult to Setono\SyliusMeilisearchPlugin\Engine\SearchResult

Check failure on line 11 in src/Event/Search/SearchResultReceived.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $searchResult of Setono\SyliusMeilisearchPlugin\Event\Search\SearchResultReceived#__construct() changed from Meilisearch\Search\SearchResult to a non-contravariant Setono\SyliusMeilisearchPlugin\Engine\SearchResult
{
}
}
21 changes: 8 additions & 13 deletions src/Form/Builder/SearchFormBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

namespace Setono\SyliusMeilisearchPlugin\Form\Builder;

use Meilisearch\Search\SearchResult;
use Setono\SyliusMeilisearchPlugin\Config\Index;
use Setono\SyliusMeilisearchPlugin\Document\Metadata\MetadataFactoryInterface;
use Setono\SyliusMeilisearchPlugin\Engine\SearchRequest;
use Setono\SyliusMeilisearchPlugin\Engine\SearchResult;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
Expand All @@ -25,7 +25,7 @@
) {
}

public function build(SearchResult $searchResult): FormInterface

Check failure on line 28 in src/Form/Builder/SearchFormBuilder.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $searchResult of Setono\SyliusMeilisearchPlugin\Form\Builder\SearchFormBuilder#build() changed from Meilisearch\Search\SearchResult to a non-contravariant Setono\SyliusMeilisearchPlugin\Engine\SearchResult
{
$metadata = $this->metadataFactory->getMetadataFor($this->index->document);

Expand Down Expand Up @@ -55,7 +55,7 @@
*
* @var array<string, array{min: int|float, max: int|float}> $facetStats
*/
$facetStats = $searchResult->getFacetStats();
$facetStats = $searchResult->facetStats;

$facets = $metadata->getFacetableAttributes();

Expand Down Expand Up @@ -108,7 +108,7 @@
* @var string $name
* @var array<string, int> $values
*/
foreach ($searchResult->getFacetDistribution() as $name => $values) {
foreach ($searchResult->facetDistribution as $name => $values) {
if (!isset($facets[$name])) {
continue;
}
Expand All @@ -129,22 +129,17 @@

private function buildPagination(SearchResult $searchResult, FormBuilderInterface $builder): void
{
$page = $searchResult->getPage();
if (null === $page) {
return;
}

$choices = [];

// current is a special choice that we need to keep the page query parameter in the url on form submission
$choices['__current'] = $page;
$choices['__current'] = $searchResult->page;

if ($searchResult->getPage() > 1) {
$choices['setono_sylius_meilisearch.form.search.pagination.previous'] = $page - 1;
if ($searchResult->page > 1) {
$choices['setono_sylius_meilisearch.form.search.pagination.previous'] = $searchResult->page - 1;
}

if ($searchResult->getPage() < $searchResult->getTotalPages()) {
$choices['setono_sylius_meilisearch.form.search.pagination.next'] = $page + 1;
if ($searchResult->page < $searchResult->totalPages) {
$choices['setono_sylius_meilisearch.form.search.pagination.next'] = $searchResult->page + 1;
}

$builder->add('p', ChoiceType::class, [
Expand Down
2 changes: 1 addition & 1 deletion src/Form/Builder/SearchFormBuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

namespace Setono\SyliusMeilisearchPlugin\Form\Builder;

use Meilisearch\Search\SearchResult;
use Setono\SyliusMeilisearchPlugin\Engine\SearchResult;
use Symfony\Component\Form\FormInterface;

interface SearchFormBuilderInterface
{
public function build(SearchResult $searchResult): FormInterface;

Check failure on line 12 in src/Form/Builder/SearchFormBuilderInterface.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $searchResult of Setono\SyliusMeilisearchPlugin\Form\Builder\SearchFormBuilderInterface#build() changed from Meilisearch\Search\SearchResult to a non-contravariant Setono\SyliusMeilisearchPlugin\Engine\SearchResult

Check failure on line 12 in src/Form/Builder/SearchFormBuilderInterface.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $searchResult of Setono\SyliusMeilisearchPlugin\Form\Builder\SearchFormBuilderInterface#build() changed from Meilisearch\Search\SearchResult to Setono\SyliusMeilisearchPlugin\Engine\SearchResult
}
3 changes: 2 additions & 1 deletion src/Resources/views/search/_hits_count.html.twig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
{{ searchResult.hitsCount }} results
{# @var searchResult \Setono\SyliusMeilisearchPlugin\Engine\SearchResult #}
{{ searchResult.totalHits }} results
16 changes: 8 additions & 8 deletions tests/Functional/SearchPaginationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ public function testItPaginatesSearchResults(): void
$searchEngine = self::getContainer()->get(SearchEngine::class);
$firstPageResult = $searchEngine->execute(new SearchRequest('jeans'));

self::assertSame(8, $firstPageResult->getTotalHits());
self::assertSame(3, $firstPageResult->getHitsPerPage());
self::assertSame(1, $firstPageResult->getPage());
self::assertSame(3, $firstPageResult->getTotalPages());
self::assertSame(8, $firstPageResult->totalHits);
self::assertSame(3, $firstPageResult->pageSize);
self::assertSame(1, $firstPageResult->page);
self::assertSame(3, $firstPageResult->totalPages);

$secondPageResult = $searchEngine->execute(new SearchRequest('jeans', page: 2));
self::assertSame(2, $secondPageResult->getPage());
self::assertSame(2, $secondPageResult->page);

self::assertNotSame($firstPageResult->getHits(), $secondPageResult->getHits());
self::assertNotSame($firstPageResult->hits, $secondPageResult->hits);

$thirdPageResult = $searchEngine->execute(new SearchRequest('jeans', page: 3));
self::assertSame(3, $thirdPageResult->getPage());
self::assertCount(2, $thirdPageResult->getHits());
self::assertSame(3, $thirdPageResult->page);
self::assertCount(2, $thirdPageResult->hits);
}
}
14 changes: 7 additions & 7 deletions tests/Functional/SearchSortingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ public function testItSortsSearchResultsByLowestPrice(): void
$searchEngine = self::getContainer()->get(SearchEngine::class);
$result = $searchEngine->execute(new SearchRequest('jeans', sort: 'price:asc'));

self::assertSame(8, $result->getTotalHits());
self::assertSame(8, $result->totalHits);

$previousKey = null;
foreach ($result->getHits() as $key => $hit) {
foreach ($result->hits as $key => $hit) {
if ($previousKey === null) {
$previousKey = $key;

continue;
}

$previousHit = (array) $result->getHit($previousKey);
$previousHit = $result->hits[$previousKey];
self::assertGreaterThanOrEqual($previousHit['price'], $hit['price']);
$previousKey = $key;
}
Expand All @@ -37,17 +37,17 @@ public function testItSortsSearchResultsByNewestDate(): void
$searchEngine = self::getContainer()->get(SearchEngine::class);
$result = $searchEngine->execute(new SearchRequest('jeans', sort: 'createdAt:desc'));

self::assertSame(8, $result->getTotalHits());
self::assertSame(8, $result->totalHits);

$previousKey = null;
foreach ($result->getHits() as $key => $hit) {
foreach ($result->hits as $key => $hit) {
if ($previousKey === null) {
$previousKey = $key;

continue;
}

$previousHit = (array) $result->getHit($previousKey);
$previousHit = $result->hits[$previousKey];
self::assertLessThanOrEqual($previousHit['createdAt'], $hit['createdAt']);
$previousKey = $key;
}
Expand All @@ -61,7 +61,7 @@ public function testItSortsResultsByBiggestDiscount(): void

$previousDiscount = null;
/** @var array{discount: float} $hit */
foreach ($result->getHits() as $hit) {
foreach ($result->hits as $hit) {
if (null === $previousDiscount) {
$previousDiscount = $hit['discount'];
}
Expand Down
8 changes: 4 additions & 4 deletions tests/Functional/SearchTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function testItProvidesSearchResults(): void
$searchEngine = self::getContainer()->get(SearchEngine::class);
$result = $searchEngine->execute(new SearchRequest('jeans'));

self::assertSame(8, $result->getTotalHits());
self::assertSame(8, $result->totalHits);
}

public function testItProvidesSearchResultByMultipleCriteria(): void
Expand All @@ -34,7 +34,7 @@ public function testItProvidesSearchResultByMultipleCriteria(): void
]),
);

foreach ($result->getHits() as $hit) {
foreach ($result->hits as $hit) {
self::assertGreaterThanOrEqual($priceBounds[0], (int) $hit['price']);
self::assertLessThanOrEqual($priceBounds[1], (int) $hit['price']);
self::assertContains(((array) $hit['brand'])[0], ['Celsius small', 'You are breathtaking']);
Expand All @@ -51,8 +51,8 @@ public function testItAlwaysDisplaysFullFacetDistribution(): void
]),
);

$this->assertSame(1, $result->getHitsCount());
$this->assertCount(4, (array) $result->getFacetDistribution()['brand']);
$this->assertSame(1, $result->totalHits);
$this->assertCount(4, (array) $result->facetDistribution['brand']);
}

/**
Expand Down
Loading