Besoin d'aide ?

Sélectionner la première ligne de chaque occurence avec with() Query Builder

Avatar de Pyon
Pyon

Bonjour,

J'apprends actuellement à développer avec Laravel et j'ai un soucis au niveau d'une requête SQL (avec query builder) que je n'arrive pas à réaliser. Je réalise un view composer pour générer une requête SQL qui doit récupérer la progression du dernier épisode des séries en cours, en pause ou planifiées (je possède une table avec l'ensemble des séries, et une autre avec les épisodes liées avec une relation 1:n).

Ma requête récupère bien les séries, mais pour les épisodes je cherche à récupérer uniquement le dernier de chaque série pour avoir son avancement. Sauf que la méthode first() ne va récupérer que le dernier épisode de la 1ere série et non le dernier épisode de chaque série.

Auriez-vous une idée de comment je devrais procéder ?

J'ai cherché quelques solutions dont limit(1), first(), take(1), mais en vain... Merci d'avance !

Voici mon fichier view composer avec ma requête

<?php

namespace App\Http\ViewComposers;

use Illuminate\View\View;
use App\ {
  Models\Series,
  Models\Episode
};

class SidebarComposer
{

  public function compose(View $view) {
    $view->with('progress', Series::select('id', 'name', 'status', 'slug', 'progress_color', 'progress_display')
      ->where('status', 'In Progress')
      ->orWhere('status', 'Paused')
      ->orWhere('status', 'Planed')
      ->where('progress_display', 1)
      ->with([
        'episodes' => function ($q) {
          $q->select('id', 'series_id', 'num', 'progress')->orderBy('num', 'DESC')->first();
        }
      ])
      ->get()
    );
  }
}

Pour les personnes qui se posent la question, progressdisplay est un boolean qui permet de dire s'il faut afficher ou non la série dans le tableau de progression que je rend disponible sur chaque page

Avatar de KYoann
KYoann

Salut,

As tu essayé avec :

->latest()->first()

ou

->last()

?

Avatar de Pyon
Pyon

Salut !

Oui, latest ne fonctionne pas car il faut enregistrer la date de création en BDD (created_at), ce que je n'ai pas. Quant à last il n'a pas l'air de connaître : Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::last()

Avatar de Pyon
Pyon

Re,

J'ai fini par trouver une solution grâce à cet article : https://www.laravelcode.com/post/how-to-get-last-record-from-leftjoin-table-in-laravel

$view->with('progress', Series::select('series.name', 'series.status', 'series.slug', 'series.progress_color', 'series.progress_display', 'episodes.num', 'episodes.progress')
          ->leftJoin('episodes', function($query) {
            $query->on('episodes.series_id','=','series.id')
            ->whereRaw('episodes.id IN (select MAX(a2.id) from episodes as a2 join series as u2 on u2.id = a2.series_id group by u2.id)');
          })
          ->where('series.status', 'In Progress')
          ->orWhere('series.status', 'Paused')
          ->orWhere('series.status', 'Planed')
          ->where('series.progress_display', 1)
          ->get()
        );

A ma connaissance, il n'y a pas moyen de simplifier ça mais si quelqu'un a une solution plus simple je suis preneur ;)

Avatar de KYoann
KYoann

Belle requête !!

Vous ne pouvez pas répondre à ce sujet.