Created
June 18, 2019 08:45
-
-
Save davzie/9989780850e06e7de5bf81622d9abc4b to your computer and use it in GitHub Desktop.
Eloquent / Fractal Pagination Station
This file contains hidden or 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
<?php | |
namespace App\Pagination; | |
use Illuminate\Database\Eloquent\Builder; | |
use League\Fractal\TransformerAbstract; | |
class EloquentPaginationStation extends PaginationStation | |
{ | |
/** | |
* @param TransformerAbstract $transformerAbstract - The transformer for the collection, should already be | |
* instantiated | |
* @param Builder $builderWithoutLimits - The Eloquent Query Builder | |
* @param string $rootScope - The Root URL For The Current Endpoint (ex: | |
* route('api.v1.threads.list') ) | |
* @param array $meta | |
* | |
* @return array | |
*/ | |
public function returnCollection( | |
TransformerAbstract $transformerAbstract, | |
Builder $builderWithoutLimits, | |
$rootScope, | |
$meta = [] | |
) | |
{ | |
if ($this->paginationShouldBeSkipped()) { | |
$totalBuilder = clone $builderWithoutLimits; | |
$results = $builderWithoutLimits->get(); | |
} else { | |
$totalBuilder = clone $builderWithoutLimits; | |
$results = $builderWithoutLimits->offset($this->getOffsetFromRequest())->take($this->getLimitFromRequest())->get(); | |
} | |
$resultSetCount = $results->count(); | |
return fractal() | |
->collection($results) | |
->addMeta(['pagination' => $this->getEloquentPaginationArray($totalBuilder, $resultSetCount, $rootScope)] + $meta) | |
->transformWith($transformerAbstract) | |
->toArray(); | |
} | |
/** | |
* @param Builder $builderWithoutLimits - The Eloquent Query Builder | |
* @param int $resultSetCount - The amount of results in this set | |
* @param string $rootScope - The Root URL For The Current Endpoint (ex: route('api.v1.threads.list') | |
* ) | |
* | |
* @return array | |
*/ | |
public function getEloquentPaginationArray(Builder $builderWithoutLimits, $resultSetCount, $rootScope) | |
{ | |
$totalCount = $builderWithoutLimits->count(); | |
return parent::getPaginationArray($totalCount, $resultSetCount, $rootScope); | |
} | |
} |
This file contains hidden or 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
<?php | |
namespace App\Pagination; | |
use Illuminate\Http\Request; | |
class PaginationStation | |
{ | |
protected $defaultLimit = 80; | |
protected $maxLimit = 300; | |
/** | |
* The request object. | |
* | |
* @var Request | |
*/ | |
protected $request; | |
protected $excludableParams = [ | |
'filters' | |
]; | |
/** | |
* PaginationStation constructor. | |
* | |
* @param Request $request | |
*/ | |
public function __construct(Request $request) | |
{ | |
$this->request = $request; | |
} | |
protected function paginationShouldBeSkipped(): bool | |
{ | |
$paramsThatTriggerPaginationDisable = ['gimmeAllYouGot', 'show_all']; | |
foreach ($paramsThatTriggerPaginationDisable as $param) { | |
if ($this->request->has($param)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* @param int $totalCount - The amount of items in the total result-set | |
* @param int $pageCount - The amount of items in the current result-set | |
* @param string $rootScope - The Root URL For The Current Endpoint (ex: route('api.v1.contacts.index') ) | |
* | |
* @return array | |
*/ | |
public function getPaginationArray($totalCount, $pageCount, $rootScope) | |
{ | |
if ($this->paginationShouldBeSkipped()) { | |
$limit = $totalCount; | |
$offset = 0; | |
$pageCount = $totalCount; | |
$this->defaultLimit = $totalCount; | |
$this->maxLimit = $totalCount; | |
$last_link = null; | |
$next_link = null; | |
$previous_link = null; | |
$totalPages = 1; | |
$thisPage = 1; | |
} else { | |
$limit = $this->getLimitFromRequest(); | |
$offset = $this->getOffsetFromRequest(); | |
$last_link = $this->buildUrl($rootScope, ['offset' => $this->getLast($totalCount)]); | |
$next_link = $this->buildUrl($rootScope, ['offset' => $this->getNext($totalCount)]); | |
$previous_link = $this->buildUrl($rootScope, ['offset' => $this->getNext($totalCount)]); | |
$totalPages = $this->getTotalPages($totalCount); | |
$thisPage = $this->getThisPage($totalCount); | |
} | |
$paginationBlock = [ | |
'total' => $totalCount, | |
'this_page' => $pageCount, | |
'per_page' => $limit, | |
'offset' => $offset, | |
'page_numbers' => [ | |
'total_pages' => $totalPages, | |
'this_page' => $thisPage, | |
], | |
'_links' => [ | |
'first' => $this->buildUrl($rootScope, ['offset' => 0]), | |
'last' => $last_link, | |
'next' => $next_link, | |
'previous' => $previous_link, | |
], | |
]; | |
return $paginationBlock; | |
} | |
protected function getLimitFromRequest() | |
{ | |
return $this->getLimit($this->request->only('limit')); | |
} | |
protected function getLimit(array $data) | |
{ | |
if (!isset($data['limit']) || (int)$data['limit'] > $this->maxLimit || (int)$data['limit'] < 1) { | |
return $this->defaultLimit; | |
} | |
return (int)$data['limit']; | |
} | |
protected function getOffsetFromRequest() | |
{ | |
return $this->getOffset($this->request->only('offset')); | |
} | |
protected function getOffset(array $data) | |
{ | |
if (!isset($data['offset']) || (int)$data['offset'] < 1) { | |
return 0; | |
} | |
return (int)$data['offset']; | |
} | |
protected function getTotalPages($totalCount) | |
{ | |
if ($this->paginationShouldBeSkipped()) { | |
return 1; | |
} | |
$limit = $this->getLimit($this->request->only('limit')); | |
$pagesPossible = ($totalCount / $limit); | |
if (floor($pagesPossible) != $pagesPossible) { | |
$pagesPossible = ceil($pagesPossible); | |
} | |
return (int)($pagesPossible); | |
} | |
protected function getThisPage($totalCount) | |
{ | |
$limit = $this->getLimit($this->request->only('limit')); | |
$offset = $this->getOffset($this->request->only('offset')); | |
if (!$offset) { | |
return 1; | |
} | |
$currentPageNumber = floor($offset / $limit) + 1; | |
$totalPages = $this->getTotalPages($totalCount); | |
return $currentPageNumber >= $totalPages ? $totalPages : $currentPageNumber; | |
} | |
protected function buildUrl($rootScope, $overriding = []) | |
{ | |
$getParams = array_merge($this->request->except($this->excludableParams), $overriding); | |
$rootScope = $rootScope . '?'; | |
foreach ($getParams as $key => $val) { | |
if ($key == 'offset' && is_null($val)) { | |
return; | |
} | |
if ($key == 'offset' && $val < 1) { | |
continue; | |
} | |
$rootScope = $rootScope . $key . '=' . $val . '&'; | |
} | |
return trim(trim($rootScope, '&'), '?'); | |
} | |
protected function getLast($totalCount) | |
{ | |
$limit = $this->getLimit($this->request->only('limit')); | |
$lastOffsetMultiplier = ($totalCount / $limit); | |
if ($lastOffsetMultiplier < 1) { | |
return 0; | |
} | |
if (floor($lastOffsetMultiplier) != $lastOffsetMultiplier) { | |
$lastOffsetMultiplier = floor($lastOffsetMultiplier); | |
} | |
return (int)($limit * $lastOffsetMultiplier); | |
} | |
protected function getNext($totalCount) | |
{ | |
$limit = $this->getLimit($this->request->only('limit')); | |
$offset = $this->getOffset($this->request->only('offset')); | |
$newOffset = $offset + $limit; | |
if ($newOffset > $totalCount) { | |
return; | |
} | |
if ($newOffset > $this->getLast($totalCount)) { | |
return $this->getLast($totalCount); | |
} | |
return $newOffset; | |
} | |
protected function getPrevious($totalCount) | |
{ | |
$limit = $this->getLimit($this->request->only('limit')); | |
$offset = $this->getOffset($this->request->only('offset')); | |
$newOffset = $offset - $limit; | |
if ($newOffset < 0) { | |
return; | |
} | |
if ($newOffset > $this->getLast($totalCount)) { | |
return $this->getLast($totalCount); | |
} | |
return $newOffset; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment