我使用Zend Framework(1.11)构建了CMS。在应用程序中,我有两个模块,一个名为'cms',包含所有CMS逻辑,另一个'web',使用户可以在CMS周围建立自己的网站。这涉及在该模块中添加控制器/视图/模型等。
该应用程序允许您使用自己的主题为应用程序的多个实例提供服务。这些实例由主机名标识。在preDispatch()期间,将对主机名执行数据库查找。基于数据库字段'theme',应用程序然后加载所需的css文件并调用Zend_Layout :: setLayout()来更改该特定实例的布局文件。
我想扩展此功能,以允许用户根据“主题”数据库字段运行不同的Web模块。然而,这是我被困的地方。就像现在一样,Web模块为应用程序的所有实例提供内容。
我需要应用程序根据'theme'数据库值切换到不同的Web模块(因此间接使用主机名)。有任何想法吗?
答案 0 :(得分:1)
嗯,在我看来,
您应该为Web模块编写一个前端控制器插件,并且这样做,当您需要其他插件时,您可以轻松完成。
前端控制器插件应如下所示:
class My_Controller_Plugin_Web extends My_Controller_Plugin_Abstract implements My_Controller_Plugin_Interface
{
public function init()
{
// If user is not logged in - send him to login page
if(!Zend_Auth::getInstance()->hasIdentity()) {
// Do something
return false;
} else {
// You then take the domain name
$domainName = $this->_request->getParam( 'domainName', null );
// Retrieve the module name from the database
$moduleName = Module_fetcher::getModuleName( $domainName );
// And set the module name of the request
$this->_request->setModuleName( $moduleName );
if(!$this->_request->isDispatched()) {
// Good place to alter the route of the request further
// the way you want, if you want
$this->_request->setControllerName( $someController );
$this->_request->setActionName( $someAction );
$this->setLayout( $someLayout );
}
}
}
/**
* Set up layout
*/
public function setLayout( $layout )
{
$layout = Zend_Layout::getMvcInstance();
$layout->setLayout( $layout );
}
}
My_Controller_Plugin_Abstract,它不是一个实际的摘要,你的控制器插件扩展,看起来像这样:
class My_Controller_Plugin_Abstract
{
protected $_request;
public function __construct($request)
{
$this->setRequest($request);
$this->init();
}
private function setRequest($request)
{
$this->_request = $request;
}
}
最后是前端控制器插件本身,它决定你应该执行哪一个特定的前端控制器插件。
require_once 'Zend/Controller/Plugin/Abstract.php';
require_once 'Zend/Locale.php';
require_once 'Zend/Translate.php';
class My_Controller_Plugin extends Zend_Controller_Plugin_Abstract
{
/**
* before dispatch set up module/controller/action
*
* @param Zend_Controller_Request_Abstract $request
*/
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
// Make sure you get something
if(is_null($this->_request->getModuleName())) $this->_request->setModuleName('web');
// You should use zend - to camelCase convertor when doing things like this
$zendFilter = new Zend_Filter_Word_SeparatorToCamelCase('-');
$pluginClass = 'My_Controller_Plugin_'
. $zendFilter->filter($this->_request->getModuleName());
// Check if it exists
if(!class_exists($pluginClass)) {
throw new Exception('The front controller plugin class "'
. $pluginClass. ' does not exist');
}
Check if it is written correctly
if(!in_array('My_Controller_Plugin_Interface', class_implements($pluginClass))) {
throw new Exception('The front controller plugin class "'
. $pluginClass.'" must implement My_Controller_Plugin_Interface');
}
// If all is well instantiate it , and you will call the construct of the
// quasi - abstract , which will then call the init method of your
// My_Plugin_Controller_Web :)
$specificController = new $pluginClass($this->_request);
}
}
如果你从未这样做过,现在是时候了。 :)
此外,要在应用程序中注册前端控制器插件,您应该在应用配置中编辑frontController条目。我会给你一个json的例子,如果你需要,我相信你可以将它翻译成ini / xml / yaml ......
"frontController": {
"moduleDirectory": "APPLICATION_PATH/modules",
"defaultModule": "web",
"modules[]": "",
"layout": "layout",
"layoutPath": "APPLICATION_PATH/layouts/scripts",
// This is the part where you register it!
"plugins": {
"plugin": "My_Controller_Plugin"
}
这可能会让人感到困惑,如果需要,请随时提出更详细的解释。