I want all Cakephp urls to use a subdomain if it is present in the users session... so if there is an entry 'subdomain:user' in the session of the user all pages will have 'user' as a prefix: Eg user.example.com, user.example.com/settings.
Is there an easy way to do this?
thanks,
kSeudo
There are custom route classes you could use. Create a file in APP/Lib/Route called UserSubdomainRoute.php and put this in it.
<?php
App::uses('AuthComponent', 'Controller/Component');
class UserSubdomainRoute extends CakeRoute {
/**
* @var CakeRequest
*/
private $Request;
/**
* Length of domain's TLD
*
* @var int
*/
public static $_tldLength = 1;
public function __construct($template, $defaults = array(), $options = array()) {
parent::__construct($template, $defaults, $options);
$this->Request = new CakeRequest();
$this->options = array_merge(array('protocol' => 'http'), $options);
}
/**
* Sets tld length
*
* @param $length
* @return mixed void|int
*/
public static function tldLength($length = null) {
if (is_null($length)) {
return self::$_tldLength;
}
self::$_tldLength = $length;
}
/**
* Writes out full url with protocol and subdomain
*
* @param $params
* @return string
*/
protected function _writeUrl($params) {
$protocol = $this->options['protocol'];
$subdomain = AuthComponent::user('subdomain');
if (empty($subdomain)) {
$subdomain = 'www';
}
$domain = $this->_getDomain();
$url = parent::_writeUrl($params);
return "{$protocol}://{$subdomain}.{$domain}{$url}";
}
/**
* Get domain name
*
* @return string
*/
protected function _getDomain() {
return $this->Request->domain(self::$_tldLength);
}
}
One improvement to the class would probably be to make the $Request static.
Unfortunately in Cake 2.0 there is no way to set a defaultRotueClass, however, I added that feature in 2.1+ and I don't want to tell you to upgrade so you are going to have to manually specify it for all your routes in the third param like so:
Router::connect(..., ..., array('routeClass' => 'UserSubdomainRoute');
Be sure to add at the top of routes.php
App::uses('UserSubdomainRoute', 'Lib/Route');
If you do upgrade to 2.1+ you can just add this at the top of your routes.php
Router::defaultRouteClass('UserSubdomainRoute');
Then any routs specified after will use that route class.
The main part of the route class is the _writeUrl
method. It checks to see if there is a subdomain
key set in the session otherwise uses www
and builds the full url to return.
Heads Up: Haven't tested the class, still at school just wanted to give you a jump start. It's just a modifed version of my SubdomainRoute which works a bit differently (it used to only match routes to when a certain subdomain is set, for ex in my app matches clients
subdomain to my ClientsAdminPanel
plugin. You can grab that here: http://bin.cakephp.org/view/50699397 So you can see how that's done as well if you need a combination of UserSubdomainRoute
and my SubdomainRoute
(in the link).
Hope this helps for now. Let me know if there are any problems.
Edit:
Here's how to force a redirection - something tells me there's a better way. I'll update if I can think of it.
public function beforeFilter() {
$subdomains = $this->request->subdomains();
$subdomain = $this->Auth->user('subdomain');
if (!empty($subdomain) && !in_array($subdomain, $subdomains)) {
$this->redirect('http://' . $subdomain . '.site.com' . $this->request->here);
}
}
well if you wish to do it for all your links probably you use the same way to show all your url on your site, do you use something like $this->html->link('/blah/asd/','blah'); ?
IN Cake/Routing/Route
class SubdomainRoute extends CakeRoute {
public function match($params) {
$subdomain = isset($params['subdomain']) ? $params['subdomain'] : null;
unset($params['subdomain']);
$path = parent::match($params);
if ($subdomain) {
$path = 'http://' . $subdomain . '.localhost' . $path;
}
return $path;
}
}
When creating links you could do the following to make links pointing at other subdomains.
echo $this->Html->link(
'Other domain',
array('subdomain' => 'test', 'controller' => 'posts', 'action' => 'add')
);