File indexing completed on 2024-12-22 05:36:49
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Loader 0017 * @subpackage PluginLoader 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** Zend_Loader_PluginLoader_Interface */ 0024 // require_once 'Zend/Loader/PluginLoader/Interface.php'; 0025 0026 /** Zend_Loader */ 0027 // require_once 'Zend/Loader.php'; 0028 0029 /** 0030 * Generic plugin class loader 0031 * 0032 * @category Zend 0033 * @package Zend_Loader 0034 * @subpackage PluginLoader 0035 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0036 * @license http://framework.zend.com/license/new-bsd New BSD License 0037 */ 0038 class Zend_Loader_PluginLoader implements Zend_Loader_PluginLoader_Interface 0039 { 0040 /** 0041 * Class map cache file 0042 * @var string 0043 */ 0044 protected static $_includeFileCache; 0045 0046 /** 0047 * Class map cache file handler 0048 * @var resource 0049 */ 0050 protected static $_includeFileCacheHandler; 0051 0052 /** 0053 * Instance loaded plugin paths 0054 * 0055 * @var array 0056 */ 0057 protected $_loadedPluginPaths = array(); 0058 0059 /** 0060 * Instance loaded plugins 0061 * 0062 * @var array 0063 */ 0064 protected $_loadedPlugins = array(); 0065 0066 /** 0067 * Instance registry property 0068 * 0069 * @var array 0070 */ 0071 protected $_prefixToPaths = array(); 0072 0073 /** 0074 * Statically loaded plugin path mappings 0075 * 0076 * @var array 0077 */ 0078 protected static $_staticLoadedPluginPaths = array(); 0079 0080 /** 0081 * Statically loaded plugins 0082 * 0083 * @var array 0084 */ 0085 protected static $_staticLoadedPlugins = array(); 0086 0087 /** 0088 * Static registry property 0089 * 0090 * @var array 0091 */ 0092 protected static $_staticPrefixToPaths = array(); 0093 0094 /** 0095 * Whether to use a statically named registry for loading plugins 0096 * 0097 * @var string|null 0098 */ 0099 protected $_useStaticRegistry = null; 0100 0101 /** 0102 * Constructor 0103 * 0104 * @param array $prefixToPaths 0105 * @param string $staticRegistryName OPTIONAL 0106 */ 0107 public function __construct(Array $prefixToPaths = array(), $staticRegistryName = null) 0108 { 0109 if (is_string($staticRegistryName) && !empty($staticRegistryName)) { 0110 $this->_useStaticRegistry = $staticRegistryName; 0111 if(!isset(self::$_staticPrefixToPaths[$staticRegistryName])) { 0112 self::$_staticPrefixToPaths[$staticRegistryName] = array(); 0113 } 0114 if(!isset(self::$_staticLoadedPlugins[$staticRegistryName])) { 0115 self::$_staticLoadedPlugins[$staticRegistryName] = array(); 0116 } 0117 } 0118 0119 foreach ($prefixToPaths as $prefix => $path) { 0120 $this->addPrefixPath($prefix, $path); 0121 } 0122 } 0123 0124 /** 0125 * Format prefix for internal use 0126 * 0127 * @param string $prefix 0128 * @return string 0129 */ 0130 protected function _formatPrefix($prefix) 0131 { 0132 if($prefix == "") { 0133 return $prefix; 0134 } 0135 0136 $nsSeparator = (false !== strpos($prefix, '\\'))?'\\':'_'; 0137 $prefix = rtrim($prefix, $nsSeparator) . $nsSeparator; 0138 //if $nsSeprator == "\" and the prefix ends in "_\" remove trailing \ 0139 //https://github.com/zendframework/zf1/issues/152 0140 if(($nsSeparator == "\\") && (substr($prefix,-2) == "_\\")) { 0141 $prefix = substr($prefix, 0, -1); 0142 } 0143 return $prefix; 0144 } 0145 0146 /** 0147 * Add prefixed paths to the registry of paths 0148 * 0149 * @param string $prefix 0150 * @param string $path 0151 * @return Zend_Loader_PluginLoader 0152 */ 0153 public function addPrefixPath($prefix, $path) 0154 { 0155 if (!is_string($prefix) || !is_string($path)) { 0156 // require_once 'Zend/Loader/PluginLoader/Exception.php'; 0157 throw new Zend_Loader_PluginLoader_Exception('Zend_Loader_PluginLoader::addPrefixPath() method only takes strings for prefix and path.'); 0158 } 0159 0160 $prefix = $this->_formatPrefix($prefix); 0161 $path = rtrim($path, '/\\') . '/'; 0162 0163 if ($this->_useStaticRegistry) { 0164 self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix][] = $path; 0165 } else { 0166 if (!isset($this->_prefixToPaths[$prefix])) { 0167 $this->_prefixToPaths[$prefix] = array(); 0168 } 0169 if (!in_array($path, $this->_prefixToPaths[$prefix])) { 0170 $this->_prefixToPaths[$prefix][] = $path; 0171 } 0172 } 0173 return $this; 0174 } 0175 0176 /** 0177 * Get path stack 0178 * 0179 * @param string $prefix 0180 * @return false|array False if prefix does not exist, array otherwise 0181 */ 0182 public function getPaths($prefix = null) 0183 { 0184 if ((null !== $prefix) && is_string($prefix)) { 0185 $prefix = $this->_formatPrefix($prefix); 0186 if ($this->_useStaticRegistry) { 0187 if (isset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix])) { 0188 return self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix]; 0189 } 0190 0191 return false; 0192 } 0193 0194 if (isset($this->_prefixToPaths[$prefix])) { 0195 return $this->_prefixToPaths[$prefix]; 0196 } 0197 0198 return false; 0199 } 0200 0201 if ($this->_useStaticRegistry) { 0202 return self::$_staticPrefixToPaths[$this->_useStaticRegistry]; 0203 } 0204 0205 return $this->_prefixToPaths; 0206 } 0207 0208 /** 0209 * Clear path stack 0210 * 0211 * @param string $prefix 0212 * @return bool False only if $prefix does not exist 0213 */ 0214 public function clearPaths($prefix = null) 0215 { 0216 if ((null !== $prefix) && is_string($prefix)) { 0217 $prefix = $this->_formatPrefix($prefix); 0218 if ($this->_useStaticRegistry) { 0219 if (isset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix])) { 0220 unset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix]); 0221 return true; 0222 } 0223 0224 return false; 0225 } 0226 0227 if (isset($this->_prefixToPaths[$prefix])) { 0228 unset($this->_prefixToPaths[$prefix]); 0229 return true; 0230 } 0231 0232 return false; 0233 } 0234 0235 if ($this->_useStaticRegistry) { 0236 self::$_staticPrefixToPaths[$this->_useStaticRegistry] = array(); 0237 } else { 0238 $this->_prefixToPaths = array(); 0239 } 0240 0241 return true; 0242 } 0243 0244 /** 0245 * Remove a prefix (or prefixed-path) from the registry 0246 * 0247 * @param string $prefix 0248 * @param string $path OPTIONAL 0249 * @return Zend_Loader_PluginLoader 0250 */ 0251 public function removePrefixPath($prefix, $path = null) 0252 { 0253 $prefix = $this->_formatPrefix($prefix); 0254 if ($this->_useStaticRegistry) { 0255 $registry =& self::$_staticPrefixToPaths[$this->_useStaticRegistry]; 0256 } else { 0257 $registry =& $this->_prefixToPaths; 0258 } 0259 0260 if (!isset($registry[$prefix])) { 0261 // require_once 'Zend/Loader/PluginLoader/Exception.php'; 0262 throw new Zend_Loader_PluginLoader_Exception('Prefix ' . $prefix . ' was not found in the PluginLoader.'); 0263 } 0264 0265 if ($path != null) { 0266 $pos = array_search($path, $registry[$prefix]); 0267 if (false === $pos) { 0268 // require_once 'Zend/Loader/PluginLoader/Exception.php'; 0269 throw new Zend_Loader_PluginLoader_Exception('Prefix ' . $prefix . ' / Path ' . $path . ' was not found in the PluginLoader.'); 0270 } 0271 unset($registry[$prefix][$pos]); 0272 } else { 0273 unset($registry[$prefix]); 0274 } 0275 0276 return $this; 0277 } 0278 0279 /** 0280 * Normalize plugin name 0281 * 0282 * @param string $name 0283 * @return string 0284 */ 0285 protected function _formatName($name) 0286 { 0287 return ucfirst((string) $name); 0288 } 0289 0290 /** 0291 * Whether or not a Plugin by a specific name is loaded 0292 * 0293 * @param string $name 0294 * @return Zend_Loader_PluginLoader 0295 */ 0296 public function isLoaded($name) 0297 { 0298 $name = $this->_formatName($name); 0299 if ($this->_useStaticRegistry) { 0300 return isset(self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]); 0301 } 0302 0303 return isset($this->_loadedPlugins[$name]); 0304 } 0305 0306 /** 0307 * Return full class name for a named plugin 0308 * 0309 * @param string $name 0310 * @return string|false False if class not found, class name otherwise 0311 */ 0312 public function getClassName($name) 0313 { 0314 $name = $this->_formatName($name); 0315 if ($this->_useStaticRegistry 0316 && isset(self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]) 0317 ) { 0318 return self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]; 0319 } elseif (isset($this->_loadedPlugins[$name])) { 0320 return $this->_loadedPlugins[$name]; 0321 } 0322 0323 return false; 0324 } 0325 0326 /** 0327 * Get path to plugin class 0328 * 0329 * @param mixed $name 0330 * @return string|false False if not found 0331 */ 0332 public function getClassPath($name) 0333 { 0334 $name = $this->_formatName($name); 0335 if ($this->_useStaticRegistry 0336 && !empty(self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name]) 0337 ) { 0338 return self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name]; 0339 } elseif (!empty($this->_loadedPluginPaths[$name])) { 0340 return $this->_loadedPluginPaths[$name]; 0341 } 0342 0343 if ($this->isLoaded($name)) { 0344 $class = $this->getClassName($name); 0345 $r = new ReflectionClass($class); 0346 $path = $r->getFileName(); 0347 if ($this->_useStaticRegistry) { 0348 self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name] = $path; 0349 } else { 0350 $this->_loadedPluginPaths[$name] = $path; 0351 } 0352 return $path; 0353 } 0354 0355 return false; 0356 } 0357 0358 /** 0359 * Load a plugin via the name provided 0360 * 0361 * @param string $name 0362 * @param bool $throwExceptions Whether or not to throw exceptions if the 0363 * class is not resolved 0364 * @return string|false Class name of loaded class; false if $throwExceptions 0365 * if false and no class found 0366 * @throws Zend_Loader_Exception if class not found 0367 */ 0368 public function load($name, $throwExceptions = true) 0369 { 0370 $name = $this->_formatName($name); 0371 if ($this->isLoaded($name)) { 0372 return $this->getClassName($name); 0373 } 0374 0375 if ($this->_useStaticRegistry) { 0376 $registry = self::$_staticPrefixToPaths[$this->_useStaticRegistry]; 0377 } else { 0378 $registry = $this->_prefixToPaths; 0379 } 0380 0381 $registry = array_reverse($registry, true); 0382 $found = false; 0383 if (false !== strpos($name, '\\')) { 0384 $classFile = str_replace('\\', DIRECTORY_SEPARATOR, $name) . '.php'; 0385 } else { 0386 $classFile = str_replace('_', DIRECTORY_SEPARATOR, $name) . '.php'; 0387 } 0388 $incFile = self::getIncludeFileCache(); 0389 foreach ($registry as $prefix => $paths) { 0390 $className = $prefix . $name; 0391 0392 if (class_exists($className, false)) { 0393 $found = true; 0394 break; 0395 } 0396 0397 $paths = array_reverse($paths, true); 0398 0399 foreach ($paths as $path) { 0400 $loadFile = $path . $classFile; 0401 if (Zend_Loader::isReadable($loadFile)) { 0402 include_once $loadFile; 0403 if (class_exists($className, false)) { 0404 if (null !== $incFile) { 0405 self::_appendIncFile($loadFile); 0406 } 0407 $found = true; 0408 break 2; 0409 } 0410 } 0411 } 0412 } 0413 0414 if (!$found) { 0415 if (!$throwExceptions) { 0416 return false; 0417 } 0418 0419 $message = "Plugin by name '$name' was not found in the registry; used paths:"; 0420 foreach ($registry as $prefix => $paths) { 0421 $message .= "\n$prefix: " . implode(PATH_SEPARATOR, $paths); 0422 } 0423 // require_once 'Zend/Loader/PluginLoader/Exception.php'; 0424 throw new Zend_Loader_PluginLoader_Exception($message); 0425 } 0426 0427 if ($this->_useStaticRegistry) { 0428 self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name] = $className; 0429 } else { 0430 $this->_loadedPlugins[$name] = $className; 0431 } 0432 return $className; 0433 } 0434 0435 /** 0436 * Set path to class file cache 0437 * 0438 * Specify a path to a file that will add include_once statements for each 0439 * plugin class loaded. This is an opt-in feature for performance purposes. 0440 * 0441 * @param string $file 0442 * @return void 0443 * @throws Zend_Loader_PluginLoader_Exception if file is not writeable or path does not exist 0444 */ 0445 public static function setIncludeFileCache($file) 0446 { 0447 if (!empty(self::$_includeFileCacheHandler)) { 0448 flock(self::$_includeFileCacheHandler, LOCK_UN); 0449 fclose(self::$_includeFileCacheHandler); 0450 } 0451 0452 self::$_includeFileCacheHandler = null; 0453 0454 if (null === $file) { 0455 self::$_includeFileCache = null; 0456 return; 0457 } 0458 0459 if (!file_exists($file) && !file_exists(dirname($file))) { 0460 // require_once 'Zend/Loader/PluginLoader/Exception.php'; 0461 throw new Zend_Loader_PluginLoader_Exception('Specified file does not exist and/or directory does not exist (' . $file . ')'); 0462 } 0463 if (file_exists($file) && !is_writable($file)) { 0464 // require_once 'Zend/Loader/PluginLoader/Exception.php'; 0465 throw new Zend_Loader_PluginLoader_Exception('Specified file is not writeable (' . $file . ')'); 0466 } 0467 if (!file_exists($file) && file_exists(dirname($file)) && !is_writable(dirname($file))) { 0468 // require_once 'Zend/Loader/PluginLoader/Exception.php'; 0469 throw new Zend_Loader_PluginLoader_Exception('Specified file is not writeable (' . $file . ')'); 0470 } 0471 0472 self::$_includeFileCache = $file; 0473 } 0474 0475 /** 0476 * Retrieve class file cache path 0477 * 0478 * @return string|null 0479 */ 0480 public static function getIncludeFileCache() 0481 { 0482 return self::$_includeFileCache; 0483 } 0484 0485 /** 0486 * Append an include_once statement to the class file cache 0487 * 0488 * @param string $incFile 0489 * @return void 0490 */ 0491 protected static function _appendIncFile($incFile) 0492 { 0493 if (!isset(self::$_includeFileCacheHandler)) { 0494 self::$_includeFileCacheHandler = fopen(self::$_includeFileCache, 'ab'); 0495 0496 if (!flock(self::$_includeFileCacheHandler, LOCK_EX | LOCK_NB, $wouldBlock) || $wouldBlock) { 0497 self::$_includeFileCacheHandler = false; 0498 } 0499 } 0500 0501 if (false !== self::$_includeFileCacheHandler) { 0502 $line = "<?php include_once '$incFile'?>\n"; 0503 fwrite(self::$_includeFileCacheHandler, $line, strlen($line)); 0504 } 0505 } 0506 }