items be treated as Models? # In this case, <$array> should be in the form of array(, "ModelName") public $model; # Integer: $total # Total number of items to paginate. public $total; # Integer: $page # The current page. public $page; # Integer: $pages # Total number of pages. public $pages; # Array: $result # The result of the pagination. # @paginated@ is a reference to this. public $result = array(); # Array: $paginated # The result of the pagination. # Reference to @result@. Enables ".paginated" in Twig. public $paginated = array(); # Array: $names # An array of the currently-used pagination URL parameters. public static $names = array(); /** * Function: __construct * Prepares an array for pagination. * * Parameters: * $array - The array to paginate. * $per_page - Number of items per page. * $name - The $_GET parameter name to determin the current page. * $model - Is it an array of model placeholders to be initialized? * $page - Page number to start at. * * Notes: * If $model is true, each $array item shown on the page will * be initialized as a model of the type specified in $array[1]. * $array[0] is expected to be an array of model placeholders. */ public function __construct( $array, $per_page = 10, $name = "page", $model = null, $page = null ) { self::$names[] = $name; if (!is_array($array)) $array = array($array); $this->array = $array; $this->per_page = $per_page; $this->name = $name; $this->model = fallback( $model, ( count($this->array) == 2 and is_array($this->array[0]) and is_string($this->array[1]) and class_exists($this->array[1]) ) ); if ($model) list($array, $model_name) = $this->array; $request = (isset($_GET[$name]) and is_numeric($_GET[$name])) ? $_GET[$name] : null ; $this->total = count($array); $this->page = intval(oneof($page, $request, 1)); $this->pages = ceil($this->total / $this->per_page); $this->result = array(); if ($this->page < 1) $this->page = 1; $offset = ($this->page - 1) * $this->per_page; if ($model) { for ($i = $offset; $i < ($offset + $this->per_page); $i++) { if (isset($array[$i])) $this->result[] = new $model_name( null, array("read_from" => $array[$i]) ); } } else { $this->result = array_slice( $array, $offset, $this->per_page ); } $this->paginated =& $this->result; } /** * Function: reslice * Reslices pagination with a new number of items per page. * * Parameters: * $per_page - Number of items per page. */ public function reslice($per_page): self { return new self( $this->array, $per_page, $this->name, $this->model, $this->page ); } /** * Function: next * Returns the next pagination sequence. */ public function next(): self { return new self( $this->array, $this->per_page, $this->name, $this->model, $this->page + 1 ); } /** * Function: prev * Returns the previous pagination sequence. */ public function prev(): self { return new self( $this->array, $this->per_page, $this->name, $this->model, $this->page - 1 ); } /** * Function: next_page * Checks whether or not it makes sense to show the Next Page link. */ public function next_page(): bool { return ( $this->pages > 1 and $this->page < $this->pages ); } /** * Function: prev_page * Checks whether or not it makes sense to show the Previous Page link. */ public function prev_page(): bool { return ( $this->page > 1 and $this->page <= $this->pages ); } /** * Function: next_link * Outputs a link to the next page. * * Parameters: * $text - The text for the link. * $class - The CSS class for the link. * $page - Page number to link to. * $anchor - An anchor target. */ public function next_link( $text = null, $class = "next_page", $page = null, $anchor = "" ): ?string { if (!$this->next_page()) return null; if (!empty($anchor)) $anchor = '#'.$anchor; fallback($text, __("Next")); return ''; } /** * Function: prev_link * Outputs a link to the previous page. * * Parameters: * $text - The text for the link. * $class - The CSS class for the link. * $page - Page number to link to. * $anchor - An anchor target. */ public function prev_link( $text = null, $class = "prev_page", $page = null, $anchor = "" ): ?string { if (!$this->prev_page()) return null; if (!empty($anchor)) $anchor = '#'.$anchor; fallback($text, __("Previous")); return ''; } /** * Function: final_link * Outputs a link to the final page. * * Parameters: * $text - The text for the link. * $class - The CSS class for the link. * $anchor - An anchor target. */ public function final_link( $text = null, $class = "final_page", $anchor = "" ): ?string { if (!$this->pages) return null; if (!empty($anchor)) $anchor = '#'.$anchor; fallback($text, __("Final")); return ''; } /** * Function: first_link * Outputs a link to the first page. * * Parameters: * $text - The text for the link. * $class - The CSS class for the link. * $anchor - An anchor target. */ public function first_link( $text = null, $class = "first_page", $anchor = "" ): ?string { if (!$this->pages) return null; if (!empty($anchor)) $anchor = '#'.$anchor; fallback($text, __("First")); return ''; } /** * Function: next_page_url * Returns the URL to the next page. * * Parameters: * $page - Page number to link to. */ public function next_page_url($page = null): string { $config = Config::current(); $route = Route::current(); $request = unfix(self_url()); # Determine how we should append the page to dirty URLs. $mark = (substr_count($request, "?")) ? "&" : "?" ; fallback( $page, ($this->next_page() ? $this->page + 1 : $this->pages) ); # Generate a URL with the page number appended or replaced. $url = !isset($_GET[$this->name]) ? ( ($config->clean_urls and $route->controller->clean_urls) ? rtrim($request, "/")."/".$this->name."/".$page."/" : $request.$mark.$this->name."=".$page ) : ( ($config->clean_urls and $route->controller->clean_urls) ? preg_replace( "/(\/{$this->name}\/([0-9]+)|$)/", "/".$this->name."/".$page, $request, 1 ) : preg_replace( "/((\?|&){$this->name}=([0-9]+)|$)/", "\\2".$this->name."=".$page, $request, 1 ) ) ; return fix($url, true); } /** * Function: prev_page_url * Returns the URL to the previous page. * * Parameters: * $page - Page number to link to. */ public function prev_page_url($page = null): string { $config = Config::current(); $route = Route::current(); $request = unfix(self_url()); # Determine how we should append the page to dirty URLs. $mark = (substr_count($request, "?")) ? "&" : "?" ; fallback( $page, ($this->prev_page() ? $this->page - 1 : 1) ); # Generate a URL with the page number appended or replaced. $url = !isset($_GET[$this->name]) ? ( ($config->clean_urls and $route->controller->clean_urls) ? rtrim($request, "/")."/".$this->name."/".$page."/" : $request.$mark.$this->name."=".$page ) : ( ($config->clean_urls and $route->controller->clean_urls) ? preg_replace( "/(\/{$this->name}\/([0-9]+)|$)/", "/".$this->name."/".$page, $request, 1 ) : preg_replace( "/((\?|&){$this->name}=([0-9]+)|$)/", "\\2".$this->name."=".$page, $request, 1 ) ) ; return fix($url, true); } }