⚙️ Filtrado dinámico de registros

⚙️ Filtrado dinámico de registros

Creando sistemas de búsqueda flexibles

El filtrado dinámico es esencial para que los usuarios puedan refinar listas de datos (productos, usuarios, posts) usando múltiples criterios (precio, categoría, estado). En lugar de escribir lógica de consulta compleja en el controlador, Laravel nos anima a usar **Query Scopes** para encapsular y reutilizar las condiciones de filtrado de manera elegante y sencilla.

🎯 ¿Qué son los Query Scopes?

Los Scopes de consulta son métodos que puedes definir en tus modelos Eloquent para encapsular lógica de consulta reutilizable. Cuando se aplican, modifican la consulta original, haciendo que el código del controlador sea mucho más limpio.

Para definir un Scope, simplemente prefija un método en tu modelo con `scope` y usa un solo argumento, `$query`:

app/Models/Product.php
// Scope para obtener productos con buen stock
public function scopeWithHighStock($query)
{
    return $query->where('stock', '>', 50);
}

// Scope con parámetros para filtrar por categoría
public function scopeOfCategory($query, $categoryId)
{
    return $query->where('category_id', $categoryId);
}

🔗 Aplicación de Scopes

Una vez definidos, puedes "encadenar" (chain) los scopes directamente en el constructor de consultas. ¡Observa que usas el nombre sin el prefijo `scope`!

app/Http/Controllers/ProductController.php
public function index(Request $request)
{
    $products = Product::query(); // Iniciar la consulta

    // 1. Aplicar filtro de stock (scope sin parámetro)
    if ($request->has('high_stock')) {
        $products->withHighStock();
    }

    // 2. Aplicar filtro de categoría (scope con parámetro)
    if ($request->filled('category')) {
        $products->ofCategory($request->category);
    }

    // Finalmente, paginar los resultados
    return view('products.index', [
        'products' => $products->paginate(15)
    ]);
}

✨ El patrón del "Filtro Elegante"

Para sistemas muy complejos, es una buena práctica centralizar toda la lógica de filtrado fuera del controlador y de los modelos, utilizando una clase dedicada, a menudo llamada "Filter".

Lógica en el Controlador simplificada
public function index(Request $request)
{
    // Una clase Filter se encarga de aplicar todos los filtros
    $products = (new ProductFilter($request))
                    ->apply(Product::query())
                    ->paginate(15);
                    
    return view('products.index', compact('products'));
}

Aunque la implementación de la clase `ProductFilter` es más avanzada, este patrón mantiene el controlador como un simple "puente" entre la solicitud HTTP y la obtención de datos.

✅ Buenas prácticas

  • **Reutiliza:** Define todos los filtros comunes (como `active`, `published`, `byUser`) como **Scopes** en el modelo para no duplicar código.
  • **Legibilidad:** El encadenamiento de scopes (`Product::withHighStock()->ofCategory(2)->get()`) es mucho más legible que múltiples cláusulas `where` y `if` anidadas.
  • **Sanitiza:** Asegúrate de usar siempre métodos como `Request::filled()` o `Request::input()` para acceder a los datos de entrada del usuario y evitar errores.
  • **Performance:** Combina el filtrado dinámico con la **paginación** para asegurar que la aplicación siempre devuelva resultados rápidos y manejables.

Publicar un comentario

0 Comentarios