Completed
Push — 2.1 ( b44a46...4c2160 )
by
unknown
12:30
created

BaseYii::t()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 7
nc 5
nop 4
crap 5
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 66
    public static function getVersion()
93
    {
94 66
        return '2.0.15-dev';
95
    }
96
97
    /**
98
     * Translates a path alias into an actual path.
99
     *
100
     * The translation is done according to the following procedure:
101
     *
102
     * 1. If the given alias does not start with '@', it is returned back without change;
103
     * 2. Otherwise, look for the longest registered alias that matches the beginning part
104
     *    of the given alias. If it exists, replace the matching part of the given alias with
105
     *    the corresponding registered path.
106
     * 3. Throw an exception or return false, depending on the `$throwException` parameter.
107
     *
108
     * For example, by default '@yii' is registered as the alias to the Yii framework directory,
109
     * say '/path/to/yii'. The alias '@yii/web' would then be translated into '/path/to/yii/web'.
110
     *
111
     * If you have registered two aliases '@foo' and '@foo/bar'. Then translating '@foo/bar/config'
112
     * would replace the part '@foo/bar' (instead of '@foo') with the corresponding registered path.
113
     * This is because the longest alias takes precedence.
114
     *
115
     * However, if the alias to be translated is '@foo/barbar/config', then '@foo' will be replaced
116
     * instead of '@foo/bar', because '/' serves as the boundary character.
117
     *
118
     * Note, this method does not check if the returned path exists or not.
119
     *
120
     * See the [guide article on aliases](guide:concept-aliases) for more information.
121
     *
122
     * @param string $alias the alias to be translated.
123
     * @param bool $throwException whether to throw an exception if the given alias is invalid.
124
     * If this is false and an invalid alias is given, false will be returned by this method.
125
     * @return string|bool the path corresponding to the alias, false if the root alias is not previously registered.
126
     * @throws InvalidArgumentException if the alias is invalid while $throwException is true.
127
     * @see setAlias()
128
     */
129 3500
    public static function getAlias($alias, $throwException = true)
130
    {
131 3500
        if (strncmp($alias, '@', 1)) {
132
            // not an alias
133 3284
            return $alias;
134
        }
135
136 3419
        $result = static::findAlias($alias);
137
138 3419
        if (is_array($result)) {
139 3419
            return $result['path'];
140
        }
141
142 1
        if ($throwException) {
143 1
            throw new InvalidArgumentException("Invalid path alias: $alias");
144
        }
145
146 1
        return false;
147
    }
148
149
    /**
150
     * Returns the root alias part of a given alias.
151
     * A root alias is an alias that has been registered via [[setAlias()]] previously.
152
     * If a given alias matches multiple root aliases, the longest one will be returned.
153
     * @param string $alias the alias
154
     * @return string|bool the root alias, or false if no root alias is found
155
     */
156 1
    public static function getRootAlias($alias)
157
    {
158 1
        $result = static::findAlias($alias);
159 1
        if (is_array($result)) {
160 1
            $result = $result['root'];
161
        }
162 1
        return $result;
163
    }
164
165
    /**
166
     * @param string $alias
167
     * @return array|bool
168
     */
169 3420
    protected static function findAlias(string $alias)
170
    {
171 3420
        $pos = strpos($alias, '/');
172 3420
        $root = $pos === false ? $alias : substr($alias, 0, $pos);
173
174 3420
        if (isset(static::$aliases[$root])) {
175 3420
            if (is_string(static::$aliases[$root])) {
176 3419
                return ['root' => $root, 'path' => $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos)];
177
            }
178
179 3
            foreach (static::$aliases[$root] as $name => $path) {
180 3
                if (strpos($alias . '/', $name . '/') === 0) {
181 3
                    return ['root' => $name, 'path' => $path . substr($alias, strlen($name))];
182
                }
183
            }
184
        }
185
186 1
        return false;
187
    }
188
189
    /**
190
     * Registers a path alias.
191
     *
192
     * A path alias is a short name representing a long path (a file path, a URL, etc.)
193
     * For example, we use '@yii' as the alias of the path to the Yii framework directory.
194
     *
195
     * A path alias must start with the character '@' so that it can be easily differentiated
196
     * from non-alias paths.
197
     *
198
     * Note that this method does not check if the given path exists or not. All it does is
199
     * to associate the alias with the path.
200
     *
201
     * Any trailing '/' and '\' characters in the given path will be trimmed.
202
     *
203
     * See the [guide article on aliases](guide:concept-aliases) for more information.
204
     *
205
     * @param string $alias the alias name (e.g. "@yii"). It must start with a '@' character.
206
     * It may contain the forward slash '/' which serves as boundary character when performing
207
     * alias translation by [[getAlias()]].
208
     * @param string $path the path corresponding to the alias. If this is null, the alias will
209
     * be removed. Trailing '/' and '\' characters will be trimmed. This can be
210
     *
211
     * - a directory or a file path (e.g. `/tmp`, `/tmp/main.txt`)
212
     * - a URL (e.g. `http://www.yiiframework.com`)
213
     * - a path alias (e.g. `@yii/base`). In this case, the path alias will be converted into the
214
     *   actual path first by calling [[getAlias()]].
215
     *
216
     * @throws InvalidArgumentException if $path is an invalid alias.
217
     * @see getAlias()
218
     */
219 3186
    public static function setAlias($alias, $path)
220
    {
221 3186
        if (strncmp($alias, '@', 1)) {
222 1
            $alias = '@' . $alias;
223
        }
224 3186
        $pos = strpos($alias, '/');
225 3186
        $root = $pos === false ? $alias : substr($alias, 0, $pos);
226 3186
        if ($path !== null) {
227 3186
            $path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
228 3186
            if (!isset(static::$aliases[$root])) {
229 10
                if ($pos === false) {
230 9
                    static::$aliases[$root] = $path;
231
                } else {
232 10
                    static::$aliases[$root] = [$alias => $path];
233
                }
234 3185
            } elseif (is_string(static::$aliases[$root])) {
235 3184
                if ($pos === false) {
236 3182
                    static::$aliases[$root] = $path;
237
                } else {
238 2
                    static::$aliases[$root] = [
239 2
                        $alias => $path,
240 3184
                        $root => static::$aliases[$root],
241
                    ];
242
                }
243
            } else {
244 1
                static::$aliases[$root][$alias] = $path;
245 3186
                krsort(static::$aliases[$root]);
246
            }
247 3
        } elseif (isset(static::$aliases[$root])) {
248 3
            if (is_array(static::$aliases[$root])) {
249 1
                unset(static::$aliases[$root][$alias]);
250 2
            } elseif ($pos === false) {
251 2
                unset(static::$aliases[$root]);
252
            }
253
        }
254 3186
    }
255
256
    /**
257
     * Creates a new object using the given configuration.
258
     *
259
     * You may view this method as an enhanced version of the `new` operator.
260
     * The method supports creating an object based on a class name, a configuration array or
261
     * an anonymous function.
262
     *
263
     * Below are some usage examples:
264
     *
265
     * ```php
266
     * // create an object using a class name
267
     * $object = Yii::createObject(\yii\db\Connection::class);
268
     *
269
     * // create an object using a configuration array
270
     * $object = Yii::createObject([
271
     *     'class' => \yii\db\Connection::class,
272
     *     'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
273
     *     'username' => 'root',
274
     *     'password' => '',
275
     *     'charset' => 'utf8',
276
     * ]);
277
     *
278
     * // create an object with two constructor parameters
279
     * $object = \Yii::createObject('MyClass', [$param1, $param2]);
280
     * ```
281
     *
282
     * Using [[\yii\di\Container|dependency injection container]], this method can also identify
283
     * dependent objects, instantiate them and inject them into the newly created object.
284
     *
285
     * @param string|array|callable $type the object type. This can be specified in one of the following forms:
286
     *
287
     * - a string: representing the class name of the object to be created
288
     * - a configuration array: the array must contain a `class` element which is treated as the object class,
289
     *   and the rest of the name-value pairs will be used to initialize the corresponding object properties
290
     * - a PHP callable: either an anonymous function or an array representing a class method (`[$class or $object, $method]`).
291
     *   The callable should return a new instance of the object being created.
292
     *
293
     * @param array $params the constructor parameters
294
     * @return object the created object
295
     * @throws InvalidConfigException if the configuration is invalid.
296
     * @see \yii\di\Container
297
     */
298 3071
    public static function createObject($type, array $params = [])
299
    {
300 3071
        if (is_string($type)) {
301 1039
            return static::$container->get($type, $params);
302 3034
        } elseif (is_array($type) && isset($type['class'])) {
303 3030
            $class = $type['class'];
304 3030
            unset($type['class']);
305 3030
            return static::$container->get($class, $params, $type);
306 8
        } elseif (is_callable($type, true)) {
307 6
            return static::$container->invoke($type, $params);
308 2
        } elseif (is_array($type)) {
309 1
            throw new InvalidConfigException('Object configuration must be an array containing a "class" element.');
310
        }
311
312 1
        throw new InvalidConfigException('Unsupported configuration type: ' . gettype($type));
313
    }
314
315
    /**
316
     * @var LoggerInterface logger instance.
317
     */
318
    private static $_logger;
319
320
    /**
321
     * @return LoggerInterface message logger
322
     */
323 1813
    public static function getLogger()
324
    {
325 1813
        if (self::$_logger !== null) {
326 1813
            return self::$_logger;
327
        }
328
329 1
        return self::$_logger = Instance::ensure(['class' => Logger::class], LoggerInterface::class);
330
    }
331
332
    /**
333
     * Sets the logger object.
334
     * @param LoggerInterface|\Closure|array|null $logger the logger object or its DI compatible configuration.
335
     */
336 26
    public static function setLogger($logger)
337
    {
338 26
        if ($logger === null) {
339 20
            self::$_logger = null;
340 20
            return;
341
        }
342
343 19
        if (is_array($logger)) {
344 7
            if (!isset($logger['class']) && is_object(self::$_logger)) {
345 7
                static::configure(self::$_logger, $logger);
346 7
                return;
347
            }
348 1
            $logger = array_merge(['class' => Logger::class], $logger);
349 13
        } elseif ($logger instanceof \Closure) {
350 1
            $logger = call_user_func($logger);
351
        }
352
353 13
        self::$_logger = Instance::ensure($logger, LoggerInterface::class);
354 13
    }
355
356
    /**
357
     * @var ProfilerInterface profiler instance.
358
     * @since 2.1
359
     */
360
    private static $_profiler;
361
362
    /**
363
     * @return ProfilerInterface profiler instance.
364
     * @since 2.1
365
     */
366 1576
    public static function getProfiler()
367
    {
368 1576
        if (self::$_profiler !== null) {
369 1576
            return self::$_profiler;
370
        }
371 2
        return self::$_profiler = Instance::ensure(['class' => Profiler::class], ProfilerInterface::class);
372
    }
373
374
    /**
375
     * @param ProfilerInterface|\Closure|array|null $profiler profiler instance or its DI compatible configuration.
376
     * @since 2.1
377
     */
378 9
    public static function setProfiler($profiler)
379
    {
380 9
        if ($profiler === null) {
381 9
            self::$_profiler = null;
382 9
            return;
383
        }
384
385 1
        if (is_array($profiler)) {
386 1
            if (!isset($profiler['class']) && is_object(self::$_profiler)) {
387 1
                static::configure(self::$_profiler, $profiler);
388 1
                return;
389
            }
390 1
            $profiler = array_merge(['class' => Profiler::class], $profiler);
391 1
        } elseif ($profiler instanceof \Closure) {
392 1
            $profiler = call_user_func($profiler);
393
        }
394
395 1
        self::$_profiler = Instance::ensure($profiler, ProfilerInterface::class);
396 1
    }
397
398
    /**
399
     * Logs a message with category.
400
     * @param string $level log level.
401
     * @param mixed $message the message to be logged. This can be a simple string or a more
402
     * complex data structure, such as array.
403
     * @param string $category the category of the message.
404
     * @since 2.1.0
405
     */
406 1812
    public static function log($level, $message, $category = 'application')
407
    {
408 1812
        $context = ['category' => $category];
409 1812
        if (!is_string($message)) {
410 12
            if ($message instanceof \Throwable) {
411
                // exceptions are string-convertable, thus should be passed as it is to the logger
412
                // if exception instance is given to produce a stack trace, it MUST be in a key named "exception".
413 1
                $context['exception'] = $message;
414
            } else {
415
                // exceptions may not be serializable if in the call stack somewhere is a Closure
416 11
                $message = VarDumper::export($message);
417
            }
418
        }
419 1812
        static::getLogger()->log($level, $message, $context);
0 ignored issues
show
Bug introduced by
It seems like $message defined by parameter $message on line 406 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...
420 1812
    }
421
422
    /**
423
     * Logs a debug message.
424
     * Trace messages are logged mainly for development purpose to see
425
     * the execution work flow of some code.
426
     * @param string|array $message the message to be logged. This can be a simple string or a more
427
     * complex data structure, such as array.
428
     * @param string $category the category of the message.
429
     * @since 2.0.14
430
     */
431 1671
    public static function debug($message, $category = 'application')
432
    {
433 1671
        if (YII_DEBUG) {
434 1671
            static::log(LogLevel::DEBUG, $message, $category);
435
        }
436 1671
    }
437
438
    /**
439
     * Logs an error message.
440
     * An error message is typically logged when an unrecoverable error occurs
441
     * during the execution of an application.
442
     * @param string|array $message the message to be logged. This can be a simple string or a more
443
     * complex data structure, such as array.
444
     * @param string $category the category of the message.
445
     */
446 6
    public static function error($message, $category = 'application')
447
    {
448 6
        static::log(LogLevel::ERROR, $message, $category);
449 6
    }
450
451
    /**
452
     * Logs a warning message.
453
     * A warning message is typically logged when an error occurs while the execution
454
     * can still continue.
455
     * @param string|array $message the message to be logged. This can be a simple string or a more
456
     * complex data structure, such as array.
457
     * @param string $category the category of the message.
458
     */
459 14
    public static function warning($message, $category = 'application')
460
    {
461 14
        static::log(LogLevel::WARNING, $message, $category);
462 14
    }
463
464
    /**
465
     * Logs an informative message.
466
     * An informative message is typically logged by an application to keep record of
467
     * something important (e.g. an administrator logs in).
468
     * @param string|array $message the message to be logged. This can be a simple string or a more
469
     * complex data structure, such as array.
470
     * @param string $category the category of the message.
471
     */
472 1619
    public static function info($message, $category = 'application')
473
    {
474 1619
        static::log(LogLevel::INFO, $message, $category);
475 1619
    }
476
477
    /**
478
     * Marks the beginning of a code block for profiling.
479
     *
480
     * This has to be matched with a call to [[endProfile]] with the same category name.
481
     * The begin- and end- calls must also be properly nested. For example,
482
     *
483
     * ```php
484
     * \Yii::beginProfile('block1');
485
     * // some code to be profiled
486
     *     \Yii::beginProfile('block2');
487
     *     // some other code to be profiled
488
     *     \Yii::endProfile('block2');
489
     * \Yii::endProfile('block1');
490
     * ```
491
     * @param string $token token for the code block
492
     * @param string $category the category of this log message
493
     * @see endProfile()
494
     */
495 1576
    public static function beginProfile($token, $category = 'application')
496
    {
497 1576
        static::getProfiler()->begin($token, ['category' => $category]);
498 1576
    }
499
500
    /**
501
     * Marks the end of a code block for profiling.
502
     * This has to be matched with a previous call to [[beginProfile]] with the same category name.
503
     * @param string $token token for the code block
504
     * @param string $category the category of this log message
505
     * @see beginProfile()
506
     */
507 1576
    public static function endProfile($token, $category = 'application')
508
    {
509 1576
        static::getProfiler()->end($token, ['category' => $category]);
510 1576
    }
511
512
    /**
513
     * Translates a message to the specified language.
514
     *
515
     * This is a shortcut method of [[\yii\i18n\I18N::translate()]].
516
     *
517
     * The translation will be conducted according to the message category and the target language will be used.
518
     *
519
     * You can add parameters to a translation message that will be substituted with the corresponding value after
520
     * translation. The format for this is to use curly brackets around the parameter name as you can see in the following example:
521
     *
522
     * ```php
523
     * $username = 'Alexander';
524
     * echo \Yii::t('app', 'Hello, {username}!', ['username' => $username]);
525
     * ```
526
     *
527
     * Further formatting of message parameters is supported using the [PHP intl extensions](http://www.php.net/manual/en/intro.intl.php)
528
     * message formatter. See [[\yii\i18n\I18N::translate()]] for more details.
529
     *
530
     * @param string $category the message category.
531
     * @param string $message the message to be translated.
532
     * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
533
     * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current
534
     * [[\yii\base\Application::language|application language]] will be used.
535
     * @return string the translated message.
536
     */
537 781
    public static function t($category, $message, $params = [], $language = null)
538
    {
539 781
        if (static::$app !== null) {
540 538
            return static::$app->getI18n()->translate($category, $message, $params, $language ?: static::$app->language);
541
        }
542
543 243
        $placeholders = [];
544 243
        foreach ((array) $params as $name => $value) {
545 3
            $placeholders['{' . $name . '}'] = $value;
546
        }
547
548 243
        return ($placeholders === []) ? $message : strtr($message, $placeholders);
549
    }
550
551
    /**
552
     * Configures an object with the initial property values.
553
     * @param object $object the object to be configured
554
     * @param array $properties the property initial values given in terms of name-value pairs.
555
     * @return object the object itself
556
     */
557 3709
    public static function configure($object, $properties)
558
    {
559 3709
        foreach ($properties as $name => $value) {
560 3709
            $object->$name = $value;
561
        }
562
563 3709
        return $object;
564
    }
565
566
    /**
567
     * Returns the public member variables of an object.
568
     * This method is provided such that we can get the public member variables of an object.
569
     * It is different from "get_object_vars()" because the latter will return private
570
     * and protected variables if it is called within the object itself.
571
     * @param object $object the object to be handled
572
     * @return array the public member variables of the object
573
     */
574 3
    public static function getObjectVars($object)
575
    {
576 3
        return get_object_vars($object);
577
    }
578
}
579