PHP CodeIgniter Pagination link broken - php

public function index($page = 0) {
$this->load->library('pagination');
$conf = array(
'total_rows' => 11,
'base_url' => 'localhost/admin/product/index',
'per_page' => 10,
'use_page_numbers' => false
);
$this->pagination->initialize($conf);
$this->load->view('product/index');
}
In view
<?php echo $this->pagination->create_links(); ?>
In the first page it work correctly. When I click on the page 2 link, it only display ONE product, this was correct, but the pagination links for current page still in page ONE. Suppose this should be page TWO.
which part I did wrong?

Well, the pagination class uses "per_page" in the query string. So, you have to divide that number by 10 (in your case) and add 1 to get the real page number, i.e.:
localhost/product/index (page 1)
localhost/product/index?per_page=10 (page 2)
localhost/product/index?per_page=20 (page 3)
...
localhost/product/index?per_page={10n) (page n+1)
This is useful to use directly in the database limit clause:
$this->db->limit(10, $this->input->get('per_page'))...
I think that's why CI chose to do it that way....

Related

Access Paginator object in controller

I am using cakePHP 2.5 and I want to access $this->Paginator->hasNext() in controller, but it through exception.
$type = array('featured', 'newest', 'trending');
foreach($type as $each)
{
$conditions = array('Product.status'=>'1', "is_$each" => '1');
$this->Product->recursive = 1;
//retrieve and set final result set
$this->paginate = array(
'fields' => array('Product.*'),
'conditions' => $conditions,
'limit' => $page_limit,
'page' => $page,
'order' => "$order_by $order_by_sort",
);
$products[$each] = $this->paginate('Product');
}
On my page, I want to display 3 type of product featured/trending/newest. Initially I load first page by default, then when user scroll down then I will call ajax and append next page like wise. But if last page is reached then I want to stop ajax call (because unknown page through 404 not found error).
To overcome that, I prevent AJAX call for unknown pages. And also make sure that first page isn't last!!
Hope my details make sense!
I could not find any answer on any forum/document. Please guide me or point me if it's duplicate of any.
You don't need to (and cannot*) access a helper in the controller.
Take a look at the source code for hasNext which is just calling the helper function _hasPage, which is simply checking the parameters array.
The paginator parameters are all available in the controller:
$paging = array(
'page' => $page,
'current' => count($results),
'count' => $count,
'prevPage' => ($page > 1),
'nextPage' => ($count > ($page * $limit)),
'pageCount' => $pageCount,
'order' => $order,
'limit' => $limit,
'options' => Hash::diff($options, $defaults),
'paramType' => $options['paramType']
);
So from the code in the question:
$this->request['paging']['Product']['nextPage']
Is the information you're looking for (it will be overwritten each time you call paginate.
Consider your application design.
Unless you have exactly the same number of featured, newest and trending records - it'd be better to have one ajax request for each type. Also see this related question, for more information on implementing infinite-scroll type pages.
* Almost anything is possible, you certainly should not need to use a helper in a controller though.
MVC Violation
$this->Paginator->hasNext()
That's a method of the helper. Helpers are not thought to be used in controllers because this is a violation of the MVC pattern and bad practice. If you think you have to you're wrong: Fix your architecture, it's broken by design.
Proper solution
Return the status of the pagination along with the data in the AJAX response:
$this->set('pagination', $this->request->paging['Product']);
$this->set('products', $result);
$this->set('_serialize', ['products', 'pagination']);
You can change the state of your view depending on the data then:
if (pagination.Product.nextPage == true) { /*... */ }

Yii Infinite scroll last row values repeating

i implement the Yii infinite scroll extension. its working fine. its scrolling 10 by 10 from the database dynamically at last 10 values are repeated one more time.
i simply printing text values only but at last row ie last 10 values are repeated once.
i added my code here :
site controller
$criteria = new CDbCriteria;
$total = Recipe::model()->count();
$pages = new CPagination($total);
$pages->pageSize = 10;
$pages->applyLimit($criteria);
$posts = Recipe::model()->findAll($criteria);
$this->render('index', array(
'posts' => $posts,
'pages' => $pages,
));
my index page here:
<div id="posts">
<?php foreach($posts as $rec): ?>
<?php $rec_id=$rec['recipe_id']; $name=$rec['name']; ?>
<?php echo $name=$rec['name']; ?>
then i added my extension below
Infinite scroll ( and yii-infinite scroll) stops querying the server when it it hits a 404 error. on the next page. Yii framework keeps returning the last results for page numbers greater than what the result has.
This is why you keep seeing duplicated rows at the end of the results.. to prevent this add this piece of code to your corresponding action in your controller.
if(isset($_GET['Model_page'])){
if($model->search()->pagination->pageCount < $_GET['Model_page']+1){
throw new CHttpException(404,'No More results');
}
}
Where Model_page is to be substituted with Post_page etc depending on your model name and $model->search() is your dataProvider, if you have some other dataProvider please use that directly after it has been declared.

Kohana pagination and JavaScript tabs

OK so basically I have created a simple page using Kohana for displaying a user's message inbox/outbox using tabs.
My controller is something like this:
$content = View::factory('messages')->bind('user', $user)->bind('received', $received)->bind('sent', $sent)->bind('pager_links', $pager_links);
$user = Auth::instance()->get_user();
$message_count = ORM::factory('message')->where('to_id', '=', $user)->where('read', '=', '0')->count_all();
$pagination = Pagination::factory(array(
'total_items' => $message_count,
'items_per_page' => 10
));
$received = ORM::factory('messages')->where('messages.to_id', '=', $user)->limit($pagination->items_per_page)->offset($pagination->offset)->find_all();
$sent = ORM::factory('messages')->where('messages.user_id', '=', $user)->limit($pagination->items_per_page)->offset($pagination->offset)->find_all();
$pager_links = $pagination->render();
$this->template->content = $content;
So far I am only displaying the received messages and pagination in the view and it is working fine. However I want to implement a tab container to display both the received and sent items on the same page.
I am scratching my head wondering how to use the pagination aspect for each tab without it affecting both tabs. What would be the best direction for this using the existing approach? Perhaps throwing an additional parameter into the URL when a tab is selected...
Thanks
Basically your issue is that you can't use page in the query string for both of the tabs at once, as obviously it will affect both pagination functions. Luckily there is in fact a configuration open that allows you to specify the source of the current page parameter in the query string.
Try this...
$pagination = Pagination::factory(array(
'current_page' => array('source' => 'query_string', 'key' => 'tab1_page'),
'total_items' => $message_count,
'items_per_page' => 10
));
Then all you need to do is make sure that your pagination view is passing the page number to the correct parameter in the query string e.g. http://mydomain.com/pagewithtabs?tab1_page=2&tab2_page=3 will put tab 1 on page 2 and tab 2 on page 3.
Hope that helps!

CakePHP 2.0 - Pagination for an image gallery (with different item limits)

I want to build a small image gallery with CakePHP. Therefore I created an index view which displays a 3x3 table with image thumbnails. For pagination and sorting I added the following code:
ImagesController.php:
var $paginate = array(
'limit' => 9,
'order' => array('Image.id' => 'desc')
);
public function index() {
$data = $this->paginate('Image');
$this->set('images', $data);
}
index.ctp:
<?php echo $this->Paginator->sort('id', 'Id'); ?> |
<?php echo $this->Paginator->sort('name', 'Title'); ?>
...
<?php echo $this->Paginator->prev(' << Previous', null, null, array('class' => 'disabled')); ?>
<?php echo $this->Paginator->numbers(array('first' => 2, 'last' => 2)); ?>
<?php echo $this->Paginator->next('Next >> ', null, null, array('class' => 'disabled')); ?>
This works great. Now, when you click on a thumbnail a single image will be displayed using a view named 'view' (e.g. localhost/gallery/images/view/1). Like the index view, this view should have a pagination too, where the image with the id of 1 is currently selected and where you can navigate to the n previous and next images relative to the currently selected one. Moreover the images should be sorted by the same criteria as the pictures on the index view (e.g. by name). Is there an elegant way to solve this problem with CakePHP?
I'd approach this by passing the page number from the original pagination to the detail view.
If you were looking at Image ID 1 on page 2, your URL would look something like:
/gallery/images/view/1/2
That is:
/gallery/images/view/:id/:page
From this information, you can query the same paginated data from the index action on the specified page, and provide back and next navigation options from that data.

cakePHP pagination and passedArgs

I am trying to build in a "search" box on a results page in my cakephp app. The page uses the cakePHP pagination component to show and "page" results. This is perfect, but I am having difficulties to get the next part to work.
The desired outcome:
A cakephp form (post) with an input box and a couple of select boxes, including a date selector so that I can select between dates. The user should be able to populate these fields and submit
On submit, the user selection should change the cakePHP pagination conditions in the controller
In the view I want the pagination bar to keep record of the user selection, so that when I filter through different pages, it keeps the users search. I understand this can be achieved using $this->passedArgs, hence why I am using post and not get.
The code:
// Form:
<?php
echo $this->Form->create('search', array('class' => false));
echo $this->Form->input('searchFor');
echo $this->Form->input('dateFrom');
echo $this->Form->input('dateTo');
echo $this->Form->end();
?>
// Controller:
if($this->request->is("post")) {
$filters = $this->request->data["search"];
$this->passedArgs["searchFor"] = $filters["searchFor"];
$this->passedArgs["dateFrom"] = $filters["dateFrom"]." 00:00:00";
$this->passedArgs["dateTo"] = $filters["dateTo"]." 00:00:00";
// Assign search parameters:
if($this->passedArgs["searchFor"] != "") {
$conditions["Model.field LIKE"] = "%".$this->passedArgs["searchFor"]."%";
}
$conditions["Model.created >="] = $this->passedArgs["dateFrom"];
$conditions["Model.created <="] = $this->passedArgs["dateTo"];
} else {
$conditions = array("Result.status_id >=" => 12);
}
$this->paginate = array(
'conditions' => $conditions,
'order' => array('Result.created ASC'),
'limit' => 20
);
$this->set("results",$this->paginate("Model");
// The view file:
<?php
$this->Paginator->options(array('url' => $this->passedArgs));
?>
Where I am now:
The initial page loads with all of the results
When I populate the search boxes it does return my results
The problem:
I am convinced the way I am doing it is incorrect as I now need to do 2 checks, a) being if results has been posted and b) check if there is passedArgs available. I am 100% convinced this is not the right way of doing it.
Let's say I have 2 free form fields for search, say name and surname, if I leave surname blank my url would be written as below, and this does not look or appear to be correct. That means I have to assign default values to ensure the items below does not happen, which does not appear to be very dynamic.
http://localhost/site/controller/action/surname:0/name:John/date:0/
On refresh it says the page does not exist because the posted values is not available anylonger.
usually I proceed like this in the controller:
//transform POST into GET
if($this->request->is("post")) {
$url = array('action'=>'index');
$filters = array();
if(isset($this->data['searchFor']) && $this->data['searchFor']){
//maybe clean up user input here??? or urlencode??
$filters['searchFor'] = $this->data['searchFor'];
}
//redirect user to the index page including the selected filters
$this->redirect(array_merge($url,$filters));
}
$conditions = array();
//check filters on passedArgs
if(isset($this->passedArgs["searchFor"])){
$conditions["Model.field LIKE"] = "%".$this->passedArgs["searchFor"]."%";
}
//paginate as normal
$this->paginate = array(
'conditions' => $conditions,
'order' => array('Result.created ASC'),
'limit' => 20
);
The idea is to transform the POST sent by your form into GET. so you wont have problems with the paginator nor the refresh
Hope this helps
What you want can be done a lot more simple and DRY by using this search plugin.
It automates what you want more or less plus it already can do more than your code.
So I suggest you to use the plugin directly or take a look at it how it does the trick. :)

Categories