Completed
Pull Request — master (#1952)
by Basil
02:05
created

Config::component()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
1
<?php
2
3
namespace luya;
4
5
use luya\helpers\ArrayHelper;
6
7
/**
8
 * Configuration array Helper.
9
 * 
10
 * The {{luya\Config}} allows you to create the configuration for different hosts and difference between web and console config.
11
 * 
12
 * ```php
13
 * $config = new Config('myapp', dirname(__DIR__), [
14
 *     'siteTitle' => 'My LUYA Project',
15
 *     'defaultRoute' => 'cms',
16
 *     // other application level configurations
17
 * ]);
18
 * 
19
 * // define global components which works either for console or web runtime
20
 * 
21
 * $config->component('mail', [
22
 *     'host' => 'xyz',
23
 *     'from' => '[email protected]',
24
 * ]);
25
 * 
26
 * $config->component('db', [
27
 *     'class' => 'yii\db\Connection',
28
 *     'dsn' => 'mysql:host=localhost;dbname=prod_db',
29
 *     'username' => 'foo',
30
 *     'password' => 'bar',
31
 * ])->env('martin');
32
 * 
33
 * 
34
 * 
35
 * // define components which are only for web or console runtime:
36
 * 
37
 * $config->webComponent('request', [
38
 *     'cookieValidationKey' => 'xyz',
39
 * ]);
40
 * 
41
 * // which is equals to, but the above is better to read and structure in the config file
42
 * 
43
 * $config->component('request', [
44
 *     'cookieValidationKey' => 'xyz',
45
 * ])->webRuntime();
46
 * 
47
 * // adding modules
48
 * 
49
 * $config->module('admin', [
50
 *     'class' => 'luya\admin\Module',
51
 *     'secureLogin' => true,
52
 * ]);
53
 * 
54
 * $config->module('cms', 'luya\cms\frontend\Module'); // which is equals to $config->module('cms', ['class' => 'luya\cms\frontend\Module']);
55
 * 
56
 * // export and generate the config for a given enviroment or environment independent.
57
 * 
58
 * return $config->toArray(); // returns the config not taking care of enviroment variables like prod, env
59
 * 
60
 * return $config->toArray(Config::ENV_PROD);
61
 * ```
62
 * 
63
 * @author Basil Suter <[email protected]>
64
 * @since 1.0.21
65
 */
66
class Config
67
{
68
    const ENV_ALL = 'all';
69
70
    const ENV_PROD = 'prod';
71
    
72
    const ENV_PREP = 'prep';
73
    
74
    const ENV_DEV = 'dev';
75
    
76
    const ENV_LOCAL = 'local';
77
78
    const RUNTIME_ALL = 0;
79
80
    const RUNTIME_CONSOLE = 1;
81
82
    const RUNTIME_WEB = 2;
83
    
84
    /**
85
     * Constructor
86
     *
87
     * @param string $id
88
     * @param string $basePath
89
     * @param array $applicationConfig
90
     */
91
    public function __construct($id, $basePath, array $applicationConfig = [])
92
    {
93
        $applicationConfig['id'] = $id;
94
        $applicationConfig['basePath'] = $basePath;
95
96
        $this->application($applicationConfig);
97
    }
98
99
    /**
100
     * register application level config
101
     *
102
     * @param array $config The array to configure
103
     * @return ConfigDefinition
104
     */
105
    public function application(array $config)
106
    {
107
        return $this->addDefinition(new ConfigDefinition(ConfigDefinition::GROUP_APPLICATIONS, md5(serialize($config)), $config));
108
    }
109
110
    /**
111
     * Register a module.
112
     *
113
     * @param string $id The module identifier.
114
     * @param string|array $config The configuration for the given module. If a string is given this will be taken as `class` property.
115
     * @return ConfigDefinition
116
     */
117
    public function module($id, $config)
118
    {
119
        return $this->addDefinition(new ConfigDefinition(ConfigDefinition::GROUP_MODULES, $id, $config));
120
    }
121
122
    /**
123
     * Register a component
124
     *
125
     * @param string $id The id of the component
126
     * @param string|array $config The configuration for the given module. If a string is given this will be taken as `class` property.
127
     * @param string $runtime The runtime for the component: all, web or console
128
     * @return ConfigDefinition
129
     */
130
    public function component($id, $config, $runtime = self::RUNTIME_ALL)
131
    {
132
        return $this->addDefinition(new ConfigDefinition(ConfigDefinition::GROUP_COMPONENTS, $id, $config))->runtime($runtime);
133
    }
134
135
    /**
136
     * Register a web runtime component.
137
     *
138
     * @param string $id The id of the component
139
     * @param string|array $config The configuration for the given module. If a string is given this will be taken as `class` property.
140
     * @return ConfigDefinition
141
     */
142
    public function webComponent($id, $config)
143
    {
144
        return $this->component($id, $config, self::RUNTIME_WEB);
145
    }
146
147
    /**
148
     * Register a console runtime component.
149
     *
150
     * @param string $id The id of the component
151
     * @param string|array $config The configuration for the given module. If a string is given this will be taken as `class` property.
152
     * @return ConfigDefinition
153
     */
154
    public function consoleComponent($id, $config)
155
    {
156
        return $this->component($id, $config, self::RUNTIME_CONSOLE);
157
    }
158
159
    private $_definitions = [];
160
161
    /**
162
     * Add a defintion into the defintions bag.
163
     *
164
     * @param ConfigDefinition $definition
165
     * @return ConfigDefinition
166
     */
167
    private function addDefinition(ConfigDefinition $definition)
168
    {
169
        $this->_definitions[] = $definition;
170
171
        return $definition;
172
    }
173
174
    private $_isCliRuntime;
175
176
    /**
177
     * Whether runtime is cli or not
178
     *
179
     * @return boolean
180
     */
181
    public function isCliRuntime()
182
    {
183
        if ($this->_isCliRuntime === null) {
184
            $this->_isCliRuntime = strtolower(php_sapi_name()) === 'cli';
185
        }
186
187
        return $this->_isCliRuntime;
188
    }
189
190
    /**
191
     * Setter method for runtime.
192
     * 
193
     * > This method is mainly used for unit testing.
194
     *
195
     * @param boolean $value
196
     */
197
    public function setCliRuntime($value)
198
    {
199
        $this->_isCliRuntime = $value;
200
    }
201
202
    /**
203
     * Export the given configuration as array for certain envs.
204
     *
205
     * @param array $envs A list of environments to export. if nothing is given all enviroments will be returned.
206
     * @return array The configuration array
207
     */
208
    public function toArray(array $envs = [])
209
    {
210
        $config = [];
211
        $envs = array_merge($envs, [self::ENV_ALL]);
212
        foreach ($this->_definitions as $definition) {
213
            /** @var ConfigDefinition $definition */
214
215
            if (!$definition->validateEnvs($envs)) {
216
                continue;
217
            }
218
219
            if ($definition->validateRuntime(self::RUNTIME_ALL)) {
220
                $this->appendConfig($config, $definition);
221
            } elseif ($this->isCliRuntime() && $definition->validateRuntime(self::RUNTIME_CONSOLE)) {
222
                $this->appendConfig($config, $definition);
223
            } elseif (!$this->isCliRuntime() && $definition->validateRuntime(self::RUNTIME_WEB)) {
224
                $this->appendConfig($config, $definition);
225
            }
226
        }
227
228
        return $config;
229
    }
230
231
    /**
232
     * Append a given defintion int othe config
233
     *
234
     * @param array $config
235
     * @param ConfigDefinition $definition
236
     */
237
    private function appendConfig(&$config, ConfigDefinition $definition)
238
    {
239
        switch ($definition->getGroup()) {
240
            case ConfigDefinition::GROUP_APPLICATIONS:
241
                foreach ($definition->getConfig() as $k => $v) {
242
                    $config[$k] = $v;
243
                }
244
                break;
245
            case ConfigDefinition::GROUP_COMPONENTS:
246
                $this->handleKeyBaseMerge($config, $definition, 'components');
247
                break;
248
249
            case ConfigDefinition::GROUP_MODULES:
250
                $this->handleKeyBaseMerge($config, $definition, 'modules');
251
                break;
252
        }
253
    }
254
255
    /**
256
     * Add a array key based component defintion.
257
     *
258
     * @param array $config
259
     * @param ConfigDefinition $definition
260
     * @param string $section
261
     */
262
    private function handleKeyBaseMerge(&$config, ConfigDefinition $definition, $section)
263
    {
264
        if (!array_key_exists($section, $config)) {
265
            $config[$section] = [];
266
        }
267
268
        if (isset($config[$section][$definition->getKey()])) {
269
            $config[$section][$definition->getKey()] = ArrayHelper::merge($config[$section][$definition->getKey()], $definition->getConfig());
270
        } else {
271
            $config[$section][$definition->getKey()] = $definition->getConfig();
272
        }
273
    }
274
}