Reputation: 55
At present, the pagination feature is working fine when displaying ALL results, or if i manipulate the query to show specific results (WHERE X = Y) and i can happily cycle through all pages. Now, i have tried to implement a search feature.
problem#1 - it only displays the FIRST page of the inputted search results correctly, when i go to next page it shows other items from the database (not relevant to the search). [SOLVED] see UPDATES in script.
problem#2 - the number of pages returned are calculated from the whole database (shows +400 pages) and not e.g. only 3 pages because the search results should be 45 items.
an outline of my structure is:
<?php
//FOR PAGINATION
$pages = new Paginator('15','n'); // number of items to show on each page
$stmt = $db->query("SELECT * FROM items "); //**FOCUS 1**
$pages->set_total($stmt->rowCount()); //pass number of records to PAGINATION
// SEARCH QUERY
if(isset($_GET['search_item'])){ // UPDATE-was POST
$search_item = $_GET['search_item']; // UPDATE-was POST
$stmt = $db->prepare("SELECT * FROM items WHERE item_name LIKE '%".$search_item."%' OR item_code LIKE '%".$search_item."%' ORDER BY item_name ".$pages->get_limit());
$stmt->execute(array("%$search_item%"));
$set_total = ($stmt->rowCount());
//$min_length = 2; not necessary for example
}
?>
<!-- SEARCH FORM -->
<form method="GET" action=""><!-- **FOCUS 2** --> <!-- WAS PREVIOUSLY POST -->
<input type="text" name="search_item" placeholder="search" style="width:200px;">
<input type="submit" value="search" id="submit">
</form>
<!-- display results here in table format using while -->
<?php
// PAGINATION RESULTS/PAGES DISPLAY
echo $pages->page_links('index.php?p=index&search_item='.$search_item.'&'); //**FOCUS 3** // UPDATE-was just echo $pages->page_links();
?>
Pagination Class:
class Paginator {
private $_perPage; // set the number of items per page. |@var numeric
private $_instance; // set get parameter for fetching the page number | @var string
private $_page; // sets the page number. | @var numeric
private $_limit; // set the limit for the data source | @var string
private $_totalRows = 0; // set the total number of records/items. | @var numeric
// __construct | pass values when class is istantiated | @param numeric $_perPage sets the number of iteems per page | @param numeric $_instance sets the instance for the GET parameter
public function __construct($perPage,$instance){
$this->_instance = $instance;
$this->_perPage = $perPage;
$this->set_instance();
}
// get_start | creates the starting point for limiting the dataset | @return numeric
private function get_start(){
return ($this->_page * $this->_perPage) - $this->_perPage;
}
// set_instance | sets the instance parameter, if numeric value is 0 then set to 1 | @var numeric
private function set_instance(){
$this->_page = (int) (!isset($_GET[$this->_instance]) ? 1 : $_GET[$this->_instance]); // 1 was changed to 1
$this->_page = ($this->_page == 0 ? 1 : $this->_page); // 1 was changed to 5
}
// set_total | collect a numberic value and assigns it to the totalRows | @var numeric
public function set_total($_totalRows){
$this->_totalRows = $_totalRows;
}
/**
* get_limit
* returns the limit for the data source, calling the get_start method and passing in the number of items perp page
* @return string
*/
public function get_limit(){
return "LIMIT ".$this->get_start().",$this->_perPage";
}
/**
* page_links
* create the html links for navigating through the dataset
* @var sting $path optionally set the path for the link
* @var sting $ext optionally pass in extra parameters to the GET
* @return string returns the html menu
*/
public function page_links($path='?',$ext=null) {
$adjacents = "2";
$prev = $this->_page - 1;
$next = $this->_page + 1;
$lastpage = ceil($this->_totalRows/$this->_perPage);
$lpm1 = $lastpage - 1;
$pagination = "";
if($lastpage > 1) {
$pagination .= "<div class='pagination'>";
if ($this->_page > 1)
$pagination.= "<a href='".$path."$this->_instance=$prev"."$ext'>«</a>";
else
$pagination.= "<span class='disabled'>«</span>";
if ($lastpage < 7 + ($adjacents * 2)) { //7
for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $this->_page)
$pagination.= "<span class='current'>$counter</span>";
else
$pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
}
}
elseif($lastpage > 3 + ($adjacents * 2)) { //3
if($this->_page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) { //4
if ($counter == $this->_page)
$pagination.= "<span class='current'>$counter</span>";
else
$pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
}
$pagination.= "...";
$pagination.= "<a href='".$path."$this->_instance=$lpm1"."$ext'>$lpm1</a>";
$pagination.= "<a href='".$path."$this->_instance=$lastpage"."$ext'>$lastpage</a>";
}
elseif($lastpage - ($adjacents * 2) > $this->_page && $this->_page > ($adjacents * 2)) {
$pagination.= "<a href='".$path."$this->_instance=1"."$ext'>1</a>";
$pagination.= "<a href='".$path."$this->_instance=2"."$ext'>2</a>";
$pagination.= "...";
for ($counter = $this->_page - $adjacents; $counter <= $this->_page + $adjacents; $counter++) {
if ($counter == $this->_page)
$pagination.= "<span class='current'>$counter</span>";
else
$pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
}
$pagination.= "..";
$pagination.= "<a href='".$path."$this->_instance=$lpm1"."$ext'>$lpm1</a>";
$pagination.= "<a href='".$path."$this->_instance=$lastpage"."$ext'>$lastpage</a>";
} else {
$pagination.= "<a href='".$path."$this->_instance=1"."$ext'>1</a>";
$pagination.= "<a href='".$path."$this->_instance=2"."$ext'>2</a>";
$pagination.= "..";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $this->_page)
$pagination.= "<span class='current'>$counter</span>";
else
$pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
}
}
}
if ($this->_page < $counter - 1)
$pagination.= "<a href='".$path."$this->_instance=$next"."$ext'>»</a>";
else
$pagination.= "<span class='disabled'>»</span>";
$pagination.= "</div>\n";
}
return $pagination;
}
}
attempts to resolve:
I have been messing around with the code and can't recall everything i have tried but things i have looked at are the FOCUS areas.
FOCUS 1 i think that in order to only generate pagination for the total results of search output i need to add something like ("WHERE item_name LIKE '%".$search_item."%' "), which has worked when i code like ("WHERE item_name LIKE 'ford') it displays the correct number of pages, but when i cycle through the results are not correct. simply adding '%".$search_item."%' to the query generates an undefined variable error, which i understand as '%".$search_item."%' has not been set until later in the coding.
Focus 2 i have tried changing method to GET and action to action="index.php?p=index&search=<?php echo $search_item ;?>". now this changes the URL to what i think should be correct 'index.php?search_item=ford'
BUT it still doesnt work as part of the search feature as i have to hard code the WHERE to display results (FOCUS 1).
Focus 3 i cant remember exactly what i did, something similar to the action in Focus 2, but when i hovered over the seperate pages it showed the correct URL paths i would expect.
It seems that when i am trying one thing, it works for one of the Focus points, but then doesn't somewhere else.
CLOSEST IV GOT SO FAR! i have now got items displaying correctly, and am able to cycle through pages correctly! i have amended the code above to what i have now, with what i 'had' in the comments. The problem i now have is showing the correct number of pages in pagination - it shows all +400 pages, however my search variable passes over to each page and i can cycle through searched results and.. it 'cuts off' where it is supposed to e.g. if i have only 50 results, then it will show results for page 1,2,3 then on pages 4+ displays nothing.
could anyone please inform me where i am going wrong or any advice on what i should be looking at.
Upvotes: 2
Views: 324
Reputation: 910
Does your $pages->get_limit()
function return the LIMIT
part of the SQL query as well? With my response, I am assuming that the method only returns an integer. If this is the case, you're missing LIMIT
from your SQL query.
Also, I cannot see anywhere in your sample code where you are obtaining the current page number to help with pagination. Does your Paginator class supply this? With the below example, I've assigned a variable $page
where I've assumed the current page number will be in $_GET['page']
.
Try this out:
$search_item = isset($_GET['search']) ? urldecode($_GET['search']) : null;
$page = 1;
if (isset($_GET['page']) && is_numeric($_GET['page']) && (int)$_GET['page'] > 0)
$page = (int)$_GET['page'];
if (is_string($search_item) && mb_strlen($search_item) > 0) {
$stmt = $db->prepare("SELECT * FROM items WHERE item_name LIKE :search_item
OR item_code LIKE :search_item ORDER BY item_name ASC LIMIT :limit OFFSET :offset");
} else {
$stmt = $db->prepare("SELECT * FROM items ORDER BY item_name ASC LIMIT :limit OFFSET :offset");
}
if ($stmt->execute(
array(
'search_item' => '%' . $search_item . '%',
'offset' => ($pages->get_limit() * ($page - 1)),
'limit' => $pages->get_limit()
)
)) {
$set_total = $stmt->rowCount();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Perhaps look at changing your form
method to GET
and using $_GET
to gather the search filters, such as the keyword and page number (as with the above example). This would save you from having to create sessions, and will allow you to easily construct pagination links.
Example:
<?php $numPages = ceil($total / $pages->get_limit()); ?>
<ul class="pagination">
<?php for ($p = 1; $p < ($numPages + 1); $p++) { ?>
<li>
<a href="index.php?p=search&search=<?php echo urlencode($search_item); ?>&page=<?php echo $p; ?>">
<?php echo $p; ?>
</a>
</li>
<?php } ?>
</ul>
Or something similar :-)
Upvotes: 1