My site has many “pages”. Pages are created for different topics and moderated by users (for example a page for Pirates of the Caribbean or a page for Justin Bieber). The page belongs to a category, for example, Movies or Music. The default URL to a page is http://www.example.com/category-directory/page-id. Optionally, if the moderator wants to establish their own link for a page as an easier means of navigation, they can do so by giving value to the “Page.link” column (for example: http://www.example.com/potc for the movie Pirates of the Caribbean).
I have my routes all set up which took some time in itself. The route checks to see if the first parameter of the URL after “.com” matches the “link” column of any page, if it does, route to that page and the controllers/actions under it. If not, route as usual.
When a user is viewing either http://www.example.com/potc/articles/99 or http://www.example.com/movies/106/articles/99 (given that Pirates of the Caribbean is page with id = 106) then the user is directed to the articles controller, view action, id = 99. 106 is passed as $page_id to the controller’s action and also set in the AppController.
The URL array I’m providing in the controller works fine for example if the id does not exist I redirect to 'controller' => 'articles', 'action' => 'index', 'page_id' = $page_id. I am redirected back to http://www.example.com/potc/articles. I don’t actually have to define the controller since by default it uses the current controller.
However, I’m having an issue with the pagination links. Say for example I’m on the articles index page and there are 100 articles but I’m only viewing the first 20. I would like the URL to be outputted as http://www.example.com/potc/articles/page:2.
Instead, if I set the URL array as 'controller' => 'articles', 'action' => 'index', 'page_id' => $page_id similar to what I did in the controller I get the link http://www.example.com/articles/page_id:106/page:2 I can understand why this route does not work because I probably have to pass along the value Page.link if it exists and if not pass along Category.directory and Page.id. I’ve tried doing the latter option using the URL array 'controller' => 'articles', 'action' => 'index', 'category' => $page['Category']['directory'], 'page_id' => $page_id. I have a route to match this but the pagination links are still generated as http://www.example.com/articles/category:movies/page_id:106/page:2
Here are some snippets from my routes.php: https://gist.github.com/9ba0a54a7f4d68803d14
My question is: “Can I use the exact current URL for pagination links (minus reference to current page I am on)?” For example, if I’m viewing http://www.example.com/dynamic-route/controller/id/page:2, the pagination link will automatically go to http://www.example.com/dynamic-route/controller/id/page:3
I put all of my pagination code into an element and I would like to include the element in my view file wherever the pagination is needed.
Right now, if I’m viewing the articles controller, index action, the default URL for the pagination links is http://www.example.com/articles/page:2, but I need it to be http://www.example.com/dynamic-route/articles/page:2
I tried using the
$this->Paginator->options = array(
'url' => 'http://www.example.com/dynamic-route/articles'
);
But the link is output like http://www.example.com/articles/http://www.example.com/dynamic-route/articles/page:2
Edit: Jeztah, you mention putting
‘customlink’ => ‘[a-z0-9]{1}([a-z0-9-]{2,}[a-z0-9]{1})?’
in my route. Well I can’t simply do this because the route does a query to check to see if the customlink is in the database and if so routes accordingly.
An example of my router file is:
after getting first param of url which would be http://www.domain.com/CUSTOM-LINK, do the following:
if($param1 != "users" && $param1){
$pagelink = str_replace('-', ' ', $param1);
$pagesModel = ClassRegistry::init('Page');
$matchedpage = $pagesModel->find('first', array(
'conditions' => array('Page.link LIKE' => "$pagelink"), 'recursive' => '-1'
));
if($matchedpage['Page']['id']){
Router::connect('/' . $param1 . '/:controller', array('action' => 'index', 'page_id' => $matchedpage['Page']['id']), array(
'pass' => array('page_id'),
'page_id' => '[0-9]+',
'persist' => array('page_id'),
));
Router::connect('/' . $param1 . '/:controller/:action/:id', array('page_id' => $matchedpage['Page']['id']), array(
'pass' => array('page_id', 'id'),
'page_id' => '[0-9]+',
'persist' => array('page_id'),
));
Router::connect('/' . $param1 . '/:controller/:id', array('action' => 'view', 'page_id' => $matchedpage['Page']['id']), array(
'pass' => array('page_id', 'id'),
'page_id' => '[0-9]+',
'id' => '[0-9]+',
'persist' => array('page_id'),
));
Router::connect('/' . $param1 . '/:controller/:action', array('page_id' => $matchedpage['Page']['id']), array(
'pass' => array('page_id'),
'page_id' => '[0-9]+',
'persist' => array('page_id'),
));
} // end if page matches
} // end if param1 is not users
If I go to http://www.domain.com/custom-link/articles, http://www.domain.com/custom-link/articles/1, http://www.domain.com/custom-link/articles/edit/1, etc the proper page is display. If I try to navigate to a page where the custom-link does not exist, continue down my router file and if no other route is matched then throw error message. All good there.
In my ArticlesController.php the redirect method works as expected. Say for example, I try to go to http://www.domain.com/custom-link/articles/99 but id 99 does not exist, I am properly redirected back to http://www.domain.com/custom-link/articles using
$this->redirect(array(‘action’ => ‘index’, ‘page_id’ => $page_id),
null, true);
However, on the pagination, I set the url options as
array(‘controller’ => ‘articles’, ‘action’ => ‘index’, ‘page_id’ =>
$page_id);
where $page_id is set in the AppController from being passed by the Router. Though I don’t need to set controller and action because the current will be used. Again, my pagination links appear as http://www.domain.com/articles/page_id:3/page:2 and not what I want which is http://www.domain.com/custom-link/articles/page:2
Edit: Jeztah
I just changed my entire route file to what you had with having a custom-link parameter (I renamed to ‘link’) and then created a component for use in the app controller to get the page id from the link.
Example route
Router::connect('/:link/:controller/:action/:id', array(), array(
'pass' => array('link', 'id'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'persist' => array('link'),
));
Router::connect('/:link/:controller/:id', array('action' => 'view'), array(
'pass' => array('link', 'id'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'id' => '[0-9]+',
'persist' => array('link'),
));
However, paginating with the url array as array('link' => 'test-example') the url is outputted as http://www.domain.com/articles/link:test-example/page:2. My code is exactly as yours minus renaming “custom-link” to “link”. Also, now my route can’t differentiate between whether I’m trying to access http://www.domain.com/custom-link which would be ‘controller’ => ‘pages’, ‘action’ => ‘view’ (his page would basically use the News model and display the latest news for the page) and if I’m trying to access http://www.domain.com/articles which would be ‘controller’ => ‘articles’, ‘action’ => ‘index’ which would display the latest articles for ALL pages. Note, articles and news are separate models.
Router::connect('/:link', array('controller' => 'pages', 'action' => 'view'), array(
'pass' => array('link'),
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
'persist' => array('link'),
));
is the same as
Router::connect('/:controller', array('action' => 'index'));
because the check to see whether or not ‘link’ belongs to a specific page is no longer done in the route.
Edit: Ok I’m making progress. I found out that next and previous pagination links don’t take to the paginator->options very well. I deleted the paginator->options and left the url array of the next button empty. The link was outputted as http://www.domain.com/articles/custom-link/articles/page:2. Progess! But is there any way to get ride of the first “articles/”?
My route is
Router::connect('/:link/:controller/*', array(), array(
'link' => '[a-z0-9]{1}([a-z0-9\-]{2,}[a-z0-9]{1})?',
));
Edit: This is an edited answer after I realized my last answer was flawed when it came to ArticlesConntroller::redirect
For anyone who has managed to read this entire question/comments and care to know the answer. I figured out a solution thanks to Jeztah’s assistance whom I will be awarding this bounty to. One of the issues giving me a hard time was the fact that a page could have 2 URLs. For example: http://www.domain.com/potc or http://www.domain.com/movies/106.
Basically I used a combination of mine and Jeztah’s ideas.
First, I have to perform a check in the routes.php to see if the first param after the .com matches a page’s shortcut “link” (example: http://www.domain.com/potc = potc).
because page_id is being passed in both the :link routing and the :category routing, I don’t have to have a component that get’s the page’s id as suggested.
Now in my ArticlesController
My pagination is stored in an element but I load the element at the bottom of the Articles index.ctp view
I would place the same code for each of my different controllers but change out the word “articles” (example : “reviews”, “news/topics”, etc)
My pagination.ctp element looks like this