I am using pagination on my CakePHP page and it works well, but I have a few pages generated by different functions in one controller file and there is an cumbersome issue.
Let's assume I've got two tables with hundreds of entries, which my paginators divide and display 15 of entries on one page:
public $paginate = array(
'Table1' => Array(
'order' => array('Table1.id' => 'desc'),
'limit' => 15
),
'Table2' => Array(
'order' => array('Table2.id' => 'asc'),
'limit' => 15
)
);
And functions in this controller file:
public function showTable1() {
$this->set('table', $this->paginate('Table1'));
}
public function showTable2() {
$this->set('table', $this->paginate('Table2));
}
When I go to the next page while displaying "Table 1", I go to the next page and it works well. But when I open another page with "Table 2" generated by another function from the same controller file, it unfortunately also goes to the second page.
What should I do to have different "pages indicators"? I mean, when I go to the third page on "Table 1", I don't want to go to the third page when I go to "Table 2".
Thanks in advance. I hope I presented my problem clearly.
instead of setting the pagination options on the top of the controller, try deleting that public $paginate and setting all the options inside action, like this (and in the similar way for the second action)
public function showTable1() {
$options = array(
'conditions' => array(
'Table1.id' => whatever
),
'fields' => array(
'Table1.id'
),
'order' => array(
'Table1.id' => 'DESC'
),
'limit' => 15
);
$this->Paginator->settings = $options;
$table = $this->Paginator->paginate('Table1');
$this->set(compact('table'));
}
Related
I have one web page and in this page I need total 2 paginations for different different 2 tables.
I have tried with different pagination but it's dependent with each other.
For ex., If I select second page of first table then second table automatically changed with 2nd page.
Here is my controller code code :
$page = $this->pageForPagination('User');
$this->paginate = array(
'User' => array(
'fields' => array(
'User.*',
),
'conditions' => $userConditions,
'page' => $page,
),
);
$this->set('users', $this->paginate('User'));
$page1 = $this->pageForPagination('Game');
$this->paginate = array(
'Game' => array(
'fields' => array(
'Game.*',
),
'conditions' => $conditions,
'page' => $page1,
),
);
$this->set('games', $this->paginate('Game'));
Here is the function that is used in above code :
function pageForPagination($model) {
$page = 1;
$sameModel = isset($this->params['named']['model']) && $this->params['named']['model'] == $model;
$pageInUrl = isset($this->params['named']['page']);
if ($sameModel && $pageInUrl) {
$page = $this->params['named']['page'];
}
$this->passedArgs['page'] = $page;
return $page;
}
Here is my view code :
echo $this->element('paging', array('model' => 'User'));
echo $this->element('paging', array('model' => 'Game'));
I have referred above code from this url : http://debuggable.com/posts/how-to-have-multiple-paginated-widgets-on-the-same-page-with-cakephp:48ad241e-b018-4532-a748-0ec74834cda3
Can any one help me because I didn't get any solution still?
The solution in the link you mentioned is to override the default pagination urls and doesn't display both models at the same time. You haven't implemented the solution completely.
You have to extract the page number manually for each model like this:
function pageForPagination($model) {
if (isset($this->params['named']['pagefor'.$model])
return $this->params['named']['pagefor'.$model];
else
return 1;
}
The code below:
echo $this->element('paging', array('model' => 'User'));
echo $this->element('paging', array('model' => 'Game'));
causes the cakephp to use the default pagination view and the urls in the default pagination are the same for both models. You have to use custom pagination view and specify the model for the page link.
For the edited function above you can use a url pattern like this:
/Controller/Action/pageforUser:215/pageforGame:35
for each page link in your view.
I think best practice to use this url pattern is to override the pagination helper so that the links that are created form the following pattern:
'/Controller/Action/pagefor[Model]:215'.[other parameters]
I'm using CakePHP v2.4.1, and I'm trying to have two separate models be paginated on the same page, through the same controller action (index)
I want to have a NewsPost paginated on a single page, and the EventPost also paginated separately on the same page. Is this bad practice, or is it possible to set conditions to change the $this->paginate variable to paginate properly depending on which model it is on?
My Controller looks like this:
public $uses = array(
'NewsPost',
'NewsPostComment',
'EventPost',
'EventPostComment'
);
public $paginate = array(
'limit' => 9,
'order' => array(
'NewsPost.created' => 'desc'
),
'recursive' => 1,
);
public function index() {
$this->paginate = array(
'limit' => 1,
'order' => array(
'EventPost.created' => 'desc'
),
'recursive' => 1,
);
$this->Paginator->settings = $this->paginate;
$newsPosts = $this->paginate('NewsPost');
$eventPosts = $this->EventPost->find('all');
$this->set(array('newsPosts' => $newsPosts, 'eventPosts' => $eventPosts));
The built-in cake paginator does not seem to allow for the options of paginating separate models, or am I wrong?
Here is the view for pagination:
<?php
$params = $this->Paginator->params();
if ($params['count'] > 0): ?>
<div class="pagination-totals pull-left">
<?php echo $this->Paginator->counter(array('format' => __('{:start} to {:end} of {:count}'))) ?>
</div>
<?php endif; ?>
<?php echo $this->Paginator->numbers(array(
'class' => 'pull-right',
'prev' => '<',
'next' => '>',
));
?>
The problem is, when I choose page two for the NewsPost, it switches to page two for the EventPost, so how can I differentiate between both separate models on the same page using CakePHP pagination?
Thanks
You have just one params named page in your page so the result in normal.
You have to handle this with ajax request and separated actions
I have recently built some admin dashboard for managing projects and blog posts together. I wanted to put both in one dashboard and show as two tables with pagination. So in controller, I put something like this:
$this->Paginator->settings = array(
'Project'=>array(
'limit' => 10,
'order' => array(
'Project.created_time' => 'desc'
),
'paramType' => 'querystring'
),
'Post'=>array(
'limit' => 10,
'order' => array(
'Post.created_time' => 'desc'
),
'paramType' => 'querystring'
)
);
$projects = $this->Paginator->paginate('Project');
$posts = $this->Paginator->paginate('Post');
$this->set('projects', $projects);
$this->set('posts', $posts);
and in the view I use
<?php echo $this->Paginator->numbers(array('model'=>'Post')); ?>
and
<?php echo $this->Paginator->numbers(array('model'=>'Project')); ?>
to manage the pages link of each model.
But the problem is when I click one page link, the other one is changing to that page as well. The url only give the paged link as dashboard?page=5
Is there anyway that I can access them separately? Like dashboard?project_page=5 ordashboard?post_page=5.
Thanks for any ideas.
hi guys i am new to cakephp
now i'm facing a little big problem
here is the situation
i hava a shop that hasMany Catalogs which is related to many products each product has a category
i want to fetch them all just by getting the shop
i dont know how to do it
trying to use hasMAny gives me just the ids
instead is there any way to get shop inside it array of catalogs each catalog has Product's array which has one array of category
thank you
Ok, I'm on my computer now :).
In ShopModel:
class ShopModel extends AppModel {
public $hasMany = array(
'Catalog' => array(
// binding params here...
),
);
}
In CatalogModel:
class CatalogModel extends AppModel {
public $hasMany = array(
'Product' => array(
// binding params...
),
),
}
... and this goes on...
If you don't want to get excessive data in all actions, you should set in AppModel:
class AppModel extends Model {
public $recursive = -1;
}
In the controller action where you call the find function with associations:
$this->Shop->Behaviors->load('Containable');
$big_array = $this->Shop->find('all', array(
'conditions' => array(
//...
),
'contain' => array(
'Catalog' => array(
'Product' => array(
// etc, you get the point :)
),
),
),
));
It is also nice to declare the $belongsTo associations too, so you can access anything from anywhere, something like this:
$this->Catalog->Behaviors->load('Containable');
$big_array = $this->Catalog->find('all', array(
'conditions' => array(
//...
),
'contain' => array(
'Product' => array(
// ...
),
'Shop' => array(
// ...
),
),
));
EDIT
I see you have a Product->Category relation that i guess would be defined with $belongsTo. If you do a query like the one above, you will get a lot of duplicate queries (same category in many products). You can use $this->Category->find('list') but very often I find this inappropriate as it is returning only one field (I would be grateful if someone knows a way how can I get more fields with the list type). For this purpose, my workaround is making a custom function in the Category model like this:
class Category extends AppModel {
public function getSorted ($options = array()) {
$temp= $this->find('all', $options);
$output = array();
foreach ($temp[$this->alias] as $row) {
$output[$this->alias][$row['id']] = $row;
}
unset($temp);
return $output;
}
}
Then in the controller I would declare two arrays, the big one without category association and the category list one:
$this->loadModel('Category');
$this->set('categories', $this->Category->getSorted());
This way, I can get the needed category row by category id wherever i need it in the view.
Do not use CakePHP association they are not good handling complex relationships, you will later face problems with....Instead create all your join queries on the fly...I am giving you one example below:
Create one function inside Shop model and join catalog and product as shown below:
$options = array(
'conditions' => array('Product.id'=>9),
'joins' => array(
array(
'alias' => 'Catalog',
'table' => 'catalogs',
'type' => 'LEFT',
'conditions' => array(
'Catalog.product_id = Product.id',
),
),
array(
'alias' => 'Product',
'table' => 'products',
'type' => 'LEFT',
'conditions' => array(
'Shop.id = Product.shop_id',
),
)
),
'fields' => array('Product.*'),
'group' => array('Product.id')
);
$returnData = $this->find('all',$options);
This will make coding little easier and you can escape from associations!
im using Drupal 7 and I want to add a new filter in views.
I have a custom table "clicks" with two fields; nid and clicks_left.
The filter should just contain a checkbox "Only display nodes with clicks left". So the filter should join node and clicks on nid..
I have read like thousands of pages of custom filters but can't get it to work =)
Please, could someone show me a working example so I understand?
I have come so far that the filter is displayed under filters but what do I need to add to do the join and get the checkbox? The relevant code below:
FILE clicks_views.inc:
function clicks_views_data() {
$data = array();
$data['clicks']['clicks_filter'] = array(
'group' => t('Clicks'),
'title' => t('Clicks left'),
'help' => t('Filter any Views based on clicks left'),
'filter' => array(
'field' => 'clicks_left',
'handler' => 'clicks_handler_filter',
),
);
return $data;
}
FILE clicks_handler_filter.inc:
<?php
class clicks_handler_filter extends views_handler_filter {
???
};
I know both functions are wrong ;)
Ok, I've found a solution. For anyone who needs it:
In clicks.module
function clicks_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'clicks') . '/includes'
);
}
In clicks.views.inc
function clicks_views_handlers() {
return array(
'info' => array(
'path' => drupal_get_path('module', 'clicks') . '/includes', // path to view files
),
'handlers' => array(
// register our custom filter, with the class/file name and parent class
'clicks_handler_filter' => array(
'parent' => 'views_handler_filter',
)
),
);
}
function clicks_views_data() {
$data = array();
if(module_exists('clicks')) {
$data['node']['clicks'] = array(
'group' => t('Clicks'),
'title' => t('Clicks left'),
'help' => t('Filter any Views based on clicks left'),
'filter' => array(
'handler' => 'clicks_handler_filter',
),
);
}
return $data;
}
In clicks_handler_filter.inc
class clicks_handler_filter extends views_handler_filter {
function admin_summary() { }
function operator_form() { }
function query() {
$table = $this->ensure_my_table();
$join = new views_join();
$join->construct('clicks', $this->table_alias, 'nid', 'nid');
$this->query->ensure_table('clicks', $this->relationship, $join);
$this->query->add_where($this->options['group'], "clicks.clicks_left", 0, ">");
}
}
This gives me a possibility to add a filter "clicks" that if enabled hides all results that doesn't have clicks left (clicks_left > 0)
Actually, if your values in your tables clicks are numeric you don't need to create your own handler, you can use the default from Views views_handler_filter_numeric.
You can see all handlers that already exists in the Views handlers.