【问题标题】:How to Use Same Models in Different Modules in Zend Framework?如何在 Zend Framework 的不同模块中使用相同的模型?
【发布时间】:2008-11-03 18:09:57
【问题描述】:

我正在一个现有项目中实施 Zend 框架,该项目有一个公共营销区域、一个私人成员区域、一个管理站点和一个营销活动管理站点。目前,这些都组织得很差,营销区域的控制器脚本和成员区域都位于站点的根目录下,然后是一个单独的 admin 文件夹和另一个用于营销活动站点的文件夹。

在实现 Zend 框架时,我想创建能够将控制器和视图拆分为模块(一个用于成员区域,一个用于公共营销区域,一个用于管理站点,一个用于营销活动管理站点),但我需要能够将每个模块指向同一个模型,因为所有三个组件都在同一个数据库和同一个业务对象上工作。

但是,我无法在文档中找到有关如何执行此操作的任何信息。任何人都可以提供有关如何执行此操作的链接或有关如何完成此操作的一些简单说明吗?

【问题讨论】:

    标签: php model-view-controller zend-framework module


    【解决方案1】:

    我所做的是将公共类保存在模块层次结构之外的“库”目录中。然后设置我的INCLUDE_PATH使用相应模块的“models”目录,加上通用的“library”目录。

    docroot/
        index.php
    application/
        library/    <-- common classes go here
        default/
            controllers/
            models/
            views/
        members/
            controllers/
            models/
            views/
        admin/
            controllers/
            models/
            views/
    . . .
    

    在我的引导脚本中,我会将“application/library/”添加到INCLUDE_PATH。然后在每个控制器的init() 函数中,将该模块的“models/”目录添加到INCLUDE_PATH

    编辑: setControllerDirectory()setModuleDirectory() 等函数不会将各自的模型目录添加到 INCLUDE_PATH。在任何情况下,您都必须自己执行此操作。这是一个如何做到这一点的例子:

    $app = APPLICATION_HOME; // you should define this in your bootstrap
    $d = DIRECTORY_SEPARATOR;
    $module = $this->_request->getModuleName(); // available after routing
    set_include_path(
      join(PATH_SEPARATOR,
        array(
          "$app{$d}library",
          "$app{$d}$module{$d}models",
          get_include_path()
        )
      )
    );
    

    您可以在引导程序中将“library”添加到您的路径中,但您不能在引导程序中为正确的模块添加“models”目录,因为该模块依赖于路由。有些人在其控制器的init() 方法中这样做,有些人为ActionController 的preDispatch hook 编写了一个插件来设置INCLUDE_PATH

    【讨论】:

    • 您是否有任何理由不使用 addControllerDirectory() 而不是向 INCLUDE_PATH 添加值?
    • addControllerDirectory() 据我所知,不会将相应的模型目录添加到您的包含路径中。请参阅我上面编辑中的示例。
    【解决方案2】:

    这也可以通过遵循Zend_Loader 的命名约定来实现。将模型文件保存在模块文件夹下的模型文件夹中。将它们命名为 Module_Models_ModelName 并将它们保存在该模块的模型文件夹中的文件名 ModelName.php 中。确保应用程序文件夹位于您的包含路径中,并假设您使用 Zend_Loader 进行自动加载,然后您可以通过它们的类名引用模型。

    这样做的好处是可以将您的模型代码与它所针对的实际模块组合在一起。这使模块包含在单个文件夹结构中,这有助于鼓励封装。如果您需要将模块移植到另一个项目,这也将有所帮助。

    【讨论】:

      【解决方案3】:

      我刚刚为您描述的问题构建了这个自定义操作助手:

      <?php
      
      class My_Controller_Action_Helper_GetModel extends Zend_Controller_Action_Helper_Abstract
      {
        /**
         * @var Zend_Loader_PluginLoader
         */
        protected $_loader;
      
        /**
         * Initialize plugin loader for models
         * 
         * @return void
         */
        public function __construct()
        {
          // Get all models across all modules
          $front = Zend_Controller_Front::getInstance();
          $curModule = $front->getRequest()->getModuleName();
      
          // Get all module names, move default and current module to
          //  back of the list so their models get precedence
          $modules = array_diff(
            array_keys($front->getDispatcher()->getControllerDirectory()),
            array('default', $curModule)
          );
          $modules[] = 'default';
          if ($curModule != 'default') {
            $modules[] = $curModule;
          }
      
          // Generate namespaces and paths for plugin loader
          $pluginPaths = array();
          foreach($modules as $module) {
            $pluginPaths[ucwords($module)] = $front->getModuleDirectory($module) . '/models';
          }
      
          // Load paths
          $this->_loader = new Zend_Loader_PluginLoader($pluginPaths);
        }
      
        /**
         * Load a model class and return an object instance
         * 
         * @param  string $model 
         * @return object
         */
        public function getModel($model)
        {
          $class = $this->_loader->load($model);
          return new $class;
        }
      
        /**
         * Proxy to getModel()
         * 
         * @param  string $model 
         * @return object
         */
        public function direct($model)
        {
          return $this->getModel($model);
        }
      }
      

      所以在你的 Bootstrap.php 中:

      Zend_Controller_Action_HelperBroker::addPrefix('My_Controller_Action_Helper');
      

      在您的任何控制器中:

      <?php
      
      class IndexController extends Zend_Controller_Action 
      {
        public function indexAction() 
        {
          $model = $this->_helper->getModel('SomeModel');
        }
      }
      

      这将允许您跨所有模块访问任何控制器中的模型。

      【讨论】:

        【解决方案4】:

        我也有同样的问题。 比尔的回答不适合我——因为我倾向于划分我的模块,而不是“谁在看他们”,而是“他们做了什么”。例如,“论坛模块”可能由管理员和公众共同管理。 我正在尝试使用前端模块,例如 admin、members、public - 但这些模块随后会使用其他模块,例如“forum/validatepost”、“forum/show users personal info”。 如果有人能阐明他们如何保护后端模块不受公众的影响,那将很方便。我猜 ACL 可能是关键,但它仍然让我紧张由对象控制访问,而不是“文件系统/.htaccess”等。

        回答 PHPoet 的问题: (i) 模块控制器目录的路径可以通过调用前端控制器来指定: 例如参见:“12.11.2. 指定模块控制器目录”(Zend Framework Docs)

        (ii) 可以使用 ViewRenderer (Controller Action Helper) 设置视图的路径 例如见:'示例 12.12。选择不同的视图脚本'(Zend 框架文档)

        通过尝试改变视图和控制器的默认路径,从而释放自动加载器以正常运行。

        (我还没有研究过自动加载器的工作方式,但是有一些映射器系统来解决这类问题是有意义的。)

        【讨论】:

          【解决方案5】:

          <?php
          return array(
          'modules' => array(
              'Application',
              'DoctrineModule',
              'DoctrineORMModule',
              'Merchant',
          ),
          'module_listener_options' => array(
              'config_glob_paths'    => array(
                  'config/autoload/{,*.}{global,local}.php',
              ),
              'module_paths' => array(
                  './module',
                  '../vendor',
          //            'here we can load module'
                  'comomonmodule'   
          
              ),
          ),
          );
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-11-21
            • 1970-01-01
            相关资源
            最近更新 更多