En esta página:
Laravel 7 cuenta con una característica llamada Query Scopes, esta característica no es algo nuevo o exclusivo de Laravel 7, esta ya existía en versiones anteriores de Laravel, solo que en las últimas versiones ha sido mejorada, para ofrecer un mejor rendimiento a los Desarrolladores, también se solucionaron errores que arrojaba esta funcionalidad cuando se hacia uso de ella, en este Post veamos de que tratan los Query Scopes en Laravel 7 y otros detalles.
Antes de continuar, te invito a leer los siguientes artículos:
- Que es Laravel + Tu Primera Aplicación con Laravel
- Las Novedades más destacadas que trae Laravel 7
- 6 Helpers de gran Utilidad en Laravel 7
- Como crear un CRUD con Galería de Imágenes en Laravel 6.2 y Bootstrap 4 – Parte 1
- Lee más artículos en la categoría Laravel
Asimismo te invito a escuchar el Podcast: “Dominio del trabajo con Varios Lenguajes de Programación”:
Spotify | SoundCloud |
Bien ahora continuemos con el Post: Como Trabajar con Query Scopes (Ámbitos de Consulta) en Laravel 7.
Que son los Query Scopes ?
Si traducimos el término al español significa Ámbitos de Consulta y es justamente lo que nos permite, el trabajar haciendo consultas a la Base de datos en diferentes ámbitos y creando determinadas restricciones en la consulta que buscamos hacer.
Los Query Scopes pueden ser utilizados en un ámbito Global (Global Scopes) o Local (Local Scopes), en el futuro puede que agreguen otros ámbitos, hasta la fecha de este Post, estos 2 ámbitos son los disponibles en Laravel.
Global Scopes (Ámbitos Globales)
En este ámbito podemos agregar restricciones a todas nuestras consultas para un modelo determinado, la característica Soft Deleting de Laravel utiliza ámbitos globales para extraer los modelos que no han sido borrados de la base de datos.
La capacidad de escribir ámbitos globales, nos puede brindar una forma conveniente y sencilla de asegurarnos que cada consulta para un determinado modelo tenga ciertas restricciones.
Para utilizar Global Scopes podemos comenzar instanciando el Trait Scope antes de iniciar la clase para nuestro Scope.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php namespace App\Scopes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; // Trait Scope class StockScope implements Scope<span> { /* Acá va nuestro código */ } |
Luego debemos hacer uso del método apply() y dentro de el le pasamos where para especificar la restricción que necesitamos hacer.
Le ponemos el nombre que queramos, yo le puse el nombre StockScope a mi Global Scope.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php namespace App\Scopes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; class StockScope implements Scope { public function apply(Builder $builder, Model $model) { $builder->where('stock', '<', 50); } } |
En el código anterior estoy haciendo una restricción a mi consulta, le estoy diciendo que seleccione items o registros desde la base de datos, que cuenten con una cantidad menor a 50 unidades en stock.
Ahora para hacer uso de mi Global Scope que he creado anteriormente, debo de anular el método booted() del modelo al cual le aplicaré el Scope y hacer uso del método addGlobalScope().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php namespace App; use App\Scopes\StockScope; // Instancio mi Scope use Illuminate\Database\Eloquent\Model; class Productos extends Model { protected static function booted() { static::addGlobalScope(new StockScope); // Paso el nombre de mi Scope } } |
Luego de aplicar mi StockScope, las consultas tendrán la restricción que le especifiqué, obtendré lo siguiente.
1 2 3 |
select * from `productos` where `stock` < 50 |
Entonces a partir de ahora, cada consulta que realice a mi modelo Productos, me devolverá solo los productos que tengan un stock menor a 50 unidades.
En ocasiones puede que necesitemos eliminar el Global Scope en determinadas consultas, para esto podemos hacer uso del método withoutGlobalScope(), a este método le pasamos el nombre del Global Scope como único argumento.
1 2 3 |
Productos::withoutGlobalScope(StockScope::class)->get(); |
Y si es que definimos el Global Scope utilizando un cierre.
1 2 3 |
Productos::withoutGlobalScope('stock')->get(); |
Si queremos eliminar algunos o todos los Global Scopes, podemos utilizar el método withoutGlobalScopes()
1 2 3 4 5 6 7 8 9 |
// Elimina algunos Global Scopes Productos::withoutGlobalScopes([ StockScope::class, OtroScope::class ])->get(); // Elimina todos los Global Scopes Productos::withoutGlobalScopes()->get(); |
Bien ahora pasemos a ver los Local Scopes
Local Scopes (Ámbitos Locales)
Los Local Scopes nos permiten trabajar con conjuntos comunes de restricciones que pueden ser reutilizados fácilmente en una aplicación. Por ejemplo, si necesitamos obtener los productos que cuentan con mucho stock, aproximadamente con un stock mayor a 60 unidades y que sean de tipo de productos 3 (supongamos que el tipo de productos 3 son postres), debemos prefijar un método de modelo Eloquent scope().
Los ámbitos siempre deben arrojar una instancia del generador de consultas (query builder).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Productos extends Model { public function scopeStock($query) { return $query->where('stock', '>', 60); } public function scopeTipo($query) { return $query->where('tipo', 3); } } |
Como estamos trabajando en un ámbito local, no necesitamos realizar otra tarea adicional en nuestro modelo.
Si quiero utilizar el Local Scope que he creado anteriormente, puedo llamar al método de alcance al realizar una consulta a un modelo, aquí no debemos incluir el prefijo scope al llamar al método, también podemos encadenar llamadas a varios scopes.
1 2 3 |
$productos = App\Productos::stock()->active()->orderBy('nombre')->get(); |
Si queremos hacer una combinación de múltiples ámbitos de modelo Eloquent a través de un operador de consulta or, puede requerir el uso de devoluciones de llamada de cierre (Closure callbacks).
1 2 3 4 5 |
$productos = App\Productos::stock()->orWhere(function (Builder $query) { $query->tipo(); })->get(); |
Pero dado que el código anterior puede a veces ser engorroso, Laravel cuenta con el método orWhere (higher order) que nos permite encadenar estos ámbitos con fluidez si hacer uso de cierres, haciendo el código más limpio y sencillo.
1 2 3 |
$productos = App\Productos::stock()->orWhere->tipo()->get(); |
De esta manera podemos hacer uso de los Query Scopes de manera Global y Local, puedes potenciarlos agregando otros métodos de Laravel.
Conclusión
Hemos aprendido, sobre el uso de de los Query Scopes, pueden tener muchos usos, a mi se me ocurre que puede ser útil para restringir los End Points de las APIs Rest que otros usuarios con accesos limitados consumirán.
La mejor forma de dominar los Query Scopes es poniéndolos en práctica en tus proyectos.
Nota(s)
- Los códigos expuestos en este Post, pueden dejar de estar vigentes, ser eliminados o continuar vigentes, esto no depende de mi, si no de los Desarrolladores que dan soporte a Laravel y PHP.
- No olvides que debemos usar la Tecnología para hacer cosas Buenas por el Mundo.
Síguenos en nuestras Redes Sociales para que no te pierdas nuestros próximos contenido.