[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/library/ezc/Base/src/ -> base.php (source)

   1  <?php
   2  /**
   3   * File containing the ezcBase class.
   4   *
   5   * @package Base
   6   * @version 1.8
   7   * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
   8   * @license http://ez.no/licenses/new_bsd New BSD License
   9   */
  10  /**
  11   * Base class implements the methods needed to use the eZ components.
  12   *
  13   * @package Base
  14   * @version 1.8
  15   * @mainclass
  16   */
  17  class ezcBase
  18  {
  19      /**
  20       * Used for dependency checking, to check for a PHP extension.
  21       */
  22      const DEP_PHP_EXTENSION = "extension";
  23  
  24      /**
  25       * Used for dependency checking, to check for a PHP version.
  26       */
  27      const DEP_PHP_VERSION = "version";
  28  
  29      /**
  30       * Denotes the production mode
  31       */
  32      const MODE_PRODUCTION = 0;
  33  
  34      /**
  35       * Denotes the development mode
  36       */
  37      const MODE_DEVELOPMENT = 1;
  38  
  39      /**
  40       * Indirectly it determines the path where the autoloads are stored.
  41       *
  42       * @var string
  43       */
  44      private static $libraryMode = "tarball";
  45  
  46      /**
  47       * Contains the current working directory, which is used when the
  48       * $libraryMode is set to "custom".
  49       *
  50       * @var string
  51       */
  52      private static $currentWorkingDirectory = null;
  53  
  54      /**
  55       * The full path to the autoload directory.
  56       *
  57       * @var string
  58       */
  59      protected static $packageDir = null;
  60  
  61      /**
  62       * Contains which development mode is used. It's "development" by default,
  63       * because of backwards compatibility reasons.
  64       */
  65      private static $runMode = self::MODE_DEVELOPMENT;
  66  
  67      /**
  68       * Stores info with additional paths where autoload files and classes for
  69       * autoloading could be found. Each item of $repositoryDirs looks like
  70       * array( autoloadFileDir, baseDir ). The array key is the prefix belonging
  71       * to classes within that repository - if provided when calling
  72       * addClassRepository(), or an autoincrement integer otherwise.
  73       *
  74       * @var array(string=>array)
  75       */
  76      protected static $repositoryDirs = array();
  77  
  78      /**
  79       * This variable stores all the elements from the autoload arrays. When a
  80       * new autoload file is loaded, their files are added to this array.
  81       *
  82       * @var array(string=>string)
  83       */
  84      protected static $autoloadArray = array();
  85  
  86      /**
  87       * This variable stores all the elements from the autoload arrays for
  88       * external repositories. When a new autoload file is loaded, their files
  89       * are added to this array.
  90       *
  91       * @var array(string=>string)
  92       */
  93      protected static $externalAutoloadArray = array();
  94  
  95      /**
  96       * Options for the ezcBase class.
  97       *
  98       * @var ezcBaseOptions
  99       */
 100      static private $options;
 101  
 102      /**
 103       * Associates an option object with this static class.
 104       *
 105       * @param ezcBaseAutoloadOptions $options
 106       */
 107      static public function setOptions( ezcBaseAutoloadOptions $options )
 108      {
 109          self::$options = $options;
 110      }
 111  
 112      /**
 113       * Tries to autoload the given className. If the className could be found
 114       * this method returns true, otherwise false.
 115       *
 116       * This class caches the requested class names (including the ones who
 117       * failed to load).
 118       *
 119       * @param string $className  The name of the class that should be loaded.
 120       *
 121       * @return bool
 122       */
 123      public static function autoload( $className )
 124      {
 125          ezcBase::setPackageDir();
 126  
 127          // Check whether the classname is already in the cached autoloadArray.
 128          if ( array_key_exists( $className, ezcBase::$autoloadArray ) )
 129          {
 130              // Is it registered as 'unloadable'?
 131              if ( ezcBase::$autoloadArray[$className] == false )
 132              {
 133                  return false;
 134              }
 135              ezcBase::loadFile( ezcBase::$autoloadArray[$className] );
 136  
 137              return true;
 138          }
 139  
 140          // Check whether the classname is already in the cached autoloadArray
 141          // for external repositories.
 142          if ( array_key_exists( $className, ezcBase::$externalAutoloadArray ) )
 143          {
 144              // Is it registered as 'unloadable'?
 145              if ( ezcBase::$externalAutoloadArray[$className] == false )
 146              {
 147                  return false;
 148              }
 149              ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] );
 150  
 151              return true;
 152          }
 153  
 154          // Not cached, so load the autoload from the package.
 155          // Matches the first and optionally the second 'word' from the classname.
 156          $fileNames = array();
 157          if ( preg_match( "/^([a-z0-9]*)([A-Z][a-z0-9]*)?([A-Z][a-z0-9]*)?/", $className, $matches ) !== false )
 158          {
 159              $autoloadFile = "";
 160              // Try to match with both names, if available.
 161              switch ( sizeof( $matches ) )
 162              {
 163                  case 4:
 164                      // check for x_y_autoload.php
 165                      $autoloadFile = strtolower( "{$matches[2]}_{$matches[3]}_autoload.php" );
 166                      $fileNames[] = $autoloadFile;
 167                      if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) )
 168                      {
 169                          return true;
 170                      }
 171                      // break intentionally missing.
 172  
 173                  case 3:
 174                      // check for x_autoload.php
 175                      $autoloadFile = strtolower( "{$matches[2]}_autoload.php" );
 176                      $fileNames[] = $autoloadFile;
 177                      if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) )
 178                      {
 179                          return true;
 180                      }
 181                      // break intentionally missing.
 182  
 183                  case 2:
 184                      // check for autoload.php
 185                      $autoloadFile = 'autoload.php';
 186                      $fileNames[] = $autoloadFile;
 187                      if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) )
 188                      {
 189                          return true;
 190                      }
 191                      break;
 192              }
 193  
 194              // Maybe there is another autoload available.
 195              // Register this classname as false.
 196              ezcBase::$autoloadArray[$className] = false;
 197          }
 198  
 199          $path = ezcBase::$packageDir . 'autoload/';
 200          $realPath = realpath( $path );
 201  
 202          if ( $realPath == '' )
 203          {
 204              // Can not be tested, because if this happens, then the autoload
 205              // environment has not been set-up correctly.
 206              trigger_error( "Couldn't find autoload directory '$path'", E_USER_ERROR );
 207          }
 208  
 209          $dirs = self::getRepositoryDirectories();
 210          if ( ezcBase::$options && ezcBase::$options->debug )
 211          {
 212              throw new ezcBaseAutoloadException( $className, $fileNames, $dirs );
 213          }
 214  
 215          return false;
 216      }
 217  
 218      /**
 219       * Sets the current working directory to $directory.
 220       *
 221       * @param string $directory
 222       */
 223      public static function setWorkingDirectory( $directory )
 224      {
 225          self::$libraryMode = 'custom';
 226          self::$currentWorkingDirectory = $directory;
 227      }
 228  
 229      /**
 230       * Figures out the base path of the eZ Components installation.
 231       *
 232       * It stores the path that it finds in a static member variable. The path
 233       * depends on the installation method of the eZ Components. The SVN version
 234       * has a different path than the PEAR installed version.
 235       */
 236      protected static function setPackageDir()
 237      {
 238          if ( ezcBase::$packageDir !== null )
 239          {
 240              return;
 241          }
 242  
 243          // Get the path to the components.
 244          $baseDir = dirname( __FILE__ );
 245  
 246          switch ( ezcBase::$libraryMode )
 247          {
 248              case "custom":
 249                  ezcBase::$packageDir = self::$currentWorkingDirectory . '/';
 250                  break;
 251              case "devel":
 252              case "tarball":
 253                  ezcBase::$packageDir = $baseDir. "/../../";
 254                  break;
 255              case "pear";
 256                  ezcBase::$packageDir = $baseDir. "/../";
 257                  break;
 258          }
 259      }
 260  
 261      /**
 262       * Tries to load the autoload array and, if loaded correctly, includes the class.
 263       *
 264       * @param string $fileName    Name of the autoload file.
 265       * @param string $className   Name of the class that should be autoloaded.
 266       * @param string $prefix      The prefix of the class repository.
 267       *
 268       * @return bool  True is returned when the file is correctly loaded.
 269       *                   Otherwise false is returned.
 270       */
 271      protected static function requireFile( $fileName, $className, $prefix )
 272      {
 273          $autoloadDir = ezcBase::$packageDir . "autoload/";
 274  
 275          // We need the full path to the fileName. The method file_exists() doesn't
 276          // automatically check the (php.ini) library paths. Therefore:
 277          // file_exists( "ezc/autoload/$fileName" ) doesn't work.
 278          if ( $prefix === 'ezc' && file_exists( "$autoloadDir$fileName" ) )
 279          {
 280              $array = require( "$autoloadDir$fileName" );
 281  
 282              if ( is_array( $array) && array_key_exists( $className, $array ) )
 283              {
 284                  // Add the array to the cache, and include the requested file.
 285                  ezcBase::$autoloadArray = array_merge( ezcBase::$autoloadArray, $array );
 286                  if ( ezcBase::$options !== null && ezcBase::$options->preload && !preg_match( '/Exception$/', $className ) )
 287                  {
 288                      foreach ( $array as $loadClassName => $file )
 289                      {
 290                          if ( $loadClassName !== 'ezcBase' && !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false ) && !preg_match( '/Exception$/', $loadClassName ) /*&& !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false )*/ )
 291                          {
 292                              ezcBase::loadFile( ezcBase::$autoloadArray[$loadClassName] );
 293                          }
 294                      }
 295                  }
 296                  else
 297                  {
 298                      ezcBase::loadFile( ezcBase::$autoloadArray[$className] );
 299                  }
 300                  return true;
 301              }
 302          }
 303  
 304          // It is not in components autoload/ dir.
 305          // try to search in additional dirs.
 306          foreach ( ezcBase::$repositoryDirs as $repositoryPrefix => $extraDir )
 307          {
 308              if ( gettype( $repositoryPrefix ) === 'string' && $repositoryPrefix !== $prefix )
 309              {
 310                  continue;
 311              }
 312  
 313              if ( file_exists( $extraDir['autoloadDirPath'] . '/' . $fileName ) )
 314              {
 315                  $array = array();
 316                  $originalArray = require( $extraDir['autoloadDirPath'] . '/' . $fileName );
 317  
 318                  // Building paths.
 319                  // Resulting path to class definition file consists of:
 320                  // path to extra directory with autoload file +
 321                  // basePath provided for current extra directory +
 322                  // path to class definition file stored in autoload file.
 323                  foreach ( $originalArray as $class => $classPath )
 324                  {
 325                      $array[$class] = $extraDir['basePath'] . '/' . $classPath;
 326                  }
 327  
 328                  if ( is_array( $array ) && array_key_exists( $className, $array ) )
 329                  {
 330                      // Add the array to the cache, and include the requested file.
 331                      ezcBase::$externalAutoloadArray = array_merge( ezcBase::$externalAutoloadArray, $array );
 332                      ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] );
 333                      return true;
 334                  }
 335              }
 336          }
 337  
 338          // Nothing found :-(.
 339          return false;
 340      }
 341  
 342      /**
 343       * Loads, require(), the given file name. If we are in development mode,
 344       * "/src/" is inserted into the path.
 345       *
 346       * @param string $file  The name of the file that should be loaded.
 347       */
 348      protected static function loadFile( $file )
 349      {
 350          switch ( ezcBase::$libraryMode )
 351          {
 352              case "devel":
 353              case "tarball":
 354                  list( $first, $second ) = explode( '/', $file, 2 );
 355                  $file = $first . "/src/" . $second;
 356                  break;
 357  
 358              case "custom":
 359                  list( $first, $second ) = explode( '/', $file, 2 );
 360                  // Add the "src/" after the package name.
 361                  if ( $first == 'Base' || $first == 'UnitTest' )
 362                  {
 363                      list( $first, $second ) = explode( '/', $file, 2 );
 364                      $file = $first . "/src/" . $second;
 365                  }
 366                  else
 367                  {
 368                      list( $first, $second, $third ) = explode( '/', $file, 3 );
 369                      $file = $first . '/' . $second . "/src/" . $third;
 370                  }
 371                  break;
 372  
 373              case "pear":
 374                  /* do nothing, it's already correct */
 375                  break;
 376          }
 377  
 378          if ( file_exists( ezcBase::$packageDir . $file ) )
 379          {
 380              require( ezcBase::$packageDir . $file );
 381          }
 382          else
 383          {
 384              // Can not be tested, because if this happens, then one of the
 385              // components has a broken autoload file.
 386              throw new ezcBaseFileNotFoundException( ezcBase::$packageDir.$file );
 387          }
 388      }
 389  
 390      /**
 391       * Loads, require(), the given file name from an external package.
 392       *
 393       * @param string $file  The name of the file that should be loaded.
 394       */
 395      protected static function loadExternalFile( $file )
 396      {
 397          if ( file_exists( $file ) )
 398          {
 399              require( $file );
 400          }
 401          else
 402          {
 403              throw new ezcBaseFileNotFoundException( $file );
 404          }
 405      }
 406  
 407      /**
 408       * Checks for dependencies on PHP versions or extensions
 409       *
 410       * The function as called by the $component component checks for the $type
 411       * dependency. The dependency $type is compared against the $value. The
 412       * function aborts the script if the dependency is not matched.
 413       *
 414       * @param string $component
 415       * @param int $type
 416       * @param mixed $value
 417       */
 418      public static function checkDependency( $component, $type, $value )
 419      {
 420          switch ( $type )
 421          {
 422              case self::DEP_PHP_EXTENSION:
 423                  if ( extension_loaded( $value ) )
 424                  {
 425                      return;
 426                  }
 427                  else
 428                  {
 429                      // Can not be tested as it would abort the PHP script.
 430                      die( "\nThe {$component} component depends on the default PHP extension '{$value}', which is not loaded.\n" );
 431                  }
 432                  break;
 433  
 434              case self::DEP_PHP_VERSION:
 435                  $phpVersion = phpversion();
 436                  if ( version_compare( $phpVersion, $value, '>=' ) )
 437                  {
 438                      return;
 439                  }
 440                  else
 441                  {
 442                      // Can not be tested as it would abort the PHP script.
 443                      die( "\nThe {$component} component depends on the PHP version '{$value}', but the current version is '{$phpVersion}'.\n" );
 444                  }
 445                  break;
 446          }
 447      }
 448  
 449      /**
 450       * Return the list of directories that contain class repositories.
 451       *
 452       * The path to the eZ components directory is always included in the result
 453       * array. Each element in the returned array has the format of:
 454       * packageDirectory => ezcBaseRepositoryDirectory
 455       *
 456       * @return array(string=>ezcBaseRepositoryDirectory)
 457       */
 458      public static function getRepositoryDirectories()
 459      {
 460          $autoloadDirs = array();
 461          ezcBase::setPackageDir();
 462          $repositoryDir = self::$currentWorkingDirectory ? self::$currentWorkingDirectory : ( realpath( dirname( __FILE__ ) . '/../../' ) );
 463          $autoloadDirs['ezc'] = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_INTERNAL, $repositoryDir, $repositoryDir . "/autoload" );
 464  
 465          foreach ( ezcBase::$repositoryDirs as $extraDirKey => $extraDirArray )
 466          {
 467              $repositoryDirectory = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_EXTERNAL, realpath( $extraDirArray['basePath'] ), realpath( $extraDirArray['autoloadDirPath'] ) );
 468              $autoloadDirs[$extraDirKey] = $repositoryDirectory;
 469          }
 470  
 471          return $autoloadDirs;
 472      }
 473  
 474      /**
 475       * Adds an additional class repository.
 476       *
 477       * Used for adding class repositoryies outside the eZ components to be
 478       * loaded by the autoload system.
 479       *
 480       * This function takes two arguments: $basePath is the base path for the
 481       * whole class repository and $autoloadDirPath the path where autoload
 482       * files for this repository are found. The paths in the autoload files are
 483       * relative to the package directory as specified by the $basePath
 484       * argument. I.e. class definition file will be searched at location
 485       * $basePath + path to the class definition file as stored in the autoload
 486       * file.
 487       *
 488       * addClassRepository() should be called somewhere in code before external classes
 489       * are used.
 490       *
 491       * Example:
 492       * Take the following facts:
 493       * <ul>
 494       * <li>there is a class repository stored in the directory "./repos"</li>
 495       * <li>autoload files for that repository are stored in "./repos/autoloads"</li>
 496       * <li>there are two components in this repository: "Me" and "You"</li>
 497       * <li>the "Me" component has the classes "erMyClass1" and "erMyClass2"</li>
 498       * <li>the "You" component has the classes "erYourClass1" and "erYourClass2"</li>
 499       * </ul>
 500       *
 501       * In this case you would need to create the following files in
 502       * "./repos/autoloads". Please note that the part before _autoload.php in
 503       * the filename is the first part of the <b>classname</b>, not considering
 504       * the all lower-case letter prefix.
 505       *
 506       * "my_autoload.php":
 507       * <code>
 508       * <?php
 509       *     return array (
 510       *       'erMyClass1' => 'Me/myclass1.php',
 511       *       'erMyClass2' => 'Me/myclass2.php',
 512       *     );
 513       * ?>
 514       * </code>
 515       *
 516       * "your_autoload.php":
 517       * <code>
 518       * <?php
 519       *     return array (
 520       *       'erYourClass1' => 'You/yourclass1.php',
 521       *       'erYourClass2' => 'You/yourclass2.php',
 522       *     );
 523       * ?>
 524       * </code>
 525       *
 526       * The directory structure for the external repository is then:
 527       * <code>
 528       * ./repos/autoloads/my_autoload.php
 529       * ./repos/autoloads/you_autoload.php
 530       * ./repos/Me/myclass1.php
 531       * ./repos/Me/myclass2.php
 532       * ./repos/You/yourclass1.php
 533       * ./repos/You/yourclass2.php
 534       * </code>
 535       *
 536       * To use this repository with the autoload mechanism you have to use the
 537       * following code:
 538       * <code>
 539       * <?php
 540       * ezcBase::addClassRepository( './repos', './repos/autoloads' );
 541       * $myVar = new erMyClass2();
 542       * ?>
 543       * </code>
 544       *
 545       * @throws ezcBaseFileNotFoundException if $autoloadDirPath or $basePath do not exist.
 546       * @param string $basePath
 547       * @param string $autoloadDirPath
 548       * @param string $prefix
 549       */
 550      public static function addClassRepository( $basePath, $autoloadDirPath = null, $prefix = null )
 551      {
 552          // check if base path exists
 553          if ( !is_dir( $basePath ) )
 554          {
 555              throw new ezcBaseFileNotFoundException( $basePath, 'base directory' );
 556          }
 557  
 558          // calculate autoload path if it wasn't given
 559          if ( is_null( $autoloadDirPath ) )
 560          {
 561              $autoloadDirPath = $basePath . '/autoload';
 562          }
 563  
 564          // check if autoload dir exists
 565          if ( !is_dir( $autoloadDirPath ) )
 566          {
 567              throw new ezcBaseFileNotFoundException( $autoloadDirPath, 'autoload directory' );
 568          }
 569  
 570          // add info to $repositoryDirs
 571          if ( $prefix === null )
 572          {
 573              $array = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath );
 574  
 575              // add info to the list of extra dirs
 576              ezcBase::$repositoryDirs[] = $array;
 577          }
 578          else
 579          {
 580              if ( array_key_exists( $prefix, ezcBase::$repositoryDirs ) )
 581              {
 582                  throw new ezcBaseDoubleClassRepositoryPrefixException( $prefix, $basePath, $autoloadDirPath );
 583              }
 584  
 585              // add info to the list of extra dirs, and use the prefix to identify the new repository.
 586              ezcBase::$repositoryDirs[$prefix] = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath );
 587          }
 588      }
 589  
 590      /**
 591       * Returns the base path of the eZ Components installation
 592       *
 593       * This method returns the base path, including a trailing directory
 594       * separator.
 595       *
 596       * @return string
 597       */
 598      public static function getInstallationPath()
 599      {
 600          self::setPackageDir();
 601  
 602          $path = realpath( self::$packageDir );
 603          if ( substr( $path, -1 ) !== DIRECTORY_SEPARATOR )
 604          {
 605              $path .= DIRECTORY_SEPARATOR;
 606          }
 607          return $path;
 608      }
 609  
 610      /**
 611       * Sets the development mode to the one specified.
 612       *
 613       * @param int $runMode
 614       */
 615      public static function setRunMode( $runMode )
 616      {
 617          if ( !in_array( $runMode, array( ezcBase::MODE_PRODUCTION, ezcBase::MODE_DEVELOPMENT ) ) )
 618          {
 619              throw new ezcBaseValueException( 'runMode', $runMode, 'ezcBase::MODE_PRODUCTION or ezcBase::MODE_DEVELOPMENT' );
 620          }
 621  
 622          self::$runMode = $runMode;
 623      }
 624  
 625      /**
 626       * Returns the current development mode.
 627       *
 628       * @return int
 629       */
 630      public static function getRunMode()
 631      {
 632          return self::$runMode;
 633      }
 634  
 635      /**
 636       * Returns true when we are in development mode.
 637       *
 638       * @return bool
 639       */
 640      public static function inDevMode()
 641      {
 642          return self::$runMode == ezcBase::MODE_DEVELOPMENT;
 643      }
 644  
 645      /**
 646       * Returns the installation method
 647       *
 648       * Possible return values are 'custom', 'devel', 'tarball' and 'pear'. Only
 649       * 'tarball' and 'pear' are returned for user-installed versions.
 650       *
 651       * @return string
 652       */
 653      public static function getInstallMethod()
 654      {
 655          return self::$libraryMode;
 656      }
 657  }
 658  ?>


Generated: Thu Jul 28 15:48:31 2011 Cross-referenced by PHPXref 0.7