Fabrice Planchette

Les scopes dans les modèles Laravel

Jun 18, 2021

Dans les modèles, l’utilisation des scopes va permettre d’ajouter de la logique dans le modèle. On va donc avoir ce qui peut modifier la requête du Query Builder de ce modèle dans celui-ci et pas ailleurs.

Scope ?

Imagine tu as une table posts (et son modèle Post), et que dans cette table tu as une colonne vote (je t’explique pas pourquoi cette colonne, t’as compris). Pour récupérer les posts ayant reçu plus de 100 votes, ça donnerait :

$posts = Post::where('votes', '>', 100)->get();

Mais en mettant ça dans un scope, cela devient :

// Méthode à placer dans le modèle
public function scopePopular($query)
{
    return $query->where('votes', '>', 100);
}

// Et pour récupérer ces articles
$posts = Post::popular()->get();

Joli non ?

Date de création dans un intervalle donné

Imagine (encore) que tu as ce même modèle Post et que tu veux récupérer les entrées créées entre 2 dates. Si tu fonces tête baissée, ça donne :

 
$startDate = Carbon::createFromFormat('Y-m-d', '2021-05-17'); 
$endDate = Carbon::createFromFormat('Y-m-d', '2021-06-17');

$posts = Post::whereBetween('created_at', '[$startDate, $endDate])->get(); 

Ok, ça marche. Sauf que created_at est un datetime, donc la partie heure/minute/seconde passe à la trappe et tu perds 24h sur la dernière journée. Ah! le piège!

Bon en fait, le plus simple serait de ne pas utiliser de BETWEEN dans ce cas mais simplement de borner en utilisant la méthode whereDate(). Voici ce que ça donne :

 
$startDate = Carbon::createFromFormat('Y-m-d', '2021-05-17'); 
$endDate = Carbon::createFromFormat('Y-m-d', '2021-06-17');

$posts = Post::whereDate('created_at', '>=', $startDate)
    ->whereDate('created_at', '<=', $endDate)
    ->get(); 

C’est sympa mais comme on ne veut pas réécrire ça à chaque fois (#dry), on va déplacer ça dans… un scope ! Bien tu suis !

 
public function scopeCreatedBetweenDates(Builder $builder, DateTimeInterface $startDate, DateTimeInterface $endDate) { 
    return $builder
        ->whereDate('created_at', '>=', $startDate)
        ->whereDate('created_at', '<=', $endDate)
} 

Et pour l’utiliser, rien de plus simple :

 
$startDate = Carbon::createFromFormat('Y-m-d', '2021-05-17'); 
$endDate = Carbon::createFromFormat('Y-m-d', '2021-06-17');

$posts = Post::createdBetweenDates($startDate, $endDate)->get(); 

C’est sympa les scopes hein ?!

Liens