> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Scout

> Pacchetto ufficiale che aggiunge la ricerca full-text ai modelli Eloquent. Supporta Meilisearch, Algolia, Typesense e il motore basato su database, con sincronizzazione automatica degli indici tramite osservatori.

## Introduzione

**Laravel Scout** è una soluzione driver-based che aggiunge la ricerca full-text ai [modelli Eloquent](/it/eloquent). Sincronizza automaticamente record Eloquent e indici di ricerca tramite osservatori del modello.

Scout include il motore integrato `database` che sfrutta il full-text di MySQL/PostgreSQL e la clausola `LIKE` senza servizi esterni. In produzione, per tolleranza ai typo, ricerche facettate e geospaziali, i motori esterni sono utili.

### Motori supportati

| Motore       | Caratteristiche                         | Uso                        |
| ------------ | --------------------------------------- | -------------------------- |
| `database`   | Full-text di MySQL/PostgreSQL           | La maggior parte delle app |
| `collection` | Filtro in PHP (anche SQLite)            | Sviluppo/test              |
| Meilisearch  | Open source, tollerante ai typo, veloce | Produzione                 |
| Algolia      | SaaS cloud, funzionalità avanzate       | Produzione                 |
| Typesense    | Open source, supporta vettori           | Produzione                 |

```mermaid theme={null}
flowchart LR
  APP["App Laravel<br>(modelli Eloquent)"] -->|"save/delete"| SCOUT["Laravel Scout<br>(osservatori)"]
  SCOUT -->|"Sync indici"| ENGINE["Motore<br>Meilisearch / Algolia / Typesense"]
  USER["Utente"] -->|"Model::search()"| APP
  ENGINE -->|"Risultati"| APP
```

## Installazione

```shell theme={null}
composer require laravel/scout
```

```shell theme={null}
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
```

Aggiungi il trait `Laravel\Scout\Searchable` al modello.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Post extends Model
{
    use Searchable;
}
```

### Code

Con motori esterni si consiglia di attivare le [code](/it/queues) per la sincronizzazione in background.

```php theme={null}
'queue' => true,
```

Oppure:

```php theme={null}
'queue' => [
    'connection' => 'redis',
    'queue' => 'scout'
],
```

Avvia un worker dedicato:

```shell theme={null}
php artisan queue:work redis --queue=scout
```

### Job univoci

Per applicazioni molto scritte, evita job duplicati sullo stesso record.

```php theme={null}
use Laravel\Scout\Jobs\MakeSearchableUniquely;
use Laravel\Scout\Jobs\RemoveFromSearchUniquely;
use Laravel\Scout\Scout;

Scout::makeSearchableUsing(MakeSearchableUniquely::class);
Scout::removeFromSearchUsing(RemoveFromSearchUniquely::class);
```

## Prerequisiti dei driver

### Algolia

```shell theme={null}
composer require algolia/algoliasearch-client-php
```

```ini theme={null}
ALGOLIA_APP_ID=your-app-id
ALGOLIA_SECRET=your-secret-key
```

#### Impostazioni indice

```php theme={null}
use App\Models\User;

'algolia' => [
    'id' => env('ALGOLIA_APP_ID', ''),
    'secret' => env('ALGOLIA_SECRET', ''),
    'index-settings' => [
        User::class => [
            'searchableAttributes' => ['id', 'name', 'email'],
            'attributesForFaceting' => ['filterOnly(email)'],
        ],
    ],
],
```

Sincronizza:

```shell theme={null}
php artisan scout:sync-index-settings
```

### Meilisearch

[Meilisearch](https://www.meilisearch.com) è veloce e open source. In locale è comodo con [Laravel Sail](https://laravel.com/docs/sail#meilisearch).

```shell theme={null}
./vendor/bin/sail up -d meilisearch
```

Docker diretto:

```shell theme={null}
docker run -it --rm \
    -p 7700:7700 \
    getmeili/meilisearch:latest \
    meilisearch --master-key="masterKey"
```

```shell theme={null}
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
```

```ini theme={null}
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=masterKey
```

<Warning>
  Controlla i [breaking change](https://github.com/meilisearch/Meilisearch/releases) di Meilisearch quando aggiorni Scout.
</Warning>

#### Impostazioni indice (Meilisearch)

Registra `filterableAttributes` per `where()` e `sortableAttributes` per `orderBy()`.

```php theme={null}
use App\Models\User;

'meilisearch' => [
    'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
    'key' => env('MEILISEARCH_KEY', null),
    'index-settings' => [
        User::class => [
            'filterableAttributes' => ['id', 'name', 'email'],
            'sortableAttributes' => ['created_at'],
        ],
    ],
],
```

Attenzione ai tipi:

```php theme={null}
public function toSearchableArray(): array
{
    return [
        'id' => (int) $this->id,
        'name' => $this->name,
        'price' => (float) $this->price,
    ];
}
```

```shell theme={null}
php artisan scout:sync-index-settings
```

### Typesense

[Typesense](https://typesense.org) è open source, supporta keyword, semantica, geo e vettori.

```shell theme={null}
composer require typesense/typesense-php
```

```ini theme={null}
SCOUT_DRIVER=typesense
TYPESENSE_API_KEY=masterKey
TYPESENSE_HOST=localhost
TYPESENSE_PORT=8108
TYPESENSE_PATH=
TYPESENSE_PROTOCOL=http
```

Casta la primary key a stringa e la data creazione a timestamp UNIX:

```php theme={null}
public function toSearchableArray(): array
{
    return array_merge($this->toArray(), [
        'id' => (string) $this->id,
        'created_at' => $this->created_at->timestamp,
    ]);
}
```

### Motore database / collection

Senza servizi esterni.

**database**: full-text MySQL/PostgreSQL e `LIKE`.

```ini theme={null}
SCOUT_DRIVER=database
```

**collection**: filtro in PHP (anche SQLite), per dev/test.

```ini theme={null}
SCOUT_DRIVER=collection
```

<Info>
  Con database engine gli indici non vanno gestiti a parte.
</Info>

## Trait Searchable

### toSearchableArray()

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Post extends Model
{
    use Searchable;

    public function toSearchableArray(): array
    {
        $array = $this->toArray();

        // Personalizza...

        return $array;
    }
}
```

### Nome dell'indice

```php theme={null}
public function searchableAs(): string
{
    return 'posts_index';
}
```

### Strategie di ricerca (database engine)

```php theme={null}
use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;

#[SearchUsingPrefix(['id', 'email'])]
#[SearchUsingFullText(['bio'])]
public function toSearchableArray(): array
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'bio' => $this->bio,
    ];
}
```

<Warning>
  Per `SearchUsingFullText` serve un [indice full-text](/it/migrations).
</Warning>

### Condizionale

```php theme={null}
public function shouldBeSearchable(): bool
{
    return $this->isPublished();
}
```

<Warning>
  Non funziona con database engine. Usa clausole `where`.
</Warning>

## Gestione degli indici

<Info>
  Sezione rilevante con Algolia/Meilisearch/Typesense. Con database engine non serve.
</Info>

### Import di record esistenti

```shell theme={null}
php artisan scout:import "App\Models\Post"
```

Con coda:

```shell theme={null}
php artisan scout:queue-import "App\Models\Post" --chunk=500
```

### Flush

```shell theme={null}
php artisan scout:flush "App\Models\Post"
```

### Pausa della sincronizzazione

```php theme={null}
use App\Models\Order;

Order::withoutSyncingToSearch(function () {
    // Operazioni non sincronizzate
});
```

### Aggiungi/rimuovi manualmente

```php theme={null}
Order::where('price', '>', 100)->searchable();
$user->orders()->searchable();

Order::where('price', '>', 100)->unsearchable();
```

Con `delete()` la rimozione è automatica.

## Ricerca

```php theme={null}
use App\Models\Order;

$orders = Order::search('Star Trek')->get();
```

Da route o controller:

```php theme={null}
use Illuminate\Http\Request;

Route::get('/search', function (Request $request) {
    return Order::search($request->search)->get();
});
```

Grezzo:

```php theme={null}
$orders = Order::search('Star Trek')->raw();
```

### Paginazione

```php theme={null}
$orders = Order::search('Star Trek')->paginate();
$orders = Order::search('Star Trek')->paginate(15);
```

Con database engine anche `simplePaginate`:

```php theme={null}
$orders = Order::search('Star Trek')->simplePaginate(15);
```

```html theme={null}
<div class="container">
    @foreach ($orders as $order)
        {{ $order->price }}
    @endforeach
</div>

{{ $orders->links() }}
```

## Filtri e ordinamento

```php theme={null}
use App\Models\Order;

$orders = Order::search('Star Trek')->where('user_id', 1)->get();

$orders = Order::search('Star Trek')->whereIn('status', ['open', 'paid'])->get();

$orders = Order::search('Star Trek')->whereNotIn('status', ['closed'])->get();
```

<Warning>
  Con Meilisearch registra prima gli [attributi filtrabili](#impostazioni-indice-meilisearch).
</Warning>

Personalizza la query Eloquent:

```php theme={null}
use Illuminate\Database\Eloquent\Builder;

$orders = Order::search('Star Trek')
    ->query(fn (Builder $query) => $query->with('invoices'))
    ->get();
```

## Eager loading

```php theme={null}
use App\Models\Order;
use Illuminate\Database\Eloquent\Builder;

$orders = Order::search('Star Trek')
    ->query(fn (Builder $query) => $query->with(['invoices', 'user']))
    ->get();
```

In batch import:

```php theme={null}
use Illuminate\Database\Eloquent\Builder;

protected function makeAllSearchableUsing(Builder $query): Builder
{
    return $query->with('author');
}
```

<Warning>
  Nelle code non è sempre possibile.
</Warning>

## Soft delete

```php theme={null}
'soft_delete' => true,
```

```php theme={null}
$orders = Order::search('Star Trek')->withTrashed()->get();
$orders = Order::search('Star Trek')->onlyTrashed()->get();
```

## Motori personalizzati

Estendi `Laravel\Scout\Engines\Engine` e implementa 8 metodi:

```php theme={null}
use Laravel\Scout\Builder;

abstract public function update($models);
abstract public function delete($models);
abstract public function search(Builder $builder);
abstract public function paginate(Builder $builder, $perPage, $page);
abstract public function mapIds($results);
abstract public function map(Builder $builder, $results, $model);
abstract public function getTotalCount($results);
abstract public function flush($model);
```

Registra in `AppServiceProvider::boot()`:

```php theme={null}
use App\ScoutExtensions\MySqlSearchEngine;
use Laravel\Scout\EngineManager;

public function boot(): void
{
    resolve(EngineManager::class)->extend('mysql', function () {
        return new MySqlSearchEngine;
    });
}
```

```php theme={null}
'driver' => 'mysql',
```

## Pagine correlate

<Card title="Eloquent ORM" icon="database" href="/it/eloquent">
  Basi dei modelli Eloquent.
</Card>

<Card title="Relazioni Eloquent" icon="link" href="/it/eloquent-relationships">
  Definizione delle relazioni e eager loading.
</Card>

<Card title="Code" icon="clock" href="/it/queues">
  Scout aggiorna gli indici in background via code.
</Card>


## Related topics

- [Ricerca](/it/search.md)
- [Laravel Sail](/it/sail.md)
- [Aggiornamenti Laravel di marzo 2026](/it/blog/changelog/202603.md)
- [MongoDB](/it/mongodb.md)
- [Laravel Telescope](/it/telescope.md)
