php pagination class first try - php

I'm trying to make a pagination class, this is my first attempt to make a real php class, besides all those basic oop class tutorials, you know those with some calculations.
What I really want is someone to look it through and tell me what's good practice and what's bad practice, some I can avoid getting some bad habits :).. and maybe some pointers in how I can devolop it further..
The class looks like this at the momment:
class Pagination {
public $db = NULL; // Get the DB
public $sqlQuery; // Get the sql string
public $per_page; // Get rows per page
public $total_results; // Get total results
public $total_pages;
public $p;
public $pages;
public $rows;
public $pagination;
public $url;
public function __construct($per_page,$sqlQuery,$db){
$this->per_page = $per_page;
$this->db = $db;
$this->sqlQuery = $sqlQuery;
$this->total_results = $this->db->query($this->sqlQuery)->num_rows;
$this->p = $p = NULL;
$this->url = 'http://'.$_SERVER['HTTP_HOST'] .$_SERVER['REQUEST_URI'];
// Makes sure we have a offset point
if(isset($_GET['p'])){
$this->p = $_GET['p'];
}else{
$this->p = 1;
}
// Get the amount of pages..
$this->total_pages = ceil($this->total_results/$this->per_page);
// Make sure we can't get false value, 0 or negative
if($this->p < 1){
$this->p = 1;
}
// Make sure property $p can't be higher than or max pages
if($this->p > $this->total_pages){
$this->p = $this->total_pages;
}
$limit = $this->p * $this->per_page;
$offset = $limit - $this->per_page;
$this->sqlQuery .= " limit ".$offset.",".$this->per_page; // possible error
$this->rows = $this->db->query($this->sqlQuery);
}
// Constructer ends
public function getResult(){
return $this->rows;
}
public function getPagination(){
$path = preg_replace("/&p=".$this->p."/","",$this->url);
$this->pagination = "";
if($this->p != 1){
$this->pagination .= "<a href='".$path."&p=1'>«</a> ";
$previous = $this->p-1;
$this->pagination .= "<a href='".$path."&p=".$previous."'>Forrige</a> ";
};
$range = 3;
//for($i=1;$i<=$this->total_pages;$i++){
for($i= ($this->p - $range); $i < (($this->p + $range) + 1); $i++){
if (($i > 0) && ($i <= $this->total_pages)) {
if($i == $this->p){
$this->pagination .= "<span>".$i."</span> ";
}else{
$this->pagination .= "<a href='".$path."&p=".$i."'>".$i."</a> ";
};
};
};
if($this->p != $this->total_pages){
$next = $this->p + 1;
$this->pagination .= "<a href='".$path."&p=".$next."'>Næste</a> ";
$this->pagination .= "<a href='".$path."&p=".$this->total_pages."'>»</a>";
};
return $this->pagination;
}
}
I know that the properby $this->url won't work in a secure http request, just don't know how to fix it at the time being.
Here's a simple call:
$db = db::getInstance();
$sqlQuery = "select * from movies order by name asc";
$result = new Pagination(5, $sqlQuery, $db);
$rows = $result->getResult();
$pagination = $result->getPagination();
$this->registry->template->rows = $rows;
$this->registry->template->pagination = $pagination;
$this->registry->template->show("movies_index");
Any pointers would be helpful :)

Related

Pagination for foreach loop

I currently have a method inside my "car class" that display the car:
static function getCars(){
$autos = DB::query("SELECT * FROM automoviles");
$retorno = array();
foreach($autos as $a){
$automovil = automovil::fromDB($a->marca, $a->modelo, $a->version, $a->year, $a->usuario_id, $a->kilometraje, $a->info,
$a->hits, $a->cilindrada, $a->estado, $a->color, $a->categoria, $a->precio, $a->idAutomovil);
array_push($retorno, $automovil);
}
return $retorno;
}
In my index.php I call that function
foreach(car::getCars() as $a){
That allows me to display the info this way ( of course inside the foreach I have a huge code with the details I'll display.
Is there a way to implement a pagination to that thing so I can handle 8 cars per page, instead of showing all of them at the same page?
You can add a $limit and $page parameter on your function so that it will only return a maximum of $limit number of items starting from $limit * $page(or will call it the $offset). You also need to add a function to get the total number of rows you have for automoviles table.
static function getCars($page = 0, $limit = 8){
$offset = $limit * max(0, $page - 1);
//replace this with prepared statement
$autos = DB::query("SELECT * FROM automoviles LIMIT $offset, $limit");
$retorno = array();
foreach($autos as $a){
$automovil = automovil::fromDB($a->marca, $a->modelo, $a->version, $a->year, $a->usuario_id, $a->kilometraje, $a->info,
$a->hits, $a->cilindrada, $a->estado, $a->color, $a->categoria, $a->precio, $a->idAutomovil);
array_push($retorno, $automovil);
}
return $retorno;
}
static function getTotal()
{
//query to get total number of rows in automoviles table
}
In your index.php do this:
foreach(car::getCars((isset($_GET['page']) ? $_GET['page'] : 1)) as $a){
...
}
and add the pagination links.
$total = car::getTotal();
if($total > 8) {
for($i = 1; $i <= intval(ceil(1.0 * $total / $limit)); $i++) {
echo '' . $i . ';
}
}

Call a function without its parameters

Below are the functions that am using to make reusable pagination. If you see the code below, theirs a function
generate_pages()
which is taking parameters from function
paged_controls()
But I would like to call the function generate_pages() without passing any parameters on body.php.
This is the error message am getting on body.php when calling function
generate_pages()
Warning: Missing argument 1 for generate_pages(), called in
E:\admin\snippets\body.php on line 11 and defined in
E:\admin\cores\pages.php on line 12
Notice: Undefined variable: limit in E:\xampp\htdocs\projects\hoplate\admin\cores\pages.php on line 16
Is that possible?
pages.php
<?php
function page_count(){
global $db;
$sql = "SELECT COUNT(pages_id) FROM pages";
$query = $db->SELECT($sql);
$rows = $db->FETCH_ROW();
foreach($rows as $row){
return $row[0];
}
}
function generate_pages($limit){
/* Run actual query now to get the records from database */
global $db;
$sql = "SELECT * FROM pages " . $limit;
$query = $db->SELECT($sql);
return $rows = $db->FETCH_OBJECT();
}
function paged_controls($page_rows = 1){
global $db;
/* Call the function page_count to get the total page count */
$row_count = page_count();
/* We use the ceil function to round the number to whole number */
$last = ceil($row_count / $page_rows);
/* Make sure that the last page cannot be less then 1 */
if($last < 1){
$last = 1;
}
/* Est. the page number variables */
$pagenum = 1;
/* Set the pagenum variables from URL else set it to 1*/
if(isset($_GET["paged"])){
$pagenum = preg_replace('#[^0-9]#', '', $_GET["paged"]);
}
/* Make sure page number canoot be less then 1 */
if($pagenum < 1){
$pagenum = 1;
} else if($pagenum > $last){
$pagenum = $last;
}
/* Set the range of query to be excuted depend on our variables values set*/
$limit = 'LIMIT '.($pagenum - 1) * $page_rows . ','. $page_rows;
generate_pages($limit);
$paged_controls = "";
/* Only if theirs more then 1 page of results */
if($last != 1){
if($pagenum > 1){
$previous = $pagenum - 1;
$paged_controls .= 'Previous ';
/* Renders the left paged numbers */
for($i = $pagenum - 4; $i < $pagenum; $i++){
if($i > 0){
$paged_controls .= ''.$i.' ';
}
}
}
/* Render the current page the user is at */
$paged_controls .= ''.$pagenum.' ';
/* Renders the right paged numbers */
for($i = $pagenum + 1; $i <= $last; $i++){
$paged_controls .= ''.$i.' ';
if($i >= $pagenum + 4){
break;
}
}
if($pagenum != $last){
$next = $pagenum + 1;
$paged_controls .= 'Next ';
}
return $paged_controls;
}
}
?>
body.php
<?php
$pages = generate_pages();
foreach($pages as $page){
echo $pages_id = $page->pages_id . "<br/>";
}
?>
Only way I would see this working is adding a check.
function generate_pages($limit = null){
/* Run actual query now to get the records from database */
$gloab $db;
$sql = "SELECT * FROM pages " . isset($limit) ? "LIMIT $limit" : "";
$query = $db->SELECT($sql);
return $rows = $db->FETCH_OBJECT();
}
So now it could be run one of two ways
generate_pages();
or:
generate_pages(10);
Compare both of your function headers:
function generate_pages($limit)
function paged_controls($page_rows = 1)
PHP offers you to specify default arguments, just like C++ (you have to scroll down a bit to see the section).
Your paged_controls-function already does this and it is a great way of achieving what you want without editing the business logic within the function.
A default argument kicks in whenever you call a function without any parameters.
So, if you edit
function generate_pages($limit)
to (for example)
function generate_pages($limit = 'LIMIT 0,18446744073709551615')
and call the function via generate_pages(), PHP will automatically assume $limit = 'LIMIT 0,18446744073709551615'.
In this specific case, calling generate_pages without a parameter will retrieve all entries in the table you select from, as we tell the database to give us 18446744073709551615 entries from the beginning.
See the MYSQL manual on select/limit.

PHP pagination function

public function paging($limit,$numRows,$page){
$allPages = ceil($numRows / $limit);
$start = ($page - 1) * $limit;
$querystring = "";
foreach ($_GET as $key => $value) {
if ($key != "page") $paginHTML .= "$key=$value&";
}
$paginHTML = "";
$paginHTML .= "Pages: ";
for ($i = 1; $i <= $allPages; $i++) {
$paginHTML .= "<a " . ($i == $page ? "class=\"selected\" " : "");
$paginHTML .= "href=\"?{$querystring}page=$i";
$paginHTML .= "\">$i</a> ";
}
return $paginHTML;
}
This is my pagination function for MVC pattern implementation.But this function has not displayed next and prev links.
I need to return HTML variable for pagination with previous and next link to controller.
I passed these variable to this function from controller.
$limit,$numRows,$page
How can I get next and prev links to above function.
I have added some conditions in the loop itself.
Hope they work.
Try the following:
<?php
public function paging($limit,$numRows,$page){
$allPages = ceil($numRows / $limit);
$start = ($page - 1) * $limit;
$querystring = "";
foreach ($_GET as $key => $value) {
if ($key != "page") $paginHTML .= "$key=$value&";
}
$paginHTML = "";
$paginHTML .= "Pages: ";
for ($i = 1; $i <= $allPages; $i++) {
if ($i>1) {
$prev = $i-1;
$paginHTML .= 'Previous';
}
$paginHTML .= "<a " . ($i == $page ? "class=\"selected\" " : "");
$paginHTML .= "href=\"?{$querystring}page=$i";
$paginHTML .= "\">$i</a> ";
if ($i<$allPages) {
$next = $i+1;
$paginHTML .= 'Next';
}
}
return $paginHTML;
}
?>
I'm using this pagination class like bellow inside my controller
case '' :
$page = isset ( $_REQUEST ['page'] ) ? $_REQUEST ['page'] : 1;
$limit = 5;
$allStudent = $student->getAllStudents();
$numRows = count($allStudent);
$start = ($page - 1) * $limit;
$students = $student->getStudentsWithLimit($start,$limit);
$paginHTML = $pagin->paging($limit,$numRows,$page);
$view->render('view/allStudent.php', array('allStudent' => $students,'pagin' => $paginHTML ));
break;
Get record function in Model class
public function getStudentsWithLimit($start,$limit){
$stmt = $this->db->con->query("SELECT * FROM student LIMIT $start, $limit");
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $results;
}
This should page with next and previous links with a max of 5 on either side of current page.
Pass in a function if you want the link formatted differently.
I've only given this very limited testing, and its been pulled out of a class, so you could replace some hard coded values in here with parameters of references to $this
function get_paging_links($result_count, callable $format_function=null)
{
if(!$format_function){
$format_function = function($url,$page,$qs){
$qs['page'] = $page;
return $url.'?'.http_build_query($qs);
};
}
$per_page = 5;
$total_pages = ceil($result_count / $per_page);
$return = [];
parse_str($_SERVER['QUERY_STRING'],$qs);
$url = $_SERVER['REQUEST_URI'];
//Remove existing query_string.
if($pos = strpos($url,'?')){
$url = substr($url,0,$pos);
}
$current_page = isset($qs['page']) ? $qs['page'] : 1;
$previous = $current_page -1;
if ($previous) {
$return['previous'] = $format_function($url,$previous,$qs);
}
for($i = max(1,$current_page-5); $i <= min($total_pages,$current_page+5); $i++) {
$return["$i"] = $format_function($url,$i,$qs);
}
$next_page = $current_page + 1;
if ($next_page < $total_pages){
$return['next'] = $format_function($url,$next_page,$qs);
}
return $return;
}

pagination class not showing correct amt of pages

the problem with the class is that if i want to display 30 records at a time and i have 60 total records the pagination divs that shows the page numbers only shows page #1 and not page #2. i have tried to figure out how to fix it but i have given up. any help would greatly be apreciated.
this is how i call attributes to the class.
$paginate = new Pagination;
$paginate->pageName = "index.php"; //sets the page to use
$paginate->perPage = 10; //show num of records per page
$paginate->adjacents = 3; //current page adjacent to
$paginate->sql = "select * from tbl_products"; //the main query
$query = $db->query($paginate->getData());
while($row = mysql_fetch_object($query)) {
print $row->pName."<br/>";
}
$paginate->showPagination(); //shows the pagination div
here is the class.
<?php
include_once("class.db.php");
class Pagination
{
var $param;
var $perPage;
var $adjacents;
var $start;
var $sql;
var $pageName;
function __construct()
{
$this->db = new MysqlDB;
$this->db->connect();
}
function setParam()
{
if(isset($_GET['page']) && is_numeric($_GET['page']) && ($_GET['page'] > 0))
{
$this->param = $_GET['page'];
}
else
{
$this->param = 1;
}
}
function setIndex()
{
$this->setParam();
return $this->start = ($this->param * $this->perPage) - $this->perPage;
}
function showPagination($param1=null,$param2=null,$param3=null)
{
$qRows = $this->db->query($this->sql);
$numRows = $this->db->num_rows($qRows);
$numOfPages = ceil($numRows / $this->perPage);
$param = $this->param;
$pageName = $this->pageName;
$string = "";
//set pagination parameters.
if($param1 != null)
{
if(isset($_GET[$param1]))
{
$param1Value = $_GET[$param1];
$string .= "&".$param1."=".$param1Value;
}
}
if($param2 != null)
{
if(isset($_GET[$param2]))
{
$param2Value = $_GET[$param2];
$string .= "&".$param2."=".$param2Value;
}
}
if($param3 != null)
{
if(isset($_GET[$param3]))
{
$param3Value = $_GET[$param3];
$string .= "&".$param3."=".$param3Value;
}
}
print "<div class='pagination'>";
print "<a href='$this->pageName?page=1$string' class='previous-off'> First </a>";
// ----------------------------------------------------------------------------
// PRINT ALL PAGES TO THE LEFT //
if(($param - $this->adjacents) > 1)
{
print "<span>...</span>";
$lowerLimit = $param - $this->adjacents;
//print all on left side.
for($i = $lowerLimit; $i< $param; $i++)
{
print "<a href='$pageName?page=$param = $i$string'> $i </a>";
}
}
else
{
//print all numbers between current page and first page.
for($i = 1; $i < $param; $i++)
{
print "<a href='$pageName?page=$i$string'> $i </a>";
}
}
// ----------------------------------------------------------------------------
//print current page
if(($param != 0) && ($param != $numOfPages))
{
print "<span class='current'>$param</span>";
}
// ----------------------------------------------------------------------------
//PRINT ALL PAGES TO THE RIGHT
if(($param + $this->adjacents) < $numOfPages)
{
$upperLimit = $param + $this->adjacents;
for($i=($param + 1); $i<=$upperLimit; $i++)
{
print "<a href='$pageName?page=$i$string'> $i </a>";
}
print "<span>...</span>";
}
else
{
//print all page numbers if out of padded range
for($i = ($param + 1); $i<$numOfPages; $i++ )
{
print "<a href='$pageName?page=$i$string'> $i </a>";
}
}
// ----------------------------------------------------------------------------
$lastPage = $numOfPages - 1;
print "<a class='next' href='$pageName?page=$lastPage$string'> Last </li>";
print "</div>";
}
function getData()
{
$query = $this->sql;
$this->start = $this->setIndex();
return "$query LIMIT $this->start, $this->perPage";
}
function errors()
{
$query = $this->sql;
print "$query LIMIT $this->start, $this->perPage"."<br/>";
print "this->start ".$this->start."<br/>";
print "this->param ".$this->param."<br/>";
print "this->perPage ".$this->perPage."<br/>";
print "this->setindex() ".$this->setIndex()."<br/>";
}
}
?>
Personally I tend to stray from SELECT * FROM tbl type queries as if you have a large table, it can be slow. Therefore, I run two queries: one to get the total number of records, and one to get the data set I need based on a paging parameter in the URL, e.g. example.com/news.php?page=2.
From there, I can instantiate my own paging class, which is pretty simple:
<?php
class Paging {
private $total;
private $batch;
private $page;
private $prefix;
public function __construct($total=0, $batch=10, $page=1, $url="") {
$this->total = intval($total);
$this->batch = intval($batch);
$this->page = intval($page);
$this->url = $url;
}
public function total_pages() {
return ceil($this->total/$this->batch);
}
public function render() {
$html = "";
// only display paging if we have more than the batch value
if ($this->total > $this->batch) {
$html.= '<p>Go to page:';
for ($i=1; $i <= $this->total_pages()) {
if ($i==$this->page) {
$html.= ' <span class="current">'.$i.'</span>';
}
else {
$html.= ' '.$i.'';
}
}
$html.= '</p>';
}
return $html;
}
}
Then to use:
<?php
// get total number of records
$sql = "SELECT COUNT(*) AS total FROM tbl";
$res = $db->query($sql);
$row = $res->fetch();
$total = $row['total'];
$batch = 20;
$page = intval($_GET['page']);
// instantiate paging class
require_once('paging.class.php');
$paging = new Paging($total, $batch, $page, "mypage.php?page=%s");
// do normal page stuff here...
// render the pagination links
echo $paging->render();
Feel free to use the above code and modify to your needs

Pagination Class calculates incorrectly

ive written a pagination class and it looks like its not outputting the correct amount of rows. i have a table full of 51 records and instead it shows only 30 records and as for the pages it shows only page 1 where it should show page 1 and 2. the pages are viewed by going to page=1 as a browser param. when i try to view page=2 i see the rest of the records. here is the class.
include_once("class.db.php");
class Pagination {
var $param;
var $perPage;
var $adjacents;
var $start;
var $sql;
var $pageName;
function __construct() {
$this->db = new MysqlDB;
$this->db->connect();
}
function setParam() {
if(isset($_GET['page']) && is_numeric($_GET['page']) && ($_GET['page'] > 0)) {
$this->param = $_GET['page'];
} else {
$this->param = 1;
}
}
function setIndex() {
$this->setParam();
return $this->start = ($this->param * $this->perPage) - $this->perPage;
}
function showPagination() {
$qRows = $this->db->query($this->sql);
$numRows = $this->db->num_rows($qRows);
$numOfPages = ceil($numRows / $this->perPage);
$param = $this->param;
$pageName = $this->pageName;
print "<div class='pagination'>";
print "<a href='$this->pageName?page=1' class='previous-off'> First </a>";
// ----------------------------------------------------------------------------
// PRINT ALL PAGES TO THE LEFT //
if(($param - $this->adjacents) > 1) {
print "<span>...</span>";
$lowerLimit = $param - $this->adjacents;
//print all on left side.
for($i = $lowerLimit; $i< $param; $i++) {
print "<a href='$pageName?page=$param = $i'> $i </a>";
}
} else {
//print all numbers between current page and first page.
for($i = 1; $i < $param; $i++) {
print "<a href='$pageName?page=$i'> $i </a>";
}
}
// ----------------------------------------------------------------------------
//print current page
if(($param != 0) && ($param != $numOfPages)) {
print "<span class='current'>$param</span>";
}
// ----------------------------------------------------------------------------
//PRINT ALL PAGES TO THE RIGHT
if(($param + $this->adjacents) < $numOfPages) {
$upperLimit = $param + $this->adjacents;
for($i=($param + 1); $i<=$upperLimit; $i++) {
print "<a href='$pageName?page=$i'> $i </a>";
}
print "<span>...</span>";
} else {
//print all page numbers if out of padded range
for($i = $param + 1; $i<$numOfPages; $i++ ) {
print "<a href='$pageName?page=$i'> $i </a>";
}
}
// ----------------------------------------------------------------------------
$lastPage = $numOfPages - 1;
print "<a class='next' href='$pageName?page=$lastPage'> Last </li>";
print "</div>";
}
function getData() {
$query = $this->sql;
$this->start = $this->setIndex();
return "$query LIMIT $this->start, $this->perPage";
}
}
this is how i use the class:
$db = new MysqlDB;
$paginate = new Pagination;
$paginate->pageName = "index.php"; //sets the page to use
$paginate->perPage = 10; //show num of records per page
$paginate->adjacents = 3; //current page adjacent to
$paginate->sql = "select * from tbl_products"; //the main query
$query = $db->query($paginate->getData());
while($row = mysql_fetch_object($query)) {
print $row->pName."<br/>";
}
$paginate->showPagination(); //shows the pagination div
In function setIndex you have to write:
return $this->start = (($this->param - 1) * $this->perPage) - $this->perPage;
because a query should look like:
for page 1: SELECT ... LIMIT 0,[nr_of_pages]
for page 2: SELECT ... LIMIT [nr_of_pages]*1,[nr_of_pages]
...

Categories