Passed
Push — master ( 596a36...36fff2 )
by Fabio
05:01
created

Prado::trace()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 10
nc 4
nop 3
dl 0
loc 15
ccs 0
cts 0
cp 0
crap 56
rs 8.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * Prado class file.
4
 *
5
 * This is the file that establishes the PRADO component model
6
 * and error handling mechanism.
7
 *
8
 * @author Qiang Xue <[email protected]>
9
 * @link https://github.com/pradosoft/prado
10
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
11
 * @package Prado
12
 */
13
14
namespace Prado;
15
16
use Prado\Exceptions\TInvalidDataValueException;
17
use Prado\Exceptions\TInvalidOperationException;
18
use Prado\Exceptions\TPhpErrorException;
19
use Prado\Exceptions\TPhpFatalErrorException;
20
use Prado\Util\TLogger;
21
use Prado\Util\TVarDumper;
22
use Prado\I18N\Translation;
23
24
// Defines the PRADO framework installation path.
25
if (!defined('PRADO_DIR')) {
26
	define('PRADO_DIR', __DIR__);
27
}
28
29
// Defines the default permission for writable directories and files
30
if (!defined('PRADO_CHMOD')) {
31
	define('PRADO_CHMOD', 0777);
32
}
33
34
// Defines the Composer's vendor/ path.
35
if (!defined('PRADO_VENDORDIR')) {
36
	$reflector = new \ReflectionClass('\Composer\Autoload\ClassLoader');
37
	define('PRADO_VENDORDIR', dirname($reflector->getFileName(), 2));
38
	unset($reflector);
39
}
40
41
/**
42
 * Prado class.
43
 *
44
 * Prado implements a few fundamental static methods.
45
 *
46
 * To use the static methods, Use Prado as the class name rather than Prado.
47
 * Prado is meant to serve as the base class of Prado. The latter might be
48
 * rewritten for customization.
49
 *
50
 * @author Qiang Xue <[email protected]>
51
 * @package Prado
52
 * @since 3.0
53
 */
54
class Prado
55
{
56
	/**
57
	 * File extension for Prado class files.
58
	 */
59
	const CLASS_FILE_EXT = '.php';
60
	/**
61
	 * @var array list of path aliases
62
	 */
63
	private static $_aliases = [
64
		'Prado' => PRADO_DIR,
65
		'Vendor' => PRADO_VENDORDIR
66
		];
67
	/**
68
	 * @var array list of namespaces currently in use
69
	 */
70
	private static $_usings = [
71
		'Prado' => PRADO_DIR
72
		];
73
	/**
74
	 * @var array list of namespaces currently in use
75
	 */
76
	public static $classMap = [];
77
	/**
78
	 * @var TApplication the application instance
79
	 */
80
	private static $_application = null;
81
	/**
82
	 * @var TLogger logger instance
83
	 */
84
	private static $_logger = null;
85
	/**
86
	 * @var array list of class exists checks
87
	 */
88
	protected static $classExists = [];
89
	/**
90
	 * @return string the version of Prado framework
91
	 */
92
	public static function getVersion()
93
	{
94
		return '4.2.0';
95
	}
96
97
	public static function init()
98
	{
99
		static::initAutoloader();
100
		static::initErrorHandlers();
101
	}
102
103
	/**
104
	 * Loads the static classmap and registers the autoload function.
105
	 */
106
	public static function initAutoloader()
107
	{
108
		self::$classMap = require(__DIR__ . '/classes.php');
109
110
		spl_autoload_register([static::class, 'autoload']);
111
	}
112
113
	/**
114
	 * Initializes error handlers.
115
	 * This method set error and exception handlers to be functions
116
	 * defined in this class.
117
	 */
118
	public static function initErrorHandlers()
119
	{
120
		/**
121
		 * Sets error handler to be Prado::phpErrorHandler
122
		 */
123
		set_error_handler([static::class, 'phpErrorHandler']);
124
		/**
125
		 * Sets shutdown function to be Prado::phpFatalErrorHandler
126
		 */
127
		register_shutdown_function([static::class, 'phpFatalErrorHandler']);
128
		/**
129
		 * Sets exception handler to be Prado::exceptionHandler
130
		 */
131
		set_exception_handler([static::class, 'exceptionHandler']);
132
		/**
133
		 * Disable php's builtin error reporting to avoid duplicated reports
134
		 */
135
		ini_set('display_errors', 0);
136
	}
137
138
	/**
139
	 * Class autoload loader.
140
	 * This method is provided to be registered within an spl_autoload_register() method.
141
	 * @param string $className class name
142
	 */
143
	public static function autoload($className)
144
	{
145
		static::using($className);
146
	}
147
148
	/**
149
	 * @param int $logoType the type of "powered logo". Valid values include 0 and 1.
150
	 * @return string a string that can be displayed on your Web page showing powered-by-PRADO information
151
	 */
152
	public static function poweredByPrado($logoType = 0)
153
	{
154
		$logoName = $logoType == 1 ? 'powered2' : 'powered';
155
		if (self::$_application !== null) {
156
			$am = self::$_application->getAssetManager();
157
			$url = $am->publishFilePath(self::getPathOfNamespace('Prado\\' . $logoName, '.gif'));
158
		} else {
159
			$url = 'http://pradosoft.github.io/docs/' . $logoName . '.gif';
160
		}
161
		return '<a title="Powered by PRADO" href="https://github.com/pradosoft/prado" target="_blank"><img src="' . $url . '" style="border-width:0px;" alt="Powered by PRADO" /></a>';
162
	}
163
164
	/**
165
	 * PHP error handler.
166
	 * This method should be registered as PHP error handler using
167
	 * {@link set_error_handler}. The method throws an exception that
168
	 * contains the error information.
169
	 * @param int $errno the level of the error raised
170
	 * @param string $errstr the error message
171
	 * @param string $errfile the filename that the error was raised in
172
	 * @param int $errline the line number the error was raised at
173
	 */
174
	public static function phpErrorHandler($errno, $errstr, $errfile, $errline)
175
	{
176
		if (error_reporting() & $errno) {
177
			throw new TPhpErrorException($errno, $errstr, $errfile, $errline);
178
		}
179
	}
180
181
	/**
182
	 * PHP shutdown function used to catch fatal errors.
183
	 * This method should be registered as PHP error handler using
184
	 * {@link register_shutdown_function}. The method throws an exception that
185
	 * contains the error information.
186
	 */
187
	public static function phpFatalErrorHandler()
188
	{
189
		$error = error_get_last();
190
		if ($error &&
191
			TPhpErrorException::isFatalError($error) &&
192
			error_reporting() & $error['type']) {
193
			self::exceptionHandler(new TPhpFatalErrorException($error['type'], $error['message'], $error['file'], $error['line']));
194
		}
195
	}
196
197
	/**
198
	 * Default exception handler.
199
	 * This method should be registered as default exception handler using
200
	 * {@link set_exception_handler}. The method tries to use the errorhandler
201
	 * module of the Prado application to handle the exception.
202
	 * If the application or the module does not exist, it simply echoes the
203
	 * exception.
204
	 * @param Exception $exception exception that is not caught
205
	 */
206
	public static function exceptionHandler($exception)
207
	{
208
		if (self::$_application !== null && ($errorHandler = self::$_application->getErrorHandler()) !== null) {
209
			$errorHandler->handleError(null, $exception);
210
		} else {
211
			echo $exception;
212
		}
213
		exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
214
	}
215
216
	/**
217
	 * Stores the application instance in the class static member.
218
	 * This method helps implement a singleton pattern for TApplication.
219
	 * Repeated invocation of this method or the application constructor
220
	 * will cause the throw of an exception.
221
	 * This method should only be used by framework developers.
222
	 * @param TApplication $application the application instance
223
	 * @throws TInvalidOperationException if this method is invoked twice or more.
224
	 */
225
	public static function setApplication($application)
226
	{
227
		if (self::$_application !== null && !defined('PRADO_TEST_RUN')) {
228
			throw new TInvalidOperationException('prado_application_singleton_required');
229
		}
230
		self::$_application = $application;
231
	}
232
233
	/**
234
	 * @return TApplication the application singleton, null if the singleton has not be created yet.
235
	 */
236
	public static function getApplication()
237
	{
238
		return self::$_application;
239
	}
240
241
	/**
242
	 * @return string the path of the framework
243
	 */
244
	public static function getFrameworkPath()
245
	{
246
		return PRADO_DIR;
247
	}
248
249
	/**
250
	 * Convert old Prado namespaces to PHP namespaces
251
	 * @param string $type old class name in Prado3 namespace format
252
	 * @return string Equivalent class name in PHP namespace format
253
	 */
254
	protected static function prado3NamespaceToPhpNamespace($type)
255
	{
256
		if (substr($type, 0, 6) === 'System') {
257
			$type = 'Prado' . substr($type, 6);
258
		}
259
260
		if (false === strpos($type, '\\')) {
261
			return str_replace('.', '\\', $type);
262
		} else {
263
			return $type;
264
		}
265
	}
266
267
	/**
268
	 * Creates a component with the specified type.
269
	 * A component type can be either the component class name
270
	 * or a namespace referring to the path of the component class file.
271
	 * For example, 'TButton', '\Prado\Web\UI\WebControls\TButton' are both
272
	 * valid component type.
273
	 * This method can also pass parameters to component constructors.
274
	 * All parameters passed to this method except the first one (the component type)
275
	 * will be supplied as component constructor parameters.
276
	 * @param string $requestedType component type
277
	 * @param array $params
278
	 * @throws TInvalidDataValueException if the component type is unknown
279
	 * @return \Prado\TComponent component instance of the specified type
280
	 */
281
	public static function createComponent($requestedType, ...$params)
282
	{
283
		$type = static::prado3NamespaceToPhpNamespace($requestedType);
284
		if (!isset(self::$classExists[$type])) {
285
			self::$classExists[$type] = class_exists($type, false);
286
		}
287
288
		if (!isset(self::$_usings[$type]) && !self::$classExists[$type]) {
289
			static::using($type);
290
			self::$classExists[$type] = class_exists($type, false);
291
		}
292
293
		/*
294
		 * Old apps compatibility support: if the component name has been specified using the
295
		 * old namespace syntax (eg. Application.Common.MyDataModule), assume that the calling
296
		 * code expects the class not to be php5.3-namespaced (eg: MyDataModule instead of
297
		 * \Application\Common\MyDataModule)
298
		 * Skip this if the class is inside the Prado\* namespace, since all Prado classes are now namespaced
299
		 */
300
		if (($pos = strrpos($type, '\\')) !== false && ($requestedType != $type) && strpos($type, 'Prado\\') !== 0) {
301
			$type = substr($type, $pos + 1);
302
		}
303
304
		if (count($params) > 0) {
305
			return new $type(...$params);
306
		} else {
307
			return new $type;
308
		}
309
	}
310
311
	/**
312
	 * Uses a namespace.
313
	 * A namespace ending with an asterisk '*' refers to a directory, otherwise it represents a PHP file.
314
	 * If the namespace corresponds to a directory, the directory will be appended
315
	 * to the include path. If the namespace corresponds to a file, it will be included (include_once).
316
	 * @param string $namespace namespace to be used
317
	 * @throws TInvalidDataValueException if the namespace is invalid
318
	 */
319
	public static function using($namespace)
320
	{
321
		$namespace = static::prado3NamespaceToPhpNamespace($namespace);
322
323
		if (isset(self::$_usings[$namespace]) ||
324
			class_exists($namespace, false) ||
325
			interface_exists($namespace, false)) {
326
			return;
327
		}
328
329
		if (array_key_exists($namespace, self::$classMap)) {
330
			// fast autoload a Prado3 class name
331
			$phpNamespace = self::$classMap[$namespace];
332
			if (class_exists($phpNamespace, true) || interface_exists($phpNamespace, true)) {
333
				if (!class_exists($namespace) && !interface_exists($namespace)) {
334
					class_alias($phpNamespace, $namespace);
335
				}
336
				return;
337
			}
338
		} elseif (($pos = strrpos($namespace, '\\')) === false) {
339
			// trying to autoload an old class name
340
			foreach (self::$_usings as $k => $v) {
341
				$path = $v . DIRECTORY_SEPARATOR . $namespace . self::CLASS_FILE_EXT;
342
				if (file_exists($path)) {
343
					$phpNamespace = '\\' . $k . '\\' . $namespace;
344
					if (class_exists($phpNamespace, true) || interface_exists($phpNamespace, true)) {
345
						if (!class_exists($namespace) && !interface_exists($namespace)) {
346
							class_alias($phpNamespace, $namespace);
347
						}
348
						return;
349
					}
350
				}
351
			}
352
		} elseif (($path = self::getPathOfNamespace($namespace, self::CLASS_FILE_EXT)) !== null) {
0 ignored issues
show
introduced by
The condition $path = self::getPathOfN...LASS_FILE_EXT) !== null is always true.
Loading history...
353
			$className = substr($namespace, $pos + 1);
354
			if ($className === '*') {  // a directory
355
				self::$_usings[substr($namespace, 0, $pos)] = $path;
356
			} else {  // a file
357
				if (class_exists($className, false) || interface_exists($className, false)) {
358
					return;
359
				}
360
361
				if (file_exists($path)) {
362
					include_once($path);
363
					if (!class_exists($className, false) && !interface_exists($className, false)) {
364
						class_alias($namespace, $className);
365
					}
366
				}
367
			}
368
		}
369
	}
370
371
	/**
372
	 * Translates a namespace into a file path.
373
	 * The first segment of the namespace is considered as a path alias
374
	 * which is replaced with the actual path. The rest segments are
375
	 * subdirectory names appended to the aliased path.
376
	 * If the namespace ends with an asterisk '*', it represents a directory;
377
	 * Otherwise it represents a file whose extension name is specified by the second parameter (defaults to empty).
378
	 * Note, this method does not ensure the existence of the resulting file path.
379
	 * @param string $namespace namespace
380
	 * @param string $ext extension to be appended if the namespace refers to a file
381
	 * @return string file path corresponding to the namespace, null if namespace is invalid
382
	 */
383
	public static function getPathOfNamespace($namespace, $ext = '')
384
	{
385
		$namespace = static::prado3NamespaceToPhpNamespace($namespace);
386
387
		if (self::CLASS_FILE_EXT === $ext || empty($ext)) {
388
			if (isset(self::$_usings[$namespace])) {
389
				return self::$_usings[$namespace];
390
			}
391
392
			if (isset(self::$_aliases[$namespace])) {
393
				return self::$_aliases[$namespace];
394
			}
395
		}
396
397
		$segs = explode('\\', $namespace);
398
		$alias = array_shift($segs);
399
400
		if (null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias))) {
401
			return rtrim($root . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $segs), '/\\') . (($file === '*') ? '' : DIRECTORY_SEPARATOR . $file . $ext);
402
		}
403
404
		return null;
405
	}
406
407
	/**
408
	 * @param string $alias alias to the path
409
	 * @return string the path corresponding to the alias, null if alias not defined.
410
	 */
411
	public static function getPathOfAlias($alias)
412
	{
413
		return self::$_aliases[$alias] ?? null;
414
	}
415
416
	protected static function getPathAliases()
417
	{
418
		return self::$_aliases;
419
	}
420
421
	/**
422
	 * @param string $alias alias to the path
423
	 * @param string $path the path corresponding to the alias
424
	 * @throws TInvalidOperationException $alias if the alias is already defined
425
	 * @throws TInvalidDataValueException $path if the path is not a valid file path
426
	 */
427
	public static function setPathOfAlias($alias, $path)
428
	{
429
		if (isset(self::$_aliases[$alias]) && !defined('PRADO_TEST_RUN')) {
430
			throw new TInvalidOperationException('prado_alias_redefined', $alias);
431
		} elseif (($rp = realpath($path)) !== false && is_dir($rp)) {
432
			if (strpos($alias, '.') === false) {
433
				self::$_aliases[$alias] = $rp;
434
			} else {
435
				throw new TInvalidDataValueException('prado_aliasname_invalid', $alias);
436
			}
437
		} else {
438
			throw new TInvalidDataValueException('prado_alias_invalid', $alias, $path);
439
		}
440
	}
441
442
	/**
443
	 * Fatal error handler.
444
	 * This method displays an error message together with the current call stack.
445
	 * The application will exit after calling this method.
446
	 * @param string $msg error message
447
	 */
448
	public static function fatalError($msg)
449
	{
450
		echo '<h1>Fatal Error</h1>';
451
		echo '<p>' . $msg . '</p>';
452
		if (!function_exists('debug_backtrace')) {
453
			return;
454
		}
455
		echo '<h2>Debug Backtrace</h2>';
456
		echo '<pre>';
457
		$index = -1;
458
		foreach (debug_backtrace() as $t) {
459
			$index++;
460
			if ($index == 0) {  // hide the backtrace of this function
461
				continue;
462
			}
463
			echo '#' . $index . ' ';
464
			if (isset($t['file'])) {
465
				echo basename($t['file']) . ':' . $t['line'];
466
			} else {
467
				echo '<PHP inner-code>';
468
			}
469
			echo ' -- ';
470
			if (isset($t['class'])) {
471
				echo $t['class'] . $t['type'];
472
			}
473
			echo $t['function'] . '(';
474
			if (isset($t['args']) && count($t['args']) > 0) {
475
				$count = 0;
476
				foreach ($t['args'] as $item) {
477
					if (is_string($item)) {
478
						$str = htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
479
						if (strlen($item) > 70) {
480
							echo "'" . substr($str, 0, 70) . "...'";
481
						} else {
482
							echo "'" . $str . "'";
483
						}
484
					} elseif (is_int($item) || is_float($item)) {
485
						echo $item;
486
					} elseif (is_object($item)) {
487
						echo get_class($item);
488
					} elseif (is_array($item)) {
489
						echo 'array(' . count($item) . ')';
490
					} elseif (is_bool($item)) {
491
						echo $item ? 'true' : 'false';
492
					} elseif ($item === null) {
493
						echo 'NULL';
494
					} elseif (is_resource($item)) {
495
						echo get_resource_type($item);
496
					}
497
					$count++;
498
					if (count($t['args']) > $count) {
499
						echo ', ';
500
					}
501
				}
502
			}
503
			echo ")\n";
504
		}
505
		echo '</pre>';
506
		exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
507
	}
508
509
	/**
510
	 * Returns a list of user preferred languages.
511
	 * The languages are returned as an array. Each array element
512
	 * represents a single language preference. The languages are ordered
513
	 * according to user preferences. The first language is the most preferred.
514
	 * @return array list of user preferred languages.
515
	 */
516
	public static function getUserLanguages()
517
	{
518
		static $languages = null;
519
		if ($languages === null) {
520
			if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
521
				$languages[0] = 'en';
522
			} else {
523
				$languages = [];
524
				foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language) {
525
					$array = explode(';q=', trim($language));
526
					$languages[trim($array[0])] = isset($array[1]) ? (float) $array[1] : 1.0;
527
				}
528
				arsort($languages);
529
				$languages = array_keys($languages);
530
				if (empty($languages)) {
531
					$languages[0] = 'en';
532
				}
533
			}
534
		}
535
		return $languages;
536
	}
537
538
	/**
539
	 * Returns the most preferred language by the client user.
540
	 * @return string the most preferred language by the client user, defaults to English.
541
	 */
542
	public static function getPreferredLanguage()
543
	{
544
		static $language = null;
545
		if ($language === null) {
546
			$langs = Prado::getUserLanguages();
547
			$lang = explode('-', $langs[0]);
548
			if (empty($lang[0]) || !ctype_alpha($lang[0])) {
549
				$language = 'en';
550
			} else {
551
				$language = $lang[0];
552
			}
553
		}
554
		return $language;
555
	}
556
557
	/**
558
	 * Writes a log message.
559
	 * This method wraps {@link log()} by checking the application mode.
560
	 * When the application is in Debug mode, debug backtrace information is appended
561
	 * to the message and the message is logged at DEBUG level.
562
	 * When the application is in Performance mode, this method does nothing.
563
	 * Otherwise, the message is logged at INFO level.
564
	 * @param string $msg message to be logged
565
	 * @param string $category category of the message
566
	 * @param (string|TControl) $ctl control of the message
0 ignored issues
show
Bug introduced by
The type Prado\TControl was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
567
	 * @see log, getLogger
568
	 */
569
	public static function trace($msg, $category = 'Uncategorized', $ctl = null)
570
	{
571
		if (self::$_application && self::$_application->getMode() === TApplicationMode::Performance) {
0 ignored issues
show
introduced by
The condition self::_application->getM...cationMode::Performance is always false.
Loading history...
572
			return;
573
		}
574
		if (!self::$_application || self::$_application->getMode() === TApplicationMode::Debug) {
575
			$trace = debug_backtrace();
576
			if (isset($trace[0]['file']) && isset($trace[0]['line'])) {
577
				$msg .= " (line {$trace[0]['line']}, {$trace[0]['file']})";
578
			}
579
			$level = TLogger::DEBUG;
580
		} else {
581
			$level = TLogger::INFO;
582
		}
583
		self::log($msg, $level, $category, $ctl);
584
	}
585
586
	/**
587
	 * Logs a message.
588
	 * Messages logged by this method may be retrieved via {@link TLogger::getLogs}
589
	 * and may be recorded in different media, such as file, email, database, using
590
	 * {@link TLogRouter}.
591
	 * @param string $msg message to be logged
592
	 * @param int $level level of the message. Valid values include
593
	 * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING,
594
	 * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL.
595
	 * @param string $category category of the message
596
	 * @param (string|TControl) $ctl control of the message
597
	 */
598
	public static function log($msg, $level = TLogger::INFO, $category = 'Uncategorized', $ctl = null)
599
	{
600
		if (self::$_logger === null) {
601
			self::$_logger = new TLogger;
602
		}
603
		self::$_logger->log($msg, $level, $category, $ctl);
604
	}
605
606
	/**
607
	 * @return TLogger message logger
608
	 */
609
	public static function getLogger()
610
	{
611
		if (self::$_logger === null) {
612
			self::$_logger = new TLogger;
613
		}
614
		return self::$_logger;
615
	}
616
617
	/**
618
	 * Converts a variable into a string representation.
619
	 * This method achieves the similar functionality as var_dump and print_r
620
	 * but is more robust when handling complex objects such as PRADO controls.
621
	 * @param mixed $var variable to be dumped
622
	 * @param int $depth maximum depth that the dumper should go into the variable. Defaults to 10.
623
	 * @param bool $highlight whether to syntax highlight the output. Defaults to false.
624
	 * @return string the string representation of the variable
625
	 */
626
	public static function varDump($var, $depth = 10, $highlight = false)
627
	{
628
		return TVarDumper::dump($var, $depth, $highlight);
629
	}
630
631
	/**
632
	 * Localize a text to the locale/culture specified in the globalization handler.
633
	 * @param string $text text to be localized.
634
	 * @param array $parameters a set of parameters to substitute.
635
	 * @param string $catalogue a different catalogue to find the localize text.
636
	 * @param string $charset the input AND output charset.
637
	 * @return string localized text.
638
	 * @see TTranslate::formatter()
639
	 * @see TTranslate::init()
640
	 */
641
	public static function localize($text, $parameters = [], $catalogue = null, $charset = null)
642
	{
643
		$app = Prado::getApplication()->getGlobalization(false);
644
645
		$params = [];
646
		foreach ($parameters as $key => $value) {
647
			$params['{' . $key . '}'] = $value;
648
		}
649
650
		//no translation handler provided
651
		if ($app === null || ($config = $app->getTranslationConfiguration()) === null) {
652
			return strtr($text, $params);
653
		}
654
655
		if ($catalogue === null) {
656
			$catalogue = $config['catalogue'] ?? 'messages';
657
		}
658
659
		Translation::init($catalogue);
660
661
		//globalization charset
662
		$appCharset = $app === null ? '' : $app->getCharset();
663
664
		//default charset
665
		$defaultCharset = ($app === null) ? 'UTF-8' : $app->getDefaultCharset();
666
667
		//fall back
668
		if (empty($charset)) {
669
			$charset = $appCharset;
670
		}
671
		if (empty($charset)) {
672
			$charset = $defaultCharset;
673
		}
674
675
		return Translation::formatter($catalogue)->format($text, $params, $catalogue, $charset);
676
	}
677
}
678
679
/**
680
 * Initialize Prado autoloader and error handler
681
 */
682
Prado::init();
683
684
/**
685
 * Defines Prado in global namespace
686
 */
687
class_alias('\Prado\Prado', 'Prado');
688