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