Skip to content

Commit 13ac5ac

Browse files
committed
Move the extraction of metadata to the factory and make the meta a value object instead
1 parent 46c318c commit 13ac5ac

20 files changed

+235
-305
lines changed

src/Config/Index.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
use Psr\Container\ContainerInterface;
88
use Setono\SyliusMeilisearchPlugin\DataProvider\IndexableDataProviderInterface;
99
use Setono\SyliusMeilisearchPlugin\Document\Document;
10+
use Setono\SyliusMeilisearchPlugin\Document\Metadata\Metadata;
1011
use Setono\SyliusMeilisearchPlugin\Document\Metadata\MetadataFactoryInterface;
11-
use Setono\SyliusMeilisearchPlugin\Document\Metadata\MetadataInterface;
1212
use Setono\SyliusMeilisearchPlugin\Indexer\IndexerInterface;
1313
use Setono\SyliusMeilisearchPlugin\Model\IndexableInterface;
1414
use Setono\SyliusMeilisearchPlugin\Resolver\IndexUid\IndexUidResolverInterface;
@@ -97,7 +97,7 @@ public function uid(): string
9797
return $indexNameResolver->resolve($this);
9898
}
9999

100-
public function metadata(): MetadataInterface
100+
public function metadata(): Metadata
101101
{
102102
/** @var MetadataFactoryInterface $metadataFactory */
103103
$metadataFactory = $this->locator->get(MetadataFactoryInterface::class);

src/DataMapper/ImageDataMapper.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function map(
3333
);
3434

3535
$metadata = $this->metadataFactory->getMetadataFor($target);
36-
foreach ($metadata->getImageAttributes() as $imageAttribute) {
36+
foreach ($metadata->imageAttributes as $imageAttribute) {
3737
$image = $imageAttribute->type === null ? $source->getImages()->first() : $source->getImagesByType($imageAttribute->type)->first();
3838
if (false === $image) {
3939
continue;
@@ -58,6 +58,6 @@ public function supports(
5858
IndexScope $indexScope,
5959
array $context = [],
6060
): bool {
61-
return $source instanceof ImagesAwareInterface && $this->metadataFactory->getMetadataFor($target)->getImageAttributes() !== [];
61+
return $source instanceof ImagesAwareInterface && $this->metadataFactory->getMetadataFor($target)->imageAttributes !== [];
6262
}
6363
}

src/DataMapper/Product/AttributesDataMapper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function supports(IndexableInterface $source, Document $target, IndexScop
4242
return $source instanceof ProductInterface &&
4343
$target instanceof ProductDocument &&
4444
null !== $indexScope->localeCode &&
45-
$this->metadataFactory->getMetadataFor($target)->getMappedProductAttributes() !== []
45+
$this->metadataFactory->getMetadataFor($target)->mappedProductAttributes !== []
4646
;
4747
}
4848
}

src/DataMapper/Product/OptionsDataMapper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function supports(IndexableInterface $source, Document $target, IndexScop
4040
{
4141
return $source instanceof ProductInterface &&
4242
$target instanceof ProductDocument &&
43-
$this->metadataFactory->getMetadataFor($target)->getMappedProductOptions() !== []
43+
$this->metadataFactory->getMetadataFor($target)->mappedProductOptions !== []
4444
;
4545
}
4646
}

src/DataMapper/Product/Setter/DocumentAttributesValuesSetter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function setFor(Document $target, array $attributes): void
1717
{
1818
$metadata = $this->metadataFactory->getMetadataFor($target);
1919

20-
foreach ($metadata->getMappedProductAttributes() as $mappedProductAttribute) {
20+
foreach ($metadata->mappedProductAttributes as $mappedProductAttribute) {
2121
$values = [];
2222
foreach ($mappedProductAttribute->codes as $code) {
2323
if (!isset($attributes[$code])) {

src/DataMapper/Product/Setter/DocumentOptionsValuesSetter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function setFor(Document $target, array $attributes): void
1717
{
1818
$metadata = $this->metadataFactory->getMetadataFor($target);
1919

20-
foreach ($metadata->getMappedProductOptions() as $property => $optionCodes) {
20+
foreach ($metadata->mappedProductOptions as $property => $optionCodes) {
2121
$values = [];
2222
/** @var string $code */
2323
foreach ($optionCodes as $code) {

src/Document/Metadata/CachedMetadataFactory.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ final class CachedMetadataFactory implements MetadataFactoryInterface
1313
/**
1414
* The loaded metadata, indexed by class name
1515
*
16-
* @var array<class-string<Document>, MetadataInterface>
16+
* @var array<class-string<Document>, Metadata>
1717
*/
1818
private array $loadedClasses = [];
1919

@@ -23,7 +23,7 @@ public function __construct(
2323
) {
2424
}
2525

26-
public function getMetadataFor(string|Document $document): MetadataInterface
26+
public function getMetadataFor(string|Document $document): Metadata
2727
{
2828
if ($document instanceof Document) {
2929
$document = $document::class;
@@ -36,7 +36,7 @@ public function getMetadataFor(string|Document $document): MetadataInterface
3636
$cacheItem = $this->cache->getItem($this->escapeClassName($document));
3737
if ($cacheItem->isHit()) {
3838
$metadata = $cacheItem->get();
39-
Assert::isInstanceOf($metadata, MetadataInterface::class);
39+
Assert::isInstanceOf($metadata, Metadata::class);
4040

4141
$this->loadedClasses[$document] = $metadata;
4242

src/Document/Metadata/Metadata.php

Lines changed: 52 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,53 @@
44

55
namespace Setono\SyliusMeilisearchPlugin\Document\Metadata;
66

7-
use Setono\SyliusMeilisearchPlugin\Document\Attribute\Facetable as FacetableAttribute;
8-
use Setono\SyliusMeilisearchPlugin\Document\Attribute\Filterable as FilterableAttribute;
9-
use Setono\SyliusMeilisearchPlugin\Document\Attribute\Image as ImageAttribute;
10-
use Setono\SyliusMeilisearchPlugin\Document\Attribute\MapProductAttribute;
11-
use Setono\SyliusMeilisearchPlugin\Document\Attribute\MapProductOption;
12-
use Setono\SyliusMeilisearchPlugin\Document\Attribute\Searchable as SearchableAttribute;
13-
use Setono\SyliusMeilisearchPlugin\Document\Attribute\Sortable as SortableAttribute;
147
use Setono\SyliusMeilisearchPlugin\Document\Document;
15-
use Webmozart\Assert\Assert;
168

17-
// TODO: Do we need an interface, why not just have public readonly properties?
18-
final class Metadata implements MetadataInterface
9+
final class Metadata
1910
{
2011
/** @var class-string<Document> */
21-
private readonly string $document;
12+
public readonly string $document;
2213

23-
/** @var array<string, Filterable> */
24-
private array $filterableAttributes = [];
14+
/**
15+
* Filterable attributes indexed by the name
16+
*
17+
* @var array<string, Filterable>
18+
*/
19+
public array $filterableAttributes = [];
2520

26-
/** @var array<string, Facet> */
27-
private array $facetableAttributes = [];
21+
/**
22+
* Facetable attributes indexed by the name
23+
*
24+
* @var array<string, Facet>
25+
*/
26+
public array $facetableAttributes = [];
2827

29-
/** @var array<string, Searchable> */
30-
private array $searchableAttributes = [];
28+
/**
29+
* Searchable attributes indexed by the name
30+
*
31+
* @var array<string, Searchable>
32+
*/
33+
public array $searchableAttributes = [];
3134

32-
/** @var array<string, Sortable> */
33-
private array $sortableAttributes = [];
35+
/**
36+
* Sortable attributes indexed by the name
37+
*
38+
* @var array<string, Sortable>
39+
*/
40+
public array $sortableAttributes = [];
3441

35-
/** @var array<string, list<string>> */
36-
private array $mappedProductOptions = [];
42+
/**
43+
* Return product options codes mapped by document property
44+
*
45+
* @var array<string, list<string>>
46+
*/
47+
public array $mappedProductOptions = [];
3748

3849
/** @var list<MappedProductAttribute> */
39-
private array $mappedProductAttributes = [];
50+
public array $mappedProductAttributes = [];
4051

4152
/** @var array<string, Image> */
42-
private array $imageAttributes = [];
53+
public array $imageAttributes = [];
4354

4455
/**
4556
* @param class-string<Document>|Document $document
@@ -51,108 +62,33 @@ public function __construct(string|Document $document)
5162
}
5263

5364
$this->document = $document;
54-
55-
$this->load();
56-
}
57-
58-
private function load(): void
59-
{
60-
$documentReflection = new \ReflectionClass($this->document);
61-
foreach ($documentReflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflectionProperty) {
62-
$this->loadAttributes($reflectionProperty);
63-
}
64-
65-
foreach ($documentReflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
66-
if (!self::isGetter($reflectionMethod)) {
67-
continue;
68-
}
69-
70-
$this->loadAttributes($reflectionMethod);
71-
}
72-
}
73-
74-
private function loadAttributes(\ReflectionProperty|\ReflectionMethod $attributesAware): void
75-
{
76-
$name = self::resolveName($attributesAware);
77-
if (null === $name) {
78-
return;
79-
}
80-
81-
foreach ($attributesAware->getAttributes() as $reflectionAttribute) {
82-
$attribute = $reflectionAttribute->newInstance();
83-
84-
if ($attribute instanceof FilterableAttribute) {
85-
$this->filterableAttributes[$name] = new Filterable($name);
86-
}
87-
88-
if ($attribute instanceof FacetableAttribute) {
89-
$this->facetableAttributes[$name] = new Facet(
90-
$name,
91-
self::getFacetType($attributesAware),
92-
$attribute->position,
93-
$attribute->sorter ?? null,
94-
);
95-
}
96-
97-
if ($attribute instanceof SearchableAttribute) {
98-
$this->searchableAttributes[$name] = new Searchable($name, $attribute->priority);
99-
}
100-
101-
if ($attribute instanceof SortableAttribute) {
102-
$this->sortableAttributes[$name] = new Sortable($name, $attribute->direction);
103-
}
104-
105-
if ($attribute instanceof MapProductOption) {
106-
Assert::isInstanceOf($attributesAware, \ReflectionProperty::class);
107-
// todo are we sure this needs to be an array?
108-
Assert::same('array', (string) $attributesAware->getType());
109-
$this->mappedProductOptions[$name] = $attribute->codes;
110-
}
111-
112-
if ($attribute instanceof MapProductAttribute) {
113-
Assert::isInstanceOf($attributesAware, \ReflectionProperty::class);
114-
$this->mappedProductAttributes[] = new MappedProductAttribute($name, (string) $attributesAware->getType(), $attribute->codes);
115-
}
116-
117-
if ($attribute instanceof ImageAttribute) {
118-
$this->imageAttributes[$name] = new Image($name, $attribute->filterSet, $attribute->type);
119-
}
120-
}
12165
}
12266

12367
/**
124-
* @return class-string<Document>
68+
* Returns the names of the filterable attributes
69+
*
70+
* @return list<string>
12571
*/
126-
public function getDocument(): string
127-
{
128-
return $this->document;
129-
}
130-
131-
public function getFilterableAttributes(): array
132-
{
133-
return $this->filterableAttributes;
134-
}
135-
13672
public function getFilterableAttributeNames(): array
13773
{
13874
return array_keys($this->filterableAttributes);
13975
}
14076

141-
public function getFacetableAttributes(): array
142-
{
143-
return $this->facetableAttributes;
144-
}
145-
77+
/**
78+
* Returns the names of the facetable attributes
79+
*
80+
* @return list<string>
81+
*/
14682
public function getFacetableAttributeNames(): array
14783
{
14884
return array_keys($this->facetableAttributes);
14985
}
15086

151-
public function getSearchableAttributes(): array
152-
{
153-
return $this->searchableAttributes;
154-
}
155-
87+
/**
88+
* Returns the names of the searchable attributes (sorted by priority)
89+
*
90+
* @return list<string>
91+
*/
15692
public function getSearchableAttributeNames(): array
15793
{
15894
$searchableAttributes = $this->searchableAttributes;
@@ -161,69 +97,13 @@ public function getSearchableAttributeNames(): array
16197
return array_map(static fn (Searchable $searchableAttribute) => $searchableAttribute->name, $searchableAttributes);
16298
}
16399

164-
public function getSortableAttributes(): array
165-
{
166-
return $this->sortableAttributes;
167-
}
168-
100+
/**
101+
* Returns the names of the sortable attributes
102+
*
103+
* @return list<string>
104+
*/
169105
public function getSortableAttributeNames(): array
170106
{
171107
return array_keys($this->sortableAttributes);
172108
}
173-
174-
public function getMappedProductOptions(): array
175-
{
176-
return $this->mappedProductOptions;
177-
}
178-
179-
public function getMappedProductAttributes(): array
180-
{
181-
return $this->mappedProductAttributes;
182-
}
183-
184-
public function getImageAttributes(): array
185-
{
186-
return $this->imageAttributes;
187-
}
188-
189-
private static function isGetter(\ReflectionMethod $reflection): bool
190-
{
191-
if ($reflection->getNumberOfParameters() > 0) {
192-
return false;
193-
}
194-
195-
$name = $reflection->getName();
196-
197-
return str_starts_with($name, 'get') || str_starts_with($name, 'is') || str_starts_with($name, 'has');
198-
}
199-
200-
private static function resolveName(\ReflectionProperty|\ReflectionMethod $reflection): ?string
201-
{
202-
if ($reflection instanceof \ReflectionProperty) {
203-
return $reflection->getName();
204-
}
205-
206-
if ($reflection->getNumberOfParameters() > 0) {
207-
return null;
208-
}
209-
210-
$name = $reflection->getName();
211-
212-
foreach (['get', 'is', 'has'] as $prefix) {
213-
if (str_starts_with($name, $prefix)) {
214-
return lcfirst(substr($name, strlen($prefix)));
215-
}
216-
}
217-
218-
return null;
219-
}
220-
221-
private static function getFacetType(\ReflectionProperty|\ReflectionMethod $attributesAware): string
222-
{
223-
if ($attributesAware instanceof \ReflectionProperty) {
224-
return str_replace('?', '', (string) $attributesAware->getType());
225-
}
226-
227-
return str_replace('?', '', (string) $attributesAware->getReturnType());
228-
}
229109
}

0 commit comments

Comments
 (0)