- Introducción
- Instalación
- Configuración
- Indexando
- Búsqueda
- Motores personalizados
- Macros de constructor (builder)
Introducción
Laravel Scout proporciona una sencilla solución, basada en un controlador (driver) para agregar búsquedas de texto completo a tus modelos Eloquent. Usando observadores de modelo, Scout mantendrá automáticamente tus índices de búsqueda sincronizados con tus registros de Eloquent.
Actualmente, Scout viene con el controlador (driver) Algolia; sin embargo, la escritura de controladores personalizados es simple y eres libre de extender Scout con tus propias implementaciones de búsqueda.
Instalación
Primero, instala Scout por medio del manejador de paquetes Composer:
composer require laravel/scout
Después de instalar Scout, debes publicar la configuración de Scout usando el comando Artisan vendor:publish
. Este comando publicará el archivo de configuración scout.php
en tu directorio config
:
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
Finalmente, agrega el trait Laravel\Scout\Searchable
al modelo en el que te gustaría hacer búsquedas. Este trait registrará un observador de modelo para mantener el modelo sincronizado con tu controlador de búsqueda:
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Post extends Model { use Searchable; }
Colas
Aunque no es estrictamente necesario para usar Scout, deberías considerar fuertemente configurar un controlador de cola antes de usar el paquete. La ejecución de un trabajador (worker) de cola permitirá a Scout poner en cola todas las operaciones que sincronizan la información de tu modelo con tus índices de búsqueda, proporcionando mejores tiempos de respuesta para la interfaz web de tu aplicación.
Una vez que hayas configurado tu controlador de cola, establece el valor de la opción queue
en tu archivo de configuración config/scout.php
a true
:
'queue' => true,
Requisitos previos del driver
Algolia
Al usar el controlador Algolia, debes configurar tus credenciales id
y secret
de Algolia en tu archivo de configuración config/scout.php
. Una vez que tus credenciales han sido configuradas, también necesitarás instalar Algolia PHP SDK por medio del manejador de paquetes Composer:
composer require algolia/algoliasearch-client-php:^2.2
Configuración
Configurando índices de modelo
Cada modelo Eloquent es sincronizado con un «índice» de búsqueda dado, el cual contiene todos los registros que pueden ser encontrados para ese modelo. En otras palabras, puedes pensar en cada índice como una tabla MySQL. De forma predeterminada, cada modelo será persistido en un índice que coincida con el típico nombre de la «tabla» del modelo. Típicamente, esta es la forma plural del nombre del modelo; sin embargo, eres libre de personalizar el índice del modelo sobrescribiendo el método searchableAs
en el modelo:
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Post extends Model { use Searchable; /** * Get the index name for the model. * * @return string */ public function searchableAs() { return 'posts_index'; } }
Configuración de datos de búsqueda
De forma predeterminada, la forma toArray
completa de un modelo dado será persistida en su índice de búsqueda. Si prefieres personalizar los datos que son sincronizados en el índice de búsqueda, puedes sobrescribir el método toSearchableArray
en el modelo:
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Post extends Model { use Searchable; /** * Get the indexable data array for the model. * * @return array */ public function toSearchableArray() { $array = $this->toArray(); // Customize array... return $array; } }
Configurando el ID del modelo
Por defecto, Scout usará la clave primaria del modelo como su ID única, almacenada en el índice de búsqueda. Si necesitas personalizar este comportamiento, puedes sobrescribir los métodos getScoutKey
y getScoutKeyName
en el modelo:
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class User extends Model { use Searchable; /** * Get the value used to index the model. * * @return mixed */ public function getScoutKey() { return $this->email; } /** * Get the key name used to index the model. * * @return mixed */ public function getScoutKeyName() { return 'email'; } }
Indexando
Importación en lote (batch)
Si estás instalando Scout en un proyecto existente, puede que ya tengas registros de base de datos que necesites importar dentro de tu manejador de búsqueda. Scout proporciona un comando Artisan import
que puedes usar para importar todos tus registros existentes a tus índices de búsqueda:
php artisan scout:import "App\Post"
El comando flush
puede ser usado para eliminar todos los registros de un modelo de tus índices de búsqueda:
php artisan scout:flush "App\Post"
Agregando registros
Una vez que has agregado el trait Laravel\Scout\Searchable
a tu modelo, todo lo que necesitas hacer es llamar a save
en una instancia de modelo y será agregada automáticamente a tu índice de búsqueda. Si has configurado Scout para usar colas esta operación será ejecutada en segundo plano por tu worker de cola:
$order = new App\Order; // ... $order->save();
Agregando por medio de consulta
Si prefieres agregar una colección de modelos a tu índice de búsqueda por medio de una consulta Eloquent, puedes encadenar el método searchable
con una consulta Eloquent. El método searchable
dividirá (chunk) los resultados de la consulta y agregará los registros a tu índice de búsqueda. Otra vez, si has configurado Scout para usar colas, todos estas porciones serán agregadas en segundo plano por tus workers de cola:
// Adding via Eloquent query... App\Order::where('price', '>', 100)->searchable(); // You may also add records via relationships... $user->orders()->searchable(); // You may also add records via collections... $orders->searchable();
El método searchable
puede ser considerado una operación «upsert». En otras palabras, si el registro del modelo ya está en tu índice, será actualizado. Si no existe en el índice de búsqueda, será agregado al índice.
Actualizando registros
Para actualizar un modelo searchable, sólo necesitas actualizar las propiedades de la instancia del modelo y llamar a save
en el modelo en tu base de datos. Scout persistirá automáticamente los cambios en tu índice de búsqueda:
$order = App\Order::find(1); // Update the order... $order->save();
También puedes usar el método searchable
en una consulta Eloquent para actualizar una colección de modelos. Si los modelos no existen en tu índice de búsqueda, serán creados:
// Updating via Eloquent query... App\Order::where('price', '>', 100)->searchable(); // You may also update via relationships... $user->orders()->searchable(); // You may also update via collections... $orders->searchable();
Eliminando registros
Para eliminar un registro de tu índice, llama a delete
en el modelo de la base de datos. Esta forma de eliminar es también compatible con los modelos eliminados lógicamente:
$order = App\Order::find(1); $order->delete();
Si no quieres obtener el modelo antes de eliminar el registro, puedes usar el método unsearchable
en una instancia de consulta de Eloquent o una colección:
// Removing via Eloquent query... App\Order::where('price', '>', 100)->unsearchable(); // You may also remove via relationships... $user->orders()->unsearchable(); // You may also remove via collections... $orders->unsearchable();
Pausando el indexamiento
Algunas veces puedes necesitar ejecutar un lote de operaciones de Eloquent en un modelo sin sincronizar los datos del modelo con tu índice de búsqueda. Puedes hacer esto usando el método withoutSyncingToSearch
. Este método acepta una sola función de retorno la cual será ejecutada inmediatamente. Cualquiera de las operaciones de modelo que ocurran dentro de la función de retorno no serán sincronizadas con el índice del modelo:
App\Order::withoutSyncingToSearch(function () { // Perform model actions... });
Instancias de modelos searchable condicionales
A veces es posible que solo tengas que hacer un modelo searchable bajo ciertas condiciones. Por ejemplo, imagina que tienes el modelo App\Post
que puede estar en uno de dos estados: «borrador (draft)» y «publicado (published)». Es posible que solo desees permitir que las publicaciones «publicadas» puedan buscarse. Para lograr esto, puedes definir un método shouldBeSearchable
en tu modelo:
public function shouldBeSearchable() { return $this->isPublished(); }
El método shouldBeSearchable
solo se aplica cuando se manipulan modelos a través del método save
, las consultas o las relaciones. Puedes hacer que los modelos o las colecciones se puedan buscar directamente utilizando el método searchable
que sobrescribirá el resultado del método shouldBeSearchable
:
// Will respect "shouldBeSearchable"... App\Order::where('price', '>', 100)->searchable(); $user->orders()->searchable(); $order->save(); // Will override "shouldBeSearchable"... $orders->searchable(); $order->searchable();
Búsqueda
Puedes empezar a buscar un modelo usando el método search
. Este método acepta una sola cadena que será usada para buscar tus modelos. Luego debes encadenar el método get
con la consulta de búsqueda para obtener los modelos Eloquent que coincidan con la consulta de búsqueda dada:
$orders = App\Order::search('Star Trek')->get();
Ya que las búsquedas de Scout devuelven una colección de modelos Eloquent, incluso puedes devolver los resultados directamente desde una ruta o controlador y serán convertidos automáticamente a JSON:
use Illuminate\Http\Request; Route::get('/search', function (Request $request) { return App\Order::search($request->search)->get(); });
Si prefieres obtener los resultados crudos (raw) antes de que sean convertidos a modelos de Eloquent, deberías usar el método raw
:
$orders = App\Order::search('Star Trek')->raw();
Las consultas de búsqueda son ejecutadas típicamente en el índice especificado por el método searchableAs
del modelo. Sin embargo, puedes usar el método within
para especificar un índice personalizado que debería ser buscado en su lugar:
$orders = App\Order::search('Star Trek') ->within('tv_shows_popularity_desc') ->get();
Cláusulas where
Scout permite que agregues cláusulas «where» sencillas a tus consultas de búsqueda. Actualmente, estas cláusulas solamente soportan verificaciones básicas de igualdad numérica y son útiles principalmente para establecer el alcance de las consultas de búsqueda por un ID. Ya que un índice de búsqueda no es una base de datos relacional, cláusulas «where» más avanzadas no están soportadas actualmente:
$orders = App\Order::search('Star Trek')->where('user_id', 1)->get();
Paginación
Además de obtener una colección de modelos, puedes paginar los resultados de tu búsqueda usando el método paginate
. Este método devolverá una instancia Paginator
justo como si hubieras paginado una consulta Eloquent tradicional:
$orders = App\Order::search('Star Trek')->paginate();
Puedes especificar cuántos modelos obtener por página al pasar la cantidad como primer argumento del método paginate
:
$orders = App\Order::search('Star Trek')->paginate(15);
Una vez que has obtenido los resultados, puedes mostrar los resultados y renderizar los enlaces de página usando Blade justo como si hubieras paginado una consulta Eloquent tradicional:
<div class="container"> @foreach ($orders as $order) {{ $order->price }} @endforeach </div> {{ $orders->links() }}
Eliminación lógica
Si tus modelos indexados son de eliminación lógica y necesitas buscar tus modelos eliminados lógicamente, establece la opción soft_delete
del archivo config/scout.php
en true
:
'soft_delete' => true,
Cuando esta opción de configuración es true
, Scout no removerá del índice los modelos eliminados lógicamente. En su lugar, establecerá un atributo escondido __soft_deleted
en el registro indexado. Luego, puedes usar los métodos withTrashed
o onlyTrashed
para recuperar los registros eliminados lógicamente al realizar una búsqueda:
// Include trashed records when retrieving results... $orders = App\Order::search('Star Trek')->withTrashed()->get(); // Only include trashed records when retrieving results... $orders = App\Order::search('Star Trek')->onlyTrashed()->get();
Cuando un modelo eliminado lógicamente es eliminado permanentemente utilizando forceDelete
, Scout lo removerá del índice de búsqueda automáticamente.
Personalizando motores de búsqueda
Si necesitas personalizar el comportamiento de un motor de búsqueda, puedes pasar una función de retorno (callback) como segundo argumento al método search
. Por ejemplo, podrías usar este callback para añadir datos de geolocalización a tus opciones de búsqueda antes de que la consulta de búsqueda sea pasada a Algolia:
use Algolia\AlgoliaSearch\SearchIndex; App\Order::search('Star Trek', function (SearchIndex $algolia, string $query, array $options) { $options['body']['query']['bool']['filter']['geo_distance'] = [ 'distance' => '1000km', 'location' => ['lat' => 36, 'lon' => 111], ]; return $algolia->search($query, $options); })->get();
Motores personalizados
Escribiendo el motor
Si ninguno de los motores de búsqueda integrados en Scout se ajusta a tus necesidades, puedes escribir tu propio motor personalizado y registrarlo con Scout. Tu motor debería extender la clase abstracta Laravel\Scout\Engines\Engine
. Esta clase abstracta contiene ocho métodos que tu motor de búsqueda personalizado debe implementar:
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);
Puedes encontrar útil revisar las implementaciones de estos métodos en la clase Laravel\Scout\Engines\AlgoliaEngine
. Esta clase te proporcionará un buen punto de inicio para aprender cómo implementar cada uno de estos métodos en tu propio motor.
Registrando el motor
Una vez que hayas escrito tu motor personalizado, puedes registrarlo con Scout usando el método extend
del administrador de motor de Scout. Deberías llamar el método extend
desde el método boot
de tu AppServiceProvider
o cualquier otro proveedor de servicio usado por tu aplicación. Por ejemplo, si has escrito un MySqlSearchEngine
, puedes registrarlo así:
use Laravel\Scout\EngineManager; /** * Bootstrap any application services. * * @return void */ public function boot() { resolve(EngineManager::class)->extend('mysql', function () { return new MySqlSearchEngine; }); }
Una vez que tu motor ha sido registrado, puedes especificarlo como tu driver
predeterminado de Scout en tu archivo de configuración config/scout.php
:
'driver' => 'mysql',
Macros de constructor (builder)
Si deseas definir un método constructor personalizado, puedes usar el método macro
en la clase Laravel\Scout\Builder
. Típicamente, las «macros» deben ser definidas dentro de un método boot
de un proveedor de servicios:
<?php namespace App\Providers; use Illuminate\Support\Facades\Response; use Illuminate\Support\ServiceProvider; use Laravel\Scout\Builder; class ScoutMacroServiceProvider extends ServiceProvider { /** * Register the application's scout macros. * * @return void */ public function boot() { Builder::macro('count', function () { return $this->engine->getTotalCount( $this->engine()->search($this) ); }); } }
La función macro
acepta un nombre como su primer argumento y un Closure como el segundo. El Closure del macro será ejecutado al momento de llamar el nombre del macro desde una implementación Laravel\Scout\Builder
:
App\Order::search('Star Trek')->count();
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.
Lección anterior Laravel Passport - Documentación de Laravel 6 Lección siguiente Laravel Socialite - Documentación de Laravel 6