基于主机名的不同模块

时间:2011-08-16 12:08:50

标签: php zend-framework

我使用Zend Framework(1.11)构建了CMS。在应用程序中,我有两个模块,一个名为'cms',包含所有CMS逻辑,另一个'web',使用户可以在CMS周围建立自己的网站。这涉及在该模块中添加控制器/视图/模型等。

该应用程序允许您使用自己的主题为应用程序的多个实例提供服务。这些实例由主机名标识。在preDispatch()期间,将对主机名执行数据库查找。基于数据库字段'theme',应用程序然后加载所需的css文件并调用Zend_Layout :: setLayout()来更改该特定实例的布局文件。

我想扩展此功能,以允许用户根据“主题”数据库字段运行不同的Web模块。然而,这是我被困的地方。就像现在一样,Web模块为应用程序的所有实例提供内容。

我需要应用程序根据'theme'数据库值切换到不同的Web模块(因此间接使用主机名)。有任何想法吗?

1 个答案:

答案 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"
     } 

这可能会让人感到困惑,如果需要,请随时提出更详细的解释。