I have some simple pagination set up in my controller like so:
public function index() {
$this->set('items', $this->paginate());
}
In my view I'm using the Paginator helper to output numbered links:
echo $this->Paginator->numbers(array(
'separator' => '',
'tag' => 'li',
'currentTag' => 'a',
'currentClass' => 'active'
));
This all works fine, however I want to use a custom URL for the paginated links. I added this to my routes.php file:
Router::connect('/things/:page', array('controller' => 'things', 'action' => 'index'), array('page' => '[0-9]+'));
Now the links outputted by the Paginator helper are the way I want. They look like http://mysite.com/things/2, http://mysite.com/things/3 etc.
But when I click the links the Paginator in my controller doesn't seem to recognize it's on a certain page, as I just get the first page's results shown. I'm guessing I need to somehow pass the page number to $this->paginate(), but I don't know what the best method is. Is there a way for Cake to get the page number automatically if I modify my route?
Thanks!
Since the Pagination component by default expect named parameter 'page:1' you need somehow to pass same variable in index.
if you make print of $this->request->params in your controller, you will see that it's missing.
See that example how you can pass named parameters in the Router:
Router::connect(
'/:controller/:action/*',
array(),
array(
'named' => array(
'wibble',
'fish' => array('action' => 'index'),
'fizz' => array('controller' => array('comments', 'other')),
'buzz' => 'val-[\d]+'
)
)
);
For more info see this section in Cakephp book
Related
I'm using CakePHP 3 and I want to paginate my users.
However when I click on the second page, the URL looks like /users?page=2 and I expect : /users/2.
I created this route in routes.php :
$routes->connect('/users/:page', ['controller' => 'users', 'action' => 'index'], ['page' => '[0-9]+']);
And in Users/index.ctp before the "prev" button I put :
<?php
$this->Paginator->options([
'url' => [
'controller' => 'users',
'action' => 'index'
]
]);
?>
Now when I click on page 2 for example, /users/2 opens and I got this error message (RuntimeException) :
Unable to locate an object compatible with paginate.
Did I miss something or where I made a mistake ?
Thanks for your help.
The PaginatorHelper has built in the url format, i.e. to use ?page=n. It will also do sorting such as users?page=2&sort=user_id&direction=asc. Your format of /users/{page} does not handle sorting.
If your REALLY want to stick to /users/{page} you'll have to override PaginatorHelper.
try this
in side your controller with paginator component . It works for me
$this->Paginator->paginate('Users')
for custom urlenter code here
u need to implement index action as
public function index($page = null){
$this->Paginator->settings = ['limit' => 15, 'page' => $page];
$this->set('users', $this->Paginator->paginate('Users'));
}
I obviously have a fundamental misunderstanding of how pagination works in CakePHP.
I have the following route set up which shows all posts in a category:
Router::connect('/:parent/:category',
array('controller' => 'posts', 'action' => 'viewCategory'),
array('parent' => '[a-z0-9-]+', 'category' => '[a-z0-9-]+'));
The pages work fine, however the pagination helper is outputting the wrong links for pagination.
I'm using $this->Paginator->numbers().
It's outputting links in this format: mysite.com/posts/viewCategory?page=2
rather than like this: mysite.com/parent-category/sub-category?page=2.
I've tried adding the following route after the first one and it still doesn't work:
Router::connect('/:parent/:category/:page',
array('controller' => 'posts', 'action' => 'viewCategory'),
array('parent' => '[a-z0-9-]+',
'category' => '[a-z0-9-]+',
'page' => '[0-9]+'));
For reference, my pagination options set in my view are as so:
<?php $this->Paginator->options(
array('url' =>
array('controller' => 'posts', 'action' => 'viewCategory')
)); ?>
What am I doing wrong here?
You are setting the url yourself
This is your paginator options call:
<?php
$this->Paginator->options(array(
'url' => array(
'controller' => 'posts',
'action' => 'viewCategory'
)
));
?>
Where you are overriding the current url - and explicitly requesting that the paginator uses the the '/posts/viewCategory' url (with no arguments) as it's base url.
Just don't define the url
Simply don't call options and the helper will use the current url - that should mean that if the current url is:
/parent-category/sub-category
Then page 2 will be (assuming you are using the paramType option to use GET arguments rather than named parameters):
/parent-category/sub-category?page=2
If that's not the case there's information missing from the question; it's important to distinguish between "vanity routes not being used" and "the url is not equivalent (the current situation).
Just had a battle fixing something similar and came across this post. Though old, but I think my answer might save someone the time I had to spend fixing it.
Basically, what you need to do is call the Paginator->options() before Paginator->numbers(), thus:
$this->Paginator->options(
array(
'controller' => 'parent-category',
'action' => 'sub-category'
)
);
Though the controller and action do not exist, it just tricks CakePHP to use them "AS IS", since the reverse routing isn't working!
And for those (like me), who want have set up a route similar to
Router::connect(
'/go/page:id',
array(
'controller' => 'blog',
'action' => 'paginated'
)
);
There might be difficulty setting up the Paginator options. This, however, worked for me:
$this->Paginator->options(
array(
'controller' => 'go',
'action' => '/'
)
);
I guess you know why it worked ;)
I'm using Zend Framework 1.12 and have this route:
$router->addRoute('item_start',
new Zend_Controller_Router_Route_Regex(
'(foo|bar|baz)',
array(
'module' => 'default',
'controller' => 'item',
'action' => 'start'
),
array(
1 => 'area'
),
'%s'
)
);
Problem is, when I call '/foo' and use the Url Helper in the View, it doesn't give me any parameters:
$this->url(array("page"=>1));
// returns '/foo' (expected '/foo/page/1')
$this->url(array("page"=>1), "item_start", true);
// also returns '/foo'
Any idea how to get the page-parameter into the URL? I can't use the wildcard like in the standard route, can't I?
In addition to David's suggestions, you could change this route to use the standard route class, and then keep the wildcard option:
$router->addRoute('item_start',
new Zend_Controller_Router_Route(
':area/*',
array(
'module' => 'default',
'controller' => 'item',
'action' => 'start'
),
array(
'area' => '(foo|bar|baz)'
)
)
);
// in your view:
echo $this->url(array('area' => 'foo', 'page' => 1), 'item_start');
Your Regex route doesn't have a page parameter, so when the url view-helper ends up calling Route::assemble() with the parameters you feed it, it ignores your page value.
The two choices that come to mind are:
Modify your regex to include a (probably optional with default value) page parameter
Manage the page parameter outside of your route in the query string.
I have one route that looks like this:
Router::connect('/Album/:slug/:id',array('controller' => 'albums', 'action' => 'photo'),array('pass' => array('slug','id'),'id' => '[0-9]+'));
and another like this:
Router::connect('/Album/:slug/*',array('controller' => 'albums','action' => 'contents'),array('pass' => array('slug')));
for what doesn't match the first. In the 'contents' action of the 'albums' controller, I take care of pagination myself - meaning I retrieve the named parameter 'page'.
A URL for the second route would look like this:
http://somesite.com/Album/foo-bar/page:2
The Above URL indeed works, but when I try to use the HTML Helper (url,link) to output a url like this, it appends the controller and action to the beginning, like this:
http://somesite.com/albums/contents/Album/foo-bar/page:2
Which i don't like.
The code that uses the HtmlHelper is as such:
$html->url(array('/Album/' . $album['Album']['slug'] . '/page:' . $next))
See below url it is very help full to you
http://book.cakephp.org/2.0/en/development/routing.html
Or read it
Passing parameters to action
When connecting routes using Route elements you may want to have routed elements be passed arguments instead. By using the 3rd argument of Router::connect() you can define which route elements should also be made available as passed arguments:
<?php
// SomeController.php
public function view($articleId = null, $slug = null) {
// some code here...
}
// routes.php
Router::connect(
'/blog/:id-:slug', // E.g. /blog/3-CakePHP_Rocks
array('controller' => 'blog', 'action' => 'view'),
array(
// order matters since this will simply map ":id" to $articleId in your action
'pass' => array('id', 'slug'),
'id' => '[0-9]+'
)
);
And now, thanks to the reverse routing capabilities, you can pass in the url array like below and Cake will know how to form the URL as defined in the routes:
// view.ctp
// this will return a link to /blog/3-CakePHP_Rocks
<?php
echo $this->Html->link('CakePHP Rocks', array(
'controller' => 'blog',
'action' => 'view',
'id' => 3,
'slug' => 'CakePHP_Rocks'
));
Is it possible in CakePHP to have URL aliases in routes.php? Or by what other means can achieve something equivalent:
Lets assume I have some paginated views. Among the possible orderings there are particular ones I want to bind to a simple URL. E.g.:
http://example.com/headlines => http://example.com/posts/listView/page:1/sort:Post.created/direction:desc
http://example.com/hottopics => http://example.com/posts/listView/page:1/sort:Post.view_count/direction:desc etc.
How do I add parameters to a Router::connect()? Pseudo code:
Router::connect('/'.__('headlines',true),
array(
'controller' => 'posts',
'action' => 'listView'
'params' => 'page:1/sort:Post.created/direction:desc',
)
);
Note that the Router "translates" a URL into Controllers, Actions and Params, it doesn't "forward" URLs to other URLs. As such, write it like this:
Router::connect('/headlines',
array(
'controller' => 'posts',
'action' => 'listView'
'page' => 1,
'sort' => 'Post.created',
'direction' => 'desc'
)
);
I don't think '/'.__('headlines', true) would work, since the app is not sufficiently set up at this point to translate anything, so you'd only always get the word in your default language back. Also, you couldn't switch the language anymore after this point, the first use of __() locks the language.
You would need to connect all URLs explictly. To save you some typing, you could do this:
$headlines = array('en' => 'headlines', 'de' => 'schlagzeilen', ...);
foreach ($headlines as $lang => $headline) {
Router::connect("/$headline", array('controller' => ..., 'lang' => $lang));
}
That will create a $this->param['named']['lang'] variable, which you should use in the URL anyway.
Yes, it is possible... Bootstrap.php loads before routes so if you set there something like:
session_start();
if(isset($_SESSION['lng'])){
Configure::write('Config.language', $_SESSION['lng']);
}
...and in your app controller in beforeFilter:
$language = 'xy';
Configure::write('Config.language', $language);
$_SESSION['lng'] = $language;
So initial page render you prompt for language, redirect to xy.site.com or www.site.com/xy whatever you prefer. Now second render will change $language and on page links and set $_SESSION['lang']...
All router links like:
Router::connect(__('/:gender/search/:looking_for/*'), array('controller' => 'users', 'action' => 'search'));
will become:
Router::connect(__('/:gender/trazi/:looking_for/*'), array('controller' => 'users', 'action' => 'search'));
or:
Router::connect(__('/:gender/suche/:looking_for/*'), array('controller' => 'users', 'action' => 'search'));
100% tested, works in CakePHP 2.2. Also further improvement is possible if you put subdomain/language url parser in the bootstrap itself...