Customize Searchable Data
Customize records# A
Scout Extended transforms your model into Algolia records with the toSearchableArray
method. You can override this method to customize what data you want to index.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Article extends Model
{
use Searchable;
/**
* Get the indexable data array for the model.
*
* @return array
*/
public function toSearchableArray()
{
$array = $this->toArray();
// Applies Scout Extended default transformations:
$array = $this->transform($array);
// Add an extra attribute:
$array['added_month'] = substr($array['created_at'], 0, 7);
return $array;
}
}
To know more about the transform
method check the section Transformers.
Relationships# A
Algolia doesn’t do any JOIN
operations. All searchable data must exist in each record.
This means that model relationships aren’t indexed by default. If you want to index relationships within a record, you need to override the toSearchableArray
method in your model and include the relationships you want to index.
Add attributes from relations#
For example, if you are indexing articles and each article has one author, all you need to do is add its full name or email.
1
2
3
4
5
6
7
8
9
10
11
public function toSearchableArray()
{
$array = $this->toArray();
$array = $this->transform($array);
$array['author_name'] = $this->author->name;
$array['author_email'] = $this->author->email;
return $array;
}
Many-to-many#
If you want to index the entire relationship you can do it by loading them before calling the toArray
method.
The resulting object has categories, converted to an array by Laravel:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public function toSearchableArray()
{
/**
* Load the categories relation so that it's
* available in the Laravel toArray() method
*/
$this->categories;
$array = $this->toArray();
$array = $this->transform($array);
return $array;
}
It could be that not all data from the relation. To clean up the data, you can do something like this:
1
2
3
4
5
6
7
8
9
10
11
12
public function toSearchableArray()
{
$array = $this->toArray();
$array = $this->transform($array);
$array['categories'] = $this->categories->map(function ($data) {
return $data['name'];
})->toArray();
return $array;
}
Bear in mind that Algolia has a size limit per record, so you should just index the data you need.
Updating relations when parent/child change# A
Once you embed information from a relation in your record, you may want to keep them up to date when you change the relation.
Depending on the relationship type between your models, you have two solutions: using the $touches
property, and listening for the saved
event.
Using the $touches
property#
Laravel has a built-in feature to let the parent relationship know that one of their children has changed.
In a typical Article <=> Comment example, all you would need to do is add article
to the $touches
property.
1
2
3
4
5
6
7
8
9
10
11
class Comment extends Model
{
use Searchable;
protected $touches = ['article'];
public function article()
{
return $this->belongsTo(Article::class);
}
}
This method only works with belongsTo
and belongsToMany
relationships.
Listening to saved
event#
If you use any other relationship, you have to listen to the saved
event and trigger the indexing.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Author extends Model
{
public static function boot()
{
parent::boot();
static::saved(function ($model) {
$model->articles->filter(function ($item) {
return $item->shouldBeSearchable();
})->searchable();
});
}
public function articles()
{
return $this->hasMany(Article::class);
}
}
Transformers# A
Some builder methods such as where
and whereBetween
require numeric values. For this reason, if toSearchableArray
isn’t defined, Scout Extended transforms, by default:
- Dates into
timestamps
- Numeric strings into
integers
orfloats
.
As usual, you can overwrite this behavior by implementing the toSearchableArray
method:
1
2
3
4
5
6
7
8
9
10
11
public function toSearchableArray()
{
$array = $this->toArray();
// If you want, apply the default transformations
$array = $this->transform($array);
// Apply custom treatment
return $array;
}
Writing custom transformers#
One of the primary benefits of creating a Transformer
class is the ability to type-hint any dependencies your transformer may need in its constructor. The declared dependencies are automatically resolved and injected into the transformer instance.
To write a transformer, you need to create a new class that implements Algolia\ScoutExtended\Contracts\TransformerContract
. The transform
method should transform the given $value
as needed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
namespace App\Search\Transformers;
use App\Contracts\TransformService;
use Algolia\ScoutExtended\Contracts\TransformerContract;
class CustomTransformer implements TransformerContract
{
/**
* @var \App\Contracts\TransformService
*/
protected $service;
/**
* Creates a new instance of the class.
*
* @param \App\Contracts\TransformService $service
*
* @return void
*/
public function __construct(TransformService $service)
{
$this->service = $service;
}
/**
* Transforms the given array.
*
* @param object $searchable
* @param array $array
*
* @return array
*/
public function transform($searchable, array $array): array
{
$array = $this->service->transform($searchable->articleType, $array);
return $array;
}
}
Finally, apply a custom transform sending the $array
into the transform
method and specifying
the transformers to apply.
1
2
3
4
5
6
7
8
9
10
11
public function toSearchableArray()
{
$array = $this->toArray();
// Apply the custom transformations
$array = $this->transform($array, [
\App\Search\Transformers\CustomTransformer::class
]);
return $array;
}