Permalink
Browse files

Changed to PSR-4 class loader.

  • Loading branch information...
1 parent fd27c25 commit 4a3a6a68ce97316bb763a4e257e6b1b0a3c7bc9d @ADmad ADmad committed Jan 8, 2014
Showing with 90 additions and 71 deletions.
  1. +77 −64 Cake/Core/ClassLoader.php
  2. +3 −1 Cake/Core/Plugin.php
  3. +1 −1 Test/TestCase/Core/PluginTest.php
  4. +9 −5 Test/init.php
View
@@ -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;
}
}
View
@@ -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']);
}
}
@@ -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(
View
@@ -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';

0 comments on commit 4a3a6a6

Please sign in to comment.