背景:构建一个Web应用程序(作为CakePHP简介),允许用户管理休息室。休息室由博客,联系人,日历等组成。每个休息室都与子域相关联(因此jcotton.lounger.local会将您带到我的休息室)。用于创建新休息室,注册用户等的网站的根目录在lounger.local上。我正在使用Cake 2.0。
问题:
我希望能够从单个休息室(lounger.local的子域)中分离与根网站(lounger.local)相关联的操作和视图。经过大量的研究,我决定采用以下方法。我设置了一个前缀路由“lounge”,并在routes.php中添加了以下代码。与休息室相关联的操作(和视图)都包含前缀lounge(例如: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);
}
每次用户在休息室内执行操作(例如在博客中发布评论,添加联系人等)时,都需要查找lounge_id(基于子域);这是验证用户是否有权执行该操作以及将相应数据与正确的休息室相关联所必需的。我已经通过AppController中的beforeFilter函数实现了这个。每次接收到子域的请求时,都会执行搜索,并将lounge_id写入会话变量。然后每个控制器加载CakeSession并读取相应的lounge_id。这比调用ClassRegistry :: Init('Lounge')并在每个控制器中进行查找更好吗?有更好的溶液吗?
提前感谢您的帮助
答案 0 :(得分:5)
我接近这个的方式是使用自定义路线,以及与您的示例类似的路线配置的一些技巧。
首先,我有一个“主域”,它被重定向到并用作多租户站点的主域。我还存储了我希望他们采取的默认操作。我将它们存储在配置变量中:
Configure::write('Domain.Master', 'mastersite.local');
Configure::write('Domain.DefaultRoute', array('controller' => 'sites', 'action' => 'add'));
接下来,我在DomainRoute
中创建了/Lib/Route/DomainRoute.php
路由类:
<?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。
我希望有所帮助!