Integrations / Frameworks / Laravel / Customize Searchable Data

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 or floats.

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;
}
Did you find this page helpful?