Blame | Letzte Änderung | Log anzeigen | RSS feed
<?phpnamespace Illuminate\Pagination;use ArrayAccess;use Closure;use Exception;use Illuminate\Contracts\Support\Htmlable;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\Pivot;use Illuminate\Http\Resources\Json\JsonResource;use Illuminate\Support\Arr;use Illuminate\Support\Collection;use Illuminate\Support\Str;use Illuminate\Support\Traits\ForwardsCalls;use Illuminate\Support\Traits\Tappable;use Traversable;/*** @mixin \Illuminate\Support\Collection*/abstract class AbstractCursorPaginator implements Htmlable{use ForwardsCalls, Tappable;/*** All of the items being paginated.** @var \Illuminate\Support\Collection*/protected $items;/*** The number of items to be shown per page.** @var int*/protected $perPage;/*** The base path to assign to all URLs.** @var string*/protected $path = '/';/*** The query parameters to add to all URLs.** @var array*/protected $query = [];/*** The URL fragment to add to all URLs.** @var string|null*/protected $fragment;/*** The cursor string variable used to store the page.** @var string*/protected $cursorName = 'cursor';/*** The current cursor.** @var \Illuminate\Pagination\Cursor|null*/protected $cursor;/*** The paginator parameters for the cursor.** @var array*/protected $parameters;/*** The paginator options.** @var array*/protected $options;/*** The current cursor resolver callback.** @var \Closure*/protected static $currentCursorResolver;/*** Get the URL for a given cursor.** @param \Illuminate\Pagination\Cursor|null $cursor* @return string*/public function url($cursor){// If we have any extra query string key / value pairs that need to be added// onto the URL, we will put them in query string form and then attach it// to the URL. This allows for extra information like sortings storage.$parameters = is_null($cursor) ? [] : [$this->cursorName => $cursor->encode()];if (count($this->query) > 0) {$parameters = array_merge($this->query, $parameters);}return $this->path().(str_contains($this->path(), '?') ? '&' : '?').Arr::query($parameters).$this->buildFragment();}/*** Get the URL for the previous page.** @return string|null*/public function previousPageUrl(){if (is_null($previousCursor = $this->previousCursor())) {return null;}return $this->url($previousCursor);}/*** The URL for the next page, or null.** @return string|null*/public function nextPageUrl(){if (is_null($nextCursor = $this->nextCursor())) {return null;}return $this->url($nextCursor);}/*** Get the "cursor" that points to the previous set of items.** @return \Illuminate\Pagination\Cursor|null*/public function previousCursor(){if (is_null($this->cursor) ||($this->cursor->pointsToPreviousItems() && ! $this->hasMore)) {return null;}if ($this->items->isEmpty()) {return null;}return $this->getCursorForItem($this->items->first(), false);}/*** Get the "cursor" that points to the next set of items.** @return \Illuminate\Pagination\Cursor|null*/public function nextCursor(){if ((is_null($this->cursor) && ! $this->hasMore) ||(! is_null($this->cursor) && $this->cursor->pointsToNextItems() && ! $this->hasMore)) {return null;}if ($this->items->isEmpty()) {return null;}return $this->getCursorForItem($this->items->last(), true);}/*** Get a cursor instance for the given item.** @param \ArrayAccess|\stdClass $item* @param bool $isNext* @return \Illuminate\Pagination\Cursor*/public function getCursorForItem($item, $isNext = true){return new Cursor($this->getParametersForItem($item), $isNext);}/*** Get the cursor parameters for a given object.** @param \ArrayAccess|\stdClass $item* @return array** @throws \Exception*/public function getParametersForItem($item){return collect($this->parameters)->flip()->map(function ($_, $parameterName) use ($item) {if ($item instanceof JsonResource) {$item = $item->resource;}if ($item instanceof Model &&! is_null($parameter = $this->getPivotParameterForItem($item, $parameterName))) {return $parameter;} elseif ($item instanceof ArrayAccess || is_array($item)) {return $this->ensureParameterIsPrimitive($item[$parameterName] ?? $item[Str::afterLast($parameterName, '.')]);} elseif (is_object($item)) {return $this->ensureParameterIsPrimitive($item->{$parameterName} ?? $item->{Str::afterLast($parameterName, '.')});}throw new Exception('Only arrays and objects are supported when cursor paginating items.');})->toArray();}/*** Get the cursor parameter value from a pivot model if applicable.** @param \ArrayAccess|\stdClass $item* @param string $parameterName* @return string|null*/protected function getPivotParameterForItem($item, $parameterName){$table = Str::beforeLast($parameterName, '.');foreach ($item->getRelations() as $relation) {if ($relation instanceof Pivot && $relation->getTable() === $table) {return $this->ensureParameterIsPrimitive($relation->getAttribute(Str::afterLast($parameterName, '.')));}}}/*** Ensure the parameter is a primitive type.** This can resolve issues that arise the developer uses a value object for an attribute.** @param mixed $parameter* @return mixed*/protected function ensureParameterIsPrimitive($parameter){return is_object($parameter) && method_exists($parameter, '__toString')? (string) $parameter: $parameter;}/*** Get / set the URL fragment to be appended to URLs.** @param string|null $fragment* @return $this|string|null*/public function fragment($fragment = null){if (is_null($fragment)) {return $this->fragment;}$this->fragment = $fragment;return $this;}/*** Add a set of query string values to the paginator.** @param array|string|null $key* @param string|null $value* @return $this*/public function appends($key, $value = null){if (is_null($key)) {return $this;}if (is_array($key)) {return $this->appendArray($key);}return $this->addQuery($key, $value);}/*** Add an array of query string values.** @param array $keys* @return $this*/protected function appendArray(array $keys){foreach ($keys as $key => $value) {$this->addQuery($key, $value);}return $this;}/*** Add all current query string values to the paginator.** @return $this*/public function withQueryString(){if (! is_null($query = Paginator::resolveQueryString())) {return $this->appends($query);}return $this;}/*** Add a query string value to the paginator.** @param string $key* @param string $value* @return $this*/protected function addQuery($key, $value){if ($key !== $this->cursorName) {$this->query[$key] = $value;}return $this;}/*** Build the full fragment portion of a URL.** @return string*/protected function buildFragment(){return $this->fragment ? '#'.$this->fragment : '';}/*** Load a set of relationships onto the mixed relationship collection.** @param string $relation* @param array $relations* @return $this*/public function loadMorph($relation, $relations){$this->getCollection()->loadMorph($relation, $relations);return $this;}/*** Load a set of relationship counts onto the mixed relationship collection.** @param string $relation* @param array $relations* @return $this*/public function loadMorphCount($relation, $relations){$this->getCollection()->loadMorphCount($relation, $relations);return $this;}/*** Get the slice of items being paginated.** @return array*/public function items(){return $this->items->all();}/*** Transform each item in the slice of items using a callback.** @param callable $callback* @return $this*/public function through(callable $callback){$this->items->transform($callback);return $this;}/*** Get the number of items shown per page.** @return int*/public function perPage(){return $this->perPage;}/*** Get the current cursor being paginated.** @return \Illuminate\Pagination\Cursor|null*/public function cursor(){return $this->cursor;}/*** Get the query string variable used to store the cursor.** @return string*/public function getCursorName(){return $this->cursorName;}/*** Set the query string variable used to store the cursor.** @param string $name* @return $this*/public function setCursorName($name){$this->cursorName = $name;return $this;}/*** Set the base path to assign to all URLs.** @param string $path* @return $this*/public function withPath($path){return $this->setPath($path);}/*** Set the base path to assign to all URLs.** @param string $path* @return $this*/public function setPath($path){$this->path = $path;return $this;}/*** Get the base path for paginator generated URLs.** @return string|null*/public function path(){return $this->path;}/*** Resolve the current cursor or return the default value.** @param string $cursorName* @return \Illuminate\Pagination\Cursor|null*/public static function resolveCurrentCursor($cursorName = 'cursor', $default = null){if (isset(static::$currentCursorResolver)) {return call_user_func(static::$currentCursorResolver, $cursorName);}return $default;}/*** Set the current cursor resolver callback.** @param \Closure $resolver* @return void*/public static function currentCursorResolver(Closure $resolver){static::$currentCursorResolver = $resolver;}/*** Get an instance of the view factory from the resolver.** @return \Illuminate\Contracts\View\Factory*/public static function viewFactory(){return Paginator::viewFactory();}/*** Get an iterator for the items.** @return \ArrayIterator*/public function getIterator(): Traversable{return $this->items->getIterator();}/*** Determine if the list of items is empty.** @return bool*/public function isEmpty(){return $this->items->isEmpty();}/*** Determine if the list of items is not empty.** @return bool*/public function isNotEmpty(){return $this->items->isNotEmpty();}/*** Get the number of items for the current page.** @return int*/public function count(): int{return $this->items->count();}/*** Get the paginator's underlying collection.** @return \Illuminate\Support\Collection*/public function getCollection(){return $this->items;}/*** Set the paginator's underlying collection.** @param \Illuminate\Support\Collection $collection* @return $this*/public function setCollection(Collection $collection){$this->items = $collection;return $this;}/*** Get the paginator options.** @return array*/public function getOptions(){return $this->options;}/*** Determine if the given item exists.** @param mixed $key* @return bool*/public function offsetExists($key): bool{return $this->items->has($key);}/*** Get the item at the given offset.** @param mixed $key* @return mixed*/public function offsetGet($key): mixed{return $this->items->get($key);}/*** Set the item at the given offset.** @param mixed $key* @param mixed $value* @return void*/public function offsetSet($key, $value): void{$this->items->put($key, $value);}/*** Unset the item at the given key.** @param mixed $key* @return void*/public function offsetUnset($key): void{$this->items->forget($key);}/*** Render the contents of the paginator to HTML.** @return string*/public function toHtml(){return (string) $this->render();}/*** Make dynamic calls into the collection.** @param string $method* @param array $parameters* @return mixed*/public function __call($method, $parameters){return $this->forwardCallTo($this->getCollection(), $method, $parameters);}/*** Render the contents of the paginator when casting to a string.** @return string*/public function __toString(){return (string) $this->render();}}