After reviewing my previous question I came up with this pagination function. On my first approach I wrote a class thinking about IDE's code assist and the review wasn't positive. In this function I decided to return a stdClass
object with necessary properties. I have my concerns about the output approach. I want one function that does the full job. Thanks in advance.
So here's the code:
/**
* @author Julio
* @date 11/MAY/23
*
*
* This function splits the dataset to be shown across multiple pages
* @param array $data_source Simple or multidimensional array
* @param int $results_per_page
* @param int $page_number
* @param string $get_var The name of the $_GET variable page number name. Default is 'page_number'
* @throws LengthException
* @throws Exception
* @return stdClass
*
* Notes about the function code:
*
* You will notice that some variables could have been ommited. I decided to
* declare them (redundant) to make the code easier to read and have the
* output assignment ($output) set all together at the end. Also, there are a
* couple of $output properties that are unnecessary: results_per_page and
* page_number. This data is known by the developer.
*
*
* Parameters explain by themselves. $get_var parameter takes the name of
* the $_GET variable desired name to hold selected page value. Its default
* value is "page_number".
*
* When page_number is out of range, function triggers a E_USER_LEVEL warning
* and sets the page_number accordingly.
* That is to say that when $page_number < 1, page_number will be set to 1.
* Or if $page_number > $total_pages, will be set to $total_pages.
*
*
* It returns a Standard Class (stdClass) object with the following properties:
*
* record_count: total number of records
* results_per_page: number of records per page (unnecessary)
* total_pages: total number of pages
* page_number: selected page (unnecessary)
* resultset: selected records according to parameters
* url_previous: previous navigator URL
* url_next: next navigator URL
* url_first: first navigator URL
* url_last: last navigator URL
* navigator: simple HTML code por navigating through pages
* css: simple CSS3 code example for styling
*
*
* TO-DO:
* - when many many pages are available limit the number of navigator links to a
* predefined number (i.e. 10). That is to say, if you are on page 34 of 98, links in
* navigator should be between 30 and 38 or so. Something like SO's pagination.
*
* - allow the developer to set HTML id and class
*
* - add support for any HTML attribute
*
*
* Usage:
// $data can be 'anything' you want:
$data = $result->fetch_all(MYSQLI_ASSOC);
// or
$data = [
["data11", "data12", "data13"],
["data21", "data22", "data23"]
];
// or
$data = [];
for ($i = 0; $i < 84; $i++) {
$data[] = $i;
}
$pagination = pagination($data, 10, $_GET['page'] ?? 1, 'page');
$html .= "<br>Results: " . $pagination->record_count; // 84 (using last $data)
$html .= "<br>Results per page: " . $pagination->results_per_page; // 10
$html .= "<br>Total pages: " . $pagination->total_pages; // 9
$html .= "<br>Page number: " . $pagination->page_number; // 3
$html .= "<br>First URL: " . $pagination->url_first; // http://url/script.php?var=value&page=1
$html .= "<br>Last URL: " . $pagination->url_last; // http://url/script.php?var=value&page=9
$html .= "<br>Previous URL: " . $pagination->url_previous; // http://url/script.php?var=value&page=2
$html .= "<br>Next URL: " . $pagination->url_next; // http://url/script.php?var=value&page=4
$html .= "<br>Resultset: " . print_r($pagination->resultset, true); // [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
$html .= $pagination->navigator; // will render HTML div navigation links
//$html .= "<pre><code>" . $pagination->css . "</code></pre>"; // styling example
$html .= "<br><br>";
echo $html;
*
*
*
*/
function pagination(
array $data_source,
int $results_per_page = 10,
int $page_number = 1,
string $get_var = "page_number"
): stdClass {
$output = new stdClass();
$record_count = count($data_source);
$total_pages = 0;
$resultset = [];
/**
* URL for resultset navigator
* @var string $url
*/
$url = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . "?";
$next_page = 0;
$previous_page = 0;
$navigator = "";
$navigator_container = "\n<div id='paginator' class='paginator'>%links\n</div>\n";
$navigator_link_tpl = "\n<a href='%url'%selected>%text</a>";
$navigator_links = "";
if ($record_count < 1) {
throw new LengthException("Data source is empty");
}
if ($results_per_page < 1) {
throw new Exception("Results per page must be equal to or greater than 1");
}
$total_pages = ceil($record_count / $results_per_page);
if ($page_number < 1) { // set it to 1
trigger_error("Page number '$page_number' is not valid; set to '1'", E_USER_WARNING);
$page_number = 1;
} elseif ($page_number > $total_pages) { // set it to max pages
trigger_error("Page number '$page_number' is not valid; set to '$total_pages'", E_USER_WARNING);
$page_number = $total_pages;
}
if (strlen($get_var) === 0) {
$get_var = "page_number";
}
if (strlen($_SERVER['QUERY_STRING']) !== 0) {
foreach ($_GET as $variable => $value) {
if ($variable !== $get_var) {
$url .= "$variable=$value&";
}
}
}
$url .= "$get_var=";
$offset = ($page_number - 1) * $results_per_page;
$resultset = array_slice($data_source, $offset, $results_per_page);
$previous_page = $page_number - 1;
if ($previous_page === 0) {
$previous_page = 1;
}
$next_page = $page_number + 1;
if ($next_page > $total_pages) {
$next_page = $total_pages;
}
// prepare navigator
if ($total_pages > 1) {
if ($page_number !== 1) {
$navigator_links .= str_replace(
["%url", "%selected", "%text"],
[$url . $previous_page, "", "<"],
$navigator_link_tpl
);
}
for ($counter = 1; $counter <= $total_pages; $counter++) {
if ($page_number !== $counter) {
$navigator_links .= str_replace(
["%url", "%selected", "%text"],
[$url . $counter, "", $counter],
$navigator_link_tpl
);
} else { // here is set the selected link styling
$navigator_links .= str_replace(
["%url", "%selected", "%text"],
["#", " class='selected'", $counter],
$navigator_link_tpl
);
}
}
if ($page_number < $total_pages) {
$navigator_links .= str_replace(
["%url", "%selected", "%text"],
[$url . $next_page, "", ">"],
$navigator_link_tpl
);
}
$navigator = str_replace("%links", $navigator_links, $navigator_container);
}
// output assignment
$output->record_count = $record_count;
$output->results_per_page = $results_per_page; // unnecessary
$output->total_pages = $total_pages;
$output->page_number = $page_number; // unnecessary
$output->resultset = $resultset;
$output->url_previous = $url . $previous_page;
$output->url_next = $url . $next_page;
$output->url_first = $url . "1";
$output->url_last = $url . $total_pages;
$output->navigator = $navigator;
$output->css = <<<EOT
#paginador a, #paginator a {
display:inline-block;
padding:10px;
border:1px solid blue;
margin-top:20px;
}
#paginador a.selected, #paginator a.selected {
background-color: blue !important;
color: white !important;
font-weight: bold !important;
}
EOT;
return $output;
}
// comment
, maybe that's because it needed a helper." So extractfunction prepare_navigator(...)
\$\endgroup\$