├── .gitignore ├── .travis.yml ├── phpunit.xml.dist ├── composer.json ├── LICENSE ├── src └── Dflydev │ └── Composer │ └── Autoload │ ├── ClassLoaderReaderInterface.php │ ├── ClassLoaderReader.php │ ├── CompositeClassLoaderReader.php │ └── ClassLoaderLocator.php ├── tests └── Dflydev │ └── Composer │ └── Autoload │ ├── ClassLoaderReaderTest.php │ ├── ClassLoaderLocatorTest.php │ └── CompositeClassLoaderReaderTest.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | composer.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3.3 5 | - 5.3 6 | - 5.4 7 | 8 | before_script: 9 | - composer install --dev 10 | 11 | script: phpunit --coverage-text --verbose 12 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./tests/Dflydev/Composer/Autoload 6 | 7 | 8 | 9 | 10 | 11 | ./src/Dflydev/Composer/Autoload/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dflydev/composer-autoload", 3 | "description": "Composer Autoload Tools", 4 | "keywords": ["composer"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Dragonfly Development Inc.", 9 | "email": "info@dflydev.com", 10 | "homepage": "http://dflydev.com" 11 | }, 12 | { 13 | "name": "Beau Simensen", 14 | "email": "beau@dflydev.com", 15 | "homepage": "http://beausimensen.com" 16 | } 17 | ], 18 | "require-dev": { 19 | "composer/composer": "1.0.*@dev" 20 | }, 21 | "autoload": { 22 | "psr-0": { "Dflydev\\Composer\\Autoload": "src" } 23 | }, 24 | "extra": { 25 | "branch-alias": { 26 | "dev-master": "1.0-dev" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Dragonfly Development Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/Dflydev/Composer/Autoload/ClassLoaderReaderInterface.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | interface ClassLoaderReaderInterface 22 | { 23 | /** 24 | * Get namespace to directory mapping 25 | * 26 | * @return array 27 | */ 28 | public function getPrefixes(); 29 | 30 | /** 31 | * Get list of fallback directories 32 | * 33 | * @return array 34 | */ 35 | public function getFallbackDirs(); 36 | 37 | /** 38 | * Get class mapping 39 | * 40 | * @return array 41 | */ 42 | public function getClassMap(); 43 | 44 | /** 45 | * Find the file for a specific class 46 | * 47 | * @param string $class 48 | * 49 | * @return string|null 50 | */ 51 | public function findFile($class); 52 | } 53 | -------------------------------------------------------------------------------- /src/Dflydev/Composer/Autoload/ClassLoaderReader.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class ClassLoaderReader implements ClassLoaderReaderInterface 22 | { 23 | /** 24 | * Class Loader 25 | * 26 | * @var \Composer\Autoload\ClassLoader 27 | */ 28 | protected $classLoader; 29 | 30 | /** 31 | * Constructor 32 | * 33 | * @param \Composer\Autoload\ClassLoader $classLoader 34 | */ 35 | public function __construct(ClassLoader $classLoader) 36 | { 37 | $this->classLoader = $classLoader; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function getPrefixes() 44 | { 45 | return $this->classLoader->getPrefixes(); 46 | } 47 | 48 | /** 49 | * {@inheritdoc} 50 | */ 51 | public function getFallbackDirs() 52 | { 53 | return $this->classLoader->getFallbackDirs(); 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function getClassMap() 60 | { 61 | return $this->classLoader->getClassMap(); 62 | 63 | } 64 | 65 | /** 66 | * {@inheritdoc} 67 | */ 68 | public function findFile($class) 69 | { 70 | return $this->classLoader->findFile($class); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/Dflydev/Composer/Autoload/ClassLoaderReaderTest.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class ClassLoaderReaderTest extends \PHPUnit_Framework_TestCase 20 | { 21 | /** 22 | * Test getters 23 | */ 24 | public function testGetters() 25 | { 26 | $classLoader = $this->getMockBuilder('Composer\Autoload\ClassLoader') 27 | ->disableOriginalConstructor() 28 | ->getMock(); 29 | 30 | $classLoader 31 | ->expects($this->once()) 32 | ->method('getPrefixes') 33 | ->with() 34 | ->will($this->returnValue(array('A\B\C' => array('src/a/b/c')))); 35 | 36 | $classLoader 37 | ->expects($this->once()) 38 | ->method('getFallbackDirs') 39 | ->with() 40 | ->will($this->returnValue(array('a', 'b', 'c'))); 41 | 42 | $classLoader 43 | ->expects($this->once()) 44 | ->method('getClassMap') 45 | ->with() 46 | ->will($this->returnValue(array('A\B\C' => 'src/a/b/c'))); 47 | 48 | $classLoaderReader = new ClassLoaderReader($classLoader); 49 | 50 | $this->assertEquals(array('A\B\C' => array('src/a/b/c')), $classLoaderReader->getPrefixes()); 51 | $this->assertEquals(array('a', 'b', 'c'), $classLoaderReader->getFallbackDirs()); 52 | $this->assertEquals(array('A\B\C' => 'src/a/b/c'), $classLoaderReader->getClassMap()); 53 | } 54 | 55 | /** 56 | * Test find files 57 | */ 58 | public function testFindFile() 59 | { 60 | $classLoader = $this->getMockBuilder('Composer\Autoload\ClassLoader') 61 | ->disableOriginalConstructor() 62 | ->getMock(); 63 | 64 | $classLoader 65 | ->expects($this->once()) 66 | ->method('findFile') 67 | ->with('A\B\C') 68 | ->will($this->returnValue('src/a/b/c')); 69 | 70 | $classLoaderReader = new ClassLoaderReader($classLoader); 71 | 72 | $this->assertEquals('src/a/b/c', $classLoaderReader->findFile('A\B\C')); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Dflydev/Composer/Autoload/CompositeClassLoaderReader.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class CompositeClassLoaderReader implements ClassLoaderReaderInterface 22 | { 23 | /** 24 | * Class Loaders 25 | * 26 | * @var \Composer\Autoload\ClassLoader[] 27 | */ 28 | protected $classLoaders; 29 | 30 | /** 31 | * Constructor 32 | * 33 | * @param \Composer\Autoload\ClassLoader[] $classLoaders 34 | */ 35 | public function __construct(array $classLoaders = array()) 36 | { 37 | $this->classLoaders = $classLoaders; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function getPrefixes() 44 | { 45 | $prefixes = array(); 46 | foreach ($this->classLoaders as $classLoader) { 47 | foreach ($classLoader->getPrefixes() as $key => $value) { 48 | if (!isset($prefixes[$key])) { 49 | $prefixes[$key] = array(); 50 | } 51 | 52 | $prefixes[$key] = array_merge($prefixes[$key], $value); 53 | } 54 | } 55 | 56 | foreach ($prefixes as $key => $value) { 57 | $prefixes[$key] = array_values(array_unique($value)); 58 | } 59 | 60 | return $prefixes; 61 | } 62 | 63 | /** 64 | * {@inheritdoc} 65 | */ 66 | public function getFallbackDirs() 67 | { 68 | $fallbackDirs = array(); 69 | foreach ($this->classLoaders as $classLoader) { 70 | $fallbackDirs = array_merge($fallbackDirs, $classLoader->getFallbackDirs()); 71 | } 72 | 73 | return array_values(array_unique($fallbackDirs)); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function getClassMap() 80 | { 81 | $classMap = array(); 82 | foreach ($this->classLoaders as $classLoader) { 83 | foreach ($classLoader->getClassMap() as $key => $value) { 84 | if (!isset($classMap[$key])) { 85 | $classMap[$key] = $value; 86 | } 87 | } 88 | } 89 | 90 | return $classMap; 91 | } 92 | 93 | /** 94 | * {@inheritdoc} 95 | */ 96 | public function findFile($class) 97 | { 98 | foreach ($this->classLoaders as $classLoader) { 99 | if (null !== $file = $classLoader->findFile($class)) { 100 | return $file; 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Composer Autoload Tools 2 | ======================= 3 | 4 | Provide a standard interface for accessing and reading [Composer][00] 5 | autoloaders. 6 | 7 | **WARNING: This API is not yet stable and may be subject to change.** 8 | 9 | 10 | Why Does This Library Exist? 11 | ---------------------------- 12 | 13 | While it is generally not considered best practice for an application 14 | to be aware of underlying autoloaders, accessing the autoloader is 15 | sometimes a necessity. 16 | 17 | The primary use case behind the creation of this library was providing 18 | a [Composer implementation][02] of the [PSR-0 Resource Locator][03]. 19 | 20 | 21 | Usage 22 | ----- 23 | 24 | ```php 25 | getReader(); 30 | 31 | // Get access to all of the prefixes registered to all of 32 | // the Composer Class Loaders in one array. 33 | $prefixes = $reader->getPrefixes(); 34 | ``` 35 | 36 | 37 | Installation 38 | ------------ 39 | 40 | Through [Composer][00] as [dflydev/composer-autoload][01]. 41 | 42 | 43 | Requirements 44 | ------------ 45 | 46 | * PHP 5.3+ 47 | 48 | 49 | API 50 | --- 51 | 52 | ### ClassLoaderLocator Class 53 | 54 | #### Class Loaders 55 | 56 | Direct access to Composer Class Loaders. 57 | 58 | * *Composer\Autoload\ClassLoader[]* **getClassLoaders()**: 59 | Get all Composer Autoload Class Loader instances. 60 | * *Composer\Autoload\ClassLoader|null* **getFirstClassLoader()**: 61 | Get the first Class Loader registered. 62 | * *Composer\Autoload\ClassLoader|null* **getFirstClassLoader()**: 63 | Get the last Class Loader registered. 64 | 65 | #### Class Loader Readers 66 | 67 | Access to underlying Class Loaders through the Class Loader Reader 68 | Interface. 69 | 70 | * *ClassLoaderReaderInterface* **getReader()**: 71 | Get a ClassLoader Reader. 72 | 73 | If multiple ClassLoaders or no Class Loaders are registered a Composite 74 | Class Loader Reader will be returned. 75 | * *ClassLoaderReaderInterface[]* **getReaders()**: 76 | Get Class Loader Readers for each registered Class Loader. 77 | * *ClassLoaderReaderInterface* **getFirstReader()**: 78 | Get the Class Loader Reader for the first Class Loader registered. 79 | * *ClassLoaderReaderInterface* **getFirstReader()**: 80 | Get the Class Loader Reader for the last Class Loader registered. 81 | 82 | #### Static Methods 83 | 84 | * **init()**: 85 | Initialize static instance. 86 | 87 | Can be used to ensure that everything is setup before it is actually used 88 | at a later time. For example, if something may be going to modify the list 89 | of registered autoloaders, this will ensure that the Composer ones can be 90 | found and recorded right away. 91 | * **reset()**: 92 | Reset the static instance. 93 | 94 | This effectively clears the located Class Loader instances. The next time 95 | something tries to access the class loaders the list of registered 96 | autoloaders will be scanned again. 97 | * **set(array $classLoaders)**: 98 | Set the list of Class Loaders. 99 | 100 | This is here primarily for testing purposes. 101 | 102 | 103 | ### ClassLoaderReaderInterface 104 | 105 | Mimics the data methods from `Composer\Autoload\ClassLoader`. 106 | 107 | * *array* **getPrefixes()**: 108 | Get namespace to directory mapping 109 | 110 | * *array* **getFallbackDirs()**: 111 | Get list of fallback directories 112 | 113 | * *array* **getClassMap()**: 114 | Get class mapping 115 | 116 | * *string|null* **findFile($class)**: 117 | Find the file for a specific class. 118 | 119 | Gotchas 120 | ------- 121 | 122 | In some cases Composer's Class Loader may be replaced by another 123 | autoload implementation. The common example for this is when a 124 | specialized Debug Class Loader is registered on top of Composer. 125 | In these cases it is advised to call `init()` immediately after 126 | `autload.php` is required to ensure that Composer's Class Loader can 127 | be located. 128 | 129 | ```php 130 | 18 | */ 19 | class ClassLoaderLocator 20 | { 21 | /** 22 | * @var \Composer\Autoload\ClassLoader[] 23 | */ 24 | private static $classLoaders = null; 25 | 26 | /** 27 | * @var ClassLoaderLocator 28 | */ 29 | private static $classLoaderLocator = null; 30 | 31 | /** 32 | * Get the first ClassLoader registered 33 | * 34 | * @return \Composer\Autoload\ClassLoader 35 | */ 36 | public function getFirstClassLoader() 37 | { 38 | $classLoaders = static::getClassLoaders(); 39 | 40 | if (!count($classLoaders)) { 41 | return null; 42 | } 43 | 44 | return $classLoaders[0]; 45 | } 46 | 47 | /** 48 | * Get the last ClassLoader registered 49 | * 50 | * @return \Composer\Autoload\ClassLoader 51 | */ 52 | public function getLastClassLoader() 53 | { 54 | $classLoaders = static::getClassLoaders(); 55 | 56 | if (!count($classLoaders)) { 57 | return null; 58 | } 59 | 60 | return $classLoaders[count($classLoaders)-1]; 61 | } 62 | 63 | /** 64 | * Locate all Composer Autoload ClassLoader instances 65 | * 66 | * @return \Composer\Autoload\ClassLoader[] 67 | */ 68 | public function getClassLoaders() 69 | { 70 | if (null !== static::$classLoaders) { 71 | return static::$classLoaders; 72 | } 73 | 74 | static::$classLoaders = array(); 75 | 76 | foreach (spl_autoload_functions() as $function) { 77 | if (is_array($function) && count($function[0]) > 0 && is_object($function[0]) && 'Composer\Autoload\ClassLoader' === get_class($function[0])) { 78 | static::$classLoaders[] = $function[0]; 79 | } 80 | } 81 | 82 | return static::$classLoaders; 83 | } 84 | 85 | /** 86 | * Get a ClassLoader Reader 87 | * 88 | * If multiple ClassLoaders or no ClassLoaders are registered a Composite 89 | * ClassLoader Reader will be returned. 90 | * 91 | * @return ClassLoaderReaderInterface 92 | */ 93 | public function getReader() 94 | { 95 | $classLoaders = static::getClassLoaders(); 96 | 97 | return 1 === count($classLoaders) 98 | ? new ClassLoaderReader($classLoaders[0]) 99 | : new CompositeClassLoaderReader($classLoaders); 100 | } 101 | 102 | /** 103 | * Get the first ClassLoader Reader 104 | * 105 | * @return ClassLoaderReader 106 | */ 107 | public function getFirstReader() 108 | { 109 | $classLoader = $this->getFirstClassLoader(); 110 | 111 | if ($classLoader) { 112 | return new ClassLoaderReader($classLoader); 113 | } 114 | 115 | return new CompositeClassLoaderReader; 116 | } 117 | 118 | /** 119 | * Get the last ClassLoader Reader 120 | * 121 | * @return ClassLoaderReader 122 | */ 123 | public function getLastReader() 124 | { 125 | $classLoader = $this->getLastClassLoader(); 126 | 127 | if ($classLoader) { 128 | return new ClassLoaderReader($classLoader); 129 | } 130 | 131 | return new CompositeClassLoaderReader; 132 | } 133 | 134 | /** 135 | * Get ClassLoader Readers for each registered ClassLoader 136 | * 137 | * @return ClassLoaderReaderInterface[] 138 | */ 139 | public function getReaders() 140 | { 141 | $readers = array(); 142 | foreach (static::getClassLoaders() as $classLoader) { 143 | $readers[] = new ClassLoaderReader($classLoader); 144 | } 145 | 146 | return $readers; 147 | } 148 | 149 | /** 150 | * Initialize static instance 151 | */ 152 | public static function init() 153 | { 154 | if (null !== static::$classLoaders) { 155 | return; 156 | } 157 | 158 | if (null !== static::$classLoaderLocator) { 159 | return; 160 | } 161 | 162 | static::$classLoaderLocator = new static; 163 | static::$classLoaderLocator->getClassLoaders(); 164 | } 165 | 166 | /** 167 | * Reset the static instance 168 | * 169 | * This effectively clears the located ClassLoader instances. 170 | */ 171 | public static function reset() 172 | { 173 | static::$classLoaders = null; 174 | } 175 | 176 | /** 177 | * Set the class loaders 178 | * 179 | * This is here primarily for testing purposes. 180 | * 181 | * @param \Composer\Autoload\ClassLoader[] $classLoaders 182 | */ 183 | public static function set(array $classLoaders) 184 | { 185 | static::$classLoaders = $classLoaders; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /tests/Dflydev/Composer/Autoload/ClassLoaderLocatorTest.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class ClassLoaderLocatorTest extends \PHPUnit_Framework_TestCase 20 | { 21 | public function testEmpty() 22 | { 23 | ClassLoaderLocator::set(array()); 24 | 25 | $classLoaderLocator = new ClassLoaderLocator; 26 | 27 | $this->assertNull($classLoaderLocator->getFirstClassLoader()); 28 | $this->assertNull($classLoaderLocator->getLastClassLoader()); 29 | $this->assertCount(0, $classLoaderLocator->getClassLoaders()); 30 | 31 | $this->assertInstanceOf('Dflydev\Composer\Autoload\CompositeClassLoaderReader', $classLoaderLocator->getFirstReader()); 32 | $this->assertInstanceOf('Dflydev\Composer\Autoload\CompositeClassLoaderReader', $classLoaderLocator->getLastReader()); 33 | } 34 | 35 | public function testExactlyOne() 36 | { 37 | $classLoader = $this->getMockBuilder('Composer\Autoload\ClassLoader') 38 | ->disableOriginalConstructor() 39 | ->getMock(); 40 | 41 | $classLoader 42 | ->expects($this->any()) 43 | ->method('getPrefixes') 44 | ->will($this->returnValue(array('A' => array('src/a')))); 45 | 46 | ClassLoaderLocator::set(array( 47 | $classLoader, 48 | )); 49 | 50 | $classLoaderLocator = new ClassLoaderLocator; 51 | 52 | $firstClassLoader = $classLoaderLocator->getFirstClassLoader(); 53 | $lastClassLoader = $classLoaderLocator->getLastClassLoader(); 54 | $allClassLoaders = $classLoaderLocator->getClassLoaders(); 55 | 56 | $this->assertEquals(array('A' => array('src/a')), $firstClassLoader->getPrefixes()); 57 | $this->assertEquals(array('A' => array('src/a')), $lastClassLoader->getPrefixes()); 58 | $this->assertCount(1, $allClassLoaders); 59 | 60 | $reader = $classLoaderLocator->getReader(); 61 | 62 | $this->assertInstanceOf('Dflydev\Composer\Autoload\ClassLoaderReader', $reader); 63 | 64 | $prefixes = $reader->getPrefixes(); 65 | 66 | $this->assertEquals('src/a', $prefixes['A'][0]); 67 | 68 | $firstReader = $classLoaderLocator->getFirstReader(); 69 | $lastReader = $classLoaderLocator->getLastReader(); 70 | 71 | $this->assertEquals(array('A' => array('src/a')), $firstReader->getPrefixes()); 72 | $this->assertEquals(array('A' => array('src/a')), $lastReader->getPrefixes()); 73 | 74 | $readers = $classLoaderLocator->getReaders(); 75 | 76 | $this->assertCount(1, $readers); 77 | $this->assertEquals(array('A' => array('src/a')), $readers[0]->getPrefixes()); 78 | } 79 | 80 | public function testTwoOrMore() 81 | { 82 | $classLoader0 = $this->getMockBuilder('Composer\Autoload\ClassLoader') 83 | ->disableOriginalConstructor() 84 | ->getMock(); 85 | 86 | $classLoader0 87 | ->expects($this->any()) 88 | ->method('getPrefixes') 89 | ->will($this->returnValue(array('A' => array('src/a')))); 90 | 91 | $classLoader1 = $this->getMockBuilder('Composer\Autoload\ClassLoader') 92 | ->disableOriginalConstructor() 93 | ->getMock(); 94 | 95 | $classLoader1 96 | ->expects($this->any()) 97 | ->method('getPrefixes') 98 | ->will($this->returnValue(array('B' => array('src/b')))); 99 | 100 | $classLoader2 = $this->getMockBuilder('Composer\Autoload\ClassLoader') 101 | ->disableOriginalConstructor() 102 | ->getMock(); 103 | 104 | $classLoader2 105 | ->expects($this->any()) 106 | ->method('getPrefixes') 107 | ->will($this->returnValue(array('C' => array('src/c')))); 108 | 109 | ClassLoaderLocator::set(array( 110 | $classLoader0, 111 | $classLoader1, 112 | $classLoader2, 113 | )); 114 | 115 | $classLoaderLocator = new ClassLoaderLocator; 116 | 117 | $firstClassLoader = $classLoaderLocator->getFirstClassLoader(); 118 | $lastClassLoader = $classLoaderLocator->getLastClassLoader(); 119 | $allClassLoaders = $classLoaderLocator->getClassLoaders(); 120 | 121 | $this->assertEquals(array('A' => array('src/a')), $firstClassLoader->getPrefixes()); 122 | $this->assertEquals(array('C' => array('src/c')), $lastClassLoader->getPrefixes()); 123 | $this->assertCount(3, $allClassLoaders); 124 | 125 | $reader = $classLoaderLocator->getReader(); 126 | 127 | $this->assertInstanceOf('Dflydev\Composer\Autoload\CompositeClassLoaderReader', $reader); 128 | 129 | $prefixes = $reader->getPrefixes(); 130 | 131 | $this->assertEquals('src/a', $prefixes['A'][0]); 132 | $this->assertEquals('src/b', $prefixes['B'][0]); 133 | $this->assertEquals('src/c', $prefixes['C'][0]); 134 | 135 | $firstReader = $classLoaderLocator->getFirstReader(); 136 | $lastReader = $classLoaderLocator->getLastReader(); 137 | 138 | $this->assertEquals(array('A' => array('src/a')), $firstReader->getPrefixes()); 139 | $this->assertEquals(array('C' => array('src/c')), $lastReader->getPrefixes()); 140 | 141 | $readers = $classLoaderLocator->getReaders(); 142 | 143 | $this->assertCount(3, $readers); 144 | $this->assertEquals(array('A' => array('src/a')), $readers[0]->getPrefixes()); 145 | $this->assertEquals(array('B' => array('src/b')), $readers[1]->getPrefixes()); 146 | $this->assertEquals(array('C' => array('src/c')), $readers[2]->getPrefixes()); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /tests/Dflydev/Composer/Autoload/CompositeClassLoaderReaderTest.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class CompositeClassLoaderReaderTest extends \PHPUnit_Framework_TestCase 20 | { 21 | protected function createMockClassLoader($prefixes = null, $fallbackDirs = null, $classMap = null, $findFileReturnValueMap = null) 22 | { 23 | if (null === $prefixes) { 24 | $prefixes = array(); 25 | } 26 | 27 | if (null === $fallbackDirs) { 28 | $fallbackDirs = array(); 29 | } 30 | 31 | if (null === $classMap) { 32 | $classMap = array(); 33 | } 34 | 35 | $classLoader = $this->getMockBuilder('Composer\Autoload\ClassLoader') 36 | ->disableOriginalConstructor() 37 | ->getMock(); 38 | 39 | $classLoader 40 | ->expects($this->any()) 41 | ->method('getPrefixes') 42 | ->with() 43 | ->will($this->returnValue($prefixes)); 44 | 45 | $classLoader 46 | ->expects($this->any()) 47 | ->method('getFallbackDirs') 48 | ->with() 49 | ->will($this->returnValue($fallbackDirs)); 50 | 51 | $classLoader 52 | ->expects($this->any()) 53 | ->method('getClassMap') 54 | ->with() 55 | ->will($this->returnValue($classMap)); 56 | 57 | if ($findFileReturnValueMap) { 58 | $classLoader 59 | ->expects($this->any()) 60 | ->method('findFile') 61 | ->will($this->returnValueMap($findFileReturnValueMap)); 62 | } else { 63 | $classLoader 64 | ->expects($this->never()) 65 | ->method('findFile'); 66 | } 67 | 68 | return $classLoader; 69 | } 70 | 71 | /** 72 | * Test getters 73 | */ 74 | public function testGetters() 75 | { 76 | $classLoader0 = $this->createMockClassLoader(array( 77 | 'A\B\C' => array('vendor/vend-0/psr0-project/src/a/b/c'), 78 | ), array( 79 | 'vendor/vend-0/fallback-project/src', 80 | ), array( 81 | 'A\B\C\ClassMapped' => 'vendor/vend-0/psr0-project/src/a/b/c/ClassMapped.php' 82 | )); 83 | 84 | $classLoader1 = $this->createMockClassLoader(array( 85 | 'L\M\N' => array('vendor/vend-1/psr0-project/src/l/m/n'), 86 | ), array( 87 | 'vendor/vend-1/fallback-project/src', 88 | ), array( 89 | 'L\M\N\ClassMapped' => 'vendor/vend-1/psr0-project/src/l/m/n/ClassMapped.php' 90 | )); 91 | 92 | $classLoader2 = $this->createMockClassLoader(array( 93 | 'X\Y\Z' => array('vendor/vend-2/psr0-project/src/x/y/z'), 94 | ), array( 95 | 'vendor/vend-2/fallback-project/src', 96 | ), array( 97 | 'X\Y\Z\ClassMapped' => 'vendor/vend-2/psr0-project/src/x/y/z/ClassMapped.php' 98 | )); 99 | 100 | // Duplicate of $classLoader2 for testing uniqueness detection capabilities. 101 | $classLoader3 = $this->createMockClassLoader(array( 102 | 'L\M\N' => array('vendor/vend-1/psr0-project/src/l/m/n'), 103 | ), array( 104 | 'vendor/vend-1/fallback-project/src', 105 | ), array( 106 | 'L\M\N\ClassMapped' => 'vendor/vend-1/psr0-project/src/l/m/n/ClassMapped.php' 107 | )); 108 | 109 | $classLoader4 = $this->createMockClassLoader(array( 110 | 'L\M\N' => array('vendor/vend-1/psr0-project-additional/src/l/m/n'), 111 | ), array( 112 | 'vendor/vend-1/fallback-project-additional/src', 113 | ), array( 114 | 'L\M\N\ClassMapped' => 'vendor/vend-1/psr0-project-additional/src/l/m/n/ClassMapped.php' 115 | )); 116 | 117 | $classLoaderReader = new CompositeClassLoaderReader(array( 118 | $classLoader0, 119 | $classLoader1, 120 | $classLoader2, 121 | $classLoader3, 122 | $classLoader4, 123 | )); 124 | 125 | $prefixes = $classLoaderReader->getPrefixes(); 126 | $fallbackDirs = $classLoaderReader->getFallbackDirs(); 127 | $classMap = $classLoaderReader->getClassMap(); 128 | 129 | $this->assertCount(3, $prefixes); 130 | $this->assertCount(4, $fallbackDirs); 131 | $this->assertCount(3, $classMap); 132 | 133 | $this->assertCount(1, $prefixes['A\B\C']); 134 | $this->assertEquals('vendor/vend-0/psr0-project/src/a/b/c', $prefixes['A\B\C'][0]); 135 | 136 | $this->assertCount(2, $prefixes['L\M\N']); 137 | $this->assertEquals('vendor/vend-1/psr0-project/src/l/m/n', $prefixes['L\M\N'][0]); 138 | 139 | $this->assertCount(1, $prefixes['X\Y\Z']); 140 | $this->assertEquals('vendor/vend-2/psr0-project/src/x/y/z', $prefixes['X\Y\Z'][0]); 141 | 142 | $this->assertEquals(array( 143 | 'vendor/vend-0/fallback-project/src', 144 | 'vendor/vend-1/fallback-project/src', 145 | 'vendor/vend-2/fallback-project/src', 146 | 'vendor/vend-1/fallback-project-additional/src', 147 | ), $fallbackDirs); 148 | 149 | $this->assertEquals('vendor/vend-0/psr0-project/src/a/b/c/ClassMapped.php', $classMap['A\B\C\ClassMapped']); 150 | $this->assertEquals('vendor/vend-1/psr0-project/src/l/m/n/ClassMapped.php', $classMap['L\M\N\ClassMapped']); 151 | $this->assertEquals('vendor/vend-2/psr0-project/src/x/y/z/ClassMapped.php', $classMap['X\Y\Z\ClassMapped']); 152 | } 153 | 154 | /** 155 | * Test find files 156 | */ 157 | public function testFindFile() 158 | { 159 | $classLoader0 = $this->createMockClassLoader(null, null, null, array( 160 | array('A\B\C\Sample', 'vendor/vend-0/psr0-project/src/a/b/c/Sample.php'), 161 | )); 162 | 163 | $classLoader1 = $this->createMockClassLoader(null, null, null, array( 164 | array('L\M\N\Sample', 'vendor/vend-1/psr0-project/src/l/m/n/Sample.php'), 165 | )); 166 | 167 | $classLoader2 = $this->createMockClassLoader(null, null, null, array( 168 | array('X\Y\Z\Sample', 'vendor/vend-2/psr0-project/src/x/y/z/Sample.php'), 169 | )); 170 | 171 | $classLoaderReader = new CompositeClassLoaderReader(array( 172 | $classLoader0, 173 | $classLoader1, 174 | $classLoader2, 175 | )); 176 | 177 | $this->assertNull($classLoaderReader->findFile('A\B\C\Missing')); 178 | $this->assertEquals('vendor/vend-0/psr0-project/src/a/b/c/Sample.php', $classLoaderReader->findFile('A\B\C\Sample')); 179 | $this->assertEquals('vendor/vend-1/psr0-project/src/l/m/n/Sample.php', $classLoaderReader->findFile('L\M\N\Sample')); 180 | $this->assertEquals('vendor/vend-2/psr0-project/src/x/y/z/Sample.php', $classLoaderReader->findFile('X\Y\Z\Sample')); 181 | } 182 | } 183 | --------------------------------------------------------------------------------