This question already has answers here:
How to Paginate lines in a foreach loop with PHP
(2 answers)
Closed 9 years ago.
Below is code I'm using to parse XML file, however file has many records and I want to paginate it, and display 20 records per page.
I also want the pagination links at bottom of page so users can go to other pages as well. It should be something like, if no value is give then it will start from 0 to 20 else if value is 2 start from 40 and stop at 60, test.php?page=2.
$xml = new SimpleXMLElement('xmlfile.xml', 0, true);
foreach ($xml->product as $key => $value) {
echo "$value->name";
echo "<br>";
}
Something like this should work:
<?php
$startPage = $_GET['page'];
$perPage = 10;
$currentRecord = 0;
$xml = new SimpleXMLElement('xmlfile.xml', 0, true);
foreach($xml->product as $key => $value)
{
$currentRecord += 1;
if($currentRecord > ($startPage * $perPage) && $currentRecord < ($startPage * $perPage + $perPage)){
echo "$value->name";
//echo $value->name;
echo "<br>";
}
}
//and the pagination:
for ($i = 1; $i <= ($currentRecord / $perPage); $i++) {
echo("<a href='thispage.php?page=".$i."'>".$i."</a>");
} ?>
You could use php's array_slice function (Documentation: http://www.php.net/manual/en/function.array-slice.php)
Start would be $page * $itemsPerPage, end would be $page * $itemsPerPage + $itemsPerPage and the number of pages would be ceil(count($xml->product) / $itemsPerPage).
Example:
$allItems = array(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
$itemsPerPage = 5;
$page = isset($_GET['page']) ? intval($_GET['page']) : 0;
foreach (array_slice($allItems, $page * $itemsPerPage, $page * $itemsPerPage + $itemsPerPage) as $item) {
echo "item $item";
}
It even works :) see: http://codepad.org/JiOiWcD1
As SimpleXMLElement is a Traversable, you can do the pagination with a LimitItertor which ships with PHP.
To get the total number of product elements you can use the SimpleXMLElement::count() function.
Pagination works like outlined in the hundreds of other questions, I preferable use the LimitPagination type for it.
It takes the current page, the total amount of elements and elements per page as arguments (see as well: PHP 5.2 and Pagination). It also has a helper function to provide the LimitIterator.
Example:
$products = $xml->product;
// pagination
$pagination = new LimitPagination($_GET['page'], $products->count(), 20);
foreach ($pagination->getLimitIterator($products) as $product) {
...
}
If you want to output a pager that allows to navigate between the pages, the LimitPagination has more to offer to make that a bit easier, e.g. for just all pages highlighting the current page (here exemplary with brackets):
foreach ($pagination->getPageRange() as $page)
{
if ($page === $pagination->getPage()) {
// current page
printf("[p%d] ", $page);
} else {
printf("p%d ", $page);
}
}
foreach ($pagination->getPageRange() as $page)
{
if ($page === $pagination->getPage()) {
// current page
printf("[p%d] ", $page);
} else {
printf("p%d ", $page);
}
}
Interactive online demo: http://codepad.viper-7.com/OjvNcO
Less interactive online demo: http://eval.in/14176
Related
I need to paginate some JSON result using PHP but as per my code its not working as expected. I am explaining my code below.
<?php
$arr='[{"sku":"Pizza001","position":0,"category_id":"67"},{"sku":"Birthday Cake","position":0,"category_id":"67"},{"sku":"Birthday Cake-1","position":0,"category_id":"67"},{"sku":"Fruit cake","position":0,"category_id":"67"},{"sku":"Birthday Cake for Gift","position":0,"category_id":"67"}]';
$raw_data = json_decode($arr, true);
paginate($raw_data,1);
function paginate($data, $page = 2, $perPage = 2) {
$x = ($page - 1) * $perPage;
$z = $page * $perPage;
$y = ($z > count($data)) ? count($data) : $z;
for(; $x < $y; $x++) {
print_r($data[$x]);
}
}
?>
Here I am getting always first 2 set o data from JSON object. I need as per $page and $perPage the data will be filtered. Suppose $page=1 and $perPage=2 then the first 2 set of record will be fetched and if $page=2 and $perPage=2 then next 2 set(i.e-from 2nd index) of data will be fetched and so on. Please help me to resolve this issue.
I have used a simple logic using array_slice as suggested by Wenchoeng Young Here you go:
$i=0;
$page=5;
$perPage=1;
$arr='[
{"sku":"Pizza001","position":0,"category_id":"67"},
{"sku":"Birthday Cake","position":0,"category_id":"67"},
{"sku":"Birthday Cake-1","position":0,"category_id":"67"},
{"sku":"Fruit cake","position":0,"category_id":"67"},
{"sku":"Birthday Cake for Gift","position":0,"category_id":"67"}
]';
$raw_data = json_decode($arr, true);
paginate($raw_data, $page, $perPage);
function paginate($data, $page, $perPage)
{ print_r(array_slice($data, $page-1, $perPage)); }
Use dynamic variable for the page number and limit your records per page. On click of page number it automatically changes the results.
<?php
$arr = '[{"sku":"Pizza001","position":0,"category_id":"67"},{"sku":"Birthday Cake","position":0,"category_id":"67"},{"sku":"Birthday Cake-1","position":0,"category_id":"67"},{"sku":"Fruit cake","position":0,"category_id":"67"},{"sku":"Birthday Cake for Gift","position":0,"category_id":"67"}]';
$raw_data = json_decode($arr, true);
paginate($raw_data, 1);
function paginate($data, $page = $pageNumber, $perPage = $limit)
{
$x = ($page - 1) * $perPage;
$z = $page * $perPage;
$y = ($z > count($data)) ? count($data) : $z;
for (; $x < $y; ++$x) {
print_r($data[$x]);
}
}
So basically I am trying to get the sum of AveragePrice of every single page on this api. Right now it only gets first page the things i've tried have only gotten it to go on an endless loop crashing wamp. Heres my code for 1 page of working.
I am just really unsure how I can get it to loop through pages and get sum of every page.
<?php
function getRap($userId){
$url = sprintf("https://www.roblox.com/Trade/InventoryHandler.ashx?userId=" . $userId . "&filter=0&page=1&itemsPerPage=14");
$results = file_get_contents($url);
$json = json_decode($results, true);
$data = $json['data']['InventoryItems'];
$rap = 0;
foreach($data as $var) {
$rap += $var['AveragePrice'];
}
echo $rap;
}
$userId = 1;
getRap($userId);
?>
You may get better answers by looking into the API you are working with regarding how many pages to look for. You want to loop until you hit the max pages. There should be an value in the result of your request that tells you that you've asked for a page that doesn't exist (ie. no more results). If you can get a total number of results to search for then you could do a for loop with that as your limit.
//Change the function to accept the page number as a variable
function getRap($userId, $i){
$url = sprintf("https://www.roblox.com/Trade/InventoryHandler.ashx?userId=" . $userId . "&filter=0&page=" . $i . "&itemsPerPage=14");
//work out how many pages it takes to include your total items
// ceil rounds a value up to next integer.
// ceil(20 / 14) = ceil(1.42..) == 2 ; It will return 2 and you will look for two pages
$limit = ceil($totalItems / $itemsPerPage);
// Then loop through calling the function passing the page number up to your limit.
for ($i = 0; $i < $limit; $i++) {
getRap($userId, $i);
}
If you cannot get the total number of items, you could loop while a fail state hasn't occured
// look for a fail state inside your getRap()
function getRap($userId, $i) {
if ($result = error) { //you will have to figure out what it returns on a fail
$tooMany = TRUE;
}
}
for ($i = 0; $tooMany !== TRUE ; $i++) {
getRap($userId, $i);
}
Edit: Reviewing my answer, looking for the fail state inside your function is poor form (and won't work because of the scope of the variable in this case). You could pass the variable back and forth, but I'll leave that part up to you.
To get the total, make sure that your function doesn't print the result (echo $rap) but returns it for further use.
Full example
<?php
function getRap($userId, $i){
$url = sprintf("https://www.roblox.com/Trade/InventoryHandler.ashx?userId=" . $userId . "&filter=0&page=" . $i . "&itemsPerPage=25");
$results = file_get_contents($url);
$json = json_decode($results, true);
if ($json['msg'] == "Inventory retreived!") {
$data = $json['data']['InventoryItems'];
$rap = 0;
foreach($data as $var) {
$rap += $var['AveragePrice'];
}
return $rap;
} else {
return FALSE;
}
}
$total = 0;
$userId = 1;
for ($i = 0; $i < 1000 /*arbitrary limit to prevent permanent loop*/ ; $i++) {
$result = getRap($userId, $i);
if ($result == FALSE) {
$pages = $i;
break;
} else {
$total += getRap($userId, $i);
}
}
echo "Total value of $total, across $pages pages";
?>
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 . ';
}
}
I have the following code for the pagination(PHP) in MongoDB database.
<?php
$mongodb = new Mongo("vvv");
$database = fff
$collection = gggg
$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
$limit = 12;
$skip = ($page - 1) * $limit;
$next = ($page + 1);
$prev = ($page - 1);
$sort = array('createdAt' => -1);
$cursor = $collection->find()->skip($skip)->limit($limit)->sort($sort);
foreach ($cursor as $r) {
--------
}
$total= $cursor->count();
if($page > 1){
echo 'Previous';
if($page * $limit < $total) {
echo ' Next';
}
} else {
if($page * $limit < $total) {
echo ' Next';
}
}
$mongodb->close();
?>
BUT my database size is 30GB+, each search provides the results of 20,000 which takes HUGE TIME to count() //$total= $cursor->count();
Can any one provide any PHP pagination code for MongoDB which does not count the total number of results but do the pagination?
cursor.skip() requires the server to walk from the beginning of the collection or index to get the offset or skip position before beginning to return results. It is not recommended to use it in pagination against 30GB+ data in your case.
If you cannot narrow a little bit your condition in find(), you can consider to add a sequence number in your docs for pagination purpose, assuming that you will rarely remove/update those documents:
{
createdAt: "2015-01-01",
...
seq_no: 1
},
{
createdAt: "2015-01-02",
...
seq_no: 2
}
Then you can implement the pagination query like this (remember to create the index on seq_no, of course):
$cursor = $collection->find({"seq_no": {"$gt":$skip, "$lte":($skip+$limit)}})
I am trying to create a dynamic page links created based on the number of rows in a mysql table. I would like to display 10 results per page and wish to have the php script create links to additional pages.
So I was thinking of using the num_rows and dividing it by 10 however if I have 53 rows the return would be 5.3 where as I would need 6 pages and not 5. I am thinking of using the round function and looping it through a for I statement until $pages > $rows_rounded. And every 10 rows add a link to pages($i) Is this the best method to acheive this or there an alternative simpler route to take?
pagenator class I made. getCurrentPages() returns all the pages you should be displaying in an array. so if you are on page one, and you want to display a total of 9 pages, you would get an array 1-9. if you were on page 10 however, your would get back an array 6-14. if there are 20 total pages and you are on page 20, you would get back an array 11-20.
<?php
class Lev_Pagenator {
private $recordsPerPage;
private $currentPage;
private $numberOfTotalRecords;
private $lastPage = null;
public function __construct($current_page, $number_of_total_records, $records_per_page = 25) {
$this->currentPage = $current_page;
$this->numberOfTotalRecords = $number_of_total_records;
$this->recordsPerPage = $records_per_page;
}
public function getCurrentStartIndex() {
return ($this->currentPage - 1) * $this->recordsPerPage;
}
public function getCurrentPages($number_of_pages_to_display = 9) {
$start_page = $this->currentPage - floor($number_of_pages_to_display / 2);
if ($start_page < 1) $start_page = 1;
$last_page = $this->getLastPage();
$pages = array($start_page);
for ($i = 1; $i < $number_of_pages_to_display; $i++) {
$temp_page = $start_page + $i;
if ($temp_page <= $last_page) {
$pages[] = $temp_page;
} else {
break;
}
}
return $pages;
}
public function getPreviousPage() {
if ($this->currentPage === 1) return false;
return $this->currentPage - 1;
}
public function getNextPage() {
if ($this->currentPage === $this->getLastPage) return false;
return $this->currentPage + 1;
}
public function getLastPage() {
if ($this->lastPage === null) $this->lastPage = ceil($this->numberOfTotalRecords / $this->recordsPerPage);
return $this->lastPage;
}
}
?>
EDIT (USAGE):
<?php
$pagenator = new Lev_Pagenator($current_page, $number_of_total_records, $records_per_page);
$pages_array = $pagenator->getCurrentPages($number_of_pages_to_display);
?>
The idea of a for loop sounds like a good one, you would use something like:
$rows_rounded = ceil(mysql_num_rows($result) / 10);
for($x = 1; $x <= $rows_rounded; $x++){
echo 'Page '.$x.'';
}
But you need to consider detecting the current page, so if, for example, the current page was 3, it might be a good idea to test for that in your for loop and if echoing the 3rd link maybe add some extra class to enable you to style it.