• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codeigniter4 / CodeIgniter4 / 12855700662

19 Jan 2025 05:28PM UTC coverage: 84.546% (+0.08%) from 84.469%
12855700662

push

github

web-flow
Merge pull request #9417 from codeigniter4/4.6

4.6.0 Merge code

720 of 841 new or added lines in 68 files covered. (85.61%)

8 existing lines in 6 files now uncovered.

20811 of 24615 relevant lines covered (84.55%)

191.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.82
/system/Config/BaseConfig.php
1
<?php
2

3
/**
4
 * This file is part of CodeIgniter 4 framework.
5
 *
6
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11

12
namespace CodeIgniter\Config;
13

14
use CodeIgniter\Exceptions\ConfigException;
15
use CodeIgniter\Exceptions\RuntimeException;
16
use Config\Encryption;
17
use Config\Modules;
18
use ReflectionClass;
19
use ReflectionException;
20

21
/**
22
 * Class BaseConfig
23
 *
24
 * Not intended to be used on its own, this class will attempt to
25
 * automatically populate the child class' properties with values
26
 * from the environment.
27
 *
28
 * These can be set within the .env file.
29
 *
30
 * @phpstan-consistent-constructor
31
 * @see \CodeIgniter\Config\BaseConfigTest
32
 */
33
class BaseConfig
34
{
35
    /**
36
     * An optional array of classes that will act as Registrars
37
     * for rapidly setting config class properties.
38
     *
39
     * @var array
40
     */
41
    public static $registrars = [];
42

43
    /**
44
     * Whether to override properties by Env vars and Registrars.
45
     */
46
    public static bool $override = true;
47

48
    /**
49
     * Has module discovery completed?
50
     *
51
     * @var bool
52
     */
53
    protected static $didDiscovery = false;
54

55
    /**
56
     * Is module discovery running or not?
57
     */
58
    protected static bool $discovering = false;
59

60
    /**
61
     * The processing Registrar file for error message.
62
     */
63
    protected static string $registrarFile = '';
64

65
    /**
66
     * The modules configuration.
67
     *
68
     * @var Modules|null
69
     */
70
    protected static $moduleConfig;
71

72
    public static function __set_state(array $array)
73
    {
74
        static::$override = false;
2✔
75
        $obj              = new static();
2✔
76
        static::$override = true;
2✔
77

78
        $properties = array_keys(get_object_vars($obj));
2✔
79

80
        foreach ($properties as $property) {
2✔
81
            $obj->{$property} = $array[$property];
2✔
82
        }
83

84
        return $obj;
2✔
85
    }
86

87
    /**
88
     * @internal For testing purposes only.
89
     * @testTag
90
     */
91
    public static function setModules(Modules $modules): void
92
    {
93
        static::$moduleConfig = $modules;
1✔
94
    }
95

96
    /**
97
     * @internal For testing purposes only.
98
     * @testTag
99
     */
100
    public static function reset(): void
101
    {
102
        static::$registrars   = [];
18✔
103
        static::$override     = true;
18✔
104
        static::$didDiscovery = false;
18✔
105
        static::$moduleConfig = null;
18✔
106
    }
107

108
    /**
109
     * Will attempt to get environment variables with names
110
     * that match the properties of the child class.
111
     *
112
     * The "shortPrefix" is the lowercase-only config class name.
113
     */
114
    public function __construct()
115
    {
116
        static::$moduleConfig ??= new Modules();
6,630✔
117

118
        if (! static::$override) {
6,630✔
119
            return;
6✔
120
        }
121

122
        $this->registerProperties();
6,626✔
123

124
        $properties  = array_keys(get_object_vars($this));
6,626✔
125
        $prefix      = static::class;
6,626✔
126
        $slashAt     = strrpos($prefix, '\\');
6,626✔
127
        $shortPrefix = strtolower(substr($prefix, $slashAt === false ? 0 : $slashAt + 1));
6,626✔
128

129
        foreach ($properties as $property) {
6,626✔
130
            $this->initEnvValue($this->{$property}, $property, $prefix, $shortPrefix);
6,626✔
131

132
            if ($this instanceof Encryption && $property === 'key') {
6,626✔
133
                if (str_starts_with($this->{$property}, 'hex2bin:')) {
34✔
134
                    // Handle hex2bin prefix
135
                    $this->{$property} = hex2bin(substr($this->{$property}, 8));
2✔
136
                } elseif (str_starts_with($this->{$property}, 'base64:')) {
32✔
137
                    // Handle base64 prefix
138
                    $this->{$property} = base64_decode(substr($this->{$property}, 7), true);
2✔
139
                }
140
            }
141
        }
142
    }
143

144
    /**
145
     * Initialization an environment-specific configuration setting
146
     *
147
     * @param array|bool|float|int|string|null $property
148
     *
149
     * @return void
150
     */
151
    protected function initEnvValue(&$property, string $name, string $prefix, string $shortPrefix)
152
    {
153
        if (is_array($property)) {
6,626✔
154
            foreach (array_keys($property) as $key) {
6,619✔
155
                $this->initEnvValue($property[$key], "{$name}.{$key}", $prefix, $shortPrefix);
6,619✔
156
            }
157
        } elseif (($value = $this->getEnvValue($name, $prefix, $shortPrefix)) !== false && $value !== null) {
6,626✔
158
            if ($value === 'false') {
6,574✔
159
                $value = false;
10✔
160
            } elseif ($value === 'true') {
6,574✔
161
                $value = true;
10✔
162
            }
163
            if (is_bool($value)) {
6,574✔
164
                $property = $value;
10✔
165

166
                return;
10✔
167
            }
168

169
            $value = trim($value, '\'"');
6,574✔
170

171
            if (is_int($property)) {
6,574✔
172
                $value = (int) $value;
10✔
173
            } elseif (is_float($property)) {
6,574✔
174
                $value = (float) $value;
10✔
175
            }
176

177
            // If the default value of the property is `null` and the type is not
178
            // `string`, TypeError will happen.
179
            // So cannot set `declare(strict_types=1)` in this file.
180
            $property = $value;
6,574✔
181
        }
182
    }
183

184
    /**
185
     * Retrieve an environment-specific configuration setting
186
     *
187
     * @return string|null
188
     */
189
    protected function getEnvValue(string $property, string $prefix, string $shortPrefix)
190
    {
191
        $shortPrefix        = ltrim($shortPrefix, '\\');
6,626✔
192
        $underscoreProperty = str_replace('.', '_', $property);
6,626✔
193

194
        switch (true) {
195
            case array_key_exists("{$shortPrefix}.{$property}", $_ENV):
6,626✔
196
                return $_ENV["{$shortPrefix}.{$property}"];
12✔
197

198
            case array_key_exists("{$shortPrefix}_{$underscoreProperty}", $_ENV):
6,626✔
199
                return $_ENV["{$shortPrefix}_{$underscoreProperty}"];
10✔
200

201
            case array_key_exists("{$shortPrefix}.{$property}", $_SERVER):
6,626✔
202
                return $_SERVER["{$shortPrefix}.{$property}"];
6,574✔
203

204
            case array_key_exists("{$shortPrefix}_{$underscoreProperty}", $_SERVER):
6,626✔
205
                return $_SERVER["{$shortPrefix}_{$underscoreProperty}"];
×
206

207
            case array_key_exists("{$prefix}.{$property}", $_ENV):
6,626✔
208
                return $_ENV["{$prefix}.{$property}"];
10✔
209

210
            case array_key_exists("{$prefix}_{$underscoreProperty}", $_ENV):
6,626✔
211
                return $_ENV["{$prefix}_{$underscoreProperty}"];
10✔
212

213
            case array_key_exists("{$prefix}.{$property}", $_SERVER):
6,626✔
214
                return $_SERVER["{$prefix}.{$property}"];
1✔
215

216
            case array_key_exists("{$prefix}_{$underscoreProperty}", $_SERVER):
6,626✔
217
                return $_SERVER["{$prefix}_{$underscoreProperty}"];
×
218

219
            default:
220
                $value = getenv("{$shortPrefix}.{$property}");
6,626✔
221
                $value = $value === false ? getenv("{$shortPrefix}_{$underscoreProperty}") : $value;
6,626✔
222
                $value = $value === false ? getenv("{$prefix}.{$property}") : $value;
6,626✔
223
                $value = $value === false ? getenv("{$prefix}_{$underscoreProperty}") : $value;
6,626✔
224

225
                return $value === false ? null : $value;
6,626✔
226
        }
227
    }
228

229
    /**
230
     * Provides external libraries a simple way to register one or more
231
     * options into a config file.
232
     *
233
     * @return void
234
     *
235
     * @throws ReflectionException
236
     */
237
    protected function registerProperties()
238
    {
239
        if (! static::$moduleConfig->shouldDiscover('registrars')) {
6,626✔
240
            return;
1✔
241
        }
242

243
        if (! static::$didDiscovery) {
6,626✔
244
            // Discovery must be completed before the first instantiation of any Config class.
245
            if (static::$discovering) {
19✔
NEW
246
                throw new ConfigException(
×
NEW
247
                    'During Auto-Discovery of Registrars,'
×
NEW
248
                    . ' "' . static::class . '" executes Auto-Discovery again.'
×
NEW
249
                    . ' "' . clean_path(static::$registrarFile) . '" seems to have bad code.',
×
NEW
250
                );
×
251
            }
252

253
            static::$discovering = true;
19✔
254

255
            $locator         = service('locator');
19✔
256
            $registrarsFiles = $locator->search('Config/Registrar.php');
19✔
257

258
            foreach ($registrarsFiles as $file) {
19✔
259
                // Saves the file for error message.
260
                static::$registrarFile = $file;
19✔
261

262
                $className = $locator->findQualifiedNameFromPath($file);
19✔
263

264
                if ($className === false) {
19✔
265
                    continue;
×
266
                }
267

268
                static::$registrars[] = new $className();
19✔
269
            }
270

271
            static::$didDiscovery = true;
19✔
272
            static::$discovering  = false;
19✔
273
        }
274

275
        $shortName = (new ReflectionClass($this))->getShortName();
6,626✔
276

277
        // Check the registrar class for a method named after this class' shortName
278
        foreach (static::$registrars as $callable) {
6,626✔
279
            // ignore non-applicable registrars
280
            if (! method_exists($callable, $shortName)) {
6,626✔
281
                continue; // @codeCoverageIgnore
6,626✔
282
            }
283

284
            $properties = $callable::$shortName();
800✔
285

286
            if (! is_array($properties)) {
800✔
287
                throw new RuntimeException('Registrars must return an array of properties and their values.');
1✔
288
            }
289

290
            foreach ($properties as $property => $value) {
799✔
291
                if (isset($this->{$property}) && is_array($this->{$property}) && is_array($value)) {
720✔
292
                    $this->{$property} = array_merge($this->{$property}, $value);
720✔
293
                } else {
294
                    $this->{$property} = $value;
×
295
                }
296
            }
297
        }
298
    }
299
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc