| <?php |
| /** |
| * File containing the ezcBase class. |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package Base |
| * @version //autogentag// |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| */ |
| /** |
| * Base class implements the methods needed to use the eZ components. |
| * |
| * @package Base |
| * @version //autogentag// |
| * @mainclass |
| */ |
| class ezcBase |
| { |
| /** |
| * Used for dependency checking, to check for a PHP extension. |
| */ |
| const DEP_PHP_EXTENSION = "extension"; |
| |
| /** |
| * Used for dependency checking, to check for a PHP version. |
| */ |
| const DEP_PHP_VERSION = "version"; |
| |
| /** |
| * Denotes the production mode |
| */ |
| const MODE_PRODUCTION = 0; |
| |
| /** |
| * Denotes the development mode |
| */ |
| const MODE_DEVELOPMENT = 1; |
| |
| /** |
| * Indirectly it determines the path where the autoloads are stored. |
| * |
| * @var string |
| */ |
| private static $libraryMode = "devel"; |
| |
| /** |
| * Contains the current working directory, which is used when the |
| * $libraryMode is set to "custom". |
| * |
| * @var string |
| */ |
| private static $currentWorkingDirectory = null; |
| |
| /** |
| * The full path to the autoload directory. |
| * |
| * @var string |
| */ |
| protected static $packageDir = null; |
| |
| /** |
| * Contains which development mode is used. It's "development" by default, |
| * because of backwards compatibility reasons. |
| */ |
| private static $runMode = self::MODE_DEVELOPMENT; |
| |
| /** |
| * Stores info with additional paths where autoload files and classes for |
| * autoloading could be found. Each item of $repositoryDirs looks like |
| * array( autoloadFileDir, baseDir ). The array key is the prefix belonging |
| * to classes within that repository - if provided when calling |
| * addClassRepository(), or an autoincrement integer otherwise. |
| * |
| * @var array(string=>array) |
| */ |
| protected static $repositoryDirs = array(); |
| |
| /** |
| * This variable stores all the elements from the autoload arrays. When a |
| * new autoload file is loaded, their files are added to this array. |
| * |
| * @var array(string=>string) |
| */ |
| protected static $autoloadArray = array(); |
| |
| /** |
| * This variable stores all the elements from the autoload arrays for |
| * external repositories. When a new autoload file is loaded, their files |
| * are added to this array. |
| * |
| * @var array(string=>string) |
| */ |
| protected static $externalAutoloadArray = array(); |
| |
| /** |
| * Options for the ezcBase class. |
| * |
| * @var ezcBaseOptions |
| */ |
| static private $options; |
| |
| /** |
| * Associates an option object with this static class. |
| * |
| * @param ezcBaseAutoloadOptions $options |
| */ |
| static public function setOptions( ezcBaseAutoloadOptions $options ) |
| { |
| self::$options = $options; |
| } |
| |
| /** |
| * Tries to autoload the given className. If the className could be found |
| * this method returns true, otherwise false. |
| * |
| * This class caches the requested class names (including the ones who |
| * failed to load). |
| * |
| * @param string $className The name of the class that should be loaded. |
| * |
| * @return bool |
| */ |
| public static function autoload( $className ) |
| { |
| ezcBase::setPackageDir(); |
| |
| // Check whether the classname is already in the cached autoloadArray. |
| if ( array_key_exists( $className, ezcBase::$autoloadArray ) ) |
| { |
| // Is it registered as 'unloadable'? |
| if ( ezcBase::$autoloadArray[$className] == false ) |
| { |
| return false; |
| } |
| ezcBase::loadFile( ezcBase::$autoloadArray[$className] ); |
| |
| return true; |
| } |
| |
| // Check whether the classname is already in the cached autoloadArray |
| // for external repositories. |
| if ( array_key_exists( $className, ezcBase::$externalAutoloadArray ) ) |
| { |
| // Is it registered as 'unloadable'? |
| if ( ezcBase::$externalAutoloadArray[$className] == false ) |
| { |
| return false; |
| } |
| ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] ); |
| |
| return true; |
| } |
| |
| // Not cached, so load the autoload from the package. |
| // Matches the first and optionally the second 'word' from the classname. |
| $fileNames = array(); |
| if ( preg_match( "/^([a-z0-9]*)([A-Z][a-z0-9]*)?([A-Z][a-z0-9]*)?/", $className, $matches ) !== false ) |
| { |
| $autoloadFile = ""; |
| // Try to match with both names, if available. |
| switch ( sizeof( $matches ) ) |
| { |
| case 4: |
| // check for x_y_autoload.php |
| $autoloadFile = strtolower( "{$matches[2]}_{$matches[3]}_autoload.php" ); |
| $fileNames[] = $autoloadFile; |
| if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) |
| { |
| return true; |
| } |
| // break intentionally missing. |
| |
| case 3: |
| // check for x_autoload.php |
| $autoloadFile = strtolower( "{$matches[2]}_autoload.php" ); |
| $fileNames[] = $autoloadFile; |
| if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) |
| { |
| return true; |
| } |
| // break intentionally missing. |
| |
| case 2: |
| // check for autoload.php |
| $autoloadFile = 'autoload.php'; |
| $fileNames[] = $autoloadFile; |
| if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) |
| { |
| return true; |
| } |
| break; |
| } |
| |
| // Maybe there is another autoload available. |
| // Register this classname as false. |
| ezcBase::$autoloadArray[$className] = false; |
| } |
| |
| $path = ezcBase::$packageDir . 'autoload/'; |
| $realPath = realpath( $path ); |
| |
| if ( $realPath == '' ) |
| { |
| // Can not be tested, because if this happens, then the autoload |
| // environment has not been set-up correctly. |
| trigger_error( "Couldn't find autoload directory '$path'", E_USER_ERROR ); |
| } |
| |
| $dirs = self::getRepositoryDirectories(); |
| if ( ezcBase::$options && ezcBase::$options->debug ) |
| { |
| throw new ezcBaseAutoloadException( $className, $fileNames, $dirs ); |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Sets the current working directory to $directory. |
| * |
| * @param string $directory |
| */ |
| public static function setWorkingDirectory( $directory ) |
| { |
| self::$libraryMode = 'custom'; |
| self::$currentWorkingDirectory = $directory; |
| } |
| |
| /** |
| * Figures out the base path of the Zeta Components installation. |
| * |
| * It stores the path that it finds in a static member variable. The path |
| * depends on the installation method of the Zeta Components. The SVN version |
| * has a different path than the PEAR installed version. |
| */ |
| protected static function setPackageDir() |
| { |
| if ( ezcBase::$packageDir !== null ) |
| { |
| return; |
| } |
| |
| // Get the path to the components. |
| $baseDir = dirname( __FILE__ ); |
| |
| switch ( ezcBase::$libraryMode ) |
| { |
| case "custom": |
| ezcBase::$packageDir = self::$currentWorkingDirectory . '/'; |
| break; |
| case "devel": |
| case "tarball": |
| ezcBase::$packageDir = $baseDir. "/../../"; |
| break; |
| case "pear"; |
| ezcBase::$packageDir = $baseDir. "/../"; |
| break; |
| } |
| } |
| |
| /** |
| * Tries to load the autoload array and, if loaded correctly, includes the class. |
| * |
| * @param string $fileName Name of the autoload file. |
| * @param string $className Name of the class that should be autoloaded. |
| * @param string $prefix The prefix of the class repository. |
| * |
| * @return bool True is returned when the file is correctly loaded. |
| * Otherwise false is returned. |
| */ |
| protected static function requireFile( $fileName, $className, $prefix ) |
| { |
| $autoloadDir = ezcBase::$packageDir . "autoload/"; |
| |
| // We need the full path to the fileName. The method file_exists() doesn't |
| // automatically check the (php.ini) library paths. Therefore: |
| // file_exists( "ezc/autoload/$fileName" ) doesn't work. |
| if ( $prefix === 'ezc' && file_exists( "$autoloadDir$fileName" ) ) |
| { |
| $array = require( "$autoloadDir$fileName" ); |
| |
| if ( is_array( $array) && array_key_exists( $className, $array ) ) |
| { |
| // Add the array to the cache, and include the requested file. |
| ezcBase::$autoloadArray = array_merge( ezcBase::$autoloadArray, $array ); |
| if ( ezcBase::$options !== null && ezcBase::$options->preload && !preg_match( '/Exception$/', $className ) ) |
| { |
| foreach ( $array as $loadClassName => $file ) |
| { |
| if ( $loadClassName !== 'ezcBase' && !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false ) && !preg_match( '/Exception$/', $loadClassName ) /*&& !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false )*/ ) |
| { |
| ezcBase::loadFile( ezcBase::$autoloadArray[$loadClassName] ); |
| } |
| } |
| } |
| else |
| { |
| ezcBase::loadFile( ezcBase::$autoloadArray[$className] ); |
| } |
| return true; |
| } |
| } |
| |
| // It is not in components autoload/ dir. |
| // try to search in additional dirs. |
| foreach ( ezcBase::$repositoryDirs as $repositoryPrefix => $extraDir ) |
| { |
| if ( gettype( $repositoryPrefix ) === 'string' && $repositoryPrefix !== $prefix ) |
| { |
| continue; |
| } |
| |
| if ( file_exists( $extraDir['autoloadDirPath'] . '/' . $fileName ) ) |
| { |
| $array = array(); |
| $originalArray = require( $extraDir['autoloadDirPath'] . '/' . $fileName ); |
| |
| // Building paths. |
| // Resulting path to class definition file consists of: |
| // path to extra directory with autoload file + |
| // basePath provided for current extra directory + |
| // path to class definition file stored in autoload file. |
| foreach ( $originalArray as $class => $classPath ) |
| { |
| $array[$class] = $extraDir['basePath'] . '/' . $classPath; |
| } |
| |
| if ( is_array( $array ) && array_key_exists( $className, $array ) ) |
| { |
| // Add the array to the cache, and include the requested file. |
| ezcBase::$externalAutoloadArray = array_merge( ezcBase::$externalAutoloadArray, $array ); |
| ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] ); |
| return true; |
| } |
| } |
| } |
| |
| // Nothing found :-(. |
| return false; |
| } |
| |
| /** |
| * Loads, require(), the given file name. If we are in development mode, |
| * "/src/" is inserted into the path. |
| * |
| * @param string $file The name of the file that should be loaded. |
| */ |
| protected static function loadFile( $file ) |
| { |
| switch ( ezcBase::$libraryMode ) |
| { |
| case "devel": |
| case "tarball": |
| list( $first, $second ) = explode( '/', $file, 2 ); |
| $file = $first . "/src/" . $second; |
| break; |
| |
| case "custom": |
| list( $first, $second ) = explode( '/', $file, 2 ); |
| // Add the "src/" after the package name. |
| if ( $first == 'Base' || $first == 'UnitTest' ) |
| { |
| list( $first, $second ) = explode( '/', $file, 2 ); |
| $file = $first . "/src/" . $second; |
| } |
| else |
| { |
| list( $first, $second, $third ) = explode( '/', $file, 3 ); |
| $file = $first . '/' . $second . "/src/" . $third; |
| } |
| break; |
| |
| case "pear": |
| /* do nothing, it's already correct */ |
| break; |
| } |
| |
| if ( file_exists( ezcBase::$packageDir . $file ) ) |
| { |
| require( ezcBase::$packageDir . $file ); |
| } |
| else |
| { |
| // Can not be tested, because if this happens, then one of the |
| // components has a broken autoload file. |
| throw new ezcBaseFileNotFoundException( ezcBase::$packageDir.$file ); |
| } |
| } |
| |
| /** |
| * Loads, require(), the given file name from an external package. |
| * |
| * @param string $file The name of the file that should be loaded. |
| */ |
| protected static function loadExternalFile( $file ) |
| { |
| if ( file_exists( $file ) ) |
| { |
| require( $file ); |
| } |
| else |
| { |
| throw new ezcBaseFileNotFoundException( $file ); |
| } |
| } |
| |
| /** |
| * Checks for dependencies on PHP versions or extensions |
| * |
| * The function as called by the $component component checks for the $type |
| * dependency. The dependency $type is compared against the $value. The |
| * function aborts the script if the dependency is not matched. |
| * |
| * @param string $component |
| * @param int $type |
| * @param mixed $value |
| */ |
| public static function checkDependency( $component, $type, $value ) |
| { |
| switch ( $type ) |
| { |
| case self::DEP_PHP_EXTENSION: |
| if ( extension_loaded( $value ) ) |
| { |
| return; |
| } |
| else |
| { |
| // Can not be tested as it would abort the PHP script. |
| die( "\nThe {$component} component depends on the default PHP extension '{$value}', which is not loaded.\n" ); |
| } |
| break; |
| |
| case self::DEP_PHP_VERSION: |
| $phpVersion = phpversion(); |
| if ( version_compare( $phpVersion, $value, '>=' ) ) |
| { |
| return; |
| } |
| else |
| { |
| // Can not be tested as it would abort the PHP script. |
| die( "\nThe {$component} component depends on the PHP version '{$value}', but the current version is '{$phpVersion}'.\n" ); |
| } |
| break; |
| } |
| } |
| |
| /** |
| * Return the list of directories that contain class repositories. |
| * |
| * The path to the eZ components directory is always included in the result |
| * array. Each element in the returned array has the format of: |
| * packageDirectory => ezcBaseRepositoryDirectory |
| * |
| * @return array(string=>ezcBaseRepositoryDirectory) |
| */ |
| public static function getRepositoryDirectories() |
| { |
| $autoloadDirs = array(); |
| ezcBase::setPackageDir(); |
| $repositoryDir = self::$currentWorkingDirectory ? self::$currentWorkingDirectory : ( realpath( dirname( __FILE__ ) . '/../../' ) ); |
| $autoloadDirs['ezc'] = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_INTERNAL, $repositoryDir, $repositoryDir . "/autoload" ); |
| |
| foreach ( ezcBase::$repositoryDirs as $extraDirKey => $extraDirArray ) |
| { |
| $repositoryDirectory = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_EXTERNAL, realpath( $extraDirArray['basePath'] ), realpath( $extraDirArray['autoloadDirPath'] ) ); |
| $autoloadDirs[$extraDirKey] = $repositoryDirectory; |
| } |
| |
| return $autoloadDirs; |
| } |
| |
| /** |
| * Adds an additional class repository. |
| * |
| * Used for adding class repositoryies outside the eZ components to be |
| * loaded by the autoload system. |
| * |
| * This function takes two arguments: $basePath is the base path for the |
| * whole class repository and $autoloadDirPath the path where autoload |
| * files for this repository are found. The paths in the autoload files are |
| * relative to the package directory as specified by the $basePath |
| * argument. I.e. class definition file will be searched at location |
| * $basePath + path to the class definition file as stored in the autoload |
| * file. |
| * |
| * addClassRepository() should be called somewhere in code before external classes |
| * are used. |
| * |
| * Example: |
| * Take the following facts: |
| * <ul> |
| * <li>there is a class repository stored in the directory "./repos"</li> |
| * <li>autoload files for that repository are stored in "./repos/autoloads"</li> |
| * <li>there are two components in this repository: "Me" and "You"</li> |
| * <li>the "Me" component has the classes "erMyClass1" and "erMyClass2"</li> |
| * <li>the "You" component has the classes "erYourClass1" and "erYourClass2"</li> |
| * </ul> |
| * |
| * In this case you would need to create the following files in |
| * "./repos/autoloads". Please note that the part before _autoload.php in |
| * the filename is the first part of the <b>classname</b>, not considering |
| * the all lower-case letter prefix. |
| * |
| * "my_autoload.php": |
| * <code> |
| * <?php |
| * return array ( |
| * 'erMyClass1' => 'Me/myclass1.php', |
| * 'erMyClass2' => 'Me/myclass2.php', |
| * ); |
| * ?> |
| * </code> |
| * |
| * "your_autoload.php": |
| * <code> |
| * <?php |
| * return array ( |
| * 'erYourClass1' => 'You/yourclass1.php', |
| * 'erYourClass2' => 'You/yourclass2.php', |
| * ); |
| * ?> |
| * </code> |
| * |
| * The directory structure for the external repository is then: |
| * <code> |
| * ./repos/autoloads/my_autoload.php |
| * ./repos/autoloads/you_autoload.php |
| * ./repos/Me/myclass1.php |
| * ./repos/Me/myclass2.php |
| * ./repos/You/yourclass1.php |
| * ./repos/You/yourclass2.php |
| * </code> |
| * |
| * To use this repository with the autoload mechanism you have to use the |
| * following code: |
| * <code> |
| * <?php |
| * ezcBase::addClassRepository( './repos', './repos/autoloads' ); |
| * $myVar = new erMyClass2(); |
| * ?> |
| * </code> |
| * |
| * @throws ezcBaseFileNotFoundException if $autoloadDirPath or $basePath do not exist. |
| * @param string $basePath |
| * @param string $autoloadDirPath |
| * @param string $prefix |
| */ |
| public static function addClassRepository( $basePath, $autoloadDirPath = null, $prefix = null ) |
| { |
| // check if base path exists |
| if ( !is_dir( $basePath ) ) |
| { |
| throw new ezcBaseFileNotFoundException( $basePath, 'base directory' ); |
| } |
| |
| // calculate autoload path if it wasn't given |
| if ( is_null( $autoloadDirPath ) ) |
| { |
| $autoloadDirPath = $basePath . '/autoload'; |
| } |
| |
| // check if autoload dir exists |
| if ( !is_dir( $autoloadDirPath ) ) |
| { |
| throw new ezcBaseFileNotFoundException( $autoloadDirPath, 'autoload directory' ); |
| } |
| |
| // add info to $repositoryDirs |
| if ( $prefix === null ) |
| { |
| $array = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath ); |
| |
| // add info to the list of extra dirs |
| ezcBase::$repositoryDirs[] = $array; |
| } |
| else |
| { |
| if ( array_key_exists( $prefix, ezcBase::$repositoryDirs ) ) |
| { |
| throw new ezcBaseDoubleClassRepositoryPrefixException( $prefix, $basePath, $autoloadDirPath ); |
| } |
| |
| // add info to the list of extra dirs, and use the prefix to identify the new repository. |
| ezcBase::$repositoryDirs[$prefix] = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath ); |
| } |
| } |
| |
| /** |
| * Returns the base path of the Zeta Components installation |
| * |
| * This method returns the base path, including a trailing directory |
| * separator. |
| * |
| * @return string |
| */ |
| public static function getInstallationPath() |
| { |
| self::setPackageDir(); |
| |
| $path = realpath( self::$packageDir ); |
| if ( substr( $path, -1 ) !== DIRECTORY_SEPARATOR ) |
| { |
| $path .= DIRECTORY_SEPARATOR; |
| } |
| return $path; |
| } |
| |
| /** |
| * Sets the development mode to the one specified. |
| * |
| * @param int $runMode |
| */ |
| public static function setRunMode( $runMode ) |
| { |
| if ( !in_array( $runMode, array( ezcBase::MODE_PRODUCTION, ezcBase::MODE_DEVELOPMENT ) ) ) |
| { |
| throw new ezcBaseValueException( 'runMode', $runMode, 'ezcBase::MODE_PRODUCTION or ezcBase::MODE_DEVELOPMENT' ); |
| } |
| |
| self::$runMode = $runMode; |
| } |
| |
| /** |
| * Returns the current development mode. |
| * |
| * @return int |
| */ |
| public static function getRunMode() |
| { |
| return self::$runMode; |
| } |
| |
| /** |
| * Returns true when we are in development mode. |
| * |
| * @return bool |
| */ |
| public static function inDevMode() |
| { |
| return self::$runMode == ezcBase::MODE_DEVELOPMENT; |
| } |
| |
| /** |
| * Returns the installation method |
| * |
| * Possible return values are 'custom', 'devel', 'tarball' and 'pear'. Only |
| * 'tarball' and 'pear' are returned for user-installed versions. |
| * |
| * @return string |
| */ |
| public static function getInstallMethod() |
| { |
| return self::$libraryMode; |
| } |
| } |
| ?> |