algolia / algolia/search-bundle

Custom Serialization Groups & Access To Root Entity Class On Normalization

Open
#283 0 comments 0 reactions 0 assignees View on GitHub
Feature Request
Dominant language
PHP
Stars
193
Forks
74
PR merge metrics
No merged PRs in 30d

Description

- Symfony version: 4.2.1
- Algolia Search Bundle version: 3.4.0
- Algolia Client Version: 1.28.0
- Language Version: 7.3.1

## Description
Currently normalizers are called with a special `searchableArray` format. However this is still not enough, since you can only determine if the data is serialized for Algolia or for different purpose (e.g. API-Platform). There's no way (or I don't see it) to support such structure:

```
[books_index] (e.g. for autocomplete)
| - book1
| | - title: Foo Bar
| | - author: John Doe
| \ - readers: 124
\ - book2
| - title: Baz Bat
| - author: Josh A.
\ - readers: 222

[categories]
| - category1
| - name: Good Books
\ - promoted
| - book1
| | - title: Foo Bar
| \ - author: John Doe
\ - book2
| - title: Baz Bat
\ - author: Josh A.
```

This is a synthetic example, but the problem has a real business use-case. If you have collection of items you cannot get a basic version of an entity for collections and advanced version of the same entity for a separate index.

This is kind of related to #139, but I basically need to differentiate between nested objects and top level indexes.

## Solutions
I see two ways of making this experience better - first is intermittent but very simple and second is advanced but flexible and easily extensible:

### Pass index entity in context
`normalize()` receives `$context` array. In this array we can add class name of the currently processed index. With such construction `normalize()` method may look like:

```php
public function normalize($object, $format = null, array $context = [])
{
$result = $this->normalizer->normalize($object, $format, $context);
if ($context['rootEntity'] === Book::class) {
$result['readers'] = $this->doSomeExpensiveCalculations();
}
//...
}
```

(of course properly it should be a separate normalizer which delegates via composition etc but I skipped this for simplicity)

This can be added literally in 5 minutes (let me know - I can submit PR) by modifying `SearchableEntity::getSearchableArray()` to call `$context['rootEntity'] = \get_class($this->entity)`.

### Allow defining normalization groups
This is a proper solution for the problem. Currently there's a blanket `searchable` group passed. This is good when I want to decide what goes to search engine and what not, however I cannot have multiple groups depending on the index.

This could be defined as follow:
```yaml
algolia_search:
indices:
- name: books
class: ACME\Entity\Book
enable_serializer_groups: true
serializer_groups:
- searchable
- searchableMainBookRoot
- name: categories
class: ACME\Entity\Category
enable_serializer_groups: true
serializer_groups:
- searchable
- searchableMainBookChild
```

Implementing this will require plugging into `SearchableEntity::getSearchableArray()` and changing how configuration is parsed to get this extra list. All in all it doesn't seem like a lot more work.

## Conclusion
RFC ;) Maybe I don't understand something, but I think in a current state what I need is not possible.

Contributor guide

Open the contributing guide

Research direction

Start with SearchableEntity::getSearchableArray() and the configuration parsing for indices. Compare the proposed rootEntity context and per-index serializer_groups approaches, then define which behavior and configuration should be supported for nested entities and separate indices. Done means the selected approach is implemented with appropriate coverage for both index contexts.

Written by the indexing model from the issue text.

Assessment

Tech stack
php, symfony
Domain
backend, search
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.