Completed
Pull Request — 2.1 (#16162)
by Leandro
13:11
created

BaseYii::getEnv()   C

Complexity

Conditions 13
Paths 11

Size

Total Lines 27
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 13

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 20
cts 20
cp 1
rs 5.1234
c 0
b 0
f 0
cc 13
eloc 20
nc 11
nop 2
crap 13

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii;
9
10
use Psr\Log\LoggerInterface;
11
use Psr\Log\LogLevel;
12
use yii\base\InvalidArgumentException;
13
use yii\base\InvalidConfigException;
14
use yii\base\UnknownClassException;
15
use yii\di\Container;
16
use yii\di\Instance;
17
use yii\helpers\VarDumper;
18
use yii\log\Logger;
19
use yii\profile\Profiler;
20
use yii\profile\ProfilerInterface;
21
22
/**
23
 * Gets the application start timestamp.
24
 */
25
defined('YII_BEGIN_TIME') or define('YII_BEGIN_TIME', microtime(true));
26
/**
27
 * This constant defines the framework installation directory.
28
 */
29
defined('YII2_PATH') or define('YII2_PATH', __DIR__);
30
/**
31
 * This constant defines whether the application should be in debug mode or not. Defaults to false.
32
 */
33
defined('YII_DEBUG') or define('YII_DEBUG', false);
34
/**
35
 * This constant defines in which environment the application is running. Defaults to 'prod', meaning production environment.
36
 * You may define this constant in the bootstrap script. The value could be 'prod' (production), 'dev' (development), 'test', 'staging', etc.
37
 */
38
defined('YII_ENV') or define('YII_ENV', 'prod');
39
/**
40
 * Whether the the application is running in production environment
41
 */
42
defined('YII_ENV_PROD') or define('YII_ENV_PROD', YII_ENV === 'prod');
43
/**
44
 * Whether the the application is running in development environment
45
 */
46
defined('YII_ENV_DEV') or define('YII_ENV_DEV', YII_ENV === 'dev');
47
/**
48
 * Whether the the application is running in testing environment
49
 */
50
defined('YII_ENV_TEST') or define('YII_ENV_TEST', YII_ENV === 'test');
51
52
/**
53
 * This constant defines whether error handling should be enabled. Defaults to true.
54
 */
55
defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', true);
56
57
/**
58
 * BaseYii is the core helper class for the Yii framework.
59
 *
60
 * Do not use BaseYii directly. Instead, use its child class [[\Yii]] which you can replace to
61
 * customize methods of BaseYii.
62
 *
63
 * @author Qiang Xue <[email protected]>
64
 * @since 2.0
65
 */
66
class BaseYii
67
{
68
    /**
69
     * @var \yii\console\Application|\yii\web\Application the application instance
70
     */
71
    public static $app;
72
    /**
73
     * @var array registered path aliases
74
     * @see getAlias()
75
     * @see setAlias()
76
     */
77
    public static $aliases = ['@yii' => __DIR__];
78
    /**
79
     * @var Container the dependency injection (DI) container used by [[createObject()]].
80
     * You may use [[Container::set()]] to set up the needed dependencies of classes and
81
     * their initial property values.
82
     * @see createObject()
83
     * @see Container
84
     */
85
    public static $container;
86
87
88
    /**
89
     * Returns a string representing the current version of the Yii framework.
90
     * @return string the version of Yii framework
91
     */
92 65
    public static function getVersion()
93
    {
94 65
        return '2.1.0-dev';
95
    }
96
97
    /**
98
    * Returns the value of an environment variable.
99
    * @param string $key the var name
100
    * @param mixed $default the default result value
101
    * @return mixed
102
    */
103 1
   public static function getEnv($key, $default = null)
104
   {
105 1
       $value = getenv($key);
106 1
       if ($value === false) {
107 1
            return $default;
108
       }
109
110 1
       switch (strtolower($value)) {
111 1
           case 'true':
112 1
           case '(true)':
113 1
               return true;
114 1
           case 'false':
115 1
           case '(false)':
116 1
               return false;
117 1
           case 'empty':
118 1
           case '(empty)':
119 1
               return '';
120 1
           case 'null':
121 1
           case '(null)':
122 1
               return;
123
       }
124
125 1
       if (($length = strlen($value)) > 1 && $value[0] === '"' && $value[$length - 1] === '"') {
126 1
           return substr($value, 1, -1);
127
       }
128 1
       return $value;
129
   }
130
131
    /**
132
     * Translates a path alias into an actual path.
133
     *
134
     * The translation is done according to the following procedure:
135
     *
136
     * 1. If the given alias does not start with '@', it is returned back without change;
137
     * 2. Otherwise, look for the longest registered alias that matches the beginning part
138
     *    of the given alias. If it exists, replace the matching part of the given alias with
139
     *    the corresponding registered path.
140
     * 3. Throw an exception or return false, depending on the `$throwException` parameter.
141
     *
142
     * For example, by default '@yii' is registered as the alias to the Yii framework directory,
143
     * say '/path/to/yii'. The alias '@yii/web' would then be translated into '/path/to/yii/web'.
144
     *
145
     * If you have registered two aliases '@foo' and '@foo/bar'. Then translating '@foo/bar/config'
146
     * would replace the part '@foo/bar' (instead of '@foo') with the corresponding registered path.
147
     * This is because the longest alias takes precedence.
148
     *
149
     * However, if the alias to be translated is '@foo/barbar/config', then '@foo' will be replaced
150
     * instead of '@foo/bar', because '/' serves as the boundary character.
151
     *
152
     * Note, this method does not check if the returned path exists or not.
153
     *
154
     * See the [guide article on aliases](guide:concept-aliases) for more information.
155
     *
156
     * @param string $alias the alias to be translated.
157
     * @param bool $throwException whether to throw an exception if the given alias is invalid.
158
     * If this is false and an invalid alias is given, false will be returned by this method.
159
     * @return string|bool the path corresponding to the alias, false if the root alias is not previously registered.
160
     * @throws InvalidArgumentException if the alias is invalid while $throwException is true.
161
     * @see setAlias()
162
     */
163 3491
    public static function getAlias($alias, $throwException = true)
164
    {
165 3491
        if (strncmp($alias, '@', 1)) {
166
            // not an alias
167 3272
            return $alias;
168
        }
169
170 3410
        $result = static::findAlias($alias);
171
172 3410
        if (is_array($result)) {
173 3410
            return $result['path'];
174
        }
175
176 1
        if ($throwException) {
177 1
            throw new InvalidArgumentException("Invalid path alias: $alias");
178
        }
179
180 1
        return false;
181
    }
182
183
    /**
184
     * Returns the root alias part of a given alias.
185
     * A root alias is an alias that has been registered via [[setAlias()]] previously.
186
     * If a given alias matches multiple root aliases, the longest one will be returned.
187
     * @param string $alias the alias
188
     * @return string|bool the root alias, or false if no root alias is found
189
     */
190 1
    public static function getRootAlias($alias)
191
    {
192 1
        $result = static::findAlias($alias);
193 1
        if (is_array($result)) {
194 1
            $result = $result['root'];
195
        }
196 1
        return $result;
197
    }
198
199
    /**
200
     * @param string $alias
201
     * @return array|bool
202
     */
203 3411
    protected static function findAlias(string $alias)
204
    {
205 3411
        $pos = strpos($alias, '/');
206 3411
        $root = $pos === false ? $alias : substr($alias, 0, $pos);
207
208 3411
        if (isset(static::$aliases[$root])) {
209 3411
            if (is_string(static::$aliases[$root])) {
210 3410
                return ['root' => $root, 'path' => $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos)];
211
            }
212
213 3
            foreach (static::$aliases[$root] as $name => $path) {
214 3
                if (strpos($alias . '/', $name . '/') === 0) {
215 3
                    return ['root' => $name, 'path' => $path . substr($alias, strlen($name))];
216
                }
217
            }
218
        }
219
220 1
        return false;
221
    }
222
223
    /**
224
     * Registers a path alias.
225
     *
226
     * A path alias is a short name representing a long path (a file path, a URL, etc.)
227
     * For example, we use '@yii' as the alias of the path to the Yii framework directory.
228
     *
229
     * A path alias must start with the character '@' so that it can be easily differentiated
230
     * from non-alias paths.
231
     *
232
     * Note that this method does not check if the given path exists or not. All it does is
233
     * to associate the alias with the path.
234
     *
235
     * Any trailing '/' and '\' characters in the given path will be trimmed.
236
     *
237
     * See the [guide article on aliases](guide:concept-aliases) for more information.
238
     *
239
     * @param string $alias the alias name (e.g. "@yii"). It must start with a '@' character.
240
     * It may contain the forward slash '/' which serves as boundary character when performing
241
     * alias translation by [[getAlias()]].
242
     * @param string $path the path corresponding to the alias. If this is null, the alias will
243
     * be removed. Trailing '/' and '\' characters will be trimmed. This can be
244
     *
245
     * - a directory or a file path (e.g. `/tmp`, `/tmp/main.txt`)
246
     * - a URL (e.g. `http://www.yiiframework.com`)
247
     * - a path alias (e.g. `@yii/base`). In this case, the path alias will be converted into the
248
     *   actual path first by calling [[getAlias()]].
249
     *
250
     * @throws InvalidArgumentException if $path is an invalid alias.
251
     * @see getAlias()
252
     */
253 3174
    public static function setAlias($alias, $path)
254
    {
255 3174
        if (strncmp($alias, '@', 1)) {
256 1
            $alias = '@' . $alias;
257
        }
258 3174
        $pos = strpos($alias, '/');
259 3174
        $root = $pos === false ? $alias : substr($alias, 0, $pos);
260 3174
        if ($path !== null) {
261 3174
            $path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
262 3174
            if (!isset(static::$aliases[$root])) {
263 10
                if ($pos === false) {
264 9
                    static::$aliases[$root] = $path;
265
                } else {
266 10
                    static::$aliases[$root] = [$alias => $path];
267
                }
268 3173
            } elseif (is_string(static::$aliases[$root])) {
269 3172
                if ($pos === false) {
270 3170
                    static::$aliases[$root] = $path;
271
                } else {
272 2
                    static::$aliases[$root] = [
273 2
                        $alias => $path,
274 3172
                        $root => static::$aliases[$root],
275
                    ];
276
                }
277
            } else {
278 1
                static::$aliases[$root][$alias] = $path;
279 3174
                krsort(static::$aliases[$root]);
280
            }
281 3
        } elseif (isset(static::$aliases[$root])) {
282 3
            if (is_array(static::$aliases[$root])) {
283 1
                unset(static::$aliases[$root][$alias]);
284 2
            } elseif ($pos === false) {
285 2
                unset(static::$aliases[$root]);
286
            }
287
        }
288 3174
    }
289
290
    /**
291
     * Creates a new object using the given configuration.
292
     *
293
     * You may view this method as an enhanced version of the `new` operator.
294
     * The method supports creating an object based on a class name, a configuration array or
295
     * an anonymous function.
296
     *
297
     * Below are some usage examples:
298
     *
299
     * ```php
300
     * // create an object using a class name
301
     * $object = Yii::createObject(\yii\db\Connection::class);
302
     *
303
     * // create an object using a configuration array
304
     * $object = Yii::createObject([
305
     *     '__class' => \yii\db\Connection::class,
306
     *     'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
307
     *     'username' => 'root',
308
     *     'password' => '',
309
     *     'charset' => 'utf8',
310
     * ]);
311
     *
312
     * // create an object with two constructor parameters
313
     * $object = \Yii::createObject('MyClass', [$param1, $param2]);
314
     * ```
315
     *
316
     * Using [[\yii\di\Container|dependency injection container]], this method can also identify
317
     * dependent objects, instantiate them and inject them into the newly created object.
318
     *
319
     * @param string|array|callable $type the object type. This can be specified in one of the following forms:
320
     *
321
     * - a string: representing the class name of the object to be created
322
     * - a configuration array: the array must contain a `class` element which is treated as the object class,
323
     *   and the rest of the name-value pairs will be used to initialize the corresponding object properties
324
     * - a PHP callable: either an anonymous function or an array representing a class method (`[$class or $object, $method]`).
325
     *   The callable should return a new instance of the object being created.
326
     *
327
     * @param array $params the constructor parameters
328
     * @return object the created object
329
     * @throws InvalidConfigException if the configuration is invalid.
330
     * @see \yii\di\Container
331
     */
332 3060
    public static function createObject($type, array $params = [])
333
    {
334 3060
        if (is_string($type)) {
335 1043
            return static::$container->get($type, $params);
336 3023
        } elseif (is_array($type) && (isset($type['__class']) || isset($type['class']))) {
337 3019
            if (isset($type['__class'])) {
338 3019
                $class = $type['__class'];
339 3019
                unset($type['__class']);
340
            } else {
341
                // @todo remove fallback
342 1
                $class = $type['class'];
343 1
                unset($type['class']);
344
            }
345 3019
            return static::$container->get($class, $params, $type);
346 9
        } elseif (is_callable($type, true)) {
347 6
            return static::$container->invoke($type, $params);
348 3
        } elseif (is_array($type)) {
349 2
            throw new InvalidConfigException('Object configuration must be an array containing a "__class" element.');
350
        }
351
352 1
        throw new InvalidConfigException('Unsupported configuration type: ' . gettype($type));
353
    }
354
355
    /**
356
     * @var LoggerInterface logger instance.
357
     */
358
    private static $_logger;
359
360
    /**
361
     * @return LoggerInterface message logger
362
     */
363 1830
    public static function getLogger()
364
    {
365 1830
        if (self::$_logger !== null) {
366 1744
            return self::$_logger;
367
        }
368
369 546
        return self::$_logger = Instance::ensure(['__class' => Logger::class], LoggerInterface::class);
370
    }
371
372
    /**
373
     * Sets the logger object.
374
     * @param LoggerInterface|\Closure|array|null $logger the logger object or its DI compatible configuration.
375
     */
376 3149
    public static function setLogger($logger)
377
    {
378 3149
        if ($logger === null) {
379 3149
            self::$_logger = null;
380 3149
            return;
381
        }
382
383 19
        if (is_array($logger)) {
384 7
            if (!isset($logger['__class']) && is_object(self::$_logger)) {
385 2
                static::configure(self::$_logger, $logger);
386 2
                return;
387
            }
388 6
            $logger = array_merge(['__class' => Logger::class], $logger);
389 13
        } elseif ($logger instanceof \Closure) {
390 1
            $logger = call_user_func($logger);
391
        }
392
393 18
        self::$_logger = Instance::ensure($logger, LoggerInterface::class);
394 18
    }
395
396
    /**
397
     * @var ProfilerInterface profiler instance.
398
     * @since 2.1
399
     */
400
    private static $_profiler;
401
402
    /**
403
     * @return ProfilerInterface profiler instance.
404
     * @since 2.1
405
     */
406 1591
    public static function getProfiler()
407
    {
408 1591
        if (self::$_profiler !== null) {
409 1591
            return self::$_profiler;
410
        }
411 2
        return self::$_profiler = Instance::ensure(['__class' => Profiler::class], ProfilerInterface::class);
412
    }
413
414
    /**
415
     * @param ProfilerInterface|\Closure|array|null $profiler profiler instance or its DI compatible configuration.
416
     * @since 2.1
417
     */
418 11
    public static function setProfiler($profiler)
419
    {
420 11
        if ($profiler === null) {
421 11
            self::$_profiler = null;
422 11
            return;
423
        }
424
425 1
        if (is_array($profiler)) {
426 1
            if (!isset($profiler['__class']) && is_object(self::$_profiler)) {
427 1
                static::configure(self::$_profiler, $profiler);
428 1
                return;
429
            }
430 1
            $profiler = array_merge(['__class' => Profiler::class], $profiler);
431 1
        } elseif ($profiler instanceof \Closure) {
432 1
            $profiler = call_user_func($profiler);
433
        }
434
435 1
        self::$_profiler = Instance::ensure($profiler, ProfilerInterface::class);
436 1
    }
437
438
    /**
439
     * Logs a message with category.
440
     * @param string $level log level.
441
     * @param mixed $message the message to be logged. This can be a simple string or a more
442
     * complex data structure, such as array.
443
     * @param string $category the category of the message.
444
     * @since 2.1.0
445
     */
446 1829
    public static function log($level, $message, $category = 'application')
447
    {
448 1829
        $context = ['category' => $category];
449 1829
        if (!is_string($message)) {
450 11
            if ($message instanceof \Throwable) {
451
                // exceptions are string-convertable, thus should be passed as it is to the logger
452
                // if exception instance is given to produce a stack trace, it MUST be in a key named "exception".
453 1
                $context['exception'] = $message;
454
            } else {
455
                // exceptions may not be serializable if in the call stack somewhere is a Closure
456 10
                $message = VarDumper::export($message);
457
            }
458
        }
459 1829
        static::getLogger()->log($level, $message, $context);
0 ignored issues
show
Bug introduced by
It seems like $message defined by parameter $message on line 446 can also be of type object<Throwable>; however, Psr\Log\LoggerInterface::log() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
460 1829
    }
461
462
    /**
463
     * Logs a debug message.
464
     * Trace messages are logged mainly for development purpose to see
465
     * the execution work flow of some code.
466
     * @param string|array $message the message to be logged. This can be a simple string or a more
467
     * complex data structure, such as array.
468
     * @param string $category the category of the message.
469
     * @since 2.0.14
470
     */
471 1688
    public static function debug($message, $category = 'application')
472
    {
473 1688
        if (YII_DEBUG) {
474 1688
            static::log(LogLevel::DEBUG, $message, $category);
475
        }
476 1688
    }
477
478
    /**
479
     * Logs an error message.
480
     * An error message is typically logged when an unrecoverable error occurs
481
     * during the execution of an application.
482
     * @param string|array $message the message to be logged. This can be a simple string or a more
483
     * complex data structure, such as array.
484
     * @param string $category the category of the message.
485
     */
486 6
    public static function error($message, $category = 'application')
487
    {
488 6
        static::log(LogLevel::ERROR, $message, $category);
489 6
    }
490
491
    /**
492
     * Logs a warning message.
493
     * A warning message is typically logged when an error occurs while the execution
494
     * can still continue.
495
     * @param string|array $message the message to be logged. This can be a simple string or a more
496
     * complex data structure, such as array.
497
     * @param string $category the category of the message.
498
     */
499 14
    public static function warning($message, $category = 'application')
500
    {
501 14
        static::log(LogLevel::WARNING, $message, $category);
502 14
    }
503
504
    /**
505
     * Logs an informative message.
506
     * An informative message is typically logged by an application to keep record of
507
     * something important (e.g. an administrator logs in).
508
     * @param string|array $message the message to be logged. This can be a simple string or a more
509
     * complex data structure, such as array.
510
     * @param string $category the category of the message.
511
     */
512 1634
    public static function info($message, $category = 'application')
513
    {
514 1634
        static::log(LogLevel::INFO, $message, $category);
515 1634
    }
516
517
    /**
518
     * Marks the beginning of a code block for profiling.
519
     *
520
     * This has to be matched with a call to [[endProfile]] with the same category name.
521
     * The begin- and end- calls must also be properly nested. For example,
522
     *
523
     * ```php
524
     * \Yii::beginProfile('block1');
525
     * // some code to be profiled
526
     *     \Yii::beginProfile('block2');
527
     *     // some other code to be profiled
528
     *     \Yii::endProfile('block2');
529
     * \Yii::endProfile('block1');
530
     * ```
531
     * @param string $token token for the code block
532
     * @param string $category the category of this log message
533
     * @see endProfile()
534
     */
535 1591
    public static function beginProfile($token, $category = 'application')
536
    {
537 1591
        static::getProfiler()->begin($token, ['category' => $category]);
538 1591
    }
539
540
    /**
541
     * Marks the end of a code block for profiling.
542
     * This has to be matched with a previous call to [[beginProfile]] with the same category name.
543
     * @param string $token token for the code block
544
     * @param string $category the category of this log message
545
     * @see beginProfile()
546
     */
547 1591
    public static function endProfile($token, $category = 'application')
548
    {
549 1591
        static::getProfiler()->end($token, ['category' => $category]);
550 1591
    }
551
552
    /**
553
     * Translates a message to the specified language.
554
     *
555
     * This is a shortcut method of [[\yii\i18n\I18N::translate()]].
556
     *
557
     * The translation will be conducted according to the message category and the target language will be used.
558
     *
559
     * You can add parameters to a translation message that will be substituted with the corresponding value after
560
     * translation. The format for this is to use curly brackets around the parameter name as you can see in the following example:
561
     *
562
     * ```php
563
     * $username = 'Alexander';
564
     * echo \Yii::t('app', 'Hello, {username}!', ['username' => $username]);
565
     * ```
566
     *
567
     * Further formatting of message parameters is supported using the [PHP intl extensions](http://www.php.net/manual/en/intro.intl.php)
568
     * message formatter. See [[\yii\i18n\I18N::translate()]] for more details.
569
     *
570
     * @param string $category the message category.
571
     * @param string $message the message to be translated.
572
     * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
573
     * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current
574
     * [[\yii\base\Application::language|application language]] will be used.
575
     * @return string the translated message.
576
     */
577 780
    public static function t($category, $message, $params = [], $language = null)
578
    {
579 780
        if (static::$app !== null) {
580 535
            return static::$app->getI18n()->translate($category, $message, $params, $language ?: static::$app->language);
581
        }
582
583 245
        $placeholders = [];
584 245
        foreach ((array) $params as $name => $value) {
585 3
            $placeholders['{' . $name . '}'] = $value;
586
        }
587
588 245
        return ($placeholders === []) ? $message : strtr($message, $placeholders);
589
    }
590
591
    /**
592
     * Configures an object with the initial property values.
593
     * @param object $object the object to be configured
594
     * @param array $properties the property initial values given in terms of name-value pairs.
595
     * @return object the object itself
596
     */
597 3700
    public static function configure($object, $properties)
598
    {
599 3700
        foreach ($properties as $name => $value) {
600 3700
            $object->$name = $value;
601
        }
602
603 3700
        return $object;
604
    }
605
606
    /**
607
     * Returns the public member variables of an object.
608
     * This method is provided such that we can get the public member variables of an object.
609
     * It is different from "get_object_vars()" because the latter will return private
610
     * and protected variables if it is called within the object itself.
611
     * @param object $object the object to be handled
612
     * @return array the public member variables of the object
613
     */
614 3
    public static function getObjectVars($object)
615
    {
616 3
        return get_object_vars($object);
617
    }
618
}
619