/Base/src/base.php
PHP | 674 lines | 337 code | 52 blank | 285 comment | 47 complexity | 2bf3fc010f4d55c2084595fc5cee3914 MD5 | raw file
- <?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;
- }
- }
- ?>