【问题标题】:CakePHP Subdomain Routing & MiscCakePHP 子域路由和杂项
【发布时间】:2012-04-04 12:32:19
【问题描述】:

背景:构建一个允许用户管理休息室的 Web 应用程序(作为 CakePHP 的介绍)。休息室由博客、联系人、日历等组成。每个休息室都与一个子域相关联(因此 jcotton.lounger.local 会将您带到我的休息室)。用于创建新休息室、注册用户等的站点根目录托管在lounge.local 上。我正在使用 Cake 2.0。

问题:

  1. 我希望能够将与根站点 (lounger.local) 关联的操作和视图与各个休息室(lounge.local 的子域)分开。经过大量研究后,我确定了以下解决方案。我设置了一个前缀路由“休息室”,并在 routes.php 中添加了以下代码。与休息室关联的操作(和视图)都包含前缀休息室(例如:lounge_index())。你会怎么处理?

         if(preg_match('/^([^.]+)\.lounger\.local$/',env("HTTP_HOST"),$matches)){
               $prefix = "lounge";
               Router::connect('/', array('controller' => 'loungememberships','action' => 'index', 'prefix' => $prefix, $prefix => true));
               /* Not currently using plugins
               Router::connect("/:plugin/:controller", array('action' => 'index', 'prefix' => $prefix, $prefix => true));
               Router::connect("/:plugin/:controller/:action/*", array('prefix' => $prefix, $prefix => true));
               */
               Router::connect("/:controller", array('action' => 'index', 'prefix' => $prefix, $prefix => true));
               Router::connect("/:controller/:action/*", array('prefix' => $prefix, $prefix => true));
               unset($prefix);
          }
    
  2. 每次用户在休息室内执行操作,例如在博客中发表评论,添加联系人等,都需要查找休息室_id(基于子域);这对于验证用户是否有权执行该操作并将相应的数据与正确的休息室相关联是必要的。我已经通过 AppController 中的 beforeFilter 函数实现了这一点。每次收到带有子域的请求时,都会执行搜索,并将 Lounge_id 写入会话变量。然后每个控制器加载 CakeSession 并读取相应的 Lounge_id。这比调用 ClassRegistry::Init('Lounge') 并在每个控制器中进行查找更好吗?有没有更好的解决方案?

提前感谢您的帮助

【问题讨论】:

  • 这感觉像是对框架的滥用。

标签: cakephp routing subdomain


【解决方案1】:

我解决这个问题的方法是使用自定义路由,以及与您的示例类似的路由配置的一些技巧。

首先,我有一个“主域”,它被重定向到并用作多租户站点的主域。我还存储了我希望他们采取的默认操作。我将这些存储在配置变量中:

Configure::write('Domain.Master', 'mastersite.local');
Configure::write('Domain.DefaultRoute', array('controller' => 'sites', 'action' => 'add'));

接下来,我在/Lib/Route/DomainRoute.php中创建了一个DomainRoute路由类:

<?php
App::uses('CakeRoute', 'Routing/Route');
App::uses('CakeResponse', 'Network');
App::uses('Cause', 'Model');

/**
 * Domain Route class will ensure a domain has been setup before allowing
 * users to continue on routes for that domain. Instead, it redirects them
 * to a default route if the domain name is not in the system, allowing
 * creation of accounts, or whatever.
 *
 * @package default
 * @author Graham Weldon (http://grahamweldon.com)
 */
class DomainRoute extends CakeRoute {

/**
 * A CakeResponse object
 *
 * @var CakeResponse
 */
    public $response = null;

/**
 * Flag for disabling exit() when this route parses a url.
 *
 * @var boolean
 */
    public $stop = true;

/**
 * Parses a string url into an array. Parsed urls will result in an automatic
 * redirection
 *
 * @param string $url The url to parse
 * @return boolean False on failure
 */
    public function parse($url) {
        $params = parent::parse($url);
        if ($params === false) {
            return false;
        }

        $domain = env('HTTP_HOST');
        $masterDomain = Configure::read('Domain.Master');

        if ($domain !== $masterDomain) {
            $defaultRoute = Configure::read('Domain.DefaultRoute');
            $Cause = new Cause();
            if (!($Cause->domainExists($domain)) && $params != $defaultRoute) {
                if (!$this->response) {
                    $this->response = new CakeResponse();
                }

                $status = 307;
                $redirect = $defaultRoute;
                $this->response->header(array('Location' => Router::url($redirect, true)));
                $this->response->statusCode($status);
                $this->response->send();
                $this->_stop();
            }
            $params['domain'] = $domain;
        }

        return $params;
    }

/**
 * Stop execution of the current script.  Wraps exit() making
 * testing easier.
 *
 * @param integer|string $status see http://php.net/exit for values
 * @return void
 */ 
    protected function _stop($code = 0) {
        if ($this->stop) {
            exit($code);
        }
    }

}

此自定义路由类在/Config/routes.php 文件中用于设置多租户。

if (env('HTTP_HOST') === Configure::read('Domain.Master')) {
    // Master domain shows the home page.
    $rootRoute = array('controller' => 'pages', 'action' => 'display', 'home');
} else {
    // Subdomains show  the cause view page.
    $rootRoute = array('controller' => 'causes', 'action' => 'view', env('HTTP_HOST'));
}
Router::connect('/', $rootRoute, array('routeClass' => 'DomainRoute'));

在检查自定义路由器时,您会看到我正在提取当前正在访问的域并将其添加到 $params 数组中。

虽然这并不能直接实现您所追求的目标,但只要稍加修改,您就会走上正确的轨道,满足您的要求。关于自定义路由的信息不多,但这里是自定义路由类的CakePHP documentation link

希望对你有帮助!

【讨论】:

  • 对于那些想知道为什么它不起作用的人,自定义路由路径已更改为app/Lib/Routing/Route,并且您需要在执行Router之前明确包含App::uses('DomainRoute', 'Routing/Route');::连接()。按照帖子中的文档链接了解更多信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-18
  • 2011-04-09
  • 2014-02-27
相关资源
最近更新 更多