PRADO PHP Cross Reference Developer Tools

Source: /framework/PradoBase.php - 632 lines - 19138 bytes - Summary - Text - Print

Description: PradoBase class file. This is the file that establishes the PRADO component model and error handling mechanism.

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

title

Description

title

Description

title

Description

title

title

Body