phpcakephpsubdomain

Add a subdomain to all urls in Cakephp


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


Solution

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