CakePHP Router::connect() aliases? - php

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...

Related

CakePHP pagination on custom route

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 ;)

Zend Url View Helper not working with Regex Routes

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.

Kohana 3.2 - Routing questions

Firstly, Kohana's documentation is terrible, before people go "read the docs" I have read the docs and they don't seem to make much sense, even copying and pasting some of the code doesn't work for some things in the documentation.
With that in mind, I have a route like so:
//(enables the user to view the profile / photos / blog, default is profile)
Route::set('profile', '<userid>(/<action>)(/)', array( // (/) for trailing slash
"userid" => "[a-zA-Z0-9_]+",
"action" => "(photos|blog)"
))->defaults(array(
'controller' => 'profile',
'action' => 'view'
))
This enables me to go http://example.com/username and be taken to the users profile, http://example.com/username/photos to be taken to view the users photos and http://example.com/username/blog to view the blog.
If somebody goes http://example.com/username/something_else I want it to default to the action view for the user specified in <userid> but I can't seem to find any way of doing this.
I could do it like this:
Route::set('profile', '<userid>(/<useraction>)(/)', array(
"userid" => "[a-zA-Z0-9_]+",
"useraction" => "(photos|blog)"
))->defaults(array(
'controller' => 'profile',
'action' => 'index'
))
then in the controller do this:
public function action_index(){
$method = $this->request->param('useraction');
if ($method && method_exists($this, "action_{$method}")) {
$this->{"action_{$method}"}();
} else if ($method) {
// redirect to remove erroneous method from url
} else {
$this->action_view(); // view profile
}
}
(it might be better in the __construct() function but you get the gist of it.)
I'd rather not do that though if there is a better method available (which there really should be)
I think the answer might be in the regex but the following does not work:
$profile_functions = "blog|images";
//(enables the user to view the images / blog)
Route::set('profile', '<id>/<action>(/)', array(
"id" => "[a-zA-Z0-9_]+",
"action" => "($profile_functions)",
))->defaults(array(
'controller' => 'profile'
));
Route::set('profile_2', '<id>(<useraction>)', array(
"id" => "[a-zA-Z0-9_]+",
"useraction" => "(?!({$profile_functions}))",
))->defaults(array(
'controller' => 'profile',
'action' => 'view'
));
although it does match when nothing is after the ID.
I would set up the route like this:
Route::set('profile', '<userid>(/<action>)(/)', array(
"userid" => "[a-zA-Z0-9_]+",
"action" => "[a-zA-Z]+"
))->defaults(array(
'controller' => 'profile',
'action' => 'index'
))
And then in the controllers before() method:
if(!in_array($this->request->_action, array('photos', 'blog', 'index')){
$this->request->_action = 'view';
}
Or somethig similiar, just validate the action in the controller...
EDIT:
This could also work:
if(!is_callable(array($this, 'action_' . $this->request->_action))){
$this->request->_action = 'view';
}

ZF wrong route rewrite

I've got 2 links in my layout.phtml and a route in the bootstrap:
1. Link:
echo $this->url(array('controller' => 'aktuelles', 'action' => 'index'), null, true );
// creates: http://localhost/aktuelles
2: Link
echo $this->url(array('controller' => 'projekte', 'action' => 'wohnen', 'projektId' => 26), 'projekte-galeria', false);
// creates: http://localhost/projekte/wohnen/26
Route:
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$route = new Zend_Controller_Router_Route( 'projekte/wohnen/:projektId',
array(
'module' => 'web',
'controller' => 'projekte',
'action' => 'wohnen',
'projektId' => null)
);
$router->addRoute( 'projekte-galeria', $route);
When I load the page everything is displayed correctly and the urls are all correct.
Problem: As soon as i click on the second link (http://localhost/projekte/wohnen/26), the first link is changing:
from: localhost/aktuelles
to : localhost/projekte/wohnen
Why is the link changed?
Try to force to use the default route: instead of null use 'default' as the second parameter in the first url.
BTW - the part 'controller' => 'projekte', 'action' => 'wohnen' in the second url is redundant, because you predefine these parameters in the route. The second link could by simplified like this:
echo $this->url(array('projektId' => 26), 'projekte-galeria', false);
Have a look at this solution as an alternative way to handle routes Simple rewrites in Zend Framework

Routing for CakePHP i18n

I'm trying to internationalize all the pages on my CakePHP site with the following format:
/en/about
/zh/about (for Chinese version)
etc.
I already have all the routes defined at router.php, eg.
Router::connect('/about/*', array('controller' => 'pages', 'action' => 'about'));
Router::connect('/login/*', array('controller' => 'users', 'action' => 'login'));
// etc...
How do I make it so that /language/ prefix is automatically applied to all the Router::connect()s?
At CakePHP library's router.php, there is an example for the similar routing and is given as such:
Router::connect('/:lang/:controller/:action/:id',
array(), array('id' => '[0-9]+', 'lang' => '[a-z]{2}'));
This however, only works for the default routing type (eg. /pages/about/) and not a specially defined one like /about for my example.
In other words, it would work when user visits /zh/pages/about but not when user visits /zh/about
Any suggestions or do I have to manually rewrite all my Router::connect()s to include lang?
Try this:
Router::connect('/:lang/:controller', array(), array('lang' => '[a-z]{2}'));
Router::connect('/:lang/:controller/:action', array(), array('lang' => '[a-z]{2}'));
Router::connect('/:lang/:controller/:action/*', array(), array('lang' => '[a-z]{2}'));

Categories