I am trying to implement a load more feature in a web app I am building.
When the app loads, it makes an ajax call to controller which retrieves the data from the database and then encodes them in JSON.
I am making use of limits and offsets in mysql query and I more data to be loaded as the user scrolls down.
This is the method in the controller which the ajax call is made to
function latest_pheeds($offset = 0) {
//Confirm if a user is logged before allowing access
if($this->isLogged())
{
//Limit
$limit = 20;
//user id
$user_id = $this->session->userdata('user_id');
//load pheeds
$dt = $this->pheed_model->get_latest_pheeds($limit,$offset);
$data = $dt['pheeds']; //data
$total = $dt['total']; //Total no of rows of data
$return['pheeds'] = $data;
echo json_encode($return); //encode in json
} else {
$this->output->set_status_header('401',"Attempting Unauthorized Access");
}
}
How do I break this data into pages, so I can simply pass the page no as argument to method via the ajax call to implement the load more with jQuery?
Calculate $offset by multiplying (page number - 1) with $limit:
$offset = ($page - 1) * $limit;
So if $page is 1, then it will be (1 - 1) * 20 = 0 * 20 = 0,
if $page is 2, then it will be (2 - 1) * 20 = 1 * 20 = 20
Also rename function parameter $offset to $page
[EDIT]
Also what i would do is to query one row more, than needed, so i can detect if there is next page, eg:
$dt = $this->pheed_model->get_latest_pheeds($limit + 1,$offset);
$next_page = false;
if (count($dt) > $limit) {
$next_page = true;
$dt = array_pop($dt); // Excluding the last row so it is same size as $limit
}
// More code....
$return['next_page_exists'] = $next_page;
Related
I make a PHP request that queries a database every time a map coordinate is changed. This returns some JSON data. I'd like to make a request every 5 hours, as the data does not change often. If this is not possible do you recommend generating a static JSON document that refreshes itself every 5 hours? How can I do this?
My actual code for querying the database on every request looks like this:
public function getAgenciesJson() {
if(Request::ajax()) { # Just validation to show/send data if requested
$ne_lat = $_GET['ne_lat'];
$sw_lat = $_GET['sw_lat'];
$ne_lng = $_GET['ne_lng'];
$sw_lng = $_GET['sw_lng'];
$page = (isset($_GET['page'])) ? (int)$_GET['page'] : 1;
$per_page = 2;
if ($page > 1) { # && $page <= $total_pages) {
$skip = ($page - 1) * $per_page;
} else {
// error - show first set of results
$skip = 0;
}
$agencies = DB::table('users')
->select('user_id','type','c_name','c_logo','c_local','state','city','sn','col','lat','lng')
->skip($skip)
->take($per_page) # Results per page
->where('active',1)
->whereNotNull('lat')
->whereNotNull('lng')
->whereRaw('lat < ? AND lat > ? AND lng < ? AND lng > ?',array($ne_lat,$sw_lat,$ne_lng,$sw_lng));
if(isset($_GET['type_l'])==true && isset($_GET['type_a'])==true) {
$agencies
->orWhere('type','l')
->where('type','a');
} elseif (isset($_GET['type_l'])==true) {
$agencies->where('type','l');
} elseif (isset($_GET['type_a'])==true) {
$agencies->where('type','a');
} else {
$agencies
->orWhere('type','l')
->where('type','a');
}
$i=0;
try {
foreach($agencies->get() as $agency) {
# Assign values
$arr[$i]['a_id'] = $agency->user_id;
$arr[$i]['type'] = $agency->type;
$arr[$i]['name'] = $agency->c_name;
$arr[$i]['logo'] = $agency->c_logo;
$arr[$i]['local'] = $agency->c_local;
$arr[$i]['state'] = $agency->state;
$arr[$i]['city'] = $agency->city;
$arr[$i]['address'] = ($agency->col) ? $agency->sn.', '.$agency->col : $agency->sn;
$arr[$i]['latlon'] = array($agency->lng,$agency->lat);#$agency->lat.",".$agency->lng;#
# Reset variables
$i++;
$latlon=NULL;
}
} catch(Exception $e) { $arr[0]['res'] = null; }
$total = $agencies->count();
$meta = array(
"page" => $page,
"per_page" => $per_page,
"count" => $total,
"total_pages"=> ceil($total/$per_page)
);
return Response::json(array('results'=>$arr,'meta'=>$meta));
} else {
App::abort(404);
}
}
Like Kepoly said in comments, cron is solution. If you have access to server and you use Debian/Ubuntu do:
# crontab -e -u <your webserver account, usually www-data>
And type in:
0 00,05,10,15,20 * * * php <path to your script>
This task will run "0th minute of 12am and 5am and 10am and 3pm and 8pm every day".
For other distros there should be similar way
If you don't have access to server you could use webcron service, like this one: http://www.mywebcron.com/
I have this php code which I use getdocuments method which connect to a web service, I pass the limit , pageNumber and optional filter array and it returns an array of data in addition to the total count of records and page number
I want to display the result in jqgrid, I want to bring for example 20 records and when user go the next page, bring the next 20 records.
<?php
//ini_set("display_errors","1");
require_once 'grid/jq-config.php';
// include the jqGrid Class
require_once "grid/jqGrid.php";
// include the driver class
require_once "grid/jqGridArray.php";
// include the calendar
require_once "grid/jqCalendar.php";
// include the document class
require_once "lib/document.php";
// include heler.php which contain some helper functions
require_once "lib/helper.php";
// create the array connection
$conn = new jqGridArray();
// Create the jqGrid instance
$grid = new jqGridRender($conn);
// prepare array that contains fileds name which user can filter on
$fields = array("BatchNumber", "SenderCode","ReceiverCode","DocumentNumber","DocumentType","InResponse","SubmitDate");
if(get_magic_quotes_gpc()){
$d = stripslashes($_REQUEST["filters"]);
}else{
$d = $_REQUEST["filters"];
}
$d = json_decode($d);
for($i = 0; $i < count($d->rules); $i++){
foreach ($fields as $value) {
if($d->rules[$i]->field == $value){
$option[$value] == $d->rules[$i]->data;
}
}
}
if(isset($_GET["page"])){
$option["PageNumber"] = $_GET["page"];
}
else{
$option["PageNumber"] = 1;
}
if(isset($_GET["rows"])){
$option["Limit"] = $_GET["rows"];
}
else{
$option["Limit"] = LIMIT_DOCUMENT;
}
$results = Document::getDocuments($option);
$arrResult = _object_to_array($results);
$documents = $arrResult["Documents"]["DocumentDataModel"];
$totalCount = $arrResult["TotalCount"] ;
$totalPages = ceil($totalCount/ $option["Limit"]);
// Always you can use SELECT * FROM data1
$grid->SelectCommand = "SELECT BatchNumber, SenderCode ,ReceiverCode , DocumentNumber, DocumentType, InResponse, SubmitDate,LastModifiedDate FROM documents";
$grid->dataType = 'json';
$grid->setPrimaryKeyId('BatchNumber');
$grid->setColModel();
//enable subgrid
// Set the parameters for the subgrid
$grid->setSubGrid("subgrid_document_attachments.php",
array('File Name'),
array(60),
array('left'));
// Enable toolbar searching
$grid->toolbarfilter = true;
$grid->setFilterOptions(array("stringResult"=>TRUE));
$grid->setUrl('grid_documents.php');
$grid->setGridOptions(array(
"width" => 1124,
"height" => 400,
"rowList"=>array(10,20,30,40,50,100),
"sortname"=>"id",
"caption" => "Documents",
"total" => $arrResult["TotalPages"],
"records" => $arrResult['TotalCount'],
"page" => $arrResult['PageNumber'],
));
$grid->setColProperty("BatchNumber", array("label"=>"Batch Number"));
$grid->setColProperty("SubmitDate", array(
"formatter"=>"date",
"formatoptions"=>array("srcformat"=>"Y-m-d H:i:s","newformat"=>"m/d/Y")
)
);
// format the last modified date
$grid->setColProperty("LastModifiedDate", array(
"formatter"=>"date",
"formatoptions"=>array("srcformat"=>"Y-m-d H:i:s","newformat"=>"m/d/Y")
)
);
// add date picker to submit date
$grid->setDatepicker("SubmitDate",array("buttonOnly"=>FALSE));
$grid->datearray = array('SubmitDate');
// Enable navigator
$grid->navigator = true;
// Enable search
$grid->setNavOptions('navigator', array("excel"=>TRUE,"add"=>false,"edit"=>false,"del"=>false,"view"=>false,"csv"=>FALSE, "pdf"=>false));
// Activate single search
$grid->setNavOptions('search',array("multipleSearch"=>false));
// Enjoy
$grid->renderGrid('#grid','#pager',true, null, null, true,true);
?>
I inspected the http request by firebug, {"records":20,"page":1,"total":1}, and grid just display 20 records with 1 page. I want to it to display 20 records and enable pagination so I can press next and bring the next 20 records. I want these values to be something like {"total":"56","page":"1","records":"560"
jqGrid will pass all the information to your web service you will need to retrieve the correct page of data you need to display. The sort index (sidx), sort order (sord), page (page) and rows (rows).
You controller/web service can get this information and then grab the appropriate data from your dataset.
public ActionResult getGridData(string sidx, string sord, int page, int rows, bool _search, string filters) {
...
var pagedDataset = fullDataset.OrderBy(sidx + " " + sord).Skip((page - 1) * rows).Take(rows);
//then format the pagedDataset for the jqGrid and pass it back.
I already using the pagination library in nearly ten modules, with no problems, but it fails in last one (and the most important).
My routing for this section is:
$route['candidate/sort/(:any)/(:any)/page/(:num)'] = 'candidate/sort/$1/$2/$3';
My Controller
public function sort($type, $id, $page = 1) {
/* Load Config */
$data = $this->data;
$data['sub_active'] = 'candidate';
$data['type'] = $type;
/* Get Candidates */
$total = $this->candidates->getTotal($type, $id);
if(($this->limit >= $total) && ($page > 1)) {
$data['candidates'] = $this->candidates->getCandidates(1, $this->limit, $type, $id);
}elseif(((($this->limit * $page) - $this->limit) >= $total) && ($page > 1)) {
$data['candidates'] = $this->candidates->getCandidates(ceil($total / $this->limit), $this->limit, $type, $id);
}else{
$data['candidates'] = $this->candidates->getCandidates($page, $this->limit, $type, $id);
}
/* Pagination */
$this->load->library('pagination');
# Config Pagination
$data['cms']['tables']['total_rows'] = $total;
$data['cms']['tables']['per_page'] = $this->limit;
$data['cms']['tables']['first_url'] = base_url($data['sub_active'].'/sort'.'/'.$type.'/'.$id);
$data['cms']['tables']['base_url'] = base_url($data['sub_active'].'/sort'.'/'.$type.'/'.$id.'/page');
$data['page'] = $page;
$data['total_pages'] = ceil($total / $this->limit);
$data['total'] = $total;
# Initialize Pagination
$this->pagination->initialize($data['cms']['tables']);
$data['pagination'] = $this->pagination->create_links();
/* Display Template */
$this->twig->display('pages/list_candidate.htm', $data);
}
Base first url = myweb.com/candidate/sort/$type/$id and base url = myweb.com/candidate/sort/$type/$id/page
But the pagination doesn’t work, it always the same page (page 1 on this case). I'm using this same schema in other controllers and it works fine, only fails with this.
Thanks in advance.
I finally found the answer:
$config['uri_segment'] = 6;
That's because codeigniter does not detect well the URL.
Nice, I am glad you found the answer Tunnecino!
But I think its need to be further explained , why
According to our wonderful CI user guide, here is how we determine the uri_segment so not to make the same mistake again :)
$this->uri->segment(n)
Permits you to retrieve a specific segment. Where n is the segment number you wish to retrieve. Segments are numbered from left to right. For example, if your full URL is this:
http://example.com/index.php/news/local/metro/crime_is_up
The segment numbers would be this:
1.news
2.local
3.metro
4.crime_is_up
By default the function returns FALSE (boolean) if the segment does not exist. There is an optional second parameter that permits you to set your own default value if the segment is missing. For example, this would tell the function to return the number zero in the event of failure:
$product_id = $this->uri->segment(3, 0);
I'm trying to get all the gameids for a particular player. The API I am working with only returns 24 games per page. I just cant figure out how to loop though the pages.
When a player no longer has anymore pages $mPages will be equal to false.
The problem is adding 1 to $iPages so it can get the next page..
My current script:
<?php
//incude sql database connection
include_once('sql.php');
//include api key
include_once('api.php');
//gamertag
$gamertag = "jam1efoster";
//variant- Valid values are "Campaign", "Firefight", "Competitive", "Arena", "Invasion", "Custom", "Unknown". "Unknown" returns all games.
$variant = "Unknown";
//page number 0 = most recent
$iPage = 0;
while(!$endPages == "stop"){
$iPage = $iPage++;
$GetGameHistory = "http://www.bungie.net/api/reach/reachapijson.svc/player/gamehistory/".$apiKey."/".rawurlencode($gamertag)."/".$variant."/".$iPage;
$output = file_get_contents($GetGameHistory);
$obj = json_decode($output);
echo $output;
$mPages = $obj->HasMorePages;
if($mPages == false){$endPages = "stop";}
foreach($obj->RecentGames as $recentgames) {
$gameid = $recentgames->GameId;
echo $gameid."<br/>";
}
}
?>
Perhaps a while loop?
while (!endOfPages) {
getMoreGames();
}
I am looking for a php pagination class, I have used a rather simple one in the past and it is no longer supported.
I was wondering if anyone had any recommendations ?
It seems pointless to build my own when there are probably so many good ones out there.
After more searching I decided that before I use a frameworked version I should fully understand what is involved in a paginator. So I built one myself. Thanks for the suggestions though!
I would suggest Zend_Paginator for the following reasons
It's loosely coupled and doesn't require the entire library.
The ZF community is larger than the PEAR community and is actively running security audits on code, and releasing maintenance versions.
It separates data sources by using the Adapter Pattern, and there are numerous examples of front end UI pattern implementations in the documentation.
Have you tried PEAR::Pager? Usage examples here.
you can try this:
Zebra_Pagination, a generic, Twitter Bootstrap compatible, pagination class written in PHP
check the link below:
http://stefangabos.ro/php-libraries/zebra-pagination
// pagination class
class Pagination
{
// database handle
private $dbh;
// total records in table
private $total_records;
// limit of items per page
private $limit;
// total number of pages needed
private $total_pages;
// first and back links
private $firstBack;
// next and last links
private $nextLast;
// where are we among all pages?
private $where;
public function __construct($dbh) {
$this->dbh = $dbh;
}
// determines the total number of records in table
public function totalRecords($query, array $params)
{
$stmt = $this->dbh->prepare($query);
$stmt->execute($params);
$this->total_records = $stmt->fetchAll(PDO::FETCH_COLUMN)[0];
if (!$this->total_records) {
echo 'No records found!';
return;
}
}
// sets limit and number of pages
public function setLimit($limit)
{
$this->limit = $limit;
// determines how many pages there will be
if (!empty($this->total_records)) {
$this->total_pages = ceil($this->total_records / $this->limit);
}
}
// determine what the current page is also, it returns the current page
public function page()
{
$pageno = (int)(isset($_GET['pageno'])) ? $_GET['pageno'] : $pageno = 1;
// out of range check
if ($pageno > $this->total_pages) {
$pageno = $this->total_pages;
} elseif ($pageno < 1) {
$pageno = 1;
}
// links
if ($pageno > 1) {
// backtrack
$prevpage = $pageno -1;
// 'first' and 'back' links
$this->firstBack = "<div class='first-back'><a href='$_SERVER[PHP_SELF]?pageno=1'>First</a> <a href='$_SERVER[PHP_SELF]?pageno=$prevpage'>Back</a></div>";
}
$this->where = "<div class='page-count'>(Page $pageno of $this->total_pages)</div>";
if ($pageno < $this->total_pages) {
// forward
$nextpage = $pageno + 1;
// 'next' and 'last' links
$this->nextLast = "<div class='next-last'><a href='$_SERVER[PHP_SELF]?pageno=$nextpage'>Next</a> <a href='$_SERVER[PHP_SELF]?pageno=$this->total_pages'>Last</a></div>";
}
return $pageno;
}
// get first and back links
public function firstBack()
{
return $this->firstBack;
}
// get next and last links
public function nextLast()
{
return $this->nextLast;
}
// get where we are among pages
public function where()
{
return $this->where;
}
}
Use:
$pagination = new Pagination($dbh);
$pagination->totalRecords('SELECT COUNT(*) FROM `photos` WHERE `user` = :user', array(':user' => $_SESSION['id']));
$pagination->setLimit(12);
$pagination->page();
echo $pagination->firstBack();
echo $pagination->where();
echo $pagination->nextLast();
Result:
<div class='first-back'><a href='/xampp/web_development/new_study_2014/imagebox2016/app/public/test.php?pageno=1'>First</a> <a href='/xampp/web_development/new_study_2014/imagebox2016/app/public/test.php?pageno=3'>Back</a></div>
<div class='page-count'>(Page 4 of 6)</div>
<div class='next-last'><a href='/xampp/web_development/new_study_2014/imagebox2016/app/public/test.php?pageno=5'>Next</a> <a href='/xampp/web_development/new_study_2014/imagebox2016/app/public/test.php?pageno=6'>Last</a></div>
public function make_pagination()
{
$total = 0;
$query = "SELECT COUNT(downloads.dn_id) FROM downloads WHERE downloads.dn_type = 'audios'";
$stmt = $this->conn->prepare($query);
$stmt->execute();
$total = $stmt->fetchColumn();
//echo 'row_count = ' . $total;
// How many items to list per page
$limit = 11;
// How many pages will there be
$pages = ceil($total / $limit);
// What page are we currently on?
$page = min($pages, filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT, array(
'options' => array(
'default' => 1,
'min_range' => 1,
),
)));
// Calculate the offset for the query
$offset = ($page - 1) * $limit;
// Some information to display to the user
$start = $offset + 1;
$end = min(($offset + $limit), $total);
// The "back" link
$prevlink = ($page > 1) ? '« ‹' : '<span class="disabled">«</span> <span class="disabled">‹</span>';
// The "forward" link
$nextlink = ($page < $pages) ? '› »' : '<span class="disabled">›</span> <span class="disabled">»</span>';
// Display the paging information
echo '<div id="paging"><p>'.$prevlink.' Page '.$page.' of '.$pages. ' pages'. $nextlink.' </p></div>';
//prepare the page query
$query2 = "
SELECT * FROM downloads, map_artists, song_artists
WHERE map_artists.dn_id = downloads.dn_id
AND song_artists.artist_id = map_artists.artist_id
AND downloads.dn_type = 'audios' GROUP BY downloads.dn_id
ORDER BY downloads.dn_time DESC LIMIT :limit OFFSET :offset ";
$stmt2 = $this->conn->prepare($query2);
$stmt2->bindParam(':limit', $limit, PDO::PARAM_INT);
$stmt2->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt2->execute();
// Do we have any results?
if ($stmt2->rowCount() > 0) {
// Define how we want to fetch the results
$stmt2->setFetchMode(PDO::FETCH_ASSOC);
$iterator = new IteratorIterator($stmt2);
// Display the results
foreach ($iterator as $row) {
echo '<p>'. $row['dn_title'].' - '. $row['artist_name'].'</p>';
}
} else {
echo '<p>No results could be displayed.</p>';
}
}
Its Very possible that your SQL SELECT statement query may 1000 result into thousand of records. But its is not good idea to display all the results on one page. So we can divide this result into many pages as per requirement as pagination Class .
PAGINATE DATA WITH PAGINATION CLASS VERY EASY
pagination Class helps to generate paging
How To Use Pagination Class
visit this link for more info
http://utlearn.com/2017/02/15/pagination-class-use-pagination-class/
<?php
/**
* #package pagination class
* #version 1.0
*/
/*
#class Name: pagination
#Author: Ahmed Mohamed
#Version: 1.0
#Author URI: https://www.fb.com/100002349977660
#Website URI: http://www.utlearn.com
#class page URI: http://utlearn.com/2017/02/15/pagination-class-use-pagination-class
*/
include_once 'libs/config.php';
include_once 'libs/Database.php';
include_once 'libs/Model.php';
include_once 'libs/pagination.php';
if(!empty($_GET["page"]) and is_numeric($_GET["page"])){
$page = htmlspecialchars(strip_tags($_GET["page"]));
} else {
$page = 1;
}
// news = table name / you page URL / current page / true or false for full query
// its false i just use table name
$pag = new pagination("news", URL."?page=", 3, $page, false);
$pagination = $pag->pagination();
$data = $pag->data();
?>
<news>
<?php foreach($data as $news){ ?>
<header><h1><?=$news->title ?></h1> | <span><?=$news->date ?></span></header>
<div>
<?=$news->content ?>
</div>
<?php } ?>
</news>
<?=$pagination ?>