Passed
Push — master ( 9a0355...07438e )
by Fabio
14:25 queued 02:39
created

Prado::getPathOfNamespace()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
cc 8
eloc 11
nc 8
nop 2
dl 0
loc 22
ccs 0
cts 0
cp 0
crap 72
rs 8.4444
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((string) $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<string, string> list of path aliases
62
	 */
63
	private static $_aliases = [
64
		'Prado' => PRADO_DIR,
65
		'Vendor' => PRADO_VENDORDIR
66
		];
67
	/**
68
	 * @var array<string, string> list of namespaces currently in use
69
	 */
70
	private static $_usings = [
71
		'Prado' => PRADO_DIR
72
		];
73
	/**
74
	 * @var array<string, string> list of namespaces currently in use
75
	 */
76
	public static $classMap = [];
77
	/**
78
	 * @var null|TApplication the application instance
79
	 */
80
	private static $_application;
81
	/**
82
	 * @var null|TLogger logger instance
83
	 */
84
	private static $_logger;
85
	/**
86
	 * @var array<string, bool> 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(): string
93
	{
94
		return '4.2.0';
95
	}
96
97
	/**
98
	 * Initializes the Prado static class
99
	 */
100
	public static function init(): void
101
	{
102
		static::initAutoloader();
103
		static::initErrorHandlers();
104
	}
105
106
	/**
107
	 * Loads the static classmap and registers the autoload function.
108
	 */
109
	public static function initAutoloader(): void
110
	{
111
		self::$classMap = require(__DIR__ . '/classes.php');
112
113
		spl_autoload_register([static::class, 'autoload']);
114
	}
115
116
	/**
117
	 * Initializes error handlers.
118
	 * This method set error and exception handlers to be functions
119
	 * defined in this class.
120
	 */
121
	public static function initErrorHandlers(): void
122
	{
123
		/**
124
		 * Sets error handler to be Prado::phpErrorHandler
125
		 */
126
		set_error_handler([static::class, 'phpErrorHandler']);
127
		/**
128
		 * Sets shutdown function to be Prado::phpFatalErrorHandler
129
		 */
130
		register_shutdown_function([static::class, 'phpFatalErrorHandler']);
131
		/**
132
		 * Sets exception handler to be Prado::exceptionHandler
133
		 */
134
		set_exception_handler([static::class, 'exceptionHandler']);
135
		/**
136
		 * Disable php's builtin error reporting to avoid duplicated reports
137
		 */
138
		ini_set('display_errors', '0');
139
	}
140
141
	/**
142
	 * Class autoload loader.
143
	 * This method is provided to be registered within an spl_autoload_register() method.
144
	 * @param string $className class name
145
	 */
146
	public static function autoload($className): void
147
	{
148
		static::using($className);
149
	}
150
151
	/**
152
	 * @param int $logoType the type of "powered logo". Valid values include 0 and 1.
153
	 * @return string a string that can be displayed on your Web page showing powered-by-PRADO information
154
	 */
155
	public static function poweredByPrado($logoType = 0): string
156
	{
157
		$logoName = $logoType == 1 ? 'powered2' : 'powered';
158
		if (self::$_application !== null) {
159
			$am = self::$_application->getAssetManager();
160
			$url = $am->publishFilePath((string) self::getPathOfNamespace('Prado\\' . $logoName, '.gif'));
161
		} else {
162
			$url = 'http://pradosoft.github.io/docs/' . $logoName . '.gif';
163
		}
164
		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>';
165
	}
166
167
	/**
168
	 * PHP error handler.
169
	 * This method should be registered as PHP error handler using
170
	 * {@link set_error_handler}. The method throws an exception that
171
	 * contains the error information.
172
	 * @param int $errno the level of the error raised
173
	 * @param string $errstr the error message
174
	 * @param string $errfile the filename that the error was raised in
175
	 * @param int $errline the line number the error was raised at
176
	 */
177
	public static function phpErrorHandler($errno, $errstr, $errfile, $errline): bool
178
	{
179
		if (error_reporting() & $errno) {
180
			throw new TPhpErrorException($errno, $errstr, $errfile, $errline);
181
		}
182
		return true;
183
	}
184
185
	/**
186
	 * PHP shutdown function used to catch fatal errors.
187
	 * This method should be registered as PHP error handler using
188
	 * {@link register_shutdown_function}. The method throws an exception that
189
	 * contains the error information.
190
	 */
191
	public static function phpFatalErrorHandler(): void
192
	{
193
		$error = error_get_last();
194
		if ($error &&
195
			TPhpErrorException::isFatalError($error) &&
196
			error_reporting() & $error['type']) {
197
			self::exceptionHandler(new TPhpFatalErrorException($error['type'], $error['message'], $error['file'], $error['line']));
198
		}
199
	}
200
201
	/**
202
	 * Default exception handler.
203
	 * This method should be registered as default exception handler using
204
	 * {@link set_exception_handler}. The method tries to use the errorhandler
205
	 * module of the Prado application to handle the exception.
206
	 * If the application or the module does not exist, it simply echoes the
207
	 * exception.
208
	 * @param \Throwable $exception exception that is not caught
209
	 */
210
	public static function exceptionHandler($exception): void
211
	{
212
		if (self::$_application !== null && ($errorHandler = self::$_application->getErrorHandler()) !== null) {
213
			$errorHandler->handleError(null, $exception);
214
		} else {
215
			echo $exception;
216
		}
217
		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...
218
	}
219
220
	/**
221
	 * Stores the application instance in the class static member.
222
	 * This method helps implement a singleton pattern for TApplication.
223
	 * Repeated invocation of this method or the application constructor
224
	 * will cause the throw of an exception.
225
	 * This method should only be used by framework developers.
226
	 * @param TApplication $application the application instance
227
	 * @throws TInvalidOperationException if this method is invoked twice or more.
228
	 */
229
	public static function setApplication($application): void
230
	{
231
		if (self::$_application !== null && !defined('PRADO_TEST_RUN')) {
232
			throw new TInvalidOperationException('prado_application_singleton_required');
233
		}
234
		self::$_application = $application;
235
	}
236
237
	/**
238
	 * @return null|TApplication the application singleton, null if the singleton has not be created yet.
239
	 */
240
	public static function getApplication(): ?TApplication
241
	{
242
		return self::$_application;
243
	}
244
245
	/**
246
	 * @return string the path of the framework
247
	 */
248
	public static function getFrameworkPath(): string
249
	{
250
		return PRADO_DIR;
251
	}
252
253
	/**
254
	 * @return int chmod permissions, defaults to 0777
255
	 */
256
	public static function getDefaultPermissions(): int
257
	{
258
		return PRADO_CHMOD;
259
	}
260
261
	/**
262
	 * Convert old Prado namespaces to PHP namespaces
263
	 * @param string $type old class name in Prado3 namespace format
264
	 * @return string Equivalent class name in PHP namespace format
265
	 */
266
	protected static function prado3NamespaceToPhpNamespace($type): string
267
	{
268
		if (substr($type, 0, 6) === 'System') {
269
			$type = 'Prado' . substr($type, 6);
270
		}
271
272
		if (false === strpos($type, '\\')) {
273
			return str_replace('.', '\\', $type);
274
		} else {
275
			return $type;
276
		}
277
	}
278
279
	/**
280
	 * Creates a component with the specified type.
281
	 * A component type can be either the component class name
282
	 * or a namespace referring to the path of the component class file.
283
	 * For example, 'TButton', '\Prado\Web\UI\WebControls\TButton' are both
284
	 * valid component type.
285
	 * This method can also pass parameters to component constructors.
286
	 * All parameters passed to this method except the first one (the component type)
287
	 * will be supplied as component constructor parameters.
288
	 * @template T
289
	 * @param class-string<T> $requestedType component type
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
290
	 * @param array<mixed> $params
291
	 * @throws TInvalidDataValueException if the component type is unknown
292
	 * @return T component instance of the specified type
293
	 */
294
	public static function createComponent($requestedType, ...$params)
295
	{
296
		$type = static::prado3NamespaceToPhpNamespace($requestedType);
297
		if (!isset(self::$classExists[$type])) {
298
			self::$classExists[$type] = class_exists($type, false);
299
		}
300
301
		if (!isset(self::$_usings[$type]) && !self::$classExists[$type]) {
302
			static::using($type);
303
			self::$classExists[$type] = class_exists($type, false);
304
		}
305
306
		/*
307
		 * Old apps compatibility support: if the component name has been specified using the
308
		 * old namespace syntax (eg. Application.Common.MyDataModule), assume that the calling
309
		 * code expects the class not to be php5.3-namespaced (eg: MyDataModule instead of
310
		 * \Application\Common\MyDataModule)
311
		 * Skip this if the class is inside the Prado\* namespace, since all Prado classes are now namespaced
312
		 */
313
		if (($pos = strrpos($type, '\\')) !== false && ($requestedType != $type) && strpos($type, 'Prado\\') !== 0) {
314
			$type = substr($type, $pos + 1);
315
		}
316
317
		if (count($params) > 0) {
318
			return new $type(...$params);
319
		} else {
320
			return new $type;
321
		}
322
	}
323
324
	/**
325
	 * Uses a namespace.
326
	 * A namespace ending with an asterisk '*' refers to a directory, otherwise it represents a PHP file.
327
	 * If the namespace corresponds to a directory, the directory will be appended
328
	 * to the include path. If the namespace corresponds to a file, it will be included (include_once).
329
	 * @param string $namespace namespace to be used
330
	 * @throws TInvalidDataValueException if the namespace is invalid
331
	 */
332
	public static function using($namespace): void
333
	{
334
		$namespace = static::prado3NamespaceToPhpNamespace($namespace);
335
336
		if (isset(self::$_usings[$namespace]) ||
337
			class_exists($namespace, false) ||
338
			interface_exists($namespace, false)) {
339
			return;
340
		}
341
342
		if (array_key_exists($namespace, self::$classMap)) {
343
			// fast autoload a Prado3 class name
344
			$phpNamespace = self::$classMap[$namespace];
345
			if (class_exists($phpNamespace, true) || interface_exists($phpNamespace, true)) {
346
				if (!class_exists($namespace) && !interface_exists($namespace)) {
347
					class_alias($phpNamespace, $namespace);
348
				}
349
				return;
350
			}
351
		} elseif (($pos = strrpos($namespace, '\\')) === false) {
352
			// trying to autoload an old class name
353
			foreach (self::$_usings as $k => $v) {
354
				$path = $v . DIRECTORY_SEPARATOR . $namespace . self::CLASS_FILE_EXT;
355
				if (file_exists($path)) {
356
					$phpNamespace = '\\' . $k . '\\' . $namespace;
357
					if (class_exists($phpNamespace, true) || interface_exists($phpNamespace, true)) {
358
						if (!class_exists($namespace) && !interface_exists($namespace)) {
359
							class_alias($phpNamespace, $namespace);
360
						}
361
						return;
362
					}
363
				}
364
			}
365
		} elseif (($path = self::getPathOfNamespace($namespace, self::CLASS_FILE_EXT)) !== null) {
366
			$className = substr($namespace, $pos + 1);
367
			if ($className === '*') {  // a directory
368
				self::$_usings[substr($namespace, 0, $pos)] = $path;
369
			} else {  // a file
370
				if (class_exists($className, false) || interface_exists($className, false)) {
371
					return;
372
				}
373
374
				if (file_exists($path)) {
375
					include_once($path);
376
					if (!class_exists($className, false) && !interface_exists($className, false)) {
377
						class_alias($namespace, $className);
378
					}
379
				}
380
			}
381
		}
382
	}
383
384
	/**
385
	 * Translates a namespace into a file path.
386
	 * The first segment of the namespace is considered as a path alias
387
	 * which is replaced with the actual path. The rest segments are
388
	 * subdirectory names appended to the aliased path.
389
	 * If the namespace ends with an asterisk '*', it represents a directory;
390
	 * Otherwise it represents a file whose extension name is specified by the second parameter (defaults to empty).
391
	 * Note, this method does not ensure the existence of the resulting file path.
392
	 * @param string $namespace namespace
393
	 * @param string $ext extension to be appended if the namespace refers to a file
394
	 * @return null|string file path corresponding to the namespace, null if namespace is invalid
395
	 */
396
	public static function getPathOfNamespace($namespace, $ext = ''): ?string
397
	{
398
		$namespace = static::prado3NamespaceToPhpNamespace($namespace);
399
400
		if (self::CLASS_FILE_EXT === $ext || empty($ext)) {
401
			if (isset(self::$_usings[$namespace])) {
402
				return self::$_usings[$namespace];
403
			}
404
405
			if (isset(self::$_aliases[$namespace])) {
406
				return self::$_aliases[$namespace];
407
			}
408
		}
409
410
		$segs = explode('\\', $namespace);
411
		$alias = array_shift($segs);
412
413
		if (null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias))) {
414
			return rtrim($root . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $segs), '/\\') . (($file === '*') ? '' : DIRECTORY_SEPARATOR . $file . $ext);
415
		}
416
417
		return null;
418
	}
419
420
	/**
421
	 * @param string $alias alias to the path
422
	 * @return null|string the path corresponding to the alias, null if alias not defined.
423
	 */
424
	public static function getPathOfAlias($alias): ?string
425
	{
426
		return self::$_aliases[$alias] ?? null;
427
	}
428
429
	/**
430
	 * @return array<string, string> list of path aliases
431
	 */
432
	protected static function getPathAliases() :array
433
	{
434
		return self::$_aliases;
435
	}
436
437
	/**
438
	 * @param string $alias alias to the path
439
	 * @param string $path the path corresponding to the alias
440
	 * @throws TInvalidOperationException $alias if the alias is already defined
441
	 * @throws TInvalidDataValueException $path if the path is not a valid file path
442
	 */
443
	public static function setPathOfAlias($alias, $path): void
444
	{
445
		if (isset(self::$_aliases[$alias]) && !defined('PRADO_TEST_RUN')) {
446
			throw new TInvalidOperationException('prado_alias_redefined', $alias);
447
		} elseif (($rp = realpath($path)) !== false && is_dir($rp)) {
448
			if (strpos($alias, '.') === false) {
449
				self::$_aliases[$alias] = $rp;
450
			} else {
451
				throw new TInvalidDataValueException('prado_aliasname_invalid', $alias);
452
			}
453
		} else {
454
			throw new TInvalidDataValueException('prado_alias_invalid', $alias, $path);
455
		}
456
	}
457
458
	/**
459
	 * Fatal error handler.
460
	 * This method displays an error message together with the current call stack.
461
	 * The application will exit after calling this method.
462
	 * @param string $msg error message
463
	 */
464
	public static function fatalError($msg): void
465
	{
466
		echo '<h1>Fatal Error</h1>';
467
		echo '<p>' . $msg . '</p>';
468
		if (!function_exists('debug_backtrace')) {
469
			return;
470
		}
471
		echo '<h2>Debug Backtrace</h2>';
472
		echo '<pre>';
473
		$index = -1;
474
		foreach (debug_backtrace() as $t) {
475
			$index++;
476
			if ($index == 0) {  // hide the backtrace of this function
477
				continue;
478
			}
479
			echo '#' . $index . ' ';
480
			if (isset($t['file'])) {
481
				echo basename($t['file']) . ':' . $t['line'];
482
			} else {
483
				echo '<PHP inner-code>';
484
			}
485
			echo ' -- ';
486
			if (isset($t['class'])) {
487
				echo $t['class'] . $t['type'];
488
			}
489
			echo $t['function'] . '(';
490
			if (isset($t['args']) && count($t['args']) > 0) {
491
				$count = 0;
492
				foreach ($t['args'] as $item) {
493
					if (is_string($item)) {
494
						$str = htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
495
						if (strlen($item) > 70) {
496
							echo "'" . substr($str, 0, 70) . "...'";
497
						} else {
498
							echo "'" . $str . "'";
499
						}
500
					} elseif (is_int($item) || is_float($item)) {
501
						echo $item;
502
					} elseif (is_object($item)) {
503
						echo get_class($item);
504
					} elseif (is_array($item)) {
505
						echo 'array(' . count($item) . ')';
506
					} elseif (is_bool($item)) {
507
						echo $item ? 'true' : 'false';
508
					} elseif ($item === null) {
509
						echo 'NULL';
510
					} elseif (is_resource($item)) {
511
						echo get_resource_type($item);
512
					}
513
					$count++;
514
					if (count($t['args']) > $count) {
515
						echo ', ';
516
					}
517
				}
518
			}
519
			echo ")\n";
520
		}
521
		echo '</pre>';
522
		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...
523
	}
524
525
	/**
526
	 * Returns a list of user preferred languages.
527
	 * The languages are returned as an array. Each array element
528
	 * represents a single language preference. The languages are ordered
529
	 * according to user preferences. The first language is the most preferred.
530
	 * @return array<string> list of user preferred languages.
531
	 */
532
	public static function getUserLanguages(): array
533
	{
534
		static $languages = null;
535
		if ($languages === null) {
536
			if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
537
				$languages[0] = 'en';
538
			} else {
539
				$languages = [];
540
				foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language) {
541
					$array = explode(';q=', trim($language));
542
					$languages[trim($array[0])] = isset($array[1]) ? (float) $array[1] : 1.0;
543
				}
544
				arsort($languages);
545
				$languages = array_keys($languages);
546
				if (empty($languages)) {
547
					$languages[0] = 'en';
548
				}
549
			}
550
		}
551
		return $languages;
552
	}
553
554
	/**
555
	 * Returns the most preferred language by the client user.
556
	 * @return string the most preferred language by the client user, defaults to English.
557
	 */
558
	public static function getPreferredLanguage(): string
559
	{
560
		static $language = null;
561
		if ($language === null) {
562
			$langs = Prado::getUserLanguages();
563
			$lang = explode('-', $langs[0]);
564
			if (empty($lang[0]) || !ctype_alpha($lang[0])) {
565
				$language = 'en';
566
			} else {
567
				$language = $lang[0];
568
			}
569
		}
570
		return $language;
571
	}
572
573
	/**
574
	 * Writes a log message.
575
	 * This method wraps {@link log()} by checking the application mode.
576
	 * When the application is in Debug mode, debug backtrace information is appended
577
	 * to the message and the message is logged at DEBUG level.
578
	 * When the application is in Performance mode, this method does nothing.
579
	 * Otherwise, the message is logged at INFO level.
580
	 * @param string $msg message to be logged
581
	 * @param string $category category of the message
582
	 * @param null|\Prado\Web\UI\TControl|string $ctl control of the message
583
	 * @see log, getLogger
584
	 */
585
	public static function trace($msg, $category = 'Uncategorized', $ctl = null): void
586
	{
587
		if (self::$_application && self::$_application->getMode() === TApplicationMode::Performance) {
588
			return;
589
		}
590
		if (!self::$_application || self::$_application->getMode() === TApplicationMode::Debug) {
591
			$trace = debug_backtrace();
592
			if (isset($trace[0]['file']) && isset($trace[0]['line'])) {
593
				$msg .= " (line {$trace[0]['line']}, {$trace[0]['file']})";
594
			}
595
			$level = TLogger::DEBUG;
596
		} else {
597
			$level = TLogger::INFO;
598
		}
599
		self::log($msg, $level, $category, $ctl);
600
	}
601
602
	/**
603
	 * Logs a message.
604
	 * Messages logged by this method may be retrieved via {@link TLogger::getLogs}
605
	 * and may be recorded in different media, such as file, email, database, using
606
	 * {@link TLogRouter}.
607
	 * @param string $msg message to be logged
608
	 * @param int $level level of the message. Valid values include
609
	 * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING,
610
	 * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL.
611
	 * @param string $category category of the message
612
	 * @param null|\Prado\Web\UI\TControl|string $ctl control of the message
613
	 */
614
	public static function log($msg, $level = TLogger::INFO, $category = 'Uncategorized', $ctl = null): void
615
	{
616
		if (self::$_logger === null) {
617
			self::$_logger = new TLogger;
618
		}
619
		self::$_logger->log($msg, $level, $category, $ctl);
620
	}
621
622
	/**
623
	 * @return TLogger message logger
624
	 */
625
	public static function getLogger(): TLogger
626
	{
627
		if (self::$_logger === null) {
628
			self::$_logger = new TLogger;
629
		}
630
		return self::$_logger;
631
	}
632
633
	/**
634
	 * Converts a variable into a string representation.
635
	 * This method achieves the similar functionality as var_dump and print_r
636
	 * but is more robust when handling complex objects such as PRADO controls.
637
	 * @param mixed $var variable to be dumped
638
	 * @param int $depth maximum depth that the dumper should go into the variable. Defaults to 10.
639
	 * @param bool $highlight whether to syntax highlight the output. Defaults to false.
640
	 * @return string the string representation of the variable
641
	 */
642
	public static function varDump($var, $depth = 10, $highlight = false): string
643
	{
644
		return TVarDumper::dump($var, $depth, $highlight);
645
	}
646
647
	/**
648
	 * Localize a text to the locale/culture specified in the globalization handler.
649
	 * @param string $text text to be localized.
650
	 * @param array<string, string> $parameters a set of parameters to substitute.
651
	 * @param string $catalogue a different catalogue to find the localize text.
652
	 * @param string $charset the input AND output charset.
653
	 * @return string localized text.
654
	 * @see TTranslate::formatter()
655
	 * @see TTranslate::init()
656
	 */
657
	public static function localize($text, $parameters = [], $catalogue = null, $charset = null): string
658
	{
659
		$params = [];
660
		foreach ($parameters as $key => $value) {
661
			$params['{' . $key . '}'] = $value;
662
		}
663
664
		// no translation handler provided
665
		if (self::$_application === null
666
			|| ($app = self::$_application->getGlobalization(false)) === null
667
			|| ($config = $app->getTranslationConfiguration()) === null) {
668
			return strtr($text, $params);
669
		}
670
671
		if ($catalogue === null) {
672
			$catalogue = $config['catalogue'] ?? 'messages';
673
		}
674
675
		Translation::init($catalogue);
676
677
		//globalization charset
678
		if (empty($charset)) {
679
			$charset = $app->getCharset();
680
		}
681
682
		//default charset
683
		if (empty($charset)) {
684
			$charset = $app->getDefaultCharset();
685
		}
686
687
		return Translation::formatter($catalogue)->format($text, $params, $catalogue, $charset);
688
	}
689
}
690
691
/**
692
 * Initialize Prado autoloader and error handler
693
 */
694
Prado::init();
695
696
/**
697
 * Defines Prado in global namespace
698
 */
699
class_alias('\Prado\Prado', 'Prado');
700