| [ Index ] |
PHP Cross Reference of MantisBT |
[Summary view] [Print] [Text view]
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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Jul 28 15:48:31 2011 | Cross-referenced by PHPXref 0.7 |