[Laravel 6] Start pagination op specifieke pagina

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 08:57

Matis

Rubber Rocket

Topicstarter
Beste PRGers,

Ik ben momenteel bezig met het maken van een interne webapp (website) in Laravel 6 waarmee we de afwezigheid van collega's kunnen tonen. Ik lees iedere dag diverse iCalendar bestanden, combineer de gegevens en toon de uiteindelijke kalender van de komende twee dagen.

Ook is er een mogelijkheid om een lijst te krijgen van alle iCalendar events (Absences). Middels Pagination kan ik een netjes geordende lijst tonen met de paginering onderaan de overzichtspagina. Ik pagineer met 25 Absences per pagina.

Op dit moment staan er zo'n 500 Absences in de database. De wens is om te sorteren op de startdatum van de Absences en zodoende een oplopende lijst te genereren. Dit lukt ook allemaal prima. Het probleem is momenteel dat de pagination altijd op pagina 1 begint. Daardoor ziet de gebruiker standaard de Absences met de meest oude startdatum. Pas op pagina 15 komt het omslagpunt waarop de startdatum van de Absences van het verleden naar de toekomst gaat.

Ik kan nu (hardcoded) de startpagina van de Pagination op 15 zetten wanneer deze niet in de Request zit.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class AbsenceController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @param Request $request
     * @return Response
     */
    public function index(Request $request): Response
    {
        $page = $request->input('page');
        if ($page === null) {
            $page = 15;
        }
        $absences = Absence::with('user')->orderBy('start_date')->paginate(25, ['*'], 'page', $page);

        return Response()->view('absence.index', compact('absences'));
    }
/* .... */
}


Wat ik graag zou willen is $page te berekenen op basis van het aantal Absences, het aantal Abscenses per pagina en het aantal Absences met een startdatum in de toekomst.

In pseudocode moet het zoiets worden
code:
1
2
3
4
5
$absencesPerPage = 25;
$totalAbsences = select count(*) as aggregate from `absences` 
$totalFutureAbsences = select count(*) as aggregate from `absences` where `start_date` > '2020-03-04 00:00:00' 
$totalPages = ceil($totalAbsences  / $absencesPerPage)
$page = $totalPages - ceil($totalFutureAbsences / $absencesPerPage)

Kleine disclaimer: het kan zijn dat ik ergens een ceil moet vervangen door een floor

Mijn vraag is echter hoe ik dit zo netjes mogelijk "the Laravel-way" kan doen zonder dat ik daarvoor heel veel duplicate queries en of code ga creëren?

Nog wat versie-informatie over mijn omgeving:
  • PHP: 7.4.2
  • Laravel Framework: 6.16.0
  • MySQL: 8.0.19
Alvast bedankt voor jullie suggesties _O_

Matis

If money talks then I'm a mime
If time is money then I'm out of time

Beste antwoord (via Matis op 06-03-2020 20:59)


  • Cartman!
  • Registratie: April 2000
  • Niet online
Je kunt toch gewoon een count doen op t aantal records die je wilt "skippen" op eerdere pagina's en uitrekenen op de hoeveelste pagina je zit adhv aantal items per pagina.

Alle reacties


Acties:
  • +1 Henk 'm!

  • dev10
  • Registratie: April 2005
  • Laatst online: 02-10 09:47
Als je nu toekomstige en historische items apart ophaalt heb je twee losse collections. Van allebei kun je bepalen hoeveel er in zitten en je kunt dan de collections samenvoegen tot een collection. Doordat je weet hoeveel historische en toekomstige items hebt, kun je aan de hand van die aantallen bepalen op welke pagina je moet beginnen.

Die samengevoegde collection kun je vervolgens weer pagineren.

[ Voor 8% gewijzigd door dev10 op 04-03-2020 13:42 ]


Acties:
  • +1 Henk 'm!

  • Beyond
  • Registratie: Juni 2001
  • Laatst online: 13:50

Beyond

Dussssss.......

Waarom gebruik je niet gewoon 'desc' in je query? Dan heb je de nieuwste absentie meldingen ook bovenaan.

code:
1
orderBy('start_date', 'desc')

[ Voor 19% gewijzigd door Beyond op 05-03-2020 11:48 ]

Al het goeie.......


Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 08:57

Matis

Rubber Rocket

Topicstarter
Beyond schreef op donderdag 5 maart 2020 @ 11:46:
Waarom gebruik je niet gewoon 'desc' in je query? Dan heb je de nieuwste absentie meldingen ook bovenaan.

code:
1
orderBy('start_date', 'desc')
Omdat er, zeker met de vakantie in aankomst, ook heel veel Absences zijn die zo ver in de toekomst liggen, dat ze nu nog niet relevant zijn.

In dat geval zou ik nu op pagina 3 uitkomen van de Pagination.

Daarnaast voelt het niet "natuurlijk" om een aflopende lijst te hebben.

@dev10 dat is iets waar ik niet aan heb gedacht. Ik ga het eens uitproberen!

[ Voor 6% gewijzigd door Matis op 05-03-2020 13:33 ]

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Hiroj
  • Registratie: Mei 2010
  • Laatst online: 04-09 14:23
Waarom kies je er niet voor om enkel absenties vanaf vandaag en verder te tonen?
Als je een lijst in het verleden wilt tonen, kun je dat gemakkelijk filteren.

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 08:57

Matis

Rubber Rocket

Topicstarter
Hiroj schreef op donderdag 5 maart 2020 @ 17:36:
Waarom kies je er niet voor om enkel absenties vanaf vandaag en verder te tonen?
Als je een lijst in het verleden wilt tonen, kun je dat gemakkelijk filteren.
Omdat dat niet de (klant)wens is :)
dev10 schreef op woensdag 4 maart 2020 @ 13:41:
Als je nu toekomstige en historische items apart ophaalt heb je twee losse collections. Van allebei kun je bepalen hoeveel er in zitten en je kunt dan de collections samenvoegen tot een collection. Doordat je weet hoeveel historische en toekomstige items hebt, kun je aan de hand van die aantallen bepalen op welke pagina je moet beginnen.

Die samengevoegde collection kun je vervolgens weer pagineren.
Ik heb hier nog eens even over nagedacht en met het implementeren van jouw voorstel werd mijn vermoeden bevestigd. Of ik begrijp je verkeerd.

In jouw geval moet ik dus de complete set van Absences ophalen uit de database, verdeeld over twee separate collections. Van beide complete collecties de lengte / aantal ophalen, eerdergenoemde berekeningen uitvoeren, dan die collecties weer samenvoegen en daarvan dan weer een Paginator bouwen.

Dat klinkt een stuk minder efficient en elegant dan een dubbele
SQL:
1
select count(*) as aggregate from `absences`


Nogmaals, of ik begrijp je compleet verkeerd of jouw voorstel is gewoon niet zo doordacht.

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • Beste antwoord
  • +1 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Je kunt toch gewoon een count doen op t aantal records die je wilt "skippen" op eerdere pagina's en uitrekenen op de hoeveelste pagina je zit adhv aantal items per pagina.

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 08:57

Matis

Rubber Rocket

Topicstarter
Cartman! schreef op donderdag 5 maart 2020 @ 21:12:
Je kunt toch gewoon een count doen op t aantal records die je wilt "skippen" op eerdere pagina's en uitrekenen op de hoeveelste pagina je zit adhv aantal items per pagina.
:o

Soms kan ik zo (onnodig) complex denken. Dit klinkt inderdaad zo eenvoudig dat ik het niet kon bedenken _/-\o_

Morgen even testen.

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Postman
  • Registratie: Februari 2000
  • Laatst online: 26-09 12:50
Maar ga je dan specifieke functies van Laravel gebruiken met deze oplossing (zoals je vraagt in zowel titel als TS), of is het een aparte SQL query die je implementeert?

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 08:57

Matis

Rubber Rocket

Topicstarter
Postman schreef op vrijdag 6 maart 2020 @ 00:37:
Maar ga je dan specifieke functies van Laravel gebruiken met deze oplossing (zoals je vraagt in zowel titel als TS), of is het een aparte SQL query die je implementeert?
Dat denk ik wel. Heb het zojuist op de volgende manier geïmplementeerd:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
    public function index(Request $request): Response
    {
        $absencesPerPage = Absence::PER_PAGE;
        $page = $request->input('page');
        if ($page === null) {
            $totalPastAbsences = Absence::where('end_date', '<=', Carbon::today())->count();
            $page = ceil($totalPastAbsences / $absencesPerPage);
        }
        $absences = Absence::with('user')->orderBy('start_date')->orderBy('id')
            ->paginate($absencesPerPage, ['*'], 'page', $page);

        return Response()->view('absence.index', compact('absences'));
    }

Dat resulteert in de volgende 4 unieke queries:
Afbeeldingslocatie: https://tweakers.net/i/kCBWW2V9_Oh7emtFYEmiqwx6ZGg=/f/image/WW2hn34Nze4ErPdas8V6x8pV.png

[ Voor 7% gewijzigd door Matis op 06-03-2020 11:52 ]

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Matis schreef op donderdag 5 maart 2020 @ 20:10:
[...]

Omdat dat niet de (klant)wens is :)
Weet je dat wel zeker :)

Het lijkt mij een heel aparte klantwens om maar op een (naar gevoel) "random" pagina uit te komen waar ergens op het scherm de 1e nieuwe absence staat (deze kan bovenaan, maar ook onderaan staan of in het midden)

Het komt op mij extreem raar over als interface...

Ik zou als interface gewoon 2 lijsten tonen :
- heden en toekomst
- verleden

Of als je het echt in 1 lijst wilt hebben dan een default begindatum van vandaag ingeven zodat je standaard is heden + toekomst (en men kan het verleden erbij halen door de begindatum aan te passen)
Ik zou nog maar even met de klant overleggen of die wel zeker weet dat die zo'n extreem aparte en onlogische interface wil hebben

Acties:
  • 0 Henk 'm!

  • Hiroj
  • Registratie: Mei 2010
  • Laatst online: 04-09 14:23
Gomez12 schreef op vrijdag 6 maart 2020 @ 13:20:
[...]

Weet je dat wel zeker :)

Het lijkt mij een heel aparte klantwens om maar op een (naar gevoel) "random" pagina uit te komen waar ergens op het scherm de 1e nieuwe absence staat (deze kan bovenaan, maar ook onderaan staan of in het midden)

Het komt op mij extreem raar over als interface...

Ik zou als interface gewoon 2 lijsten tonen :
- heden en toekomst
- verleden

Of als je het echt in 1 lijst wilt hebben dan een default begindatum van vandaag ingeven zodat je standaard is heden + toekomst (en men kan het verleden erbij halen door de begindatum aan te passen)
Ik zou nog maar even met de klant overleggen of die wel zeker weet dat die zo'n extreem aparte en onlogische interface wil hebben
Hier sluit ik mij dus volledig bij aan. Vandaar dat ik het ook suggereerde.
Uiteraard is het niet onbekend dat klanten soms de raarste wensen kunnen hebben.

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 08:57

Matis

Rubber Rocket

Topicstarter
Bedankt voor de ondersteuning om met de klant aan tafel te gaan, maar dit is juist naar hun wens zo gemaakt.

Dat staat overigens los van mijn eerdere vraag, maar die lijkt voor nu beantwoord.
Dank allemaal _/-\o_

If money talks then I'm a mime
If time is money then I'm out of time

Pagina: 1