Автозагрузчик модулей в ZF

В руководстве по 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

Это требует от меня создания пустого класса начальной загрузки для каждого из моих модулей, иначе автозагрузка ресурсов для каждого модуля не будет работать со встроенным автозагрузчиком.

Теперь у меня два вопроса

  • Что такое дискретный модуль?
  • Есть ли способ зарегистрировать этот автозагрузчик ресурсов по умолчанию для каждого модуля без необходимости создавать файл начальной загрузки для каждого модуля? Я хочу, чтобы он был доступен в каждом модуле, и я бы предпочел не создавать так много пустых классов начальной загрузки.

person ChrisR    schedule 10.05.2010    source источник


Ответы (5)


Я понимаю ваше нежелание добавлять пустой класс начальной загрузки в каждый модуль. Однако рассмотрите случай повторного использования: если вы можете собрать свой модуль отдельно, вы можете позже добавить его в другое приложение, и автозагрузка будет работать сразу, без дополнительной работы. Это был один из вариантов использования начальной загрузки модулей, и почему сейчас он работает так, как работает.

(«Дискретный» в данном случае означает «автономный», а не часть модуля «приложения».)

Если вам не нравится, как это работает, вы можете пропустить начальную загрузку модуля - вам просто нужно каким-то образом добавить автозагрузчик ресурсов для модуля. Это можно сделать с помощью метода ресурсов начальной загрузки довольно легко. Однако, как кто-то ранее писал: зачем заново изобретать велосипед, когда то, что проверено и задокументировано, выполняет свою работу? :)

person weierophinney    schedule 11.05.2010
comment
Спасибо Мэтью ... ваши аргументы действительно имеют смысл. Я могу жить с пустыми файлами начальной загрузки, и, как сказали Трэвис и Джереми, придет время, когда мне все равно нужно будет их загрузить, поэтому я просто справлюсь с этим и буду использовать пустые файлы начальной загрузки :) - person ChrisR; 11.05.2010

Причина, по которой загрузчики модулей включают автозагрузку, заключается в том, что они расширяют Zend_Application_Module_Bootstrap, который устанавливает автозагрузчик в конструкторе следующим образом.

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

Это выполняется, потому что ресурс модулей запускает загрузку для каждого модуля в функции инициализации...

       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;
    }

Короткий ответ: если вы не пишете пустые файлы начальной загрузки, вам придется абстрагировать часть этого хорошо функционирующего, хорошо протестированного кода в свой собственный глобальный файл начальной загрузки, а затем потерять гибкость наличия загрузочных файлов для ваших модулей, когда / если вам нужно загрузить их позже в вашем приложении.

person Travis    schedule 10.05.2010
comment
Спасибо за объяснение, просто кажется контрпродуктивным и не лучшей практикой просто засорять мои модули пустыми классами начальной загрузки только для того, чтобы включить загрузку ресурсов конкретного модуля. Действительно, когда я хочу загрузить модуль, я должен добавить загрузку модуля, но поскольку во ВСЕХ модулях должна быть доступна автозагрузка ресурсов, мне было интересно, не было ли в области приложения чего-то, что могло бы это настроить? - person ChrisR; 11.05.2010
comment
Я понимаю. Если они пусты, они просто кажутся бесполезными, но, по моему опыту, в каждом приложении наступал момент времени, когда мне нужно было загрузить мой модуль. Я использую его для определения маршрутов, специфичных для пользовательских модулей, захвата определенных отформатированных файлов конфигурации для самих модулей и других подобных вещей. Вы можете легко удалить необходимость в этом из своего приложения, добавив этот код в свой бутстрап, если это вас сильно беспокоит, но ИМХО, оно того не стоит. - person Travis; 11.05.2010

Модули позволяют разделить ваше приложение на конкретные задачи. Часто мои большие приложения будут иметь модуль по умолчанию для пользователей и модуль администратора, содержащий все административные функции. Я использую структуру каталогов, рекомендованную в разделе Рекомендуемая структура проекта для приложений Zend Framework MVC -> Структура модуля документации Zend Framework.

Что касается вашего второго вопроса, то ответ и да, и нет. Если вы хотите воспользоваться функцией автозагрузки по умолчанию (загрузка Admin_Form_Settings из каталога admin/forms), вам понадобится загрузчик в каждом модуле. См. статью Мэтью Вейера О'Финни на странице Загрузка модулей в Zend Framework: что можно и чего нельзя делать для получения дополнительной информации. Вы также можете найти в Google и просмотреть сообщение Роба Аллена «Загрузка модулей в ZF 1.8 и выше».

Отвечая «нет» на ваш второй вопрос: один из методов, который мне нравится использовать и который не требует пустых загрузочных загрузок в каждом модуле, заключается в размещении всех ваших классов приложений в папке lib приложения и имитации структуры каталогов Zend Framework. Если мое приложение называется Example, я создам папку с именем Example в моем каталоге /lib. Моя регистрационная форма пользователя будет помещена в /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 в любом месте вашего приложения, не размещая пустые загрузочные файлы в каждом модуле.

ПРИМЕЧАНИЕ. Я пытался публиковать ссылки непосредственно на документы и на статью Роба Аллена, но, поскольку я новичок, мне была разрешена только одна ссылка. Приносим извинения за просьбу к элементам Google, которые должны быть ссылками.

person Jeremy Kendall    schedule 11.05.2010
comment
Привет Джереми, спасибо за ответ. Просто чтобы прояснить ситуацию ... я знаю, что такое модули, и использую их с тех пор, как они стали доступны в ZF, но я имел в виду дискретную часть :) И что касается второго вопроса, я подумал об импорте почти всего в пространство имен приложения, но поскольку большинство модулей, которые я создаю, являются модулями plug and play, я хотел бы хранить все, что связано с модулем, вместе в папке модуля. - person ChrisR; 11.05.2010
comment
Ага. Насколько я могу судить, дискретная часть — это просто описание модулей как полностью содержащихся отдельных частей вашего приложения. Я не думаю, что это предназначено для интерпретации как другой тип модуля. Сбивает с толку, поскольку дискретность может иметь особое значение в технических областях. Что касается вашего второго вопроса, учитывая ваши требования, я не знаю, как избежать добавления модулей начальной загрузки. Однако есть много разработчиков ZF, которые намного умнее меня. Вы можете проверить ссылки внизу статьи Мэтью, чтобы найти новые идеи. - person Jeremy Kendall; 11.05.2010

Есть два способа (известных мне) включить автозагрузчики ресурсов модулей. Первый был рассмотрен в приведенных выше ответах, а именно:

Добавьте строку ресурсов модулей в ваш application.ini:

resources.modules[] =

Затем создайте пустой файл начальной загрузки модуля.

Во-вторых, добавьте следующий метод начальной загрузки в загрузочную программу всего приложения (не модуля):

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

Но вам нужно будет создать автозагрузчик каждого модуля отдельно. Лично я предпочитаю пустые файлы начальной загрузки по причинам, упомянутым выше — мне это кажется более ручным.

Примечание. Я считаю, что это «метод ресурсов начальной загрузки», упомянутый @weierophinney выше.

person gerard    schedule 03.04.2011

Начальная загрузка:

$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;
    }

} 
person user3422301    schedule 04.08.2012
comment
Добро пожаловать в Stack Overflow, не могли бы вы сообщить свои ответы и вопросы на английском языке, чтобы люди, не говорящие по-испански, могли их понять и извлечь из них пользу? - person Jonas G. Drange; 04.08.2012
comment
Хорошо, сначала позвольте мне перевести текст, гугл-переводчик и немного английского. Спасибо... - person user3422301; 05.08.2012