-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #814 from hydephp/add-pagination-feature-to-public…
…ations Add pagination feature to publications
- Loading branch information
Showing
8 changed files
with
665 additions
and
1 deletion.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
packages/framework/resources/views/components/publications/pagination-navigation.blade.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
@php/** @var \Hyde\Framework\Features\Publications\Paginator $paginator */@endphp | ||
<nav class="flex justify-between mt-4"> | ||
@if($paginator->previous()) | ||
<x-link :href="$paginator->previous()">Prev</x-link> | ||
@else | ||
<span class="opacity-75">Prev</span> | ||
@endif | ||
|
||
<div> | ||
@foreach($paginator->getPageLinks() as $pageNumber => $destination) | ||
@if($paginator->currentPage() === $pageNumber) | ||
<strong>{{ $pageNumber }}</strong> | ||
@else | ||
<x-link :href="$destination">{{ $pageNumber }}</x-link> | ||
@endif | ||
@endforeach | ||
</div> | ||
|
||
@if($paginator->next()) | ||
<x-link :href="$paginator->next()">Next</x-link> | ||
@else | ||
<span class="opacity-75">Next</span> | ||
@endif | ||
</nav> |
3 changes: 2 additions & 1 deletion
3
packages/framework/resources/views/layouts/publication_list.blade.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
packages/framework/resources/views/layouts/publication_paginated_list.blade.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
@php/** @var \Hyde\Framework\Features\Publications\Models\PublicationType $publicationType*/@endphp | ||
@php | ||
$paginator = $publicationType->getPaginator($page->matter('paginatorPage')); | ||
@endphp | ||
@extends('hyde::layouts.app') | ||
@section('content') | ||
<main id="content" class="mx-auto max-w-7xl py-16 px-8"> | ||
<div class="prose dark:prose-invert"> | ||
<h1>Publications for type {{ $publicationType->name }}</h1> | ||
|
||
<ol start="{{ $paginator->firstItemNumberOnPage() }}"> | ||
@foreach($paginator->getItemsForPage() as $publication) | ||
<li> | ||
<x-link :href="$publication->getRoute()">{{ $publication->title }}</x-link> | ||
</li> | ||
@endforeach | ||
</ol> | ||
|
||
@include('hyde::components.publications.pagination-navigation') | ||
</div> | ||
</main> | ||
@endsection |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
210 changes: 210 additions & 0 deletions
210
packages/framework/src/Framework/Features/Publications/Paginator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Hyde\Framework\Features\Publications; | ||
|
||
use function collect; | ||
use Hyde\Hyde; | ||
use Hyde\Support\Models\Route; | ||
use Illuminate\Contracts\Support\Arrayable; | ||
use Illuminate\Support\Collection; | ||
use InvalidArgumentException; | ||
use function range; | ||
use function sprintf; | ||
|
||
/** | ||
* @see \Hyde\Framework\Testing\Feature\PaginatorTest | ||
*/ | ||
class Paginator | ||
{ | ||
protected Collection $paginatedItems; | ||
|
||
protected int $pageSize = 25; | ||
protected int $currentPage = 1; | ||
|
||
/** | ||
* Optionally provide a route basename to be used in generating the pagination links. | ||
*/ | ||
protected string $routeBasename; | ||
|
||
public function __construct(Arrayable|array $items = [], int $pageSize = 25, int $currentPageNumber = null, string $paginationRouteBasename = null) | ||
{ | ||
$this->pageSize = $pageSize; | ||
|
||
$this->generate(collect($items)); | ||
|
||
if ($currentPageNumber) { | ||
$this->setCurrentPage($currentPageNumber); | ||
} | ||
|
||
if ($paginationRouteBasename) { | ||
$this->routeBasename = $paginationRouteBasename; | ||
} | ||
} | ||
|
||
protected function generate(Collection $items): void | ||
{ | ||
$this->paginatedItems = $items->chunk($this->perPage()); | ||
} | ||
|
||
/** Set the current page number. */ | ||
public function setCurrentPage(int $currentPage): Paginator | ||
{ | ||
$this->validateCurrentPageValue($currentPage); | ||
|
||
$this->currentPage = $currentPage; | ||
|
||
return $this; | ||
} | ||
|
||
/** Get the current page number (which is used as a cursor). */ | ||
public function currentPage(): int | ||
{ | ||
return $this->currentPage; | ||
} | ||
|
||
/** Get the paginated collection */ | ||
public function getPaginatedItems(): Collection | ||
{ | ||
return $this->paginatedItems; | ||
} | ||
|
||
public function getItemsForPage(): Collection | ||
{ | ||
return $this->paginatedItems->get($this->currentPage - 1); | ||
} | ||
|
||
public function getPageLinks(): array | ||
{ | ||
$array = []; | ||
$pageRange = range(1, $this->totalPages()); | ||
if ($this->routeBasename) { | ||
foreach ($pageRange as $number) { | ||
$array[$number] = Route::getOrFail("$this->routeBasename/page-$number"); | ||
} | ||
} else { | ||
foreach ($pageRange as $number) { | ||
$array[$number] = Hyde::formatLink("page-$number.html"); | ||
} | ||
} | ||
|
||
return $array; | ||
} | ||
|
||
/** The number of items to be shown per page. */ | ||
public function perPage(): int | ||
{ | ||
return $this->pageSize; | ||
} | ||
|
||
/** Get the total number of pages. */ | ||
public function totalPages(): int | ||
{ | ||
return $this->paginatedItems->count(); | ||
} | ||
|
||
/** Determine if there are enough items to split into multiple pages. */ | ||
public function hasMultiplePages(): bool | ||
{ | ||
return $this->totalPages() > 1; | ||
} | ||
|
||
/** Get the page number of the last available page. */ | ||
public function lastPage(): int | ||
{ | ||
return $this->totalPages(); | ||
} | ||
|
||
/** Determine if there are fewer items after the cursor in the data store. */ | ||
public function canNavigateBack(): bool | ||
{ | ||
return $this->currentPage > $this->firstPage(); | ||
} | ||
|
||
/** Determine if there are more items after the cursor in the data store. */ | ||
public function canNavigateForward(): bool | ||
{ | ||
return $this->currentPage < $this->lastPage(); | ||
} | ||
|
||
public function previousPageNumber(): false|int | ||
{ | ||
if (! $this->canNavigateBack()) { | ||
return false; | ||
} | ||
|
||
return $this->currentPage - 1; | ||
} | ||
|
||
public function nextPageNumber(): false|int | ||
{ | ||
if (! $this->canNavigateForward()) { | ||
return false; | ||
} | ||
|
||
return $this->currentPage + 1; | ||
} | ||
|
||
public function previous(): false|string|Route | ||
{ | ||
if (! $this->canNavigateBack()) { | ||
return false; | ||
} | ||
|
||
if (! isset($this->routeBasename)) { | ||
return $this->formatLink(-1); | ||
} | ||
|
||
return $this->getRoute(-1); | ||
} | ||
|
||
public function next(): false|string|Route | ||
{ | ||
if (! $this->canNavigateForward()) { | ||
return false; | ||
} | ||
|
||
if (! isset($this->routeBasename)) { | ||
return $this->formatLink(+1); | ||
} | ||
|
||
return $this->getRoute(+1); | ||
} | ||
|
||
public function firstItemNumberOnPage(): int | ||
{ | ||
return (($this->currentPage - 1) * $this->perPage()) + 1; | ||
} | ||
|
||
protected function validateCurrentPageValue(int $currentPage): void | ||
{ | ||
if ($currentPage < $this->firstPage()) { | ||
throw new InvalidArgumentException('Current page number must be greater than 0.'); | ||
} | ||
|
||
if ($currentPage > $this->lastPage()) { | ||
throw new InvalidArgumentException('Current page number must be less than or equal to the last page number.'); | ||
} | ||
} | ||
|
||
protected function formatPageName(int $offset): string | ||
{ | ||
return sprintf('page-%d', $this->currentPage + $offset); | ||
} | ||
|
||
protected function formatLink(int $offset): string | ||
{ | ||
return Hyde::formatLink("{$this->formatPageName($offset)}.html"); | ||
} | ||
|
||
protected function getRoute(int $offset): ?Route | ||
{ | ||
return Route::get("$this->routeBasename/{$this->formatPageName($offset)}"); | ||
} | ||
|
||
protected function firstPage(): int | ||
{ | ||
return 1; | ||
} | ||
} |
Oops, something went wrong.