Completed
Push — master ( ef7f65...d97899 )
by Jani
02:36
created

Environment::merge()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 2
crap 1
1
<?php
2
3
namespace janisto\environment;
4
5
/**
6
 * Environment class for Yii 2, used to set configuration for console and web apps depending on the server environment.
7
 *
8
 * @author Jani Mikkonen <[email protected]>
9
 * @license public domain (http://unlicense.org)
10
 * @link https://github.com/janisto/yii2-environment
11
 */
12
class Environment
13
{
14
    /**
15
     * Environment variable. Use Apache SetEnv or export in shell.
16
     *
17
     * @var string environment variable name
18
     */
19
    protected $envName = 'YII_ENV';
20
    /**
21
     * @var array list of valid modes
22
     */
23
    protected $validModes = [
24
        'dev',
25
        'test',
26
        'stage',
27
        'prod',
28
    ];
29
    /**
30
     * @var array configuration directory(s)
31
     */
32
    protected $configDir = [];
33
    /**
34
     * @var string selected environment mode
35
     */
36
    protected $mode;
37
    /**
38
     * @var string path to Yii.php
39
     */
40
    public $yiiPath;
41
    /**
42
     * @var boolean debug mode or not
43
     */
44
    public $yiiDebug;
45
    /**
46
     * @var string defines in which environment the application is running
47
     */
48
    public $yiiEnv;
49
    /**
50
     * @var array register path aliases
51
     */
52
    public $aliases = [];
53
    /**
54
     * @var array merge class map used by the Yii autoloading mechanism
55
     */
56
    public $classMap = [];
57
    /**
58
     * @var array web application configuration array
59
     */
60
    public $web = [];
61
    /**
62
     * @var array console application configuration array
63
     */
64
    public $console = [];
65
66
    /**
67
     * Constructor. Initializes the Environment class.
68
     *
69
     * @param string|array $configDir configuration directory(s)
70
     * @param string $mode override automatically set environment mode
71
     * @throws \Exception
72
     */
73 28
    public function __construct($configDir, $mode = null)
74
    {
75 28
        $this->setConfigDir($configDir);
76 26
        $this->setMode($mode);
77 24
        $this->setEnvironment();
78 18
    }
79
80
    /**
81
     * Set configuration directory(s) where the config files are stored.
82
     *
83
     * @param string|array $configDir configuration directory(s)
84
     * @throws \Exception
85
     */
86 28
    protected function setConfigDir($configDir)
87
    {
88 28
        $this->configDir = [];
89 28
        foreach ((array) $configDir as $k => $v) {
90 28
            $dir = rtrim($v, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
91 28
            if (!is_dir($dir)) {
92 2
                throw new \Exception('Invalid configuration directory "' . $dir . '".');
93
            }
94 26
            $this->configDir[$k] = $dir;
95 26
        }
96 26
    }
97
98
    /**
99
     * Set environment mode.
100
     *
101
     * @param string|null $mode environment mode
102
     * @throws \Exception
103
     */
104 26
    protected function setMode($mode)
105
    {
106 26
        if ($mode === null) {
107
            // Return mode based on environment variable.
108 16
            $mode = getenv($this->envName);
109 16
            if ($mode === false) {
110
                // Defaults to production.
111 2
                $mode = 'prod';
112 2
            }
113 16
        }
114
115
        // Check if mode is valid.
116 26
        $mode = strtolower($mode);
117 26
        if (!in_array($mode, $this->validModes, true)) {
118 2
            throw new \Exception('Invalid environment mode supplied or selected: ' . $mode);
119
        }
120
121 24
        $this->mode = $mode;
122 24
    }
123
124
    /**
125
     * Load and merge configuration files into one array.
126
     *
127
     * @return array $config array to be processed by setEnvironment
128
     * @throws \Exception
129
     */
130 24
    protected function getConfig()
131
    {
132 24
        $configMerged = [];
133 24
        foreach ($this->configDir as $configDir) {
134
            // Merge main config.
135 24
            $fileMainConfig = $configDir . 'main.php';
136 24
            if (!file_exists($fileMainConfig)) {
137 2
                throw new \Exception('Cannot find main config file "' . $fileMainConfig . '".');
138
            }
139 22
            $configMain = require($fileMainConfig);
140 22
            if (is_array($configMain)) {
141 22
                $configMerged = static::merge($configMerged, $configMain);
142 22
            }
143
144
            // Merge mode specific config.
145 22
            $fileSpecificConfig = $configDir . 'mode_' . $this->mode . '.php';
146 22
            if (!file_exists($fileSpecificConfig)) {
147 2
                throw new \Exception('Cannot find mode specific config file "' . $fileSpecificConfig . '".');
148
            }
149 20
            $configSpecific = require($fileSpecificConfig);
150 20
            if (is_array($configSpecific)) {
151 20
                $configMerged = static::merge($configMerged, $configSpecific);
152 20
            }
153
154
            // If one exists, merge local config.
155 20
            $fileLocalConfig = $configDir . 'local.php';
156 20
            if (file_exists($fileLocalConfig)) {
157 18
                $configLocal = require($fileLocalConfig);
158 18
                if (is_array($configLocal)) {
159 18
                    $configMerged = static::merge($configMerged, $configLocal);
160 18
                }
161 18
            }
162 20
        }
163
164 20
        return $configMerged;
165
    }
166
167
    /**
168
     * Sets the environment and configuration for the selected mode.
169
     *
170
     * @throws \Exception
171
     */
172 24
    protected function setEnvironment()
173
    {
174 24
        $config = $this->getConfig();
175 20
        if (!is_readable($config['yiiPath'])) {
176 2
            throw new \Exception('Invalid Yii framework path "' . $config['yiiPath'] . '".');
177
        }
178
179
        // Set attributes.
180 18
        $this->yiiPath = $config['yiiPath'];
181 18
        $this->yiiDebug = isset($config['yiiDebug']) ? $config['yiiDebug'] : false;
182 18
        $this->yiiEnv = isset($config['yiiEnv']) ? $config['yiiEnv'] : $this->mode;
183 18
        $this->web = isset($config['web']) ? $config['web'] : [];
184 18
        $this->web['params']['environment'] = $this->mode;
185 18
        $this->console = isset($config['console']) ? $config['console'] : [];
186 18
        $this->console['params']['environment'] = $this->mode;
187 18
        $this->aliases = isset($config['aliases']) ? $config['aliases'] : [];
188 18
        $this->classMap = isset($config['classMap']) ? $config['classMap'] : [];
189 18
    }
190
191
    /**
192
     * Merges two arrays into one recursively.
193
     *
194
     * @param array $a array to be merged to
195
     * @param array $b array to be merged from.
196
     * @return array the merged array (the original arrays are not changed.)
197
     */
198 22
    protected static function merge($a, $b)
199
    {
200 22
        return \yii\helpers\ArrayHelper::merge($a, $b);
201
    }
202
203
    /**
204
     * Defines Yii constants, includes base Yii class, sets aliases and merges class map.
205
     */
206 2
    public function setup()
207
    {
208
        /**
209
         * This constant defines whether the application should be in debug mode or not.
210
         */
211 2
        defined('YII_DEBUG') or define('YII_DEBUG', $this->yiiDebug);
212
        /**
213
         * This constant defines in which environment the application is running.
214
         * The value could be 'prod' (production), 'stage' (staging), 'test' (testing) or 'dev' (development).
215
         */
216 2
        defined('YII_ENV') or define('YII_ENV', $this->yiiEnv);
217
        /**
218
         * Whether the the application is running in staging environment.
219
         */
220 2
        defined('YII_ENV_STAGE') or define('YII_ENV_STAGE', YII_ENV === 'stage');
221
222
        // Include Yii.
223 2
        require($this->yiiPath);
224
225
        // Set aliases.
226 2
        foreach ($this->aliases as $alias => $path) {
227 2
            \Yii::setAlias($alias, $path);
228 2
        }
229
230
        // Merge class map.
231 2
        if (!empty($this->classMap)) {
232 2
            \Yii::$classMap = static::merge(\Yii::$classMap, $this->classMap);
233 2
        }
234 2
    }
235
236
    /**
237
     * Show current Environment class values.
238
     */
239 2
    public function showDebug()
240
    {
241
        print '<div style="position: absolute; left: 0; width: 100%; height: 250px; overflow: auto;'
242
            . 'bottom: 0; z-index: 9999; color: #000; margin: 0; border-top: 1px solid #000;">'
243 2
            . '<pre style="margin: 0; background-color: #ddd; padding: 5px;">'
244 2
            . htmlspecialchars(print_r($this, true)) . '</pre></div>';
245 2
    }
246
}
247