Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: bug of extra first & last page showing up in small data set. #56

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# 0.8.5

* build: Symfony 7.1 compatibility
* fix: bug of extra first & last page showing up in small data set.

# 0.8.4

Expand Down
66 changes: 41 additions & 25 deletions packages/rekapager-core/src/Pager/Internal/ProximityPager.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,23 +88,43 @@ public function __construct(
$this->lastPage = $this->decorate($lastPage->withPageNumber(null));
}

// check previous pages
// preps

if ($currentIsFirstPage) {
$previousPages = [];
} else {
$previousPages = $currentPage->getPreviousPages($this->proximity * 2);
$previousPages = $currentPage->getPreviousPages($this->proximity * 2 + 2);
}

$nextPages = $currentPage->getNextPages($this->proximity * 2 + 2);

// calculate the number of neighboring pages to show

$previousPagesCount = \count($previousPages);
$nextPagesCount = \count($nextPages);

$neighboringPreviousPagesCount = min($previousPagesCount, $this->proximity);
$neighboringNextPagesCount = min($nextPagesCount, $this->proximity);

if ($neighboringPreviousPagesCount < $this->proximity) {
$neighboringNextPagesCount += $this->proximity - $neighboringPreviousPagesCount;
}

if ($neighboringNextPagesCount < $this->proximity) {
$neighboringPreviousPagesCount += $this->proximity - $neighboringNextPagesCount;
}

if (\count($previousPages) >= $this->proximity + 2) {
// check previous pages

if ($previousPagesCount >= $neighboringPreviousPagesCount + 2) {
$currentIsFirstPage = false;
$firstIsFirstPage = false;
$hasGapToFirstPage = true;
} elseif (\count($previousPages) === $this->proximity + 1) {
} elseif ($previousPagesCount === $neighboringPreviousPagesCount + 1) {
$currentIsFirstPage = false;
$firstIsFirstPage = false;
$hasGapToFirstPage = false;
} elseif (\count($previousPages) === 0) {
} elseif ($previousPagesCount === 0) {
$currentIsFirstPage = true;
$firstIsFirstPage = false;
$hasGapToFirstPage = false;
Expand All @@ -116,17 +136,15 @@ public function __construct(

// check next pages

$nextPages = $currentPage->getNextPages($this->proximity * 2);

if (\count($nextPages) >= $this->proximity + 2) {
if ($nextPagesCount >= $neighboringNextPagesCount + 2) {
$currentIsLastPage = false;
$lastIsLastPage = false;
$hasGapToLastPage = true;
} elseif (\count($nextPages) === $this->proximity + 1) {
} elseif ($nextPagesCount === $neighboringNextPagesCount + 1) {
$currentIsLastPage = false;
$lastIsLastPage = false;
$hasGapToLastPage = false;
} elseif (\count($nextPages) === 0) {
} elseif ($nextPagesCount === 0) {
$currentIsLastPage = true;
$lastIsLastPage = false;
$hasGapToLastPage = false;
Expand All @@ -136,22 +154,9 @@ public function __construct(
$hasGapToLastPage = false;
}

// calculate the number of neighboring pages to show

$previousPagesCount = min(\count($previousPages), $this->proximity);
$nextPagesCount = min(\count($nextPages), $this->proximity);

if ($previousPagesCount < $this->proximity) {
$nextPagesCount += $this->proximity - $previousPagesCount;
}

if ($nextPagesCount < $this->proximity) {
$previousPagesCount += $this->proximity - $nextPagesCount;
}

// add previous pages

foreach (range(0, $previousPagesCount - 1) as $i) {
foreach (range(0, $neighboringPreviousPagesCount - 1) as $i) {
$page = array_pop($previousPages);

if ($page === null) {
Expand All @@ -163,7 +168,7 @@ public function __construct(

// add next pages

foreach (range(0, $nextPagesCount - 1) as $i) {
foreach (range(0, $neighboringNextPagesCount - 1) as $i) {
$page = array_shift($nextPages);

if ($page === null) {
Expand Down Expand Up @@ -196,6 +201,14 @@ public function __construct(
$this->hasHiddenPagesBefore = true;
}

// if first page in the previous neighboring pages is the first page,
// then remove it

$firstInPreviousPages = reset($this->previousNeighboringPages) ?: null;
if ($firstInPreviousPages?->getPageNumber() === 1) {
array_shift($this->previousNeighboringPages);
}

// append last page

if ($currentIsLastPage) {
Expand All @@ -205,6 +218,9 @@ public function __construct(
// page from the next neighboring pages, and set it as the last page
$lastPage = array_pop($this->nextNeighboringPages);
$this->lastPage = $lastPage;
// } elseif (!$lastIsLastPage && !$hasGapToLastPage) {
// $lastPage = array_pop($this->nextNeighboringPages);
// $this->lastPage = $lastPage;
} else {
if ($hasGapToLastPage) {
$this->hasHiddenPagesAfter = true;
Expand Down
1 change: 1 addition & 0 deletions tests/src/App/Form/PagerParametersType.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
])
->add('itemsPerPage', ChoiceType::class, [
'choices' => [
'3' => 3,
'5' => 5,
'10' => 10,
'20' => 20,
Expand Down
137 changes: 137 additions & 0 deletions tests/src/IntegrationTests/Pager/KeysetPagerSmallDatasetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

declare(strict_types=1);

/*
* This file is part of rekalogika/rekapager package.
*
* (c) Priyadi Iman Nurcahyo <https://rekalogika.dev>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

namespace Rekalogika\Rekapager\Tests\IntegrationTests\Pager;

use PHPUnit\Framework\Attributes\DataProviderExternal;
use Rekalogika\Rekapager\Tests\IntegrationTests\DataProvider\PageableGeneratorProvider;

class KeysetPagerSmallDatasetTest extends PagerTestCase
{
public function getItemsPerPage(): int
{
return 3;
}

public function getSetName(): string
{
return 'small';
}

#[DataProviderExternal(PageableGeneratorProvider::class, 'keyset')]
public function testFirstPage(string $pageableGeneratorClass): void
{
$pageable = $this->createPageableFromGenerator($pageableGeneratorClass);
$pager = $this->createPagerFromPageable($pageable);

$this->assertPager(
$pager,
proximity: 2,
hasPrevious: false,
hasNext: true,
hasFirst: false,
hasLast: true,
hasGapToFirstPage: false,
hasGapToLastPage: false,
numOfPreviousNeighboringPages: 0,
numOfNextNeighboringPages: 2,
firstPageNumber: null,
lastPageNumber: 4,
currentPageNumber: 1,
previousPageNumbers: [],
nextPageNumbers: [2, 3],
currentCount: 3,
);
}

#[DataProviderExternal(PageableGeneratorProvider::class, 'keyset')]
public function testSecondPage(string $pageableGeneratorClass): void
{
$pageable = $this->createPageableFromGenerator($pageableGeneratorClass);
$page = $this->getNthPageFromBeginning($pageable, 2);
$pager = $this->createPagerFromPage($page);

$this->assertPager(
$pager,
proximity: 2,
hasPrevious: true,
hasNext: true,
hasFirst: true,
hasLast: true,
hasGapToFirstPage: false,
hasGapToLastPage: false,
numOfPreviousNeighboringPages: 0,
numOfNextNeighboringPages: 1,
firstPageNumber: 1,
lastPageNumber: 4,
currentPageNumber: 2,
previousPageNumbers: [],
nextPageNumbers: [3],
currentCount: 3,
);
}

#[DataProviderExternal(PageableGeneratorProvider::class, 'keyset')]
public function testThirdPage(string $pageableGeneratorClass): void
{
$pageable = $this->createPageableFromGenerator($pageableGeneratorClass);
$page = $this->getNthPageFromBeginning($pageable, 3);
$pager = $this->createPagerFromPage($page);

$this->assertPager(
$pager,
proximity: 2,
hasPrevious: true,
hasNext: true,
hasFirst: true,
hasLast: true,
hasGapToFirstPage: false,
hasGapToLastPage: false,
numOfPreviousNeighboringPages: 1,
numOfNextNeighboringPages: 0,
firstPageNumber: 1,
lastPageNumber: 4,
currentPageNumber: 3,
previousPageNumbers: [2],
nextPageNumbers: [],
currentCount: 3,
);
}

#[DataProviderExternal(PageableGeneratorProvider::class, 'keyset')]
public function testFourthPage(string $pageableGeneratorClass): void
{
$pageable = $this->createPageableFromGenerator($pageableGeneratorClass);
$page = $this->getNthPageFromBeginning($pageable, 4);
$pager = $this->createPagerFromPage($page);

$this->assertPager(
$pager,
proximity: 2,
hasPrevious: true,
hasNext: false,
hasFirst: true,
hasLast: false,
hasGapToFirstPage: false,
hasGapToLastPage: false,
numOfPreviousNeighboringPages: 2,
numOfNextNeighboringPages: 0,
firstPageNumber: 1,
lastPageNumber: null,
currentPageNumber: 4,
previousPageNumbers: [2, 3],
nextPageNumbers: [],
currentCount: 1,
);
}
}
Loading