Skip to content

Commit 24bcb39

Browse files
committed
Refactor building the filter
1 parent 3994534 commit 24bcb39

File tree

11 files changed

+188
-47
lines changed

11 files changed

+188
-47
lines changed

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@
9191
},
9292
"autoload-dev": {
9393
"psr-4": {
94-
"Setono\\SyliusMeilisearchPlugin\\Tests\\": "tests/"
94+
"Setono\\SyliusMeilisearchPlugin\\Tests\\": "tests/",
95+
"TestApp\\": "tests/Application/src/"
9596
},
9697
"classmap": [
9798
"tests/Application/Kernel.php"

src/Engine/SearchEngine.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ public function execute(?string $query, array $parameters = []): SearchResult
2929
{
3030
$page = max(1, (int) ($parameters['p'] ?? 1));
3131
$sort = (string) ($parameters['sort'] ?? '');
32+
$facetsFilter = $parameters['facets'] ?? [];
3233

3334
$metadata = $this->metadataFactory->getMetadataFor($this->index->document);
3435
$indexUid = $this->indexNameResolver->resolve($this->index);
3536
$query = $query ?? '';
3637
$facets = array_map(static fn (Facet $facet) => $facet->name, $metadata->getFacets());
37-
$filter = $this->filterBuilder->build($parameters);
38+
$filter = $this->filterBuilder->build($facetsFilter);
3839

3940
$mainQuery = $this->buildSearchQuery($indexUid, $query, $facets, $filter)
4041
->setHitsPerPage($this->hitsPerPage)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\Meilisearch\Builder;
6+
7+
final class CompositeFilterBuilder implements FilterBuilderInterface
8+
{
9+
/**
10+
* @param iterable<FilterBuilderInterface> $filterBuilders
11+
*/
12+
public function __construct(
13+
private readonly iterable $filterBuilders,
14+
) {
15+
}
16+
17+
public function build(array $facets): string|array
18+
{
19+
$filters = [];
20+
21+
foreach ($this->filterBuilders as $filterBuilder) {
22+
if ($filterBuilder->supports($facets)) {
23+
$filters[] = $filterBuilder->build($facets);
24+
}
25+
}
26+
27+
return $filters;
28+
}
29+
30+
public function supports(array $facets): bool
31+
{
32+
return true;
33+
}
34+
}

src/Meilisearch/Builder/FilterBuilder.php

-42
This file was deleted.

src/Meilisearch/Builder/FilterBuilderInterface.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@
66

77
interface FilterBuilderInterface
88
{
9-
public function build(array $parameters): array;
9+
public function build(array $facets): string|array;
10+
11+
public function supports(array $facets): bool;
1012
}

src/Resources/config/services/meilisearch.xml

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
<services>
55
<!-- Builder -->
66
<service id="Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\FilterBuilderInterface"
7-
alias="Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\FilterBuilder"/>
7+
alias="Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\CompositeFilterBuilder"/>
88

9-
<service id="Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\FilterBuilder"/>
9+
<service id="Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\CompositeFilterBuilder">
10+
<argument type="tagged_iterator" tag="setono_sylius_meilisearch.filter_builder"/>
11+
</service>
1012

1113
<!-- Synonym resolver -->
1214
<service id="Setono\SyliusMeilisearchPlugin\Meilisearch\SynonymResolverInterface"

tests/Application/config/services.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,16 @@
22
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
33
parameters:
44
locale: en_US
5+
6+
services:
7+
_defaults:
8+
autowire: true # Automatically injects dependencies in your services.
9+
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
10+
11+
TestApp\:
12+
resource: '../src/*'
13+
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
14+
15+
_instanceof:
16+
Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\FilterBuilderInterface:
17+
tags: [ 'setono_sylius_meilisearch.filter_builder' ]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TestApp\FilterBuilder;
6+
7+
use Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\FilterBuilderInterface;
8+
9+
final class BrandFilterBuilder implements FilterBuilderInterface
10+
{
11+
public function build(array $facets): string|array
12+
{
13+
$brandQuery = [];
14+
/** @var string $size */
15+
foreach ($facets['brand'] as $size) {
16+
$brandQuery[] = sprintf('brand = "%s"', $size);
17+
}
18+
19+
return '(' . implode(' OR ', $brandQuery) . ')';
20+
}
21+
22+
public function supports(array $facets): bool
23+
{
24+
return isset($facets['brand']);
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\Tests\Application\src\FilterBuilder;
6+
7+
use Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\FilterBuilderInterface;
8+
9+
final class OnSaleFilterBuilder implements FilterBuilderInterface
10+
{
11+
public function build(array $facets): string|array
12+
{
13+
return 'onSale = true';
14+
}
15+
16+
public function supports(array $facets): bool
17+
{
18+
return isset($facets['onSale']);
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TestApp\FilterBuilder;
6+
7+
use Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\FilterBuilderInterface;
8+
9+
final class SizeFilterBuilder implements FilterBuilderInterface
10+
{
11+
public function build(array $facets): string|array
12+
{
13+
$sizeQuery = [];
14+
/** @var string $size */
15+
foreach ($facets['size'] as $size) {
16+
$sizeQuery[] = sprintf('size = "%s"', $size);
17+
}
18+
19+
return '(' . implode(' OR ', $sizeQuery) . ')';
20+
}
21+
22+
public function supports(array $facets): bool
23+
{
24+
return isset($facets['size']);
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\Tests\Unit\Meilisearch\Builder;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\CompositeFilterBuilder;
9+
use Setono\SyliusMeilisearchPlugin\Meilisearch\Builder\FilterBuilderInterface;
10+
11+
final class CompositeFilterBuilderTest extends TestCase
12+
{
13+
public function test_it_returns_filters(): void
14+
{
15+
$brandFilterBuilder = $this->createMock(FilterBuilderInterface::class);
16+
$brandFilterBuilder->method('build')->willReturn('(brand = "brand1")');
17+
$brandFilterBuilder->method('supports')->willReturn(true);
18+
19+
$sizeFilterBuilder = $this->createMock(FilterBuilderInterface::class);
20+
$sizeFilterBuilder->method('build')->willReturn('(size = "size1" OR size = "size2")');
21+
$sizeFilterBuilder->method('supports')->willReturn(true);
22+
23+
$compositeFilterBuilder = new CompositeFilterBuilder([$brandFilterBuilder, $sizeFilterBuilder]);
24+
25+
$filters = $compositeFilterBuilder->build([
26+
'onSale' => true,
27+
'brand' => ['brand1'],
28+
'size' => ['size1', 'size2'],
29+
]);
30+
31+
$this->assertSame([
32+
'(brand = "brand1")',
33+
'(size = "size1" OR size = "size2")',
34+
], $filters);
35+
}
36+
37+
public function test_it_uses_only_supported_filter_builders(): void
38+
{
39+
$brandFilterBuilder = $this->createMock(FilterBuilderInterface::class);
40+
$brandFilterBuilder->expects($this->never())->method('build');
41+
$brandFilterBuilder->method('supports')->willReturn(false);
42+
43+
$sizeFilterBuilder = $this->createMock(FilterBuilderInterface::class);
44+
$sizeFilterBuilder->method('build')->willReturn('(size = "size1" OR size = "size2")');
45+
$sizeFilterBuilder->method('supports')->willReturn(true);
46+
47+
$compositeFilterBuilder = new CompositeFilterBuilder([$brandFilterBuilder, $sizeFilterBuilder]);
48+
49+
$filters = $compositeFilterBuilder->build([
50+
'onSale' => true,
51+
'size' => ['size1', 'size2'],
52+
]);
53+
54+
$this->assertSame([
55+
'(size = "size1" OR size = "size2")',
56+
], $filters);
57+
}
58+
}

0 commit comments

Comments
 (0)