【问题标题】:different module based on hostname基于主机名的不同模块
【发布时间】:2011-08-16 22:57:25
【问题描述】:

我已经使用 Zend Framework (1.11) 构建了一个 CMS。在应用程序中,我有两个模块,一个称为“cms”,其中包含所有 CMS 逻辑,另一个“web”使用户能够围绕 CMS 构建自己的网站。这涉及在该模块中添加控制器/视图/模型等。

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

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

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

【问题讨论】:

    标签: php zend-framework


    【解决方案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"
         } 
    

    这可能有点令人困惑,如果需要,请随时要求更详细的解释。

    【讨论】:

    • 哇,非常感谢。它工作得很好。但是,我现在卡住了,我想为每个主机名包含一个自定义导航。我发现很难使用相同的插件架构解决方案来解决这个问题,因为导航是在引导程序中设置的(在运行任何插件之前)。对此也有什么想法吗?
    • 当然。我在工作,有时间会考虑一下,然后今天发布解决方案。如果它对您有帮助,请接受我在上面发布的答案 - 如果您将其标记为已接受,其他人也会从中受益。 :)
    猜你喜欢
    • 2013-08-18
    • 2014-10-16
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    相关资源
    最近更新 更多