May 11, 2014

May 11, 2014
In this article, we are going to discuss about How to create a custom Route classes and pagination in CakePHP. Recently I have faces some issues with the buit-in Paginator Helper when combined with custom routes. I have the site setup so that admins can create Category pages with unique URL slugs so that they can edit pages and also get nice URLs like so:

I've set this up in CakePHP using a custom Route class as per the docs and this works great. Below I've got the routes.php code to check for a Category slug and use the view action of the ProductCategories Controller.

// app\Config\routes.php file
Router::connect('/:slug/*', array('controller' => 'product_categories', 'action' => 'view'), array('routeClass' => 'CategorySlugRoute'));

This is the Route class code, which is pretty straight forward just in case you need to do anything similar. I've added caching to speed things up and the only caveat are the sub-categories; as these are separated with a forward slash we have to rebuild them to ensure we're checking the slugs for sub categories as well as top level categories.

 * Deal with Category Slugs
App::uses('ProductCategory', 'Model');
class CategorySlugRoute extends CakeRoute {

* Parse the URL
* @param string $url
* @return boolean
function parse($url) {
$params = parent::parse($url);
if (empty($params)) {
return false;

// See if slugs are cached
$slugs = Cache::read('slugs_categories');
if (!$slugs) {
// Get all slugs
$ProductCategory = new ProductCategory();
$slugs = $ProductCategory->find('list', array(
'fields' => array('ProductCategory.slug'),
'recursive' => -1

Cache::write('slugs_categories', $slugs);

// Reverse slugs for easy comparison
$slugs = array_flip($slugs);

// See if sub categories have been passed
if (!empty($params['pass'])) {
$params['slug'] .= '/' . implode('/', $params['pass']);

// Match passed slug with Category slugs
if (isset($slugs[$params['slug']])) {
return $params;

return FALSE;

When it came to paginating those result it wasn't clear how to take advantage of the custom slug I was using. I tried a few different solutions however all the generated pagination links all included the /product_categories/view in the URL which is incorrect.

To fix the links I had to pass in the slug as a url Paginator option before the calls to generate the links. After this CakePHP knew what was going on and correctly built the correct URL.

// app\View\ProductCategories\index.ctp
$this->Paginator->options(array('url' => array('slug' => $category['ProductCategory']['slug'])));
echo $this->Paginator->prev('Prev');
echo $this->Paginator->numbers();
echo $this->Paginator->next('Next');


Post a Comment