Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 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 <qiang.xue@gmail.com>
9
 * @link http://www.pradosoft.com/
10
 * @copyright Copyright &copy; 2005-2008 PradoSoft
11
 * @license http://www.pradosoft.com/license/
12
 * @version $Id: PradoBase.php 2602 2009-01-12 01:08:39Z qiang.xue $
13
 * @package System
14
 */
15
 
16
/**
17
 * Defines the PRADO framework installation path.
18
 */
19
if(!defined('PRADO_DIR'))
20
	define('PRADO_DIR',dirname(__FILE__));
21
/**
22
 * Defines the default permission for writable directories and files
23
 */
24
if(!defined('PRADO_CHMOD'))
25
	define('PRADO_CHMOD',0777);
26
 
27
/**
28
 * PradoBase class.
29
 *
30
 * PradoBase implements a few fundamental static methods.
31
 *
32
 * To use the static methods, Use Prado as the class name rather than PradoBase.
33
 * PradoBase is meant to serve as the base class of Prado. The latter might be
34
 * rewritten for customization.
35
 *
36
 * @author Qiang Xue <qiang.xue@gmail.com>
37
 * @version $Id: PradoBase.php 2602 2009-01-12 01:08:39Z qiang.xue $
38
 * @package System
39
 * @since 3.0
40
 */
41
class PradoBase
42
{
43
	/**
44
	 * File extension for Prado class files.
45
	 */
46
	const CLASS_FILE_EXT='.php';
47
	/**
48
	 * @var array list of path aliases
49
	 */
50
	private static $_aliases=array('System'=>PRADO_DIR);
51
	/**
52
	 * @var array list of namespaces currently in use
53
	 */
54
	private static $_usings=array();
55
	/**
56
	 * @var TApplication the application instance
57
	 */
58
	private static $_application=null;
59
	/**
60
	 * @var TLogger logger instance
61
	 */
62
	private static $_logger=null;
63
 
64
	/**
65
	 * @return string the version of Prado framework
66
	 */
67
	public static function getVersion()
68
	{
69
		return '3.1.4';
70
	}
71
 
72
	/**
73
	 * Initializes error handlers.
74
	 * This method set error and exception handlers to be functions
75
	 * defined in this class.
76
	 */
77
	public static function initErrorHandlers()
78
	{
79
		/**
80
		 * Sets error handler to be Prado::phpErrorHandler
81
		 */
82
		set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting());
83
		/**
84
		 * Sets exception handler to be Prado::exceptionHandler
85
		 */
86
		set_exception_handler(array('PradoBase','exceptionHandler'));
87
	}
88
 
89
	/**
90
	 * Class autoload loader.
91
	 * This method is provided to be invoked within an __autoload() magic method.
92
	 * @param string class name
93
	 */
94
	public static function autoload($className)
95
	{
96
		include_once($className.self::CLASS_FILE_EXT);
97
		if(!class_exists($className,false) && !interface_exists($className,false))
98
			self::fatalError("Class file for '$className' cannot be found.");
99
	}
100
 
101
	/**
102
	 * @param integer the type of "powered logo". Valid values include 0 and 1.
103
	 * @return string a string that can be displayed on your Web page showing powered-by-PRADO information
104
	 */
105
	public static function poweredByPrado($logoType=0)
106
	{
107
		$logoName=$logoType==1?'powered2':'powered';
108
		if(self::$_application!==null)
109
		{
110
			$am=self::$_application->getAssetManager();
111
			$url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
112
		}
113
		else
114
			$url='http://www.pradosoft.com/images/'.$logoName.'.gif';
115
		return '<a title="Powered by PRADO" href="http://www.pradosoft.com/" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>';
116
	}
117
 
118
	/**
119
	 * PHP error handler.
120
	 * This method should be registered as PHP error handler using
121
	 * {@link set_error_handler}. The method throws an exception that
122
	 * contains the error information.
123
	 * @param integer the level of the error raised
124
	 * @param string the error message
125
	 * @param string the filename that the error was raised in
126
	 * @param integer the line number the error was raised at
127
	 */
128
	public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
129
	{
130
		if(error_reporting()!=0)
131
			throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
132
	}
133
 
134
	/**
135
	 * Default exception handler.
136
	 * This method should be registered as default exception handler using
137
	 * {@link set_exception_handler}. The method tries to use the errorhandler
138
	 * module of the Prado application to handle the exception.
139
	 * If the application or the module does not exist, it simply echoes the
140
	 * exception.
141
	 * @param Exception exception that is not caught
142
	 */
143
	public static function exceptionHandler($exception)
144
	{
145
		if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
146
		{
147
			$errorHandler->handleError(null,$exception);
148
		}
149
		else
150
		{
151
			echo $exception;
152
		}
153
		exit(1);
154
	}
155
 
156
	/**
157
	 * Stores the application instance in the class static member.
158
	 * This method helps implement a singleton pattern for TApplication.
159
	 * Repeated invocation of this method or the application constructor
160
	 * will cause the throw of an exception.
161
	 * This method should only be used by framework developers.
162
	 * @param TApplication the application instance
163
	 * @throws TInvalidOperationException if this method is invoked twice or more.
164
	 */
165
	public static function setApplication($application)
166
	{
167
		if(self::$_application!==null)
168
			throw new TInvalidOperationException('prado_application_singleton_required');
169
		self::$_application=$application;
170
	}
171
 
172
	/**
173
	 * @return TApplication the application singleton, null if the singleton has not be created yet.
174
	 */
175
	public static function getApplication()
176
	{
177
		return self::$_application;
178
	}
179
 
180
	/**
181
	 * @return string the path of the framework
182
	 */
183
	public static function getFrameworkPath()
184
	{
185
		return PRADO_DIR;
186
	}
187
 
188
	/**
189
	 * Serializes a data.
190
	 * The original PHP serialize function has a bug that may not serialize
191
	 * properly an object.
192
	 * @param mixed data to be serialized
193
	 * @return string the serialized data
194
	 */
195
	public static function serialize($data)
196
	{
197
		$arr[0]=$data;
198
		return serialize($arr);
199
	}
200
 
201
	/**
202
	 * Unserializes a data.
203
	 * The original PHP unserialize function has a bug that may not unserialize
204
	 * properly an object.
205
	 * @param string data to be unserialized
206
	 * @return mixed unserialized data, null if unserialize failed
207
	 */
208
	public static function unserialize($str)
209
	{
210
		$arr=unserialize($str);
211
		return isset($arr[0])?$arr[0]:null;
212
	}
213
 
214
	/**
215
	 * Creates a component with the specified type.
216
	 * A component type can be either the component class name
217
	 * or a namespace referring to the path of the component class file.
218
	 * For example, 'TButton', 'System.Web.UI.WebControls.TButton' are both
219
	 * valid component type.
220
	 * This method can also pass parameters to component constructors.
221
	 * All parameters passed to this method except the first one (the component type)
222
	 * will be supplied as component constructor parameters.
223
	 * @param string component type
224
	 * @return TComponent component instance of the specified type
225
	 * @throws TInvalidDataValueException if the component type is unknown
226
	 */
227
	public static function createComponent($type)
228
	{
229
		self::using($type);
230
		if(($pos=strrpos($type,'.'))!==false)
231
			$type=substr($type,$pos+1);
232
		if(($n=func_num_args())>1)
233
		{
234
			$args=func_get_args();
235
			$s='$args[1]';
236
			for($i=2;$i<$n;++$i)
237
				$s.=",\$args[$i]";
238
			eval("\$component=new $type($s);");
239
			return $component;
240
		}
241
		else
242
			return new $type;
243
	}
244
 
245
	/**
246
	 * Uses a namespace.
247
	 * A namespace ending with an asterisk '*' refers to a directory, otherwise it represents a PHP file.
248
	 * If the namespace corresponds to a directory, the directory will be appended
249
	 * to the include path. If the namespace corresponds to a file, it will be included (include_once).
250
	 * @param string namespace to be used
251
	 * @param boolean whether to check the existence of the class after the class file is included
252
	 * @throws TInvalidDataValueException if the namespace is invalid
253
	 */
254
	public static function using($namespace,$checkClassExistence=true)
255
	{
256
		if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
257
			return;
258
		if(($pos=strrpos($namespace,'.'))===false)  // a class name
259
		{
260
			try
261
			{
262
				include_once($namespace.self::CLASS_FILE_EXT);
263
			}
264
			catch(Exception $e)
265
			{
266
				if($checkClassExistence && !class_exists($namespace,false))
267
					throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
268
				else
269
					throw $e;
270
			}
271
		}
272
		else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
273
		{
274
			$className=substr($namespace,$pos+1);
275
			if($className==='*')  // a directory
276
			{
277
				self::$_usings[$namespace]=$path;
278
				set_include_path(get_include_path().PATH_SEPARATOR.$path);
279
			}
280
			else  // a file
281
			{
282
				self::$_usings[$namespace]=$path;
283
				if(!$checkClassExistence || !class_exists($className,false))
284
				{
285
					try
286
					{
287
						include_once($path);
288
					}
289
					catch(Exception $e)
290
					{
291
						if($checkClassExistence && !class_exists($className,false))
292
							throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
293
						else
294
							throw $e;
295
					}
296
				}
297
			}
298
		}
299
		else
300
			throw new TInvalidDataValueException('prado_using_invalid',$namespace);
301
	}
302
 
303
	/**
304
	 * Translates a namespace into a file path.
305
	 * The first segment of the namespace is considered as a path alias
306
	 * which is replaced with the actual path. The rest segments are
307
	 * subdirectory names appended to the aliased path.
308
	 * If the namespace ends with an asterisk '*', it represents a directory;
309
	 * Otherwise it represents a file whose extension name is specified by the second parameter (defaults to empty).
310
	 * Note, this method does not ensure the existence of the resulting file path.
311
	 * @param string namespace
312
	 * @param string extension to be appended if the namespace refers to a file
313
	 * @return string file path corresponding to the namespace, null if namespace is invalid
314
	 */
315
	public static function getPathOfNamespace($namespace,$ext='')
316
	{
317
		if(isset(self::$_usings[$namespace]))
318
			return self::$_usings[$namespace];
319
		else if(isset(self::$_aliases[$namespace]))
320
			return self::$_aliases[$namespace];
321
		else
322
		{
323
			$segs=explode('.',$namespace);
324
			$alias=array_shift($segs);
325
			if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null)
326
				return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file==='*')?'':DIRECTORY_SEPARATOR.$file.$ext);
327
			else
328
				return null;
329
		}
330
	}
331
 
332
	/**
333
	 * @param string alias to the path
334
	 * @return string the path corresponding to the alias, null if alias not defined.
335
	 */
336
	public static function getPathOfAlias($alias)
337
	{
338
		return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
339
	}
340
 
341
	protected static function getPathAliases()
342
	{
343
		return self::$_aliases;
344
	}
345
 
346
	/**
347
	 * @param string alias to the path
348
	 * @param string the path corresponding to the alias
349
	 * @throws TInvalidOperationException if the alias is already defined
350
	 * @throws TInvalidDataValueException if the path is not a valid file path
351
	 */
352
	public static function setPathOfAlias($alias,$path)
353
	{
354
		if(isset(self::$_aliases[$alias]))
355
			throw new TInvalidOperationException('prado_alias_redefined',$alias);
356
		else if(($rp=realpath($path))!==false && is_dir($rp))
357
		{
358
			if(strpos($alias,'.')===false)
359
				self::$_aliases[$alias]=$rp;
360
			else
361
				throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
362
		}
363
		else
364
			throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
365
	}
366
 
367
	/**
368
	 * Fatal error handler.
369
	 * This method displays an error message together with the current call stack.
370
	 * The application will exit after calling this method.
371
	 * @param string error message
372
	 */
373
	public static function fatalError($msg)
374
	{
375
		echo '<h1>Fatal Error</h1>';
376
		echo '<p>'.$msg.'</p>';
377
		if(!function_exists('debug_backtrace'))
378
			return;
379
		echo '<h2>Debug Backtrace</h2>';
380
		echo '<pre>';
381
		$index=-1;
382
		foreach(debug_backtrace() as $t)
383
		{
384
			$index++;
385
			if($index==0)  // hide the backtrace of this function
386
				continue;
387
			echo '#'.$index.' ';
388
			if(isset($t['file']))
389
				echo basename($t['file']) . ':' . $t['line'];
390
			else
391
			   echo '<PHP inner-code>';
392
			echo ' -- ';
393
			if(isset($t['class']))
394
				echo $t['class'] . $t['type'];
395
			echo $t['function'] . '(';
396
			if(isset($t['args']) && sizeof($t['args']) > 0)
397
			{
398
				$count=0;
399
				foreach($t['args'] as $item)
400
				{
401
					if(is_string($item))
402
					{
403
						$str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
404
						if (strlen($item) > 70)
405
							echo "'". substr($str, 0, 70) . "...'";
406
						else
407
							echo "'" . $str . "'";
408
					}
409
					else if (is_int($item) || is_float($item))
410
						echo $item;
411
					else if (is_object($item))
412
						echo get_class($item);
413
					else if (is_array($item))
414
						echo 'array(' . count($item) . ')';
415
					else if (is_bool($item))
416
						echo $item ? 'true' : 'false';
417
					else if ($item === null)
418
						echo 'NULL';
419
					else if (is_resource($item))
420
						echo get_resource_type($item);
421
					$count++;
422
					if (count($t['args']) > $count)
423
						echo ', ';
424
				}
425
			}
426
			echo ")\n";
427
		}
428
		echo '</pre>';
429
		exit(1);
430
	}
431
 
432
	/**
433
	 * Returns a list of user preferred languages.
434
	 * The languages are returned as an array. Each array element
435
	 * represents a single language preference. The languages are ordered
436
	 * according to user preferences. The first language is the most preferred.
437
	 * @return array list of user preferred languages.
438
	 */
439
	public static function getUserLanguages()
440
	{
441
		static $languages=null;
442
		if($languages===null)
443
		{
444
			if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
445
				$languages[0]='en';
446
			else
447
			{
448
				$languages=array();
449
				foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
450
				{
451
					$array=split(';q=',trim($language));
452
					$languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
453
				}
454
				arsort($languages);
455
				$languages=array_keys($languages);
456
				if(empty($languages))
457
					$languages[0]='en';
458
			}
459
		}
460
		return $languages;
461
	}
462
 
463
	/**
464
	 * Returns the most preferred language by the client user.
465
	 * @return string the most preferred language by the client user, defaults to English.
466
	 */
467
	public static function getPreferredLanguage()
468
	{
469
		static $language=null;
470
		if($language===null)
471
		{
472
			$langs=Prado::getUserLanguages();
473
			$lang=explode('-',$langs[0]);
474
			if(empty($lang[0]) || !ctype_alpha($lang[0]))
475
				$language='en';
476
			else
477
				$language=$lang[0];
478
		}
479
		return $language;
480
	}
481
 
482
	/**
483
	 * Writes a log message.
484
	 * This method wraps {@link log()} by checking the application mode.
485
	 * When the application is in Debug mode, debug backtrace information is appended
486
	 * to the message and the message is logged at DEBUG level.
487
	 * When the application is in Performance mode, this method does nothing.
488
	 * Otherwise, the message is logged at INFO level.
489
	 * @param string message to be logged
490
	 * @param string category of the message
491
	 * @see log, getLogger
492
	 */
493
	public static function trace($msg,$category='Uncategorized')
494
	{
495
		if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
496
			return;
497
		if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
498
		{
499
			$trace=debug_backtrace();
500
			if(isset($trace[0]['file']) && isset($trace[0]['line']))
501
				$msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
502
			$level=TLogger::DEBUG;
503
		}
504
		else
505
			$level=TLogger::INFO;
506
		self::log($msg,$level,$category);
507
	}
508
 
509
	/**
510
	 * Logs a message.
511
	 * Messages logged by this method may be retrieved via {@link TLogger::getLogs}
512
	 * and may be recorded in different media, such as file, email, database, using
513
	 * {@link TLogRouter}.
514
	 * @param string message to be logged
515
	 * @param integer level of the message. Valid values include
516
	 * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING,
517
	 * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL.
518
	 * @param string category of the message
519
	 */
520
	public static function log($msg,$level=TLogger::INFO,$category='Uncategorized')
521
	{
522
		if(self::$_logger===null)
523
			self::$_logger=new TLogger;
524
		self::$_logger->log($msg,$level,$category);
525
	}
526
 
527
	/**
528
	 * @return TLogger message logger
529
	 */
530
	public static function getLogger()
531
	{
532
		if(self::$_logger===null)
533
			self::$_logger=new TLogger;
534
		return self::$_logger;
535
	}
536
 
537
	/**
538
	 * Converts a variable into a string representation.
539
	 * This method achieves the similar functionality as var_dump and print_r
540
	 * but is more robust when handling complex objects such as PRADO controls.
541
	 * @param mixed variable to be dumped
542
	 * @param integer maximum depth that the dumper should go into the variable. Defaults to 10.
543
	 * @param boolean whether to syntax highlight the output. Defaults to false.
544
	 * @return string the string representation of the variable
545
	 */
546
	public static function varDump($var,$depth=10,$highlight=false)
547
	{
548
		Prado::using('System.Util.TVarDumper');
549
		return TVarDumper::dump($var,$depth,$highlight);
550
	}
551
 
552
	/**
553
	 * Localize a text to the locale/culture specified in the globalization handler.
554
	 * @param string text to be localized.
555
	 * @param array a set of parameters to substitute.
556
	 * @param string a different catalogue to find the localize text.
557
	 * @param string the input AND output charset.
558
	 * @return string localized text.
559
	 * @see TTranslate::formatter()
560
	 * @see TTranslate::init()
561
	 */
562
	public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
563
	{
564
		Prado::using('System.I18N.Translation');
565
		$app = Prado::getApplication()->getGlobalization(false);
566
 
567
		$params = array();
568
		foreach($parameters as $key => $value)
569
			$params['{'.$key.'}'] = $value;
570
 
571
		//no translation handler provided
572
		if($app===null || ($config = $app->getTranslationConfiguration())===null)
573
			return strtr($text, $params);
574
 
575
		if ($catalogue===null)
576
			$catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
577
 
578
		Translation::init($catalogue);
579
 
580
		//globalization charset
581
		$appCharset = $app===null ? '' : $app->getCharset();
582
 
583
		//default charset
584
		$defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
585
 
586
		//fall back
587
		if(empty($charset)) $charset = $appCharset;
588
		if(empty($charset)) $charset = $defaultCharset;
589
 
590
		return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
591
	}
592
}
593
 
594
/**
595
 * TReflectionClass class.
596
 * This class was originally written to cope with the incompatibility between different PHP versions.
597
 * It is equivalent to ReflectionClass for PHP version >= 5.1.0
598
 * @author Qiang Xue <qiang.xue@gmail.com>
599
 * @version $Id: PradoBase.php 2602 2009-01-12 01:08:39Z qiang.xue $
600
 * @package System
601
 * @since 3.0
602
 */
603
class TReflectionClass extends ReflectionClass
604
{
605
}
606
 
607
/**
608
 * Includes the classes essential for PradoBase class
609
 */
610
PradoBase::using('System.TComponent');
611
PradoBase::using('System.Exceptions.TException');
612
PradoBase::using('System.Util.TLogger');
613
 
614
?>