Skip to content

Commit 73501b9

Browse files
committed
Encapsulate the facet distribution and facet stats in our own objects
1 parent adc4885 commit 73501b9

12 files changed

+350
-108
lines changed

src/Engine/FacetDistribution.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\Engine;
6+
7+
use Webmozart\Assert\Assert;
8+
9+
/**
10+
* @implements \IteratorAggregate<string, FacetValues>
11+
* @implements \ArrayAccess<string, FacetValues>
12+
*/
13+
final class FacetDistribution implements \Countable, \IteratorAggregate, \ArrayAccess
14+
{
15+
/** @var array<string, FacetValues> */
16+
private array $facetValues = [];
17+
18+
/**
19+
* @param array<string, mixed> $facetDistribution
20+
*/
21+
public function __construct(array $facetDistribution)
22+
{
23+
foreach ($facetDistribution as $facet => $facetValues) {
24+
Assert::isArray($facetValues);
25+
26+
$this->facetValues[$facet] = new FacetValues($facet, $facetValues);
27+
}
28+
}
29+
30+
/**
31+
* @psalm-assert-if-true FacetValues $this->facetValues[$facet]
32+
*/
33+
public function has(string $facet): bool
34+
{
35+
return isset($this->facetValues[$facet]);
36+
}
37+
38+
public function get(string $facet): FacetValues
39+
{
40+
if (!$this->has($facet)) {
41+
throw new \InvalidArgumentException(sprintf('Facet "%s" does not exist', $facet));
42+
}
43+
44+
return $this->facetValues[$facet];
45+
}
46+
47+
/**
48+
* @return \ArrayIterator<string, FacetValues>
49+
*/
50+
public function getIterator(): \ArrayIterator
51+
{
52+
return new \ArrayIterator($this->facetValues);
53+
}
54+
55+
public function count(): int
56+
{
57+
return count($this->facetValues);
58+
}
59+
60+
public function isEmpty(): bool
61+
{
62+
return [] === $this->facetValues;
63+
}
64+
65+
public function offsetExists(mixed $offset): bool
66+
{
67+
return $this->has($offset);
68+
}
69+
70+
public function offsetGet(mixed $offset): FacetValues
71+
{
72+
return $this->get($offset);
73+
}
74+
75+
public function offsetSet(mixed $offset, mixed $value): void
76+
{
77+
throw new \LogicException('You cannot set an offset');
78+
}
79+
80+
public function offsetUnset(mixed $offset): void
81+
{
82+
throw new \LogicException('You cannot unset an offset');
83+
}
84+
}

src/Engine/FacetStat.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\Engine;
6+
7+
final class FacetStat
8+
{
9+
public readonly float|int $min;
10+
11+
public readonly float|int $max;
12+
13+
public function __construct(
14+
public readonly string $name,
15+
array $values,
16+
) {
17+
if (!isset($values['min'], $values['max'])) {
18+
throw new \InvalidArgumentException('The $values must contain a min and a max key');
19+
}
20+
21+
if (!is_numeric($values['min']) || !is_numeric($values['max'])) {
22+
throw new \InvalidArgumentException('The $values must contain numeric values');
23+
}
24+
25+
$this->min = $values['min'] + 0;
26+
$this->max = $values['max'] + 0;
27+
}
28+
}

src/Engine/FacetStats.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\Engine;
6+
7+
use Webmozart\Assert\Assert;
8+
9+
/**
10+
* @implements \IteratorAggregate<string, FacetStat>
11+
* @implements \ArrayAccess<string, FacetStat>
12+
*/
13+
final class FacetStats implements \Countable, \IteratorAggregate, \ArrayAccess
14+
{
15+
/** @var array<string, FacetStat> */
16+
private array $facetStats = [];
17+
18+
/**
19+
* @param array<string, mixed> $facetStats
20+
*/
21+
public function __construct(array $facetStats)
22+
{
23+
foreach ($facetStats as $facet => $facetStat) {
24+
Assert::isArray($facetStat);
25+
26+
$this->facetStats[$facet] = new FacetStat($facet, $facetStat);
27+
}
28+
}
29+
30+
/**
31+
* @psalm-assert-if-true FacetStat $this->facetStats[$facet]
32+
*/
33+
public function has(string $facet): bool
34+
{
35+
return isset($this->facetStats[$facet]);
36+
}
37+
38+
public function get(string $facet): FacetStat
39+
{
40+
if (!$this->has($facet)) {
41+
throw new \InvalidArgumentException(sprintf('Facet "%s" does not exist', $facet));
42+
}
43+
44+
return $this->facetStats[$facet];
45+
}
46+
47+
/**
48+
* @return \ArrayIterator<string, FacetStat>
49+
*/
50+
public function getIterator(): \ArrayIterator
51+
{
52+
return new \ArrayIterator($this->facetStats);
53+
}
54+
55+
public function count(): int
56+
{
57+
return count($this->facetStats);
58+
}
59+
60+
public function isEmpty(): bool
61+
{
62+
return [] === $this->facetStats;
63+
}
64+
65+
public function offsetExists(mixed $offset): bool
66+
{
67+
return $this->has($offset);
68+
}
69+
70+
public function offsetGet(mixed $offset): FacetStat
71+
{
72+
return $this->get($offset);
73+
}
74+
75+
public function offsetSet(mixed $offset, mixed $value): void
76+
{
77+
throw new \LogicException('You cannot set an offset');
78+
}
79+
80+
public function offsetUnset(mixed $offset): void
81+
{
82+
throw new \LogicException('You cannot unset an offset');
83+
}
84+
}

src/Engine/FacetValues.php

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusMeilisearchPlugin\Engine;
6+
7+
use Webmozart\Assert\Assert;
8+
9+
/**
10+
* @implements \ArrayAccess<string, int>
11+
* @implements \IteratorAggregate<string, int>
12+
*/
13+
final class FacetValues implements \Countable, \IteratorAggregate, \ArrayAccess
14+
{
15+
/**
16+
* This holds the facet values for the respective facet and search results. Examples for $values include:
17+
*
18+
* [
19+
* "Celsius Small" => 3
20+
* "Date & Banana" => 2
21+
* "Modern Wear" => 6
22+
* "You are breathtaking" => 10
23+
* ]
24+
*
25+
* [
26+
* "false" => 16
27+
* "true" => 5
28+
* ]
29+
*
30+
* [
31+
* "1.74" => 1
32+
* "12.21" => 1
33+
* "16.52" => 1
34+
* "21.06" => 1
35+
* "22.49" => 1
36+
* "24.19" => 1
37+
* ]
38+
*
39+
* @var array<string, int>
40+
*/
41+
private array $values = [];
42+
43+
public function __construct(
44+
public readonly string $name,
45+
array $values,
46+
) {
47+
foreach ($values as $key => $value) {
48+
if (!is_string($key) || !is_int($value)) {
49+
throw new \InvalidArgumentException(sprintf(
50+
'The values of the facet must be an array of strings and integers. Input array was: %s',
51+
json_encode($values, \JSON_THROW_ON_ERROR),
52+
));
53+
}
54+
55+
$this->values[$key] = $value;
56+
}
57+
}
58+
59+
/**
60+
* @return list<string>
61+
*/
62+
public function getValues(): array
63+
{
64+
return array_keys($this->values);
65+
}
66+
67+
public function getValueCount(string $value): int
68+
{
69+
if (!$this->has($value)) {
70+
throw new \InvalidArgumentException(sprintf('Facet value "%s" does not exist', $value));
71+
}
72+
73+
return $this->values[$value];
74+
}
75+
76+
/**
77+
* @psalm-assert-if-true int $this->values[$value]
78+
*/
79+
public function has(string $value): bool
80+
{
81+
return isset($this->values[$value]);
82+
}
83+
84+
/**
85+
* @return \ArrayIterator<string, int>
86+
*/
87+
public function getIterator(): \ArrayIterator
88+
{
89+
return new \ArrayIterator($this->values);
90+
}
91+
92+
public function offsetExists(mixed $offset): bool
93+
{
94+
return $this->has($offset);
95+
}
96+
97+
public function offsetGet(mixed $offset): int
98+
{
99+
return $this->values[$offset];
100+
}
101+
102+
public function offsetSet(mixed $offset, mixed $value): void
103+
{
104+
throw new \LogicException('You cannot set an offset');
105+
}
106+
107+
public function offsetUnset(mixed $offset): void
108+
{
109+
throw new \LogicException('You cannot unset an offset');
110+
}
111+
112+
public function count(): int
113+
{
114+
return count($this->values);
115+
}
116+
117+
public function isEmpty(): bool
118+
{
119+
return [] === $this->values;
120+
}
121+
}

src/Engine/SearchResult.php

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,8 @@ public function __construct(
2020
public readonly int $page,
2121
public readonly int $pageSize,
2222
public readonly int $totalPages,
23-
24-
/** @var array<string, mixed> $facetStats */
25-
public readonly array $facetStats,
26-
27-
/** @var array<string, mixed> $facetDistribution */
28-
public readonly array $facetDistribution,
23+
public readonly FacetStats $facetStats,
24+
public readonly FacetDistribution $facetDistribution,
2925
) {
3026
}
3127

@@ -54,8 +50,8 @@ public static function fromMeilisearchSearchResult(Index $index, MeilisearchSear
5450
$page,
5551
$pageSize,
5652
$totalPages,
57-
$meilisearchSearchResult->getFacetStats(),
58-
$meilisearchSearchResult->getFacetDistribution(),
53+
new FacetStats($meilisearchSearchResult->getFacetStats()),
54+
new FacetDistribution($meilisearchSearchResult->getFacetDistribution()),
5955
);
6056
}
6157
}

src/Form/Builder/CheckboxFilterFormBuilder.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
namespace Setono\SyliusMeilisearchPlugin\Form\Builder;
66

77
use Setono\SyliusMeilisearchPlugin\Document\Metadata\Facet;
8+
use Setono\SyliusMeilisearchPlugin\Engine\FacetStat;
9+
use Setono\SyliusMeilisearchPlugin\Engine\FacetValues;
810
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
911
use Symfony\Component\Form\FormBuilderInterface;
1012
use function Symfony\Component\String\u;
1113

1214
final class CheckboxFilterFormBuilder implements FilterFormBuilderInterface
1315
{
14-
public function build(FormBuilderInterface $builder, Facet $facet, array $values, array $stats = null): void
16+
public function build(FormBuilderInterface $builder, Facet $facet, FacetValues $values, FacetStat $stats = null): void
1517
{
1618
$builder->add($facet->name, CheckboxType::class, [
1719
'label' => sprintf('setono_sylius_meilisearch.form.search.facet.%s', u($facet->name)->snake()),
@@ -24,7 +26,7 @@ public function build(FormBuilderInterface $builder, Facet $facet, array $values
2426
]);
2527
}
2628

27-
public function supports(Facet $facet, array $values, array $stats = null): bool
29+
public function supports(Facet $facet, FacetValues $values, FacetStat $stats = null): bool
2830
{
2931
return $facet->type === 'bool' && match (count($values)) {
3032
1 => isset($values['true']),

0 commit comments

Comments
 (0)