Salut à vous,
J'aurais une question. Actuellement je travaille sur un système de notifications, et pour cela j'utilise une relation polymorphique, car les notifications peuvent faire références à toutes sortes d'actions (réponse à un commentaire, "j'aime" sur un commentaire, etc). Le soucis du coup c'est que les relations polymorphiques obligent (ou alors je ne sais pas comment contourner ce problème) à une requête pour récupérer les données.
Sachant aussi que les "j'aimes" font aussi l'objet d'une relation polymorphique, vu qu'on peut "aimer" plusieurs éléments sur le site.
Du coup lorsque je me retrouve à faire un affichage comme ceci :
$notificable->article->slug
$notif->notificable->article->category->slug
// ou
$notificable->likeable->article->slug
$notificable->likeable->article->category->slug
Je me retrouve alors avec 4 requêtes générées fois 5 notifications du coup, ce qui n'est pas super optimisé. Voici comment je récupère mes notifications, et les relations qui en découlent :
public function getLastNotifications(User $userTo, $take = 5, $paginate = false)
{
$query = $this->model
->with(['from' => function($query) {
$query->select('id', 'pseudo');
}])
->where('user_to', $userTo->id)
->latest();
if( $paginate ) {
return $query->paginate($take);
} else {
return $query->take($take)->get();
}
}
/**
* Relation polymorphique
*
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function notificable()
{
return $this->morphTo();
}
En fait j'aimerais diviser mon nombre de requêtes par 2 (ou 4 dans l'optimum). Par exemple, la liste des 5 dernières notifications
Imaginons qu'il y a deux notifications pour des "j'aimes" et 3 notifications pour une réponse à un commentaire, je me retrouve donc avec :
Pour chaque "j'aime" :
Pour chaque Réponse de commentaire :
je me retrouve donc avec 20 requêtes en tout pour liste ces éléments, ce qui fait beaucoup. Laravel n'aurait pas un tour caché pour alléger tout ça ? Ou devrais-je faire autrement ?
Voici mon foreach listant les notifications si ça peut aider :
@foreach( $notifications as $notif )
@if( $notif->type == 'comment' )
<li><a href="{{ route('articles.show', ['cat' => $notif->notificable->article->category->slug, $notif->notificable->article->slug]) }}#{{ $notif->notificable_id }}">{{ $notif->from->pseudo }} a répondu à votre commentaire</a></li>
@elseif ($notif->type == 'like' )
@if( $notif->notificable->up )
<li><a href="{{ route('articles.show', ['cat' => $notif->notificable->likeable->article->category->slug, 'slug' => $notif->notificable->likeable->article->slug]) }}#{{ $notif->notificable->likeable_id }}">{{ $notif->from->pseudo }} a aimé votre commentaire</a></li>
@else
<li><a href="{{ route('articles.show', ['cat' => $notif->notificable->likeable->likeable->article->category->slug, 'slug' => $notif->notificable->likeable->article->slug]) }}#{{ $notif->notificable->likeable_id }}">{{ $notif->from->pseudo }} n'a pas aimé votre commentaire</a></li>
@endif
@endif
@endforeach
Et du coup j'obtiens forcément trop de requêtes.
select * from `notifications` where `user_to` = '34639' and `read` = '0' order by `created_at` desc limit 5
select `id`, `pseudo` from `users` where `users`.`deleted_at` is null and `users`.`id` in ('34813')
select * from `likes` where `likes`.`id` = '10' limit 1
select * from `comments` where `comments`.`deleted_at` is null and `comments`.`id` = '126648' limit 1
select * from `articles` where `articles`.`deleted_at` is null and `articles`.`id` = '13460' limit 1
select * from `categories` where `categories`.`deleted_at` is null and `categories`.`id` in ('1')
select * from `likes` where `likes`.`id` = '9' limit 1
select * from `comments` where `comments`.`deleted_at` is null and `comments`.`id` = '126657' limit 1
select * from `articles` where `articles`.`deleted_at` is null and `articles`.`id` = '13460' limit 1
select * from `categories` where `categories`.`deleted_at` is null and `categories`.`id` in ('1')
select * from `likes` where `likes`.`id` = '8' limit 1
select * from `comments` where `comments`.`deleted_at` is null and `comments`.`id` = '126658' limit 1
select * from `articles` where `articles`.`deleted_at` is null and `articles`.`id` = '13460' limit 1
select * from `categories` where `categories`.`deleted_at` is null and `categories`.`id` in ('1')
select * from `comments` where `comments`.`deleted_at` is null and `comments`.`id` = '126661' limit 1
select * from `articles` where `articles`.`deleted_at` is null and `articles`.`id` = '13460' limit 1
select * from `categories` where `categories`.`deleted_at` is null and `categories`.`id` in ('1')
select * from `comments` where `comments`.`deleted_at` is null and `comments`.`id` = '126660' limit 1
select * from `categories` where `categories`.`deleted_at` is null and `categories`.`id` in ('1')
select * from `comments` where `comments`.`deleted_at` is null and `comments`.`id` = '126
Alors je ne suis pas à la recherche d'une solution toute faîte, mais d'une piste sur comment mettre en place un cache, ou des techniques pour permettre de réduire le nombre de requêtes en trichant sur les relations ou je ne sais pas :/
Merci à vous =)
Hello,
Si tu utilise la méthode with
dispo sur les requetes eloquent ?
Par exemple :
Model::with(['my_poly_relation','my_poly_relation.likes','my_poly_relation.comments']);
Ca ne changerais pas le nombre de requetes ?
Salut et merci de ta réponse,
Le soucis c'est que tu ne peux pas (il me semble) faire une relation de ce type avec les relations polymorphiques.
Salut à toi,
Alors je te confirme que de mon côté, ce système fonctionne.
J'ai un model User avec une relation poly avec Citizen et Company (qui contient les détails des users en fonction du type).
Et dans mes requetes Eloquent, je fait :
//Controller
User::whereTrucMuch('truc')->with('details')->get();
//Model User
public function details(){
return $this->morphTo();
}