Completed
Push — master ( 43ed01...e90eeb )
by Fabio
07:20
created

PradoBase::localize()   B

Complexity

Conditions 9
Paths 66

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
cc 9
nc 66
nop 4
dl 0
loc 36
ccs 0
cts 17
cp 0
crap 90
rs 8.0555
c 0
b 0
f 0
1
<?php
2
/**
3
 * PradoBase 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
}
39
40
/**
41
 * PradoBase class.
42
 *
43
 * PradoBase implements a few fundamental static methods.
44
 *
45
 * To use the static methods, Use Prado as the class name rather than PradoBase.
46
 * PradoBase is meant to serve as the base class of Prado. The latter might be
47
 * rewritten for customization.
48
 *
49
 * @author Qiang Xue <[email protected]>
50
 * @package Prado
51
 * @since 3.0
52
 */
53
class PradoBase
54
{
55
	/**
56
	 * File extension for Prado class files.
57
	 */
58
	const CLASS_FILE_EXT = '.php';
59
	/**
60
	 * @var array list of path aliases
61
	 */
62
	private static $_aliases = [
63
		'Prado' => PRADO_DIR,
64
		'Vendor' => PRADO_VENDORDIR
65
		];
66
	/**
67
	 * @var array list of namespaces currently in use
68
	 */
69
	private static $_usings = [
70
		'Prado' => PRADO_DIR
71
		];
72
	/**
73
	 * @var array list of namespaces currently in use
74
	 */
75
	public static $classMap = [];
76
	/**
77
	 * @var TApplication the application instance
78
	 */
79
	private static $_application = null;
80
	/**
81
	 * @var TLogger logger instance
82
	 */
83
	private static $_logger = null;
84
	/**
85
	 * @var array list of class exists checks
86
	 */
87
	protected static $classExists = [];
88
	/**
89
	 * @return string the version of Prado framework
90
	 */
91 3
	public static function getVersion()
92
	{
93 3
		return '4.1.0';
94
	}
95
96
	public static function init()
97
	{
98
		static::initAutoloader();
99
		static::initErrorHandlers();
100
	}
101
102
	/**
103
	 * Loads the static classmap and registers the autoload function.
104
	 */
105
	public static function initAutoloader()
106
	{
107
		self::$classMap = require(__DIR__ . '/classes.php');
108
109
		spl_autoload_register([get_called_class(), 'autoload']);
110
	}
111
112
	/**
113
	 * Initializes error handlers.
114
	 * This method set error and exception handlers to be functions
115
	 * defined in this class.
116
	 */
117
	public static function initErrorHandlers()
118
	{
119
		/**
120
		 * Sets error handler to be Prado::phpErrorHandler
121
		 */
122
		set_error_handler(['\Prado\PradoBase', 'phpErrorHandler']);
123
		/**
124
		 * Sets shutdown function to be Prado::phpFatalErrorHandler
125
		 */
126
		register_shutdown_function(['PradoBase', 'phpFatalErrorHandler']);
127
		/**
128
		 * Sets exception handler to be Prado::exceptionHandler
129
		 */
130
		set_exception_handler(['\Prado\PradoBase', 'exceptionHandler']);
131
		/**
132
		 * Disable php's builtin error reporting to avoid duplicated reports
133
		 */
134
		ini_set('display_errors', 0);
135
	}
136
137
	/**
138
	 * Class autoload loader.
139
	 * This method is provided to be invoked within an __autoload() magic method.
140
	 * @param string $className class name
141
	 */
142 7
	public static function autoload($className)
143
	{
144 7
		static::using($className);
145 7
	}
146
147
	/**
148
	 * @param int $logoType the type of "powered logo". Valid values include 0 and 1.
149
	 * @return string a string that can be displayed on your Web page showing powered-by-PRADO information
150
	 */
151
	public static function poweredByPrado($logoType = 0)
152
	{
153
		$logoName = $logoType == 1 ? 'powered2' : 'powered';
154
		if (self::$_application !== null) {
155
			$am = self::$_application->getAssetManager();
156
			$url = $am->publishFilePath(self::getPathOfNamespace('Prado\\' . $logoName, '.gif'));
157
		} else {
158
			$url = 'http://pradosoft.github.io/docs/' . $logoName . '.gif';
159
		}
160
		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>';
161
	}
162
163
	/**
164
	 * PHP error handler.
165
	 * This method should be registered as PHP error handler using
166
	 * {@link set_error_handler}. The method throws an exception that
167
	 * contains the error information.
168
	 * @param int $errno the level of the error raised
169
	 * @param string $errstr the error message
170
	 * @param string $errfile the filename that the error was raised in
171
	 * @param int $errline the line number the error was raised at
172
	 */
173 14
	public static function phpErrorHandler($errno, $errstr, $errfile, $errline)
174
	{
175 14
		if (error_reporting() & $errno) {
176
			throw new TPhpErrorException($errno, $errstr, $errfile, $errline);
177
		}
178 14
	}
179
180
	/**
181
	 * PHP shutdown function used to catch fatal errors.
182
	 * This method should be registered as PHP error handler using
183
	 * {@link register_shutdown_function}. The method throws an exception that
184
	 * contains the error information.
185
	 */
186
	public static function phpFatalErrorHandler()
187
	{
188
		$error = error_get_last();
189
		if ($error &&
0 ignored issues
show
Bug Best Practice introduced by
The expression $error of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
190
			TPhpErrorException::isFatalError($error) &&
191
			error_reporting() & $error['type']) {
192
			self::exceptionHandler(new TPhpFatalErrorException($error['type'], $error['message'], $error['file'], $error['line']));
193
		}
194
	}
195
196
	/**
197
	 * Default exception handler.
198
	 * This method should be registered as default exception handler using
199
	 * {@link set_exception_handler}. The method tries to use the errorhandler
200
	 * module of the Prado application to handle the exception.
201
	 * If the application or the module does not exist, it simply echoes the
202
	 * exception.
203
	 * @param Exception $exception exception that is not caught
204
	 */
205
	public static function exceptionHandler($exception)
206
	{
207
		if (self::$_application !== null && ($errorHandler = self::$_application->getErrorHandler()) !== null) {
208
			$errorHandler->handleError(null, $exception);
209
		} else {
210
			echo $exception;
211
		}
212
		exit(1);
213
	}
214
215
	/**
216
	 * Stores the application instance in the class static member.
217
	 * This method helps implement a singleton pattern for TApplication.
218
	 * Repeated invocation of this method or the application constructor
219
	 * will cause the throw of an exception.
220
	 * This method should only be used by framework developers.
221
	 * @param TApplication $application the application instance
222
	 * @throws TInvalidOperationException if this method is invoked twice or more.
223
	 */
224 55
	public static function setApplication($application)
225
	{
226 55
		if (self::$_application !== null && !defined('PRADO_TEST_RUN')) {
227
			throw new TInvalidOperationException('prado_application_singleton_required');
228
		}
229 55
		self::$_application = $application;
230 55
	}
231
232
	/**
233
	 * @return TApplication the application singleton, null if the singleton has not be created yet.
234
	 */
235 96
	public static function getApplication()
236
	{
237 96
		return self::$_application;
238
	}
239
240
	/**
241
	 * @return string the path of the framework
242
	 */
243 108
	public static function getFrameworkPath()
244
	{
245 108
		return PRADO_DIR;
246
	}
247
248
	/**
249
	 * Convert old Prado namespaces to PHP namespaces
250
	 * @param string $type old class name in Prado3 namespace format
251
	 * @return string Equivalent class name in PHP namespace format
252
	 */
253 116
	protected static function prado3NamespaceToPhpNamespace($type)
254
	{
255 116
		if (substr($type, 0, 6) === 'System') {
256 9
			$type = 'Prado' . substr($type, 6);
257
		}
258
259 116
		if (false === strpos($type, '\\')) {
260 111
			return str_replace('.', '\\', $type);
261
		} else {
262 9
			return $type;
263
		}
264
	}
265
266
	/**
267
	 * Creates a component with the specified type.
268
	 * A component type can be either the component class name
269
	 * or a namespace referring to the path of the component class file.
270
	 * For example, 'TButton', '\Prado\Web\UI\WebControls\TButton' are both
271
	 * valid component type.
272
	 * This method can also pass parameters to component constructors.
273
	 * All parameters passed to this method except the first one (the component type)
274
	 * will be supplied as component constructor parameters.
275
	 * @param string $requestedType component type
276
	 * @param array $params
277
	 * @throws TInvalidDataValueException if the component type is unknown
278
	 * @return TComponent component instance of the specified type
279
	 */
280 103
	public static function createComponent($requestedType, ...$params)
281
	{
282 103
		$type = static::prado3NamespaceToPhpNamespace($requestedType);
283 103
		if (!isset(self::$classExists[$type])) {
284 24
			self::$classExists[$type] = class_exists($type, false);
285
		}
286
287 103
		if (!isset(self::$_usings[$type]) && !self::$classExists[$type]) {
288 3
			static::using($type);
289 3
			self::$classExists[$type] = class_exists($type, false);
290
		}
291
292
		/*
293
		 * Old apps compatibility support: if the component name has been specified using the
294
		 * old namespace syntax (eg. Application.Common.MyDataModule), assume that the calling
295
		 * code expects the class not to be php5.3-namespaced (eg: MyDataModule instead of
296
		 * \Application\Common\MyDataModule)
297
		 * Skip this if the class is inside the Prado\* namespace, since all Prado classes are now namespaced
298
		 */
299 103
		if (($pos = strrpos($type, '\\')) !== false && ($requestedType != $type) && strpos($type, 'Prado\\') !== 0) {
300
			$type = substr($type, $pos + 1);
301
		}
302
303 103
		if (count($params) > 0) {
304 10
			return new $type(...$params);
305
		} else {
306 96
			return new $type;
307
		}
308
	}
309
310
	/**
311
	 * Uses a namespace.
312
	 * A namespace ending with an asterisk '*' refers to a directory, otherwise it represents a PHP file.
313
	 * If the namespace corresponds to a directory, the directory will be appended
314
	 * to the include path. If the namespace corresponds to a file, it will be included (include_once).
315
	 * @param string $namespace namespace to be used
316
	 * @param bool $checkClassExistence whether to check the existence of the class after the class file is included
317
	 * @throws TInvalidDataValueException if the namespace is invalid
318
	 */
319 12
	public static function using($namespace, $checkClassExistence = true)
320
	{
321 12
		$namespace = static::prado3NamespaceToPhpNamespace($namespace);
322
323 12
		if (isset(self::$_usings[$namespace]) || class_exists($namespace, false)) {
324
			return;
325
		}
326
327 12
		if (array_key_exists($namespace, self::$classMap)) {
328
			// fast autoload a Prado3 class name
329 7
			$phpNamespace = self::$classMap[$namespace];
330 7 View Code Duplication
			if (class_exists($phpNamespace, true) || interface_exists($phpNamespace, true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
331 7
				if (!class_exists($namespace) && !interface_exists($namespace)) {
332 7
					class_alias($phpNamespace, $namespace);
333
				}
334 7
				return;
335
			}
336 5
		} elseif (($pos = strrpos($namespace, '\\')) === false) {
337
			// trying to autoload an old class name
338
			foreach (self::$_usings as $k => $v) {
339
				$path = $v . DIRECTORY_SEPARATOR . $namespace . self::CLASS_FILE_EXT;
340
				if (file_exists($path)) {
341
					$phpNamespace = '\\' . $k . '\\' . $namespace;
342 View Code Duplication
					if (class_exists($phpNamespace, true) || interface_exists($phpNamespace, true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
343
						if (!class_exists($namespace) && !interface_exists($namespace)) {
344
							class_alias($phpNamespace, $namespace);
345
						}
346
						return;
347
					}
348
				}
349
			}
350
351
			if ($checkClassExistence && !class_exists($namespace, false) && !interface_exists($namespace, false)) {
352
				throw new TInvalidOperationException('prado_component_unknown', $namespace, '');
353
			}
354 5
		} elseif (($path = self::getPathOfNamespace($namespace, self::CLASS_FILE_EXT)) !== null) {
355 5
			$className = substr($namespace, $pos + 1);
356 5
			if ($className === '*') {  // a directory
357
				self::$_usings[substr($namespace, 0, $pos)] = $path;
358
			} else {  // a file
359
				//self::$_usings[$namespace]=$path;
360 5
				if (!$checkClassExistence || (!class_exists($className, false) && !interface_exists($className, false))) {
361
					try {
362 5
						include_once($path);
363 5
						if (class_exists($namespace, false) || interface_exists($namespace, false)) {
364 5
							class_alias($namespace, $className);
365
						}
366
					} catch (\Exception $e) {
367
						if ($checkClassExistence && !class_exists($className, false)) {
368
							throw new TInvalidOperationException('prado_component_unknown', $className, $e->getMessage());
369
						} else {
370
							throw $e;
371
						}
372
					}
373
				}
374
			}
375
		}
376 5
	}
377
378
	/**
379
	 * Translates a namespace into a file path.
380
	 * The first segment of the namespace is considered as a path alias
381
	 * which is replaced with the actual path. The rest segments are
382
	 * subdirectory names appended to the aliased path.
383
	 * If the namespace ends with an asterisk '*', it represents a directory;
384
	 * Otherwise it represents a file whose extension name is specified by the second parameter (defaults to empty).
385
	 * Note, this method does not ensure the existence of the resulting file path.
386
	 * @param string $namespace namespace
387
	 * @param string $ext extension to be appended if the namespace refers to a file
388
	 * @return string file path corresponding to the namespace, null if namespace is invalid
389
	 */
390 10
	public static function getPathOfNamespace($namespace, $ext = '')
391
	{
392 10
		$namespace = static::prado3NamespaceToPhpNamespace($namespace);
393
394 10
		if (self::CLASS_FILE_EXT === $ext || empty($ext)) {
395 6
			if (isset(self::$_usings[$namespace])) {
396
				return self::$_usings[$namespace];
397
			}
398
399 6
			if (isset(self::$_aliases[$namespace])) {
400 1
				return self::$_aliases[$namespace];
401
			}
402
		}
403
404 10
		$segs = explode('\\', $namespace);
405 10
		$alias = array_shift($segs);
406
407 10
		if (null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias))) {
408 9
			return rtrim($root . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $segs), '/\\') . (($file === '*') ? '' : DIRECTORY_SEPARATOR . $file . $ext);
409
		}
410
411 2
		return null;
412
	}
413
414
	/**
415
	 * @param string $alias alias to the path
416
	 * @return string the path corresponding to the alias, null if alias not defined.
417
	 */
418 9
	public static function getPathOfAlias($alias)
419
	{
420 9
		return isset(self::$_aliases[$alias]) ? self::$_aliases[$alias] : null;
421
	}
422
423
	protected static function getPathAliases()
424
	{
425
		return self::$_aliases;
426
	}
427
428
	/**
429
	 * @param string $alias alias to the path
430
	 * @param string $path the path corresponding to the alias
431
	 * @throws TInvalidOperationException $alias if the alias is already defined
432
	 * @throws TInvalidDataValueException $path if the path is not a valid file path
433
	 */
434 61
	public static function setPathOfAlias($alias, $path)
435
	{
436 61
		if (isset(self::$_aliases[$alias]) && !defined('PRADO_TEST_RUN')) {
437
			throw new TInvalidOperationException('prado_alias_redefined', $alias);
438 61
		} elseif (($rp = realpath($path)) !== false && is_dir($rp)) {
439 61
			if (strpos($alias, '.') === false) {
440 61
				self::$_aliases[$alias] = $rp;
441
			} else {
442 61
				throw new TInvalidDataValueException('prado_aliasname_invalid', $alias);
443
			}
444
		} else {
445
			throw new TInvalidDataValueException('prado_alias_invalid', $alias, $path);
446
		}
447 61
	}
448
449
	/**
450
	 * Fatal error handler.
451
	 * This method displays an error message together with the current call stack.
452
	 * The application will exit after calling this method.
453
	 * @param string $msg error message
454
	 */
455
	public static function fatalError($msg)
456
	{
457
		echo '<h1>Fatal Error</h1>';
458
		echo '<p>' . $msg . '</p>';
459
		if (!function_exists('debug_backtrace')) {
460
			return;
461
		}
462
		echo '<h2>Debug Backtrace</h2>';
463
		echo '<pre>';
464
		$index = -1;
465
		foreach (debug_backtrace() as $t) {
466
			$index++;
467
			if ($index == 0) {  // hide the backtrace of this function
468
				continue;
469
			}
470
			echo '#' . $index . ' ';
471
			if (isset($t['file'])) {
472
				echo basename($t['file']) . ':' . $t['line'];
473
			} else {
474
				echo '<PHP inner-code>';
475
			}
476
			echo ' -- ';
477
			if (isset($t['class'])) {
478
				echo $t['class'] . $t['type'];
479
			}
480
			echo $t['function'] . '(';
481
			if (isset($t['args']) && count($t['args']) > 0) {
482
				$count = 0;
483
				foreach ($t['args'] as $item) {
484
					if (is_string($item)) {
485
						$str = htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
486
						if (strlen($item) > 70) {
487
							echo "'" . substr($str, 0, 70) . "...'";
488
						} else {
489
							echo "'" . $str . "'";
490
						}
491
					} elseif (is_int($item) || is_float($item)) {
492
						echo $item;
493
					} elseif (is_object($item)) {
494
						echo get_class($item);
495
					} elseif (is_array($item)) {
496
						echo 'array(' . count($item) . ')';
497
					} elseif (is_bool($item)) {
498
						echo $item ? 'true' : 'false';
499
					} elseif ($item === null) {
500
						echo 'NULL';
501
					} elseif (is_resource($item)) {
502
						echo get_resource_type($item);
503
					}
504
					$count++;
505
					if (count($t['args']) > $count) {
506
						echo ', ';
507
					}
508
				}
509
			}
510
			echo ")\n";
511
		}
512
		echo '</pre>';
513
		exit(1);
514
	}
515
516
	/**
517
	 * Returns a list of user preferred languages.
518
	 * The languages are returned as an array. Each array element
519
	 * represents a single language preference. The languages are ordered
520
	 * according to user preferences. The first language is the most preferred.
521
	 * @return array list of user preferred languages.
522
	 */
523 1
	public static function getUserLanguages()
524
	{
525 1
		static $languages = null;
526 1
		if ($languages === null) {
527 1
			if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
528
				$languages[0] = 'en';
529
			} else {
530 1
				$languages = [];
531 1
				foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language) {
532 1
					$array = explode(';q=', trim($language));
533 1
					$languages[trim($array[0])] = isset($array[1]) ? (float) $array[1] : 1.0;
534
				}
535 1
				arsort($languages);
536 1
				$languages = array_keys($languages);
537 1
				if (empty($languages)) {
538
					$languages[0] = 'en';
539
				}
540
			}
541
		}
542 1
		return $languages;
543
	}
544
545
	/**
546
	 * Returns the most preferred language by the client user.
547
	 * @return string the most preferred language by the client user, defaults to English.
548
	 */
549 113
	public static function getPreferredLanguage()
550
	{
551 113
		static $language = null;
552 113
		if ($language === null) {
553 1
			$langs = Prado::getUserLanguages();
554 1
			$lang = explode('-', $langs[0]);
555 1
			if (empty($lang[0]) || !ctype_alpha($lang[0])) {
556
				$language = 'en';
557
			} else {
558 1
				$language = $lang[0];
559
			}
560
		}
561 113
		return $language;
562
	}
563
564
	/**
565
	 * Writes a log message.
566
	 * This method wraps {@link log()} by checking the application mode.
567
	 * When the application is in Debug mode, debug backtrace information is appended
568
	 * to the message and the message is logged at DEBUG level.
569
	 * When the application is in Performance mode, this method does nothing.
570
	 * Otherwise, the message is logged at INFO level.
571
	 * @param string $msg message to be logged
572
	 * @param string $category category of the message
573
	 * @param (string|TControl) $ctl control of the message
574
	 * @see log, getLogger
575
	 */
576 32
	public static function trace($msg, $category = 'Uncategorized', $ctl = null)
577
	{
578 32
		if (self::$_application && self::$_application->getMode() === TApplicationMode::Performance) {
579
			return;
580
		}
581 32
		if (!self::$_application || self::$_application->getMode() === TApplicationMode::Debug) {
582 32
			$trace = debug_backtrace();
583 32
			if (isset($trace[0]['file']) && isset($trace[0]['line'])) {
584 32
				$msg .= " (line {$trace[0]['line']}, {$trace[0]['file']})";
585
			}
586 32
			$level = TLogger::DEBUG;
587
		} else {
588
			$level = TLogger::INFO;
589
		}
590 32
		self::log($msg, $level, $category, $ctl);
591 32
	}
592
593
	/**
594
	 * Logs a message.
595
	 * Messages logged by this method may be retrieved via {@link TLogger::getLogs}
596
	 * and may be recorded in different media, such as file, email, database, using
597
	 * {@link TLogRouter}.
598
	 * @param string $msg message to be logged
599
	 * @param int $level level of the message. Valid values include
600
	 * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING,
601
	 * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL.
602
	 * @param string $category category of the message
603
	 * @param (string|TControl) $ctl control of the message
604
	 */
605 32
	public static function log($msg, $level = TLogger::INFO, $category = 'Uncategorized', $ctl = null)
606
	{
607 32
		if (self::$_logger === null) {
608 1
			self::$_logger = new TLogger;
609
		}
610 32
		self::$_logger->log($msg, $level, $category, $ctl);
611 32
	}
612
613
	/**
614
	 * @return TLogger message logger
615
	 */
616
	public static function getLogger()
617
	{
618
		if (self::$_logger === null) {
619
			self::$_logger = new TLogger;
620
		}
621
		return self::$_logger;
622
	}
623
624
	/**
625
	 * Converts a variable into a string representation.
626
	 * This method achieves the similar functionality as var_dump and print_r
627
	 * but is more robust when handling complex objects such as PRADO controls.
628
	 * @param mixed $var variable to be dumped
629
	 * @param int $depth maximum depth that the dumper should go into the variable. Defaults to 10.
630
	 * @param bool $highlight whether to syntax highlight the output. Defaults to false.
631
	 * @return string the string representation of the variable
632
	 */
633
	public static function varDump($var, $depth = 10, $highlight = false)
634
	{
635
		return TVarDumper::dump($var, $depth, $highlight);
636
	}
637
638
	/**
639
	 * Localize a text to the locale/culture specified in the globalization handler.
640
	 * @param string $text text to be localized.
641
	 * @param array $parameters a set of parameters to substitute.
642
	 * @param string $catalogue a different catalogue to find the localize text.
643
	 * @param string $charset the input AND output charset.
644
	 * @return string localized text.
645
	 * @see TTranslate::formatter()
646
	 * @see TTranslate::init()
647
	 */
648
	public static function localize($text, $parameters = [], $catalogue = null, $charset = null)
649
	{
650
		$app = Prado::getApplication()->getGlobalization(false);
651
652
		$params = [];
653
		foreach ($parameters as $key => $value) {
654
			$params['{' . $key . '}'] = $value;
655
		}
656
657
		//no translation handler provided
658
		if ($app === null || ($config = $app->getTranslationConfiguration()) === null) {
659
			return strtr($text, $params);
660
		}
661
662
		if ($catalogue === null) {
663
			$catalogue = $config['catalogue'] ?? 'messages';
664
		}
665
666
		Translation::init($catalogue);
667
668
		//globalization charset
669
		$appCharset = $app === null ? '' : $app->getCharset();
670
671
		//default charset
672
		$defaultCharset = ($app === null) ? 'UTF-8' : $app->getDefaultCharset();
673
674
		//fall back
675
		if (empty($charset)) {
676
			$charset = $appCharset;
677
		}
678
		if (empty($charset)) {
679
			$charset = $defaultCharset;
680
		}
681
682
		return Translation::formatter($catalogue)->format($text, $params, $catalogue, $charset);
683
	}
684
}
685