Refactoriza consultas con whereHas usando whereRelation en Laravel

Spread the love

Comprobar la existencia de relaciones y obtener registros de un modelo es bastante simple en Laravel.

Pero a veces complica visualmente las consultas, sobre todo cuando usas whereHas.

Así que, como una forma de mejorar el código y la experiencia de desarrollo; en la versión 8 de Laravel se agrego el método whereRelation como una forma corta de whereHas

Pero… ¿Qué es WhereRelation?

Veamos este nuevo método de Eloquent:

/**
* Add a basic where clause to a relationship query.
*
* @param  string  $relation
* @param  \Closure|string|array|\Illuminate\Database\Query\Expression  $column
* @param  mixed  $operator
* @param  mixed  $value
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function whereRelation($relation, $column, $operator = null, $value = null)
{
    return $this->whereHas($relation, function (Builder $builder) use ($column, $operator, $value) {
        $builder->where($column, $operator, $value);
    });
}

Como puedes observar el método whereRelation usa de forma interna whereHas y la ventaja que tiene, es que la relación y las condiciones se pasan como parametros, con esto evitas los molestos closures cuando tienes que usar condiciones simples.

Por ejemplo el siguiente código:

// muestra todos los post que estan como borradores
$users = User::whereHas('posts', function ($query) {
    $query->where('status', 'draft');
})->get();

Puede ser reescrito de la siguente forma:

$users = User::whereRelation('posts', 'status', 'draft')->get();

El código ahora es mas simple y más fácil de leer!

Ya que desaparece el Closure en la lista de parámetros del método whereRelation.

Además, la parte que corresponde a la condición where, tambien puede aceptar un arreglo:

$comments = Comment::whereMorphRelation('commentable', '*', [
    'is_public' => true,
    'is_vip' => false,
])->get();

A pesar del arreglo, el código sigue siendo visualmente mas sencillo que con whereHas.

$comments = Comment::whereHasMorph(
    'commentable',
    '*',
    function (Builder $query) {
        $query->where([
            'is_public' => true,
            'is_vip' => false,
        ]);
    }
)->get();

Como era de esperarse, este método tiene algunas variantes como orWhereRelation, whereMorphRelation y orWhereMorphRelation.

Un punto importante que debes tener en cuenta, es que whereRelation utiliza de forma interna una cláusula where, por lo tanto no es posible utilizar scopes o funciones.

Así que el siguiente ejemplo no es posible usarlo con whereRelation.

//Esto no se puede usar con whereRelation
User::whereHas('posts', functions($query){
    $query->published();
})->get()

Si bien no es posible refactorizar todos los casos que usan whereHas, si estoy seguro que esta nueva característica te hará la vida mas fácil cuando crees consultas con Eloquent.

Si tienes alguna duda o sugerencia deja tu comentario!.