ZF中的模块自动加载器

时间:2010-05-10 22:49:13

标签: zend-framework autoload

Zend_Application_Module_Autoloader上的手册说明了以下内容:

  

将模块引导与Zend_Application一起使用时,默认情况下会为每个离散模块创建Zend_Application_Module_Autoloader的实例,允许您自动加载模块资源。

     

来源: http://framework.zend.com/manual/zh/zend.loader.autoloader-resource.html#zend.loader.autoloader-resource.module

这要求我为每个模块创建一个空引导类,否则每个模块的资源自动加载将无法与内置自动加载器一起使用。

现在我有两个问题

  • 什么是分立模块?
  • 是否有办法让每个模块默认注册此资源自动加载器,而无需为每个模块创建引导程序文件?我希望它在每个模块中都可用,并且创建如此多的空引导类是我宁愿阻止的。

5 个答案:

答案 0 :(得分:7)

我理解您不愿意为每个模块添加一个空引导类。但是,请考虑重复使用的情况:如果您能够单独捆绑模块,则可以稍后将其放入另一个应用程序,并且自动加载将立即生效,无需额外工作。这是模块引导的用例之一,以及它目前的工作原理。

(在这种情况下,“离散”意味着“自包含”,而不是“应用程序”模块的一部分。)

如果您不喜欢它的运行方式,您可以省略模块引导程序 - 您只需要以某种方式为模块添加资源自动加载器。这可以通过引导资源方法很容易地完成。然而,正如有人早先发布的那样:为什么在经过测试和记录的工作完成工作后重新发明轮子? :)

答案 1 :(得分:2)

模块bootstraps启用自动加载的原因是因为它们扩展了Zend_Application_Module_Bootstrap,它在构造函数中设置自动加载器,如此

public function __construct($application)
{
  //...
  if ($application->hasOption('resourceloader')) {
      $this->setOptions(array(
          'resourceloader' => $application->getOption('resourceloader')
      ));
  }
  $this->initResourceLoader();
  //...
}

这是因为模块资源为init函数中的每个模块运行引导程序...

       foreach ($modules as $module => $moduleDirectory) {
        $bootstrapClass = $this->_formatModuleName($module) . '_Bootstrap';
        if (!class_exists($bootstrapClass, false)) {
            $bootstrapPath  = dirname($moduleDirectory) . '/Bootstrap.php';
            if (file_exists($bootstrapPath)) {
                $eMsgTpl = 'Bootstrap file found for module "%s" but bootstrap class "%s" not found';
                include_once $bootstrapPath;
                if (($default != $module)
                    && !class_exists($bootstrapClass, false)
                ) {
                    throw new Zend_Application_Resource_Exception(sprintf(
                        $eMsgTpl, $module, $bootstrapClass
                    ));
                } elseif ($default == $module) {
                    if (!class_exists($bootstrapClass, false)) {
                        $bootstrapClass = 'Bootstrap';
                        if (!class_exists($bootstrapClass, false)) {
                            throw new Zend_Application_Resource_Exception(sprintf(
                                $eMsgTpl, $module, $bootstrapClass
                            ));
                        }
                    }
                }
            } else {
                continue;
            }
        }

        if ($bootstrapClass == $curBootstrapClass) {
            // If the found bootstrap class matches the one calling this
            // resource, don't re-execute.
            continue;
        }

        $moduleBootstrap = new $bootstrapClass($bootstrap);
        $moduleBootstrap->bootstrap();
        $this->_bootstraps[$module] = $moduleBootstrap;
    }

简短的回答是,如果你不编写空的bootstrap文件,你必须将一些运行良好,经过良好测试的代码抽象到你自己的全局引导程序文件中,然后失去为你提供引导的灵活性模块何时/如果您需要稍后在应用程序中引导它们。

答案 2 :(得分:2)

模块允许您将应用程序分离为特定问题。我的大型应用程序经常会有一个用户默认模块和一个包含所有管理功能的管理模块。我使用Zend Framework MVC应用程序的推荐项目结构中推荐的目录结构 - > Zend Framework文档的模块结构部分。

关于你的第二个问题,答案是肯定的,不是。如果要利用默认的自动加载功能(从admin / forms目录加载Admin_Form_Settings),则需要在每个模块中使用引导程序。有关详细信息,请参阅Matthew Weier O'Phinney关于Module Bootstraps in Zend Framework: Do's and Don'ts的文章。您可能还想谷歌并查看Rob Allen的帖子“在ZF 1.8及更高版本中使用Bootstrapping模块。”

回答第二个问题:我喜欢使用的一种技术不需要在每个模块中使用空引导程序将所有应用程序类放在应用程序的lib文件夹中,并模仿Zend Framework的目录结构。如果我的应用程序名为Example,我将在my / lib目录中创建一个名为Example的文件夹。我的用户注册表将放在/ lib / Example / Form中,可能名为UserRegistration.php。我的类将被命名为Example_Form_UserRegistration。自动加载我的表单将需要Bootstrap.php文件中的以下内容:

protected function _initAppAutoload() {

    $autoloader = Zend_Loader_Autoloader::getInstance();

    return $autoloader;
}

我的application.ini将包含行

resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.modules[] = 
autoloaderNamespaces[] = "Example_"

使用这种技术,您应该可以在应用程序的任何位置自动加载/ lib / Example中的任何类,而无需在每个模块中放置空引导。

注意:我尝试将链接直接发布到文档和Rob Allen的文章,但由于我是一个新人,我只允许一个链接。抱歉向您询问应该是链接的Google商品。

答案 3 :(得分:2)

有两种方法(我知道)可以启用模块资源自动加载器。第一个问题已在上述答案中涉及,即:

在application.ini中添加模块资源行:

resources.modules[] =

然后创建一个空的模块引导程序文件。

第二种是将以下引导方法添加到应用程序范围(非模块)引导程序中:

protected function _initModuleAutoload()
{
    $autoloader = new Zend_Application_Module_Autoloader(array(
        'namespace' => 'Foo',
        'basePath' => APPLICATION_PATH . "/modules/Foo",
    ));
    return $autoloader;
}

但您需要单独创建每个模块的自动加载器。就个人而言,出于上述原因,我更喜欢空引导文件 - 这对我来说更加手动。

注意:我相信这是@weierophinney上面提到的“bootstrap资源方法”。

答案 4 :(得分:0)

自举:

$uri = explode('/',$_SERVER['REQUEST_URI']);
if($uri['1'] == 'flok'){
    $flok = new Zend_Controller_Router_Route('flok/:controller/:action/:id/*',  array('module' => 'flok', 'controller' => 'index', 'action' => 'index',  'id' =>null));
    $router->addRoute('flok', $flok);

    $resourceLoader = new Zend_Application_Module_Autoloader(array(
        'basePath'  => APPLICATION_PATH . "/flok/flok",
        'namespace' => 'Flok',
    ));

    //Init
    $frontController->registerPlugin(new Flok_Plugin_Init(),'flok');
    //Auth
    $frontController->registerPlugin(new Flok_Plugin_Auth(),'flok');

    // dynamic modules
    $ruta = APPLICATION_PATH.'/flok';
    foreach(scandir($ruta) as $mod) {
        if(!is_dir($mod) and $mod != '.DS_Store'){
            $Modululflok = new Zend_Controller_Router_Route('flok/'.$mod.'/:controller/:action/:id/*',  array('submodules' => 'flok','module' => $mod , 'controller' => 'index', 'action' => 'index',  'id' =>null));
            $router->addRoute($mod, $Modululflok);
            $resourceLoader = new Zend_Application_Module_Autoloader(array(
                'basePath'  => APPLICATION_PATH . "/flok/".$mod,
                'namespace' => ucfirst($mod),
            ));
        }
    }

    $layout = Zend_Layout::getMvcInstance();

    $layout
        ->setLayout('layout')
        ->setLayoutPath(APPLICATION_PATH . '/flok/flok/views/scripts');

    $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    $viewRenderer->initView();
    $viewRenderer->view->addHelperPath(APPLICATION_PATH . '/flok/flok/helpers');
} else {
    $default = new Zend_Controller_Router_Route('*',  array('module' => 'default', 'controller' => 'index', 'action' => 'index'));
    $router->addRoute('default', $default);
}

这个帮助器在核心模块中插入数据(菜单,视图等):

class Zend_View_Helper_Models
{
    public function Models($tipo)
    {
        // load modules
        $ruta = APPLICATION_PATH.'/flok';
        foreach(scandir($ruta) as $mod) {
            if(!is_dir($mod) and $mod != '.DS_Store'){
                $rutaphp = $ruta.'/'.$mod.'/'.$mod.'.php';
                if(file_exists($rutaphp)){ 
                include_once($rutaphp);
                    $modul = new $mod;
                    if(isset($modul->$tipo) and $modul->$tipo === true){
                       $data = $tipo.'Data';
                       $m[] = $modul->$data;
                    } 
                }
            }
        }
        return $m;
    }

}