Completed
Push — 2.1 ( 866c70...fd9384 )
by Alexander
08:57
created

BaseYii::setProfiler()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6.1308

Importance

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