From 4a3a6a68ce97316bb763a4e257e6b1b0a3c7bc9d Mon Sep 17 00:00:00 2001 From: ADmad Date: Thu, 9 Jan 2014 02:38:48 +0530 Subject: [PATCH] Changed to PSR-4 class loader. --- Cake/Core/ClassLoader.php | 141 ++++++++++++++++-------------- Cake/Core/Plugin.php | 4 +- Test/TestCase/Core/PluginTest.php | 2 +- Test/init.php | 14 +-- 4 files changed, 90 insertions(+), 71 deletions(-) diff --git a/Cake/Core/ClassLoader.php b/Cake/Core/ClassLoader.php index fb1d8fb3197..47ff6522c73 100644 --- a/Cake/Core/ClassLoader.php +++ b/Cake/Core/ClassLoader.php @@ -22,100 +22,113 @@ class ClassLoader { /** - * File extension + * An associative array where the key is a namespace prefix and the value + * is an array of base directories for classes in that namespace. * - * @var string + * @var array */ - protected $_fileExtension; + protected $_prefixes = []; /** - * The path a given namespace maps to. + * Register loader with SPL autoloader stack. * - * @var string + * @return void */ - protected $_path; + public function register() { + spl_autoload_register([$this, 'loadClass']); + } /** - * Registered namespace + * Adds a base directory for a namespace prefix. * - * @var string + * @param string $prefix The namespace prefix. + * @param string $baseDir A base directory for class files in the + * namespace. + * @param bool $prepend If true, prepend the base directory to the stack + * instead of appending it; this causes it to be searched first rather + * than last. + * @return void */ - protected $_namespace; + public function addNamespace($prefix, $baseDir, $prepend = false) { + $prefix = trim($prefix, '\\') . '\\'; -/** - * Store the namespace length for performance - * - * @var integer - */ - protected $_namespaceLength; + $baseDir = rtrim($baseDir, '/') . DIRECTORY_SEPARATOR; + $baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR) . '/'; -/** - * Constructor - * - * @param string $ns The _namespace to use. - */ - public function __construct($ns = null, $path = null, $fileExtension = '.php') { - $this->_namespace = rtrim($ns, '\\') . '\\'; - $this->_namespaceLength = strlen($this->_namespace); - $this->_path = $path; - $this->_fileExtension = '.php'; - } + if (!isset($this->_prefixes[$prefix])) { + $this->_prefixes[$prefix] = []; + } -/** - * Gets the base include path for all class files in the _namespace of this class loader. - * - * @return string - */ - public function getIncludePath() { - return $this->_includePath; + if ($prepend) { + array_unshift($this->_prefixes[$prefix], $baseDir); + } else { + array_push($this->_prefixes[$prefix], $baseDir); + } } /** - * Gets the file extension of class files in the _namespace of this class loader. + * Loads the class file for a given class name. * - * @return string + * @param string $class The fully-qualified class name. + * @return mixed The mapped file name on success, or boolean false on + * failure. */ - public function getFileExtension() { - return $this->_fileExtension; - } + public function loadClass($class) { + $prefix = $class; -/** - * Installs this class loader on the SPL autoload stack. - * - * @return void - */ - public function register() { - spl_autoload_register([$this, 'loadClass']); + while (($pos = strrpos($prefix, '\\')) !== false) { + $prefix = substr($class, 0, $pos + 1); + $relativeClass = substr($class, $pos + 1); + + $mappedFile = $this->_loadMappedFile($prefix, $relativeClass); + if ($mappedFile) { + return $mappedFile; + } + + $prefix = rtrim($prefix, '\\'); + } + + return false; } /** - * Uninstalls this class loader from the SPL autoloader stack. + * Load the mapped file for a namespace prefix and relative class. * - * @return void + * @param string $prefix The namespace prefix. + * @param string $relativeClass The relative class name. + * @return mixed Boolean false if no mapped file can be loaded, or the + * name of the mapped file that was loaded. */ - public function unregister() { - spl_autoload_unregister([$this, 'loadClass']); + protected function _loadMappedFile($prefix, $relativeClass) { + if (!isset($this->_prefixes[$prefix])) { + return false; + } + + foreach ($this->_prefixes[$prefix] as $baseDir) { + $file = $baseDir . + str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass) . '.php'; + $file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php'; + + if ($this->_requireFile($file)) { + return $file; + } + } + + return false; } /** - * Loads the given class or interface. + * If a file exists, require it from the file system. * - * @param string $className The name of the class to load. - * @return boolean + * @param string $file The file to require. + * @return bool True if the file exists, false if not. */ - public function loadClass($className) { - if (strpos($className, 'Cake\\Test\\') === 0) { - $className = substr($className, 5); - } elseif (strpos($className, 'App\\Test\\') === 0) { - $className = substr($className, 4); - } elseif (substr($className, 0, $this->_namespaceLength) !== $this->_namespace) { - return false; - } - $path = $this->_path . DS . str_replace('\\', DS, $className) . $this->_fileExtension; - if (!file_exists($path)) { - return false; + protected function _requireFile($file) { + if (file_exists($file)) { + require $file; + return true; } - return require $path; + return false; } } diff --git a/Cake/Core/Plugin.php b/Cake/Core/Plugin.php index a6c9b24813a..30e252ecbb2 100644 --- a/Cake/Core/Plugin.php +++ b/Cake/Core/Plugin.php @@ -142,7 +142,9 @@ public static function load($plugin, $config = []) { } if ($config['autoload'] === true) { - (new ClassLoader($config['namespace'], dirname($config['path'])))->register(); + $loader = new ClassLoader; + $loader->register(); + $loader->addNamespace($config['namespace'], $config['path']); } } diff --git a/Test/TestCase/Core/PluginTest.php b/Test/TestCase/Core/PluginTest.php index 26beb55031a..3728176711b 100644 --- a/Test/TestCase/Core/PluginTest.php +++ b/Test/TestCase/Core/PluginTest.php @@ -104,7 +104,7 @@ public function testLoadSingleWithAutoload() { $this->assertFalse(class_exists('Company\TestPluginThree\Utility\Hello')); Plugin::load('TestPluginThree', [ 'namespace' => 'Company\TestPluginThree', - 'path' => TEST_APP . 'Plugin/TestPluginThree', + 'path' => TEST_APP . 'Plugin/Company/TestPluginThree', 'autoload' => true, ]); $this->assertTrue( diff --git a/Test/init.php b/Test/init.php index 0ba3fd75738..3b2f2dfa5ea 100644 --- a/Test/init.php +++ b/Test/init.php @@ -51,11 +51,15 @@ require CORE_PATH . 'Cake/Core/ClassLoader.php'; -(new Cake\Core\ClassLoader('Cake', ROOT))->register(); -(new Cake\Core\ClassLoader('TestApp', ROOT . '/Test'))->register(); -(new Cake\Core\ClassLoader('TestPlugin', CORE_TESTS . 'TestApp/Plugin/'))->register(); -(new Cake\Core\ClassLoader('TestPluginTwo', CORE_TESTS . 'TestApp/Plugin/'))->register(); -(new Cake\Core\ClassLoader('PluginJs', CORE_TESTS . 'TestApp/Plugin/'))->register(); +$loader = new Cake\Core\ClassLoader; +$loader->register(); + +$loader->addNamespace('Cake', ROOT . '/Cake'); +$loader->addNamespace('Cake\Test', ROOT . '/Test'); +$loader->addNamespace('TestApp', ROOT . '/Test/TestApp'); +$loader->addNamespace('TestPlugin', CORE_TESTS . 'TestApp/Plugin/TestPlugin'); +$loader->addNamespace('TestPluginTwo', CORE_TESTS . 'TestApp/Plugin/TestPluginTwo'); +$loader->addNamespace('PluginJs', CORE_TESTS . 'TestApp/Plugin/PluginJs'); require CORE_PATH . 'Cake/bootstrap.php';