Zend Framework — Объединение конфигов с поддержкой модулей

Одним из недостатков Zend Framework является то, что «автоматически» подгружается только один конфигурационный файл application.ini. Однако иногда идеологически правильнее использовать несколько конфигов. Например, вынести всю конфигурацию для модуля в отдельный файл, находящийся в директории модуля. Или отделить конфигурацию базы данных от общего файла, что является наиболее правильным, особенно при разработке проектов командой разработчиков с использованием системы контроля версий (svn, cvs и т.п.). Во-первых не всем нужно знать пароли БД для production версии проекта, и у каждого могут быть свои параметры для работы с БД своей копии development версии. В этом случае логичнее отделить параметры базы данных от файла application.ini, который у всех должен быть общим и записать их в файл, например, db.ini, который у каждого будет индивидуальным и будет игнорироваться системой контроля версий.

Предложенный код будет автоматически подгружать конфиги ini и xml из директории configs всех директорий модулей. Для модуля по умолчанию файл application.ini будет игнорироваться. Именование параметров для всех файлов кроме module.ini и module.xml аналогично файлу application.ini.

Для файлов module.* следует опускать modulename.. То есть если в application.ini для модуля admin надо писать:

admin.resources.view.doctype = "HTML4_STRICT"
admin.resources.view.title = "Администрирование"

То в module.ini надо писать

?Download module.ini
resources.view.doctype = "HTML4_STRICT"
resources.view.title = "Администрирование"

«admin» добавится автоматически.

Файлы module.* подгружаются после всех других конфигураций, соответственно при дублировании параметров перезаписывают соответствующее содержание.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php
/**
 * Config glue
 * Склеивает конфиги, расположенные в папке configs каждого модуля.
 *
 * @category   RV
 * @package    RV_Application
 * @subpackage Resource
 * @copyright  Copyright (c) 2010 Roman V. Konovaltsev
 * @author     Roman V. Konovaltsev
 * @version    1.0
 */
 
/**
 * @see Zend_Application_Resource_ResourceAbstract
 */
require_once 'Zend/Application/Resource/ResourceAbstract.php';
 
class RV_Application_Resource_Configlue extends Zend_Application_Resource_ResourceAbstract {
    public function init() {
        $this->_mergeConfigs();
    }
 
    protected function _mergeConfigs() {
 
        $front = Zend_Controller_Front::getInstance ();
 
        $modules = $front->getControllerDirectory();
 
//      Приклеиваем все конфиги кроме конфигов модулей
        foreach (array_keys($modules) as $module)
        {
            $configPath = $front->getModuleDirectory($module) . DIRECTORY_SEPARATOR . 'configs';
            if(is_dir($configPath))
            {
                $cfgdir = new DirectoryIterator($configPath);
                $config = new Zend_Config($this->getBootstrap()->getOptions(), true);
                $modified = false;
                foreach ($cfgdir as $file)
                {
                    $filePath = $file->getPathname();
                    if ($file->isFile() && is_file($filePath))
                    {
                        $pi = pathinfo($filePath);
                        $ext = strtolower($pi['extension']);
                        if(($ext == 'ini' || $ext == 'xml') && !(($module == $front->getDefaultModule() && $pi['filename']=='application') || $pi['filename'] == 'module'))
                        {
                            $options = $this->_loadOptions($filePath);
                            $config->merge($options);
                            $modified = true;
                        }
                    }
                }
                if($modified) $this->getBootstrap()->setOptions($config->toArray());
            }
        }
//      Приклеиваем конфиги модулей
        foreach (array_keys($modules) as $module)
        {
            $configPath  = $front->getModuleDirectory($module) . DIRECTORY_SEPARATOR . 'configs';
            if(is_dir($configPath))
            {
                $appOptions = $this->getBootstrap()->getOptions();
                $modified = false;
                if(is_file($configPath.DIRECTORY_SEPARATOR.'module.ini'))
                {
                    $modified = true;
                    $options = $this->_loadOptions($configPath.DIRECTORY_SEPARATOR.'module.ini');
                    if (array_key_exists($module, $appOptions))
                    {
                        if (is_array($appOptions[$module]))
                            $appOptions[$module] = array_merge($appOptions[$module], $options->toArray());
                        else
                            $appOptions[$module] = $options->toArray();
                    }
                    else
                        $appOptions[$module] = $options->toArray();
 
                }
                if(is_file($configPath.DIRECTORY_SEPARATOR.'module.xml'))
                {
                    $modified = true;
                    $options = $this->_loadOptions($configPath.DIRECTORY_SEPARATOR.'module.xml');
                    if (array_key_exists($module, $appOptions))
                    {
                        if (is_array($appOptions[$module]))
                            $appOptions[$module] = array_merge($appOptions[$module], $options->toArray());
                        else
                            $appOptions[$module] = $options->toArray();
                    }
                    else
                        $appOptions[$module] = $options->toArray();
                }
                if($modified) $this->getBootstrap()->setOptions($appOptions);
            }
        }
    }
 
    /**
     * Load the config file
     *
     * @param string $fullpath
     * @return array
     */
    protected function _loadOptions($fullpath){
        if (file_exists ( $fullpath ))
        {
            $pi = pathinfo($fullpath);
            switch (strtolower ( $pi['extension'] ) )
            {
                case 'ini' :
                    $cfg = new Zend_Config_Ini ( $fullpath, $this->getBootstrap ()->getEnvironment () );
                    break;
                case 'xml' :
                    $cfg = new Zend_Config_Xml ( $fullpath, $this->getBootstrap ()->getEnvironment () );
                    break;
                default :
                    throw new Zend_Config_Exception ( 'Invalid format for config file' );
                    break;
            }
        }
        else
        {
            throw new Zend_Application_Resource_Exception ( 'File does not exist' );
        }
        return $cfg;
    }
}

Для работы данного кода необходимо положить данный файл по адресу
/path/to/your/project/library/RV/Application/Resource/Configlue.php
и прописать следующее в application.ini:

pluginPaths.RV_Application_Resource = "RV/Application/Resource"
resources.configlue =

см. также

Вы можете отслеживать комментарии к этой записи с помощью RSS 2.0. Вы можете оставить комментарий, или использовать trackback с вашего сайта.

Комментарии: 4 »

 
  • Pashen:

    У меня не работало. Когда в главном Bootstrap были функции инициализации.

    <?php

    class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
    {
    protected function _initView()
    {
    // some code
    }

    }

    Текст ошибки

    ( ! ) Fatal error: Call to a member function doctype() on a non-object in D:\Middleware\OracleWT1\instances\instance1\config\OHS\ohs1\Konovaltsev\library\RV\Controller\Plugin\ModuleConfigLV.php on line 53

    Поэтому не лишним будет указать что bootstrap.path = APPLICATION_PATH "/Bootstrap.php" должен быть следующего содежания

    <?php

    class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
    {

    }

    Будет интересно увидеть объяснение такого поведения от автора. Возможно бонально объявление initView() перетирает объект View и Zend просто игнорирует его. Заранее спасибо.

  • Roman:

    Не работал, видимо, сам конфиг
    resources.view.doctype = "HTML4_STRICT"
    а не склейка как таковая. Данный конфиг приведен просто для примера. Если где-то в коде что-то пытается дёрнуть из ресурсов объект view, а ему отдается ни разу не view (так как мы сами где-то что-то так написали) — ну, понятное дело, это не сработает :).

  • Александр:

    Подключил ваш ресурс для склейки, спасибо. Но router прописанные в modules/mod1/configs/module.ini не применяется. Отследил по коду, что в переменную $appOptions добавляется router под ключем mod1, затем вызывается
    $this->getBootstrap()->setOptions($appOptions);
    Подскажите, в чем суть

  • Roman:

    В application.ini я не вижу секции [production], от которой наследуются отсальные. Есть подозрение, что
    ; glue config from module
    autoloaderNamespaces.Zendadd = «Zendadd_»
    pluginPaths.Zendadd_Application_Resource = «Zendadd/Application/Resource»
    resources.configlue =
    просто не применяется. Если тут всё верно, то надо дебажить в вашем конкретном случае — во первых дергается ли Zendadd_Application_Resource_Configlue. Если дергается — насколько корректно склеиваются конфиги. Применяются ли они и не перезатираются ли чем-то потом…

 

Добавить комментарий

XHTML: Можно использовать эти теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>