From 4c0c206b600e4f3d560c3db5aefd3310a878a5b7 Mon Sep 17 00:00:00 2001 From: RWOverdijk Date: Thu, 9 Aug 2012 10:43:19 +0200 Subject: [PATCH 1/4] Reverted broken phar --- test/_files/PharModule.phar | Bin 6820 -> 6821 bytes test/_files/PharModuleExplicit.phar | Bin 6828 -> 6829 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/_files/PharModule.phar b/test/_files/PharModule.phar index 132592f8d04161fc04e14f85f15181830f1aa744..578440bf3ad02ac455440e708a3f780833f860b5 100644 GIT binary patch delta 60 zcmZ2ty3}-otP~^fWLYUq-e28qetHZH481kC>$Xh}mNJ!@C*@O{q*(B1`aQlQA|=!8 PYBE`zn1CwWoqU}Da=R1P delta 58 zcmZ2#y2NyYtkh&VDNSB`dwV}U1_lQE8v8o?$stmvGWJqFwMmKvKnXs3krI2mnoJfa LCZGy;CtoK3#%>Nr diff --git a/test/_files/PharModuleExplicit.phar b/test/_files/PharModuleExplicit.phar index 39ccedb03c25e2d1e9502c1e209eddf1b0793751..76bbab0d4b2737e81b0db2aa76c927c86c0bfdd0 100644 GIT binary patch delta 59 zcmZ2uy4G}qtP~^fWLYUq-iswu{LB~_7_2h|rM68Dma>yxXgPD8eD5pfKda_eq_A16 P|DJk@38=u`$=3-0Ll_hS delta 57 zcmZ2$y2f;atkh&VDNSDc5_>;01_lP}OhGC8$stm9()O12_VV`j%=Y&76)9{M_V%gv LOh5(hPQFe6qmd0W From 834024720b9443a5f0775c1dbe561b006be16ef0 Mon Sep 17 00:00:00 2001 From: Michel Hunziker Date: Fri, 31 Aug 2012 17:30:38 +0200 Subject: [PATCH 2/4] Add missing @throws annotations --- src/ClassMapAutoloader.php | 2 ++ src/PluginClassLoader.php | 1 + src/StandardAutoloader.php | 3 +++ 3 files changed, 6 insertions(+) diff --git a/src/ClassMapAutoloader.php b/src/ClassMapAutoloader.php index b8f61bf..ca3aa46 100644 --- a/src/ClassMapAutoloader.php +++ b/src/ClassMapAutoloader.php @@ -73,6 +73,7 @@ public function setOptions($options) * classname/file pairs. * * @param string|array $map + * @throws Exception\InvalidArgumentException * @return ClassMapAutoloader */ public function registerAutoloadMap($map) @@ -105,6 +106,7 @@ public function registerAutoloadMap($map) * Register many autoload maps at once * * @param array $locations + * @throws Exception\InvalidArgumentException * @return ClassMapAutoloader */ public function registerAutoloadMaps($locations) diff --git a/src/PluginClassLoader.php b/src/PluginClassLoader.php index 2cd353a..c2cd035 100644 --- a/src/PluginClassLoader.php +++ b/src/PluginClassLoader.php @@ -58,6 +58,7 @@ public function __construct($map = null) * A null value will clear the static map. * * @param null|array|Traversable $map + * @throws Exception\InvalidArgumentException * @return void */ public static function addStaticMap($map) diff --git a/src/StandardAutoloader.php b/src/StandardAutoloader.php index 92672ec..896b1c3 100644 --- a/src/StandardAutoloader.php +++ b/src/StandardAutoloader.php @@ -77,6 +77,7 @@ public function __construct($options = null) * * * @param array|\Traversable $options + * @throws Exception\InvalidArgumentException * @return StandardAutoloader */ public function setOptions($options) @@ -153,6 +154,7 @@ public function registerNamespace($namespace, $directory) * Register many namespace/directory pairs at once * * @param array $namespaces + * @throws Exception\InvalidArgumentException * @return StandardAutoloader */ public function registerNamespaces($namespaces) @@ -186,6 +188,7 @@ public function registerPrefix($prefix, $directory) * Register many namespace/directory pairs at once * * @param array $prefixes + * @throws Exception\InvalidArgumentException * @return StandardAutoloader */ public function registerPrefixes($prefixes) From 151de3067b31053577f347af2a8c73c4973f0126 Mon Sep 17 00:00:00 2001 From: Michel Hunziker Date: Fri, 31 Aug 2012 19:52:32 +0200 Subject: [PATCH 3/4] Resolve undefined classes in phpDoc --- src/AutoloaderFactory.php | 3 ++- src/ClassMapAutoloader.php | 6 ++++-- src/PluginClassLoader.php | 2 +- src/PluginClassLocator.php | 2 ++ src/SplAutoloader.php | 4 +++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/AutoloaderFactory.php b/src/AutoloaderFactory.php index 583ecf2..0b92fa0 100644 --- a/src/AutoloaderFactory.php +++ b/src/AutoloaderFactory.php @@ -11,6 +11,7 @@ namespace Zend\Loader; use ReflectionClass; +use Traversable; require_once __DIR__ . '/SplAutoloader.php'; @@ -74,7 +75,7 @@ public static function factory($options = null) return; } - if (!is_array($options) && !($options instanceof \Traversable)) { + if (!is_array($options) && !($options instanceof Traversable)) { require_once __DIR__ . '/Exception/InvalidArgumentException.php'; throw new Exception\InvalidArgumentException( 'Options provided must be an array or Traversable' diff --git a/src/ClassMapAutoloader.php b/src/ClassMapAutoloader.php index ca3aa46..0547f76 100644 --- a/src/ClassMapAutoloader.php +++ b/src/ClassMapAutoloader.php @@ -10,6 +10,8 @@ namespace Zend\Loader; +use Traversable; + // Grab SplAutoloader interface require_once __DIR__ . '/SplAutoloader.php'; @@ -40,7 +42,7 @@ class ClassMapAutoloader implements SplAutoloader * * Create a new instance, and optionally configure the autoloader. * - * @param null|array|\Traversable $options + * @param null|array|Traversable $options */ public function __construct($options = null) { @@ -111,7 +113,7 @@ public function registerAutoloadMap($map) */ public function registerAutoloadMaps($locations) { - if (!is_array($locations) && !($locations instanceof \Traversable)) { + if (!is_array($locations) && !($locations instanceof Traversable)) { require_once __DIR__ . '/Exception/InvalidArgumentException.php'; throw new Exception\InvalidArgumentException('Map list must be an array or implement Traversable'); } diff --git a/src/PluginClassLoader.php b/src/PluginClassLoader.php index c2cd035..58238c0 100644 --- a/src/PluginClassLoader.php +++ b/src/PluginClassLoader.php @@ -212,7 +212,7 @@ public function load($name) * Returns an instance of ArrayIterator, containing a map of * all plugins * - * @return Iterator + * @return ArrayIterator */ public function getIterator() { diff --git a/src/PluginClassLocator.php b/src/PluginClassLocator.php index 07401e3..a54eecd 100644 --- a/src/PluginClassLocator.php +++ b/src/PluginClassLocator.php @@ -10,6 +10,8 @@ namespace Zend\Loader; +use Traversable; + /** * Plugin class locator interface * diff --git a/src/SplAutoloader.php b/src/SplAutoloader.php index e9fb09f..e243d12 100644 --- a/src/SplAutoloader.php +++ b/src/SplAutoloader.php @@ -10,6 +10,8 @@ namespace Zend\Loader; +use Traversable; + if (interface_exists('Zend\Loader\SplAutoloader')) return; /** @@ -25,7 +27,7 @@ interface SplAutoloader * * Allow configuration of the autoloader via the constructor. * - * @param null|array|\Traversable $options + * @param null|array|Traversable $options */ public function __construct($options = null); From 6524484752e6e527a5dfa3963fd0e6a5028176c4 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Fri, 31 Aug 2012 14:44:59 -0500 Subject: [PATCH 4/4] [zendframework/zf2#2284][ZF2-507] Updated README - Notice about Date header --- .coveralls.yml | 3 + .gitattributes | 6 + .gitignore | 14 + .php_cs | 43 +++ .travis.yml | 35 ++ CONTRIBUTING.md | 229 ++++++++++++ LICENSE.txt | 27 ++ README.md | 7 + composer.json | 37 ++ phpunit.xml.dist | 68 ++++ phpunit.xml.travis | 68 ++++ src/AutoloaderFactory.php | 224 +++++++++++ src/ClassMapAutoloader.php | 217 +++++++++++ src/Exception/BadMethodCallException.php | 23 ++ src/Exception/DomainException.php | 21 ++ src/Exception/ExceptionInterface.php | 18 + src/Exception/InvalidArgumentException.php | 22 ++ src/Exception/InvalidPathException.php | 21 ++ .../MissingResourceNamespaceException.php | 22 ++ src/Exception/PluginLoaderException.php | 24 ++ src/Exception/RuntimeException.php | 21 ++ src/Exception/SecurityException.php | 21 ++ src/ModuleAutoloader.php | 353 ++++++++++++++++++ src/PluginClassLoader.php | 220 +++++++++++ src/PluginClassLocator.php | 45 +++ src/ShortNameLocator.php | 44 +++ src/SplAutoloader.php | 64 ++++ src/StandardAutoloader.php | 328 ++++++++++++++++ test/AutoloadDoesNotHideParseError.php | 15 + test/AutoloadableClass.php | 18 + test/AutoloaderFactoryTest.php | 198 ++++++++++ test/AutoloaderMultiVersionTest.php | 206 ++++++++++ test/ClassMapAutoloaderTest.php | 185 +++++++++ test/ModuleAutoloaderTest.php | 200 ++++++++++ test/MyLoader.php | 24 ++ test/MyOverloader.php | 34 ++ test/PluginClassLoaderTest.php | 266 +++++++++++++ test/StandardAutoloaderTest.php | 197 ++++++++++ test/TestAsset/ClassMappedClass.php | 27 ++ test/TestAsset/CustomClassLoader.php | 23 ++ test/TestAsset/ExtendedPluginClassLoader.php | 28 ++ .../TestAsset/Name_Space/Namespaced/Class.php | 21 ++ test/TestAsset/NamespacedClass.php | 21 ++ test/TestAsset/PrefixedClass.php | 19 + test/TestAsset/SamplePlugin.php | 27 ++ test/TestAsset/ServiceLocator.php | 37 ++ test/TestAsset/StandardAutoloader.php | 42 +++ test/TestAsset/TestNamespace/FallbackCase.php | 21 ++ .../NoDuplicateAutoloadersCase.php | 21 ++ test/TestAsset/TestPluginMap.php | 41 ++ test/TestAsset/TestPlugins/Bar.php | 21 ++ test/TestAsset/TestPlugins/Baz.php | 21 ++ test/TestAsset/TestPlugins/Foo.php | 21 ++ test/TestAsset/TestPlugins2/Foo.php | 21 ++ test/TestAsset/UnMappedClass.php | 21 ++ test/TestAsset/plugins/Baz.php | 23 ++ test/TestAsset/plugins/first/Bat.php | 23 ++ test/TestAsset/plugins/first/Foobar.php | 23 ++ test/TestAsset/plugins/second/Bat.php | 21 ++ test/TestAsset/plugins/second/Foobar.php | 23 ++ test/TestAsset/plugins/second/Foobarbaz.php | 19 + test/_files/AutoloaderClosure.php | 5 + test/_files/FooModule/Module.php | 15 + test/_files/FooModule/SubModule/Module.php | 15 + test/_files/InvalidInterfaceAutoloader.php | 4 + test/_files/NoModuleClassModule/Module.php | 2 + test/_files/NonmatchingModule/Module.php | 15 + test/_files/ParseError.php | 21 ++ test/_files/PharModule.phar | Bin 0 -> 6821 bytes test/_files/PharModuleBz2.phar.bz2 | Bin 0 -> 2690 bytes test/_files/PharModuleExplicit.phar | Bin 0 -> 6829 bytes test/_files/PharModuleFake.tar/readme | 2 + test/_files/PharModuleFake.zip | Bin 0 -> 175 bytes test/_files/PharModuleGz.phar.gz | Bin 0 -> 2529 bytes test/_files/PharModuleNested.tar.gz | Bin 0 -> 141 bytes test/_files/PharModuleNestedFake.tar.gz | Bin 0 -> 131 bytes test/_files/PharModulePharTar.phar.tar | Bin 0 -> 4096 bytes test/_files/PharModulePharTarBz2.phar.tar.bz2 | Bin 0 -> 318 bytes test/_files/PharModulePharTarGz.phar.tar.gz | Bin 0 -> 291 bytes test/_files/PharModulePharZip.phar.zip | Bin 0 -> 585 bytes test/_files/PharModuleTar.tar | Bin 0 -> 2048 bytes test/_files/PharModuleTarBz2.tar.bz2 | Bin 0 -> 145 bytes test/_files/PharModuleTarGz.tar.gz | Bin 0 -> 137 bytes test/_files/PharModuleZip.zip | Bin 0 -> 203 bytes test/_files/ZendLoaderAutoloader/Foo.php | 18 + test/_files/ZfTest/CacheTest.php | 20 + test/_files/ZfTest/FormSubmit.php | 20 + test/_files/Zfns/Foo.php | 15 + test/_files/_buildPhars.php | 77 ++++ test/_files/badmap.php | 2 + test/_files/classmap.phar | Bin 0 -> 6954 bytes test/_files/goodmap.php | 7 + test/bootstrap.php | 34 ++ 93 files changed, 4405 insertions(+) create mode 100644 .coveralls.yml create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .php_cs create mode 100644 .travis.yml create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 composer.json create mode 100644 phpunit.xml.dist create mode 100644 phpunit.xml.travis create mode 100644 src/AutoloaderFactory.php create mode 100644 src/ClassMapAutoloader.php create mode 100644 src/Exception/BadMethodCallException.php create mode 100644 src/Exception/DomainException.php create mode 100644 src/Exception/ExceptionInterface.php create mode 100644 src/Exception/InvalidArgumentException.php create mode 100644 src/Exception/InvalidPathException.php create mode 100644 src/Exception/MissingResourceNamespaceException.php create mode 100644 src/Exception/PluginLoaderException.php create mode 100644 src/Exception/RuntimeException.php create mode 100644 src/Exception/SecurityException.php create mode 100644 src/ModuleAutoloader.php create mode 100644 src/PluginClassLoader.php create mode 100644 src/PluginClassLocator.php create mode 100644 src/ShortNameLocator.php create mode 100644 src/SplAutoloader.php create mode 100644 src/StandardAutoloader.php create mode 100644 test/AutoloadDoesNotHideParseError.php create mode 100644 test/AutoloadableClass.php create mode 100644 test/AutoloaderFactoryTest.php create mode 100644 test/AutoloaderMultiVersionTest.php create mode 100644 test/ClassMapAutoloaderTest.php create mode 100644 test/ModuleAutoloaderTest.php create mode 100644 test/MyLoader.php create mode 100644 test/MyOverloader.php create mode 100644 test/PluginClassLoaderTest.php create mode 100644 test/StandardAutoloaderTest.php create mode 100644 test/TestAsset/ClassMappedClass.php create mode 100644 test/TestAsset/CustomClassLoader.php create mode 100644 test/TestAsset/ExtendedPluginClassLoader.php create mode 100644 test/TestAsset/Name_Space/Namespaced/Class.php create mode 100644 test/TestAsset/NamespacedClass.php create mode 100644 test/TestAsset/PrefixedClass.php create mode 100644 test/TestAsset/SamplePlugin.php create mode 100644 test/TestAsset/ServiceLocator.php create mode 100644 test/TestAsset/StandardAutoloader.php create mode 100644 test/TestAsset/TestNamespace/FallbackCase.php create mode 100644 test/TestAsset/TestNamespace/NoDuplicateAutoloadersCase.php create mode 100644 test/TestAsset/TestPluginMap.php create mode 100644 test/TestAsset/TestPlugins/Bar.php create mode 100644 test/TestAsset/TestPlugins/Baz.php create mode 100644 test/TestAsset/TestPlugins/Foo.php create mode 100644 test/TestAsset/TestPlugins2/Foo.php create mode 100644 test/TestAsset/UnMappedClass.php create mode 100644 test/TestAsset/plugins/Baz.php create mode 100644 test/TestAsset/plugins/first/Bat.php create mode 100644 test/TestAsset/plugins/first/Foobar.php create mode 100644 test/TestAsset/plugins/second/Bat.php create mode 100644 test/TestAsset/plugins/second/Foobar.php create mode 100644 test/TestAsset/plugins/second/Foobarbaz.php create mode 100644 test/_files/AutoloaderClosure.php create mode 100644 test/_files/FooModule/Module.php create mode 100644 test/_files/FooModule/SubModule/Module.php create mode 100644 test/_files/InvalidInterfaceAutoloader.php create mode 100644 test/_files/NoModuleClassModule/Module.php create mode 100644 test/_files/NonmatchingModule/Module.php create mode 100644 test/_files/ParseError.php create mode 100644 test/_files/PharModule.phar create mode 100644 test/_files/PharModuleBz2.phar.bz2 create mode 100644 test/_files/PharModuleExplicit.phar create mode 100644 test/_files/PharModuleFake.tar/readme create mode 100644 test/_files/PharModuleFake.zip create mode 100644 test/_files/PharModuleGz.phar.gz create mode 100644 test/_files/PharModuleNested.tar.gz create mode 100644 test/_files/PharModuleNestedFake.tar.gz create mode 100644 test/_files/PharModulePharTar.phar.tar create mode 100644 test/_files/PharModulePharTarBz2.phar.tar.bz2 create mode 100644 test/_files/PharModulePharTarGz.phar.tar.gz create mode 100644 test/_files/PharModulePharZip.phar.zip create mode 100644 test/_files/PharModuleTar.tar create mode 100644 test/_files/PharModuleTarBz2.tar.bz2 create mode 100644 test/_files/PharModuleTarGz.tar.gz create mode 100644 test/_files/PharModuleZip.zip create mode 100644 test/_files/ZendLoaderAutoloader/Foo.php create mode 100644 test/_files/ZfTest/CacheTest.php create mode 100644 test/_files/ZfTest/FormSubmit.php create mode 100644 test/_files/Zfns/Foo.php create mode 100644 test/_files/_buildPhars.php create mode 100644 test/_files/badmap.php create mode 100644 test/_files/classmap.phar create mode 100644 test/_files/goodmap.php create mode 100644 test/bootstrap.php diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 0000000..53bda82 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1,3 @@ +coverage_clover: clover.xml +json_path: coveralls-upload.json +src_dir: src diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..85dc9a8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +/test export-ignore +/vendor export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.travis.yml export-ignore +.php_cs export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4cac0a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.buildpath +.DS_Store +.idea +.project +.settings/ +.*.sw* +.*.un~ +nbproject +tmp/ + +clover.xml +coveralls-upload.json +phpunit.xml +vendor diff --git a/.php_cs b/.php_cs new file mode 100644 index 0000000..bf4b799 --- /dev/null +++ b/.php_cs @@ -0,0 +1,43 @@ +notPath('TestAsset') + ->notPath('_files') + ->filter(function (SplFileInfo $file) { + if (strstr($file->getPath(), 'compatibility')) { + return false; + } + }); +$config = Symfony\CS\Config\Config::create(); +$config->level(null); +$config->fixers( + array( + 'braces', + 'duplicate_semicolon', + 'elseif', + 'empty_return', + 'encoding', + 'eof_ending', + 'function_call_space', + 'function_declaration', + 'indentation', + 'join_function', + 'line_after_namespace', + 'linefeed', + 'lowercase_keywords', + 'parenthesis', + 'multiple_use', + 'method_argument_space', + 'object_operator', + 'php_closing_tag', + 'psr0', + 'remove_lines_between_uses', + 'short_tag', + 'standardize_not_equal', + 'trailing_spaces', + 'unused_use', + 'visibility', + 'whitespacy_lines', + ) +); +$config->finder($finder); +return $config; diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..fe909ec --- /dev/null +++ b/.travis.yml @@ -0,0 +1,35 @@ +sudo: false + +language: php + +matrix: + fast_finish: true + include: + - php: 5.5 + - php: 5.6 + env: + - EXECUTE_TEST_COVERALLS=true + - EXECUTE_CS_CHECK=true + - php: 7 + - php: hhvm + allow_failures: + - php: 7 + - php: hhvm + +notifications: + irc: "irc.freenode.org#zftalk.dev" + email: false + +before_install: + - if [[ $EXECUTE_TEST_COVERALLS != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi + +install: + - composer install --no-interaction --prefer-source + +script: + - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/phpunit -c phpunit.xml.travis --coverage-clover clover.xml ; fi + - if [[ $EXECUTE_TEST_COVERALLS != 'true' ]]; then ./vendor/bin/phpunit -c phpunit.xml.travis ; fi + - if [[ $EXECUTE_CS_CHECK == 'true' ]]; then ./vendor/bin/php-cs-fixer fix -v --diff --dry-run --config-file=.php_cs ; fi + +after_script: + - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/coveralls ; fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..db2149b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,229 @@ +# CONTRIBUTING + +## RESOURCES + +If you wish to contribute to Zend Framework, please be sure to +read/subscribe to the following resources: + + - [Coding Standards](https://github.com/zendframework/zf2/wiki/Coding-Standards) + - [Contributor's Guide](http://framework.zend.com/participate/contributor-guide) + - ZF Contributor's mailing list: + Archives: http://zend-framework-community.634137.n4.nabble.com/ZF-Contributor-f680267.html + Subscribe: zf-contributors-subscribe@lists.zend.com + - ZF Contributor's IRC channel: + #zftalk.dev on Freenode.net + +If you are working on new features or refactoring [create a proposal](https://github.com/zendframework/zend-loader/issues/new). + +## Reporting Potential Security Issues + +If you have encountered a potential security vulnerability, please **DO NOT** report it on the public +issue tracker: send it to us at [zf-security@zend.com](mailto:zf-security@zend.com) instead. +We will work with you to verify the vulnerability and patch it as soon as possible. + +When reporting issues, please provide the following information: + +- Component(s) affected +- A description indicating how to reproduce the issue +- A summary of the security vulnerability and impact + +We request that you contact us via the email address above and give the project +contributors a chance to resolve the vulnerability and issue a new release prior +to any public exposure; this helps protect users and provides them with a chance +to upgrade and/or update in order to protect their applications. + +For sensitive email communications, please use [our PGP key](http://framework.zend.com/zf-security-pgp-key.asc). + +## RUNNING TESTS + +> ### Note: testing versions prior to 2.4 +> +> This component originates with Zend Framework 2. During the lifetime of ZF2, +> testing infrastructure migrated from PHPUnit 3 to PHPUnit 4. In most cases, no +> changes were necessary. However, due to the migration, tests may not run on +> versions < 2.4. As such, you may need to change the PHPUnit dependency if +> attempting a fix on such a version. + +To run tests: + +- Clone the repository: + + ```console + $ git clone git@github.com:zendframework/zend-loader.git + $ cd + ``` + +- Install dependencies via composer: + + ```console + $ curl -sS https://getcomposer.org/installer | php -- + $ ./composer.phar install + ``` + + If you don't have `curl` installed, you can also download `composer.phar` from https://getcomposer.org/ + +- Run the tests via `phpunit` and the provided PHPUnit config, like in this example: + + ```console + $ ./vendor/bin/phpunit + ``` + +You can turn on conditional tests with the phpunit.xml file. +To do so: + + - Copy `phpunit.xml.dist` file to `phpunit.xml` + - Edit `phpunit.xml` to enable any specific functionality you + want to test, as well as to provide test values to utilize. + +## Running Coding Standards Checks + +This component uses [php-cs-fixer](http://cs.sensiolabs.org/) for coding +standards checks, and provides configuration for our selected checks. +`php-cs-fixer` is installed by default via Composer. + +To run checks only: + +```console +$ ./vendor/bin/php-cs-fixer fix . -v --diff --dry-run --config-file=.php_cs +``` + +To have `php-cs-fixer` attempt to fix problems for you, omit the `--dry-run` +flag: + +```console +$ ./vendor/bin/php-cs-fixer fix . -v --diff --config-file=.php_cs +``` + +If you allow php-cs-fixer to fix CS issues, please re-run the tests to ensure +they pass, and make sure you add and commit the changes after verification. + +## Recommended Workflow for Contributions + +Your first step is to establish a public repository from which we can +pull your work into the master repository. We recommend using +[GitHub](https://github.com), as that is where the component is already hosted. + +1. Setup a [GitHub account](http://github.com/), if you haven't yet +2. Fork the repository (http://github.com/zendframework/zend-loader) +3. Clone the canonical repository locally and enter it. + + ```console + $ git clone git://github.com:zendframework/zend-loader.git + $ cd zend-loader + ``` + +4. Add a remote to your fork; substitute your GitHub username in the command + below. + + ```console + $ git remote add {username} git@github.com:{username}/zend-loader.git + $ git fetch {username} + ``` + +### Keeping Up-to-Date + +Periodically, you should update your fork or personal repository to +match the canonical ZF repository. Assuming you have setup your local repository +per the instructions above, you can do the following: + + +```console +$ git checkout master +$ git fetch origin +$ git rebase origin/master +# OPTIONALLY, to keep your remote up-to-date - +$ git push {username} master:master +``` + +If you're tracking other branches -- for example, the "develop" branch, where +new feature development occurs -- you'll want to do the same operations for that +branch; simply substitute "develop" for "master". + +### Working on a patch + +We recommend you do each new feature or bugfix in a new branch. This simplifies +the task of code review as well as the task of merging your changes into the +canonical repository. + +A typical workflow will then consist of the following: + +1. Create a new local branch based off either your master or develop branch. +2. Switch to your new local branch. (This step can be combined with the + previous step with the use of `git checkout -b`.) +3. Do some work, commit, repeat as necessary. +4. Push the local branch to your remote repository. +5. Send a pull request. + +The mechanics of this process are actually quite trivial. Below, we will +create a branch for fixing an issue in the tracker. + +```console +$ git checkout -b hotfix/9295 +Switched to a new branch 'hotfix/9295' +``` + +... do some work ... + + +```console +$ git commit +``` + +... write your log message ... + + +```console +$ git push {username} hotfix/9295:hotfix/9295 +Counting objects: 38, done. +Delta compression using up to 2 threads. +Compression objects: 100% (18/18), done. +Writing objects: 100% (20/20), 8.19KiB, done. +Total 20 (delta 12), reused 0 (delta 0) +To ssh://git@github.com/{username}/zend-loader.git + b5583aa..4f51698 HEAD -> master +``` + +To send a pull request, you have two options. + +If using GitHub, you can do the pull request from there. Navigate to +your repository, select the branch you just created, and then select the +"Pull Request" button in the upper right. Select the user/organization +"zendframework" as the recipient. + +If using your own repository - or even if using GitHub - you can use `git +format-patch` to create a patchset for us to apply; in fact, this is +**recommended** for security-related patches. If you use `format-patch`, please +send the patches as attachments to: + +- zf-devteam@zend.com for patches without security implications +- zf-security@zend.com for security patches + +#### What branch to issue the pull request against? + +Which branch should you issue a pull request against? + +- For fixes against the stable release, issue the pull request against the + "master" branch. +- For new features, or fixes that introduce new elements to the public API (such + as new public methods or properties), issue the pull request against the + "develop" branch. + +### Branch Cleanup + +As you might imagine, if you are a frequent contributor, you'll start to +get a ton of branches both locally and on your remote. + +Once you know that your changes have been accepted to the master +repository, we suggest doing some cleanup of these branches. + +- Local branch cleanup + + ```console + $ git branch -d + ``` + +- Remote branch removal + + ```console + $ git push {username} : + ``` diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..6eab5aa --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2005-2015, Zend Technologies USA, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Zend Technologies USA, Inc. nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c6ba05 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# zend-loader + +`Zend\Loader` provides different strategies for autoloading PHP classes. + + +- File issues at https://github.com/zendframework/zend-loader/issues +- Documentation is at http://framework.zend.com/manual/current/en/index.html#zend-loader diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..0545920 --- /dev/null +++ b/composer.json @@ -0,0 +1,37 @@ +{ + "name": "zendframework/zend-loader", + "description": " ", + "license": "BSD-3-Clause", + "keywords": [ + "zf2", + "loader" + ], + "homepage": "https://github.com/zendframework/zend-loader", + "autoload": { + "psr-4": { + "Zend\\Loader": "src/" + } + }, + "require": { + "php": ">=5.3.3" + }, + "extra": { + "branch-alias": { + "dev-master": "2.4-dev", + "dev-develop": "2.5-dev" + } + }, + "suggest": { + "zendframework/zend-stdlib": "Zend\\Stdlib component" + }, + "autoload-dev": { + "psr-4": { + "ZendTest\\Loader\\": "test/" + } + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "satooshi/php-coveralls": "dev-master", + "phpunit/PHPUnit": "~4.0" + } +} \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..5bffa08 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,68 @@ + + + + + ./test/ + + + + + + disable + + + + + + ./src + + + + + + + + + + + + + + + + + + diff --git a/phpunit.xml.travis b/phpunit.xml.travis new file mode 100644 index 0000000..5bffa08 --- /dev/null +++ b/phpunit.xml.travis @@ -0,0 +1,68 @@ + + + + + ./test/ + + + + + + disable + + + + + + ./src + + + + + + + + + + + + + + + + + + diff --git a/src/AutoloaderFactory.php b/src/AutoloaderFactory.php new file mode 100644 index 0000000..583ecf2 --- /dev/null +++ b/src/AutoloaderFactory.php @@ -0,0 +1,224 @@ + + * array( + * '' => $autoloaderOptions, + * ) + * + * + * The factory will then loop through and instantiate each autoloader with + * the specified options, and register each with the spl_autoloader. + * + * You may retrieve the concrete autoloader instances later using + * {@link getRegisteredAutoloaders()}. + * + * Note that the class names must be resolvable on the include_path or via + * the Zend library, using PSR-0 rules (unless the class has already been + * loaded). + * + * @param array|Traversable $options (optional) options to use. Defaults to Zend\Loader\StandardAutoloader + * @return void + * @throws Exception\InvalidArgumentException for invalid options + * @throws Exception\InvalidArgumentException for unloadable autoloader classes + * @throws Exception\DomainException for autoloader classes not implementing SplAutoloader + */ + public static function factory($options = null) + { + if (null === $options) { + if (!isset(static::$loaders[static::STANDARD_AUTOLOADER])) { + $autoloader = static::getStandardAutoloader(); + $autoloader->register(); + static::$loaders[static::STANDARD_AUTOLOADER] = $autoloader; + } + + // Return so we don't hit the next check's exception (we're done here anyway) + return; + } + + if (!is_array($options) && !($options instanceof \Traversable)) { + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException( + 'Options provided must be an array or Traversable' + ); + } + + foreach ($options as $class => $options) { + if (!isset(static::$loaders[$class])) { + $autoloader = static::getStandardAutoloader(); + if (!class_exists($class) && !$autoloader->autoload($class)) { + require_once 'Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException( + sprintf('Autoloader class "%s" not loaded', $class) + ); + } + + if (!self::isSubclassOf($class, 'Zend\Loader\SplAutoloader')) { + require_once 'Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException( + sprintf('Autoloader class %s must implement Zend\\Loader\\SplAutoloader', $class) + ); + } + + if ($class === static::STANDARD_AUTOLOADER) { + $autoloader->setOptions($options); + } else { + $autoloader = new $class($options); + } + $autoloader->register(); + static::$loaders[$class] = $autoloader; + } else { + static::$loaders[$class]->setOptions($options); + } + } + } + + /** + * Get an list of all autoloaders registered with the factory + * + * Returns an array of autoloader instances. + * + * @return array + */ + public static function getRegisteredAutoloaders() + { + return static::$loaders; + } + + /** + * Retrieves an autoloader by class name + * + * @param string $class + * @return SplAutoloader + * @throws Exception\InvalidArgumentException for non-registered class + */ + public static function getRegisteredAutoloader($class) + { + if (!isset(static::$loaders[$class])) { + require_once 'Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException(sprintf('Autoloader class "%s" not loaded', $class)); + } + return static::$loaders[$class]; + } + + /** + * Unregisters all autoloaders that have been registered via the factory. + * This will NOT unregister autoloaders registered outside of the fctory. + * + * @return void + */ + public static function unregisterAutoloaders() + { + foreach (static::getRegisteredAutoloaders() as $class => $autoloader) { + spl_autoload_unregister(array($autoloader, 'autoload')); + unset(static::$loaders[$class]); + } + } + + /** + * Unregister a single autoloader by class name + * + * @param string $autoloaderClass + * @return bool + */ + public static function unregisterAutoloader($autoloaderClass) + { + if (!isset(static::$loaders[$autoloaderClass])) { + return false; + } + + $autoloader = static::$loaders[$autoloaderClass]; + spl_autoload_unregister(array($autoloader, 'autoload')); + unset(static::$loaders[$autoloaderClass]); + return true; + } + + /** + * Get an instance of the standard autoloader + * + * Used to attempt to resolve autoloader classes, using the + * StandardAutoloader. The instance is marked as a fallback autoloader, to + * allow resolving autoloaders not under the "Zend" namespace. + * + * @return SplAutoloader + */ + protected static function getStandardAutoloader() + { + if (null !== static::$standardAutoloader) { + return static::$standardAutoloader; + } + + + if (!class_exists(static::STANDARD_AUTOLOADER)) { + // Extract the filename from the classname + $stdAutoloader = substr(strrchr(static::STANDARD_AUTOLOADER, '\\'), 1); + require_once __DIR__ . "/$stdAutoloader.php"; + } + $loader = new StandardAutoloader(); + static::$standardAutoloader = $loader; + return static::$standardAutoloader; + } + + /** + * Checks if the object has this class as one of its parents + * + * @see https://bugs.php.net/bug.php?id=53727 + * @see https://github.com/zendframework/zf2/pull/1807 + * + * @param string $className + * @param string $type + * @return bool + */ + protected static function isSubclassOf($className, $type) + { + if (is_subclass_of($className, $type)) { + return true; + } + if (version_compare(PHP_VERSION, '5.3.7', '>=')) { + return false; + } + if (!interface_exists($type)) { + return false; + } + $r = new ReflectionClass($className); + return $r->implementsInterface($type); + } +} diff --git a/src/ClassMapAutoloader.php b/src/ClassMapAutoloader.php new file mode 100644 index 0000000..b8f61bf --- /dev/null +++ b/src/ClassMapAutoloader.php @@ -0,0 +1,217 @@ +setOptions($options); + } + } + + /** + * Configure the autoloader + * + * Proxies to {@link registerAutoloadMaps()}. + * + * @param array|Traversable $options + * @return ClassMapAutoloader + */ + public function setOptions($options) + { + $this->registerAutoloadMaps($options); + return $this; + } + + /** + * Register an autoload map + * + * An autoload map may be either an associative array, or a file returning + * an associative array. + * + * An autoload map should be an associative array containing + * classname/file pairs. + * + * @param string|array $map + * @return ClassMapAutoloader + */ + public function registerAutoloadMap($map) + { + if (is_string($map)) { + $location = $map; + if ($this === ($map = $this->loadMapFromFile($location))) { + return $this; + } + } + + if (!is_array($map)) { + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException(sprintf( + 'Map file provided does not return a map. Map file: "%s"', + (isset($location) && is_string($location) ? $location : 'unexpected type: ' . gettype($map)) + )); + } + + $this->map = array_merge($this->map, $map); + + if (isset($location)) { + $this->mapsLoaded[] = $location; + } + + return $this; + } + + /** + * Register many autoload maps at once + * + * @param array $locations + * @return ClassMapAutoloader + */ + public function registerAutoloadMaps($locations) + { + if (!is_array($locations) && !($locations instanceof \Traversable)) { + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException('Map list must be an array or implement Traversable'); + } + foreach ($locations as $location) { + $this->registerAutoloadMap($location); + } + return $this; + } + + /** + * Retrieve current autoload map + * + * @return array + */ + public function getAutoloadMap() + { + return $this->map; + } + + /** + * Defined by Autoloadable + * + * @param string $class + * @return void + */ + public function autoload($class) + { + if (isset($this->map[$class])) { + require_once $this->map[$class]; + } + } + + /** + * Register the autoloader with spl_autoload registry + * + * @return void + */ + public function register() + { + spl_autoload_register(array($this, 'autoload'), true, true); + } + + /** + * Load a map from a file + * + * If the map has been previously loaded, returns the current instance; + * otherwise, returns whatever was returned by calling include() on the + * location. + * + * @param string $location + * @return ClassMapAutoloader|mixed + * @throws Exception\InvalidArgumentException for nonexistent locations + */ + protected function loadMapFromFile($location) + { + if (!file_exists($location)) { + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException(sprintf( + 'Map file provided does not exist. Map file: "%s"', + (is_string($location) ? $location : 'unexpected type: ' . gettype($location)) + )); + } + + if (!$path = static::realPharPath($location)) { + $path = realpath($location); + } + + if (in_array($path, $this->mapsLoaded)) { + // Already loaded this map + return $this; + } + + $map = include $path; + + return $map; + } + + /** + * Resolve the real_path() to a file within a phar. + * + * @see https://bugs.php.net/bug.php?id=52769 + * @param string $path + * @return string + */ + public static function realPharPath($path) + { + if (strpos($path, 'phar:///') !== 0) { + return; + } + + $parts = explode('/', str_replace(array('/','\\'), '/', substr($path, 8))); + $parts = array_values(array_filter($parts, function($p) { return ($p !== '' && $p !== '.'); })); + + array_walk($parts, function ($value, $key) use(&$parts) { + if ($value === '..') { + unset($parts[$key], $parts[$key-1]); + $parts = array_values($parts); + } + }); + + if (file_exists($realPath = 'phar:///' . implode('/', $parts))) { + return $realPath; + } + } +} diff --git a/src/Exception/BadMethodCallException.php b/src/Exception/BadMethodCallException.php new file mode 100644 index 0000000..3366d5a --- /dev/null +++ b/src/Exception/BadMethodCallException.php @@ -0,0 +1,23 @@ + path + */ + protected $explicitPaths = array(); + + /** + * @var array An array of supported phar extensions (filled on constructor) + */ + protected $pharExtensions = array(); + + /** + * @var array An array of module classes to their containing files + */ + protected $moduleClassMap = array(); + + /** + * Constructor + * + * Allow configuration of the autoloader via the constructor. + * + * @param null|array|Traversable $options + */ + public function __construct($options = null) + { + if (extension_loaded('phar')) { + $this->pharExtensions = array( + 'phar', + 'phar.tar', + 'tar', + ); + + // ext/zlib enabled -> phar can read gzip & zip compressed files + if (extension_loaded('zlib')) { + $this->pharExtensions[] = 'phar.gz'; + $this->pharExtensions[] = 'phar.tar.gz'; + $this->pharExtensions[] = 'tar.gz'; + + $this->pharExtensions[] = 'phar.zip'; + $this->pharExtensions[] = 'zip'; + } + + // ext/bzip2 enabled -> phar can read bz2 compressed files + if (extension_loaded('bzip2')) { + $this->pharExtensions[] = 'phar.bz2'; + $this->pharExtensions[] = 'phar.tar.bz2'; + $this->pharExtensions[] = 'tar.bz2'; + } + } + + if (null !== $options) { + $this->setOptions($options); + } + } + + /** + * Configure the autoloader + * + * In most cases, $options should be either an associative array or + * Traversable object. + * + * @param array|Traversable $options + * @return SplAutoloader + */ + public function setOptions($options) + { + $this->registerPaths($options); + return $this; + } + + /** + * Autoload a class + * + * @param $class + * @return mixed + * False [if unable to load $class] + * get_class($class) [if $class is successfully loaded] + */ + public function autoload($class) + { + // Limit scope of this autoloader + if (substr($class, -7) !== '\Module') { + return false; + } + + $moduleName = substr($class, 0, -7); + if (isset($this->explicitPaths[$moduleName])) { + $classLoaded = $this->loadModuleFromDir($this->explicitPaths[$moduleName], $class); + if ($classLoaded) { + return $classLoaded; + } + + $classLoaded = $this->loadModuleFromPhar($this->explicitPaths[$moduleName], $class); + if ($classLoaded) { + return $classLoaded; + } + } + + $moduleClassPath = str_replace('\\', DIRECTORY_SEPARATOR, $moduleName); + + $pharSuffixPattern = null; + if ($this->pharExtensions) { + $pharSuffixPattern = '(' . implode('|', array_map('preg_quote', $this->pharExtensions)) . ')'; + } + + foreach ($this->paths as $path) { + $path = $path . $moduleClassPath; + + $classLoaded = $this->loadModuleFromDir($path, $class); + if ($classLoaded) { + return $classLoaded; + } + + // No directory with Module.php, searching for phars + if ($pharSuffixPattern) { + foreach (new GlobIterator($path . '.*') as $entry) { + if ($entry->isDir()) { + continue; + } + + if (!preg_match('#.+\.' . $pharSuffixPattern . '$#', $entry->getPathname())) { + continue; + } + + $classLoaded = $this->loadModuleFromPhar($entry->getPathname(), $class); + if ($classLoaded) { + return $classLoaded; + } + } + } + } + + return false; + } + + /** + * loadModuleFromDir + * + * @param string $dirPath + * @param string $class + * @return mixed + * False [if unable to load $class] + * get_class($class) [if $class is successfully loaded] + */ + protected function loadModuleFromDir($dirPath, $class) + { + $file = new SplFileInfo($dirPath . '/Module.php'); + if ($file->isReadable() && $file->isFile()) { + // Found directory with Module.php in it + require_once $file->getRealPath(); + if (class_exists($class)) { + $this->moduleClassMap[$class] = $file->getRealPath(); + return $class; + } + } + return false; + } + + /** + * loadModuleFromPhar + * + * @param string $pharPath + * @param string $class + * @return mixed + * False [if unable to load $class] + * get_class($class) [if $class is successfully loaded] + */ + protected function loadModuleFromPhar($pharPath, $class) + { + $pharPath = static::normalizePath($pharPath, false); + $file = new SplFileInfo($pharPath); + if (!$file->isReadable() || !$file->isFile()) { + return false; + } + + $fileRealPath = $file->getRealPath(); + + // Phase 0: Check for executable phar with Module class in stub + if (strpos($fileRealPath, '.phar') !== false) { + // First see if the stub makes the Module class available + require_once $fileRealPath; + if (class_exists($class)) { + $this->moduleClassMap[$class] = $fileRealPath; + return $class; + } + } + + // Phase 1: Not executable phar, no stub, or stub did not provide Module class; try Module.php directly + $moduleClassFile = 'phar://' . $fileRealPath . '/Module.php'; + $moduleFile = new SplFileInfo($moduleClassFile); + if ($moduleFile->isReadable() && $moduleFile->isFile()) { + require_once $moduleClassFile; + if (class_exists($class)) { + $this->moduleClassMap[$class] = $moduleClassFile; + return $class; + } + } + + // Phase 2: Check for nested module directory within archive + // Checks for /path/to/MyModule.tar/MyModule/Module.php + // (shell-integrated zip/tar utilities wrap directories like this) + $pharBaseName = $this->pharFileToModuleName($fileRealPath); + $moduleClassFile = 'phar://' . $fileRealPath . '/' . $pharBaseName . '/Module.php'; + $moduleFile = new SplFileInfo($moduleClassFile); + if ($moduleFile->isReadable() && $moduleFile->isFile()) { + require_once $moduleClassFile; + if (class_exists($class)) { + $this->moduleClassMap[$class] = $moduleClassFile; + return $class; + } + } + + return false; + } + + /** + * Register the autoloader with spl_autoload registry + * + * @return void + */ + public function register() + { + spl_autoload_register(array($this, 'autoload')); + } + + /** + * Unregister the autoloader with spl_autoload registry + * + * @return void + */ + public function unregister() + { + $test = spl_autoload_unregister(array($this, 'autoload')); + } + + /** + * registerPaths + * + * @param array|Traversable $paths + * @return ModuleLoader + */ + public function registerPaths($paths) + { + if (!is_array($paths) && !$paths instanceof Traversable) { + throw new \InvalidArgumentException( + 'Parameter to \\Zend\\Loader\\ModuleAutoloader\'s ' + . 'registerPaths method must be an array or ' + . 'implement the \\Traversable interface' + ); + } + + foreach ($paths as $module => $path) { + if (is_string($module)) { + $this->registerPath($path, $module); + } else { + $this->registerPath($path); + } + } + + return $this; + } + + /** + * registerPath + * + * @param string $path + * @param string $moduleName + * @return ModuleLoader + */ + public function registerPath($path, $moduleName = false) + { + if (!is_string($path)) { + throw new \InvalidArgumentException(sprintf( + 'Invalid path provided; must be a string, received %s', + gettype($path) + )); + } + if ($moduleName) { + $this->explicitPaths[$moduleName] = static::normalizePath($path); + } else { + $this->paths[] = static::normalizePath($path); + } + return $this; + } + + /** + * getPaths + * + * This is primarily for unit testing, but could have other uses. + * + * @return array + */ + public function getPaths() + { + return $this->paths; + } + + /** + * Returns the base module name from the path to a phar + * + * @param string $pharPath + * @return string + */ + protected function pharFileToModuleName($pharPath) + { + do { + $pathinfo = pathinfo($pharPath); + $pharPath = $pathinfo['filename']; + } while (isset($pathinfo['extension'])); + return $pathinfo['filename']; + } + + /** + * Normalize a path for insertion in the stack + * + * @param string $path + * @return string + */ + public static function normalizePath($path, $trailingSlash = true) + { + $path = rtrim($path, '/'); + $path = rtrim($path, '\\'); + if ($trailingSlash) { + $path .= DIRECTORY_SEPARATOR; + } + return $path; + } +} diff --git a/src/PluginClassLoader.php b/src/PluginClassLoader.php new file mode 100644 index 0000000..2cd353a --- /dev/null +++ b/src/PluginClassLoader.php @@ -0,0 +1,220 @@ + class name pairs + * @var array + */ + protected $plugins = array(); + + /** + * Static map allow global seeding of plugin loader + * @var array + */ + protected static $staticMap = array(); + + /** + * Constructor + * + * @param null|array|Traversable $map If provided, seeds the loader with a map + */ + public function __construct($map = null) + { + // Merge in static overrides + if (!empty(static::$staticMap)) { + $this->registerPlugins(static::$staticMap); + } + + // Merge in constructor arguments + if ($map !== null) { + $this->registerPlugins($map); + } + } + + /** + * Add a static map of plugins + * + * A null value will clear the static map. + * + * @param null|array|Traversable $map + * @return void + */ + public static function addStaticMap($map) + { + if (null === $map) { + static::$staticMap = array(); + return; + } + + if (!is_array($map) && !$map instanceof \Traversable) { + throw new Exception\InvalidArgumentException('Expects an array or Traversable object'); + } + foreach ($map as $key => $value) { + static::$staticMap[$key] = $value; + } + } + + /** + * Register a class to a given short name + * + * @param string $shortName + * @param string $className + * @return PluginClassLoader + */ + public function registerPlugin($shortName, $className) + { + $this->plugins[strtolower($shortName)] = $className; + return $this; + } + + /** + * Register many plugins at once + * + * If $map is a string, assumes that the map is the class name of a + * Traversable object (likely a ShortNameLocator); it will then instantiate + * this class and use it to register plugins. + * + * If $map is an array or Traversable object, it will iterate it to + * register plugin names/classes. + * + * For all other arguments, or if the string $map is not a class or not a + * Traversable class, an exception will be raised. + * + * @param string|array|Traversable $map + * @return PluginClassLoader + * @throws Exception\InvalidArgumentException + */ + public function registerPlugins($map) + { + if (is_string($map)) { + if (!class_exists($map)) { + throw new Exception\InvalidArgumentException('Map class provided is invalid'); + } + $map = new $map; + } + if (is_array($map)) { + $map = new ArrayIterator($map); + } + if (!$map instanceof Traversable) { + throw new Exception\InvalidArgumentException('Map provided is invalid; must be traversable'); + } + + // iterator_apply doesn't work as expected with IteratorAggregate + if ($map instanceof IteratorAggregate) { + $map = $map->getIterator(); + } + + foreach ($map as $name => $class) { + if (is_int($name) || is_numeric($name)) { + if (!is_object($class) && class_exists($class)) { + $class = new $class(); + } + + if ($class instanceof Traversable) { + $this->registerPlugins($class); + continue; + } + } + + $this->registerPlugin($name, $class); + } + + return $this; + } + + /** + * Unregister a short name lookup + * + * @param mixed $shortName + * @return PluginClassLoader + */ + public function unregisterPlugin($shortName) + { + $lookup = strtolower($shortName); + if (array_key_exists($lookup, $this->plugins)) { + unset($this->plugins[$lookup]); + } + return $this; + } + + /** + * Get a list of all registered plugins + * + * @return array|Traversable + */ + public function getRegisteredPlugins() + { + return $this->plugins; + } + + /** + * Whether or not a plugin by a specific name has been registered + * + * @param string $name + * @return bool + */ + public function isLoaded($name) + { + $lookup = strtolower($name); + return isset($this->plugins[$lookup]); + } + + /** + * Return full class name for a named helper + * + * @param string $name + * @return string|false + */ + public function getClassName($name) + { + return $this->load($name); + } + + /** + * Load a helper via the name provided + * + * @param string $name + * @return string|false + */ + public function load($name) + { + if (!$this->isLoaded($name)) { + return false; + } + return $this->plugins[strtolower($name)]; + } + + /** + * Defined by IteratorAggregate + * + * Returns an instance of ArrayIterator, containing a map of + * all plugins + * + * @return Iterator + */ + public function getIterator() + { + return new ArrayIterator($this->plugins); + } +} diff --git a/src/PluginClassLocator.php b/src/PluginClassLocator.php new file mode 100644 index 0000000..07401e3 --- /dev/null +++ b/src/PluginClassLocator.php @@ -0,0 +1,45 @@ + + * spl_autoload_register(array($this, 'autoload')); + * + * + * @return void + */ + public function register(); +} diff --git a/src/StandardAutoloader.php b/src/StandardAutoloader.php new file mode 100644 index 0000000..92672ec --- /dev/null +++ b/src/StandardAutoloader.php @@ -0,0 +1,328 @@ +setOptions($options); + } + } + + /** + * Configure autoloader + * + * Allows specifying both "namespace" and "prefix" pairs, using the + * following structure: + * + * array( + * 'namespaces' => array( + * 'Zend' => '/path/to/Zend/library', + * 'Doctrine' => '/path/to/Doctrine/library', + * ), + * 'prefixes' => array( + * 'Phly_' => '/path/to/Phly/library', + * ), + * 'fallback_autoloader' => true, + * ) + * + * + * @param array|\Traversable $options + * @return StandardAutoloader + */ + public function setOptions($options) + { + if (!is_array($options) && !($options instanceof \Traversable)) { + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException('Options must be either an array or Traversable'); + } + + foreach ($options as $type => $pairs) { + switch ($type) { + case self::AUTOREGISTER_ZF: + if ($pairs) { + $this->registerNamespace('Zend', dirname(__DIR__)); + } + break; + case self::LOAD_NS: + if (is_array($pairs) || $pairs instanceof \Traversable) { + $this->registerNamespaces($pairs); + } + break; + case self::LOAD_PREFIX: + if (is_array($pairs) || $pairs instanceof \Traversable) { + $this->registerPrefixes($pairs); + } + break; + case self::ACT_AS_FALLBACK: + $this->setFallbackAutoloader($pairs); + break; + default: + // ignore + } + } + return $this; + } + + /** + * Set flag indicating fallback autoloader status + * + * @param bool $flag + * @return StandardAutoloader + */ + public function setFallbackAutoloader($flag) + { + $this->fallbackAutoloaderFlag = (bool) $flag; + return $this; + } + + /** + * Is this autoloader acting as a fallback autoloader? + * + * @return bool + */ + public function isFallbackAutoloader() + { + return $this->fallbackAutoloaderFlag; + } + + /** + * Register a namespace/directory pair + * + * @param string $namespace + * @param string $directory + * @return StandardAutoloader + */ + public function registerNamespace($namespace, $directory) + { + $namespace = rtrim($namespace, self::NS_SEPARATOR). self::NS_SEPARATOR; + $this->namespaces[$namespace] = $this->normalizeDirectory($directory); + return $this; + } + + /** + * Register many namespace/directory pairs at once + * + * @param array $namespaces + * @return StandardAutoloader + */ + public function registerNamespaces($namespaces) + { + if (!is_array($namespaces) && !$namespaces instanceof \Traversable) { + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException('Namespace pairs must be either an array or Traversable'); + } + + foreach ($namespaces as $namespace => $directory) { + $this->registerNamespace($namespace, $directory); + } + return $this; + } + + /** + * Register a prefix/directory pair + * + * @param string $prefix + * @param string $directory + * @return StandardAutoloader + */ + public function registerPrefix($prefix, $directory) + { + $prefix = rtrim($prefix, self::PREFIX_SEPARATOR). self::PREFIX_SEPARATOR; + $this->prefixes[$prefix] = $this->normalizeDirectory($directory); + return $this; + } + + /** + * Register many namespace/directory pairs at once + * + * @param array $prefixes + * @return StandardAutoloader + */ + public function registerPrefixes($prefixes) + { + if (!is_array($prefixes) && !$prefixes instanceof \Traversable) { + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException('Prefix pairs must be either an array or Traversable'); + } + + foreach ($prefixes as $prefix => $directory) { + $this->registerPrefix($prefix, $directory); + } + return $this; + } + + /** + * Defined by Autoloadable; autoload a class + * + * @param string $class + * @return false|string + */ + public function autoload($class) + { + $isFallback = $this->isFallbackAutoloader(); + if (false !== strpos($class, self::NS_SEPARATOR)) { + if ($this->loadClass($class, self::LOAD_NS)) { + return $class; + } elseif ($isFallback) { + return $this->loadClass($class, self::ACT_AS_FALLBACK); + } + return false; + } + if (false !== strpos($class, self::PREFIX_SEPARATOR)) { + if ($this->loadClass($class, self::LOAD_PREFIX)) { + return $class; + } elseif ($isFallback) { + return $this->loadClass($class, self::ACT_AS_FALLBACK); + } + return false; + } + if ($isFallback) { + return $this->loadClass($class, self::ACT_AS_FALLBACK); + } + return false; + } + + /** + * Register the autoloader with spl_autoload + * + * @return void + */ + public function register() + { + spl_autoload_register(array($this, 'autoload')); + } + + /** + * Transform the class name to a filename + * + * @param string $class + * @param string $directory + * @return string + */ + protected function transformClassNameToFilename($class, $directory) + { + // $class may contain a namespace portion, in which case we need + // to preserve any underscores in that portion. + $matches = array(); + preg_match('/(?P.+\\\)?(?P[^\\\]+$)/', $class, $matches); + + $class = (isset($matches['class'])) ? $matches['class'] : ''; + $namespace = (isset($matches['namespace'])) ? $matches['namespace'] : ''; + + return $directory + . str_replace(self::NS_SEPARATOR, '/', $namespace) + . str_replace(self::PREFIX_SEPARATOR, '/', $class) + . '.php'; + } + + /** + * Load a class, based on its type (namespaced or prefixed) + * + * @param string $class + * @param string $type + * @return bool|string + * @throws Exception\InvalidArgumentException + */ + protected function loadClass($class, $type) + { + if (!in_array($type, array(self::LOAD_NS, self::LOAD_PREFIX, self::ACT_AS_FALLBACK))) { + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + throw new Exception\InvalidArgumentException(); + } + + // Fallback autoloading + if ($type === self::ACT_AS_FALLBACK) { + // create filename + $filename = $this->transformClassNameToFilename($class, ''); + $resolvedName = stream_resolve_include_path($filename); + if ($resolvedName !== false) { + return include $resolvedName; + } + return false; + } + + // Namespace and/or prefix autoloading + foreach ($this->$type as $leader => $path) { + if (0 === strpos($class, $leader)) { + // Trim off leader (namespace or prefix) + $trimmedClass = substr($class, strlen($leader)); + + // create filename + $filename = $this->transformClassNameToFilename($trimmedClass, $path); + if (file_exists($filename)) { + return include $filename; + } + return false; + } + } + return false; + } + + /** + * Normalize the directory to include a trailing directory separator + * + * @param string $directory + * @return string + */ + protected function normalizeDirectory($directory) + { + $last = $directory[strlen($directory) - 1]; + if (in_array($last, array('/', '\\'))) { + $directory[strlen($directory) - 1] = DIRECTORY_SEPARATOR; + return $directory; + } + $directory .= DIRECTORY_SEPARATOR; + return $directory; + } + +} diff --git a/test/AutoloadDoesNotHideParseError.php b/test/AutoloadDoesNotHideParseError.php new file mode 100644 index 0000000..912cf2e --- /dev/null +++ b/test/AutoloadDoesNotHideParseError.php @@ -0,0 +1,15 @@ +loaders = spl_autoload_functions(); + if (!is_array($this->loaders)) { + // spl_autoload_functions does not return empty array when no + // autoloaders registered... + $this->loaders = array(); + } + + // Store original include_path + $this->includePath = get_include_path(); + } + + public function tearDown() + { + AutoloaderFactory::unregisterAutoloaders(); + // Restore original autoloaders + $loaders = spl_autoload_functions(); + if (is_array($loaders)) { + foreach ($loaders as $loader) { + spl_autoload_unregister($loader); + } + } + + foreach ($this->loaders as $loader) { + spl_autoload_register($loader); + } + + // Restore original include_path + set_include_path($this->includePath); + } + + public function testRegisteringValidMapFilePopulatesAutoloader() + { + AutoloaderFactory::factory(array( + 'Zend\Loader\ClassMapAutoloader' => array( + __DIR__ . '/_files/goodmap.php', + ), + )); + $loader = AutoloaderFactory::getRegisteredAutoloader('Zend\Loader\ClassMapAutoloader'); + $map = $loader->getAutoloadMap(); + $this->assertTrue(is_array($map)); + $this->assertEquals(2, count($map)); + } + + /** + * This tests checks if invalid autoloaders cause exceptions + * + * @expectedException InvalidArgumentException + */ + public function testFactoryCatchesInvalidClasses() + { + if (!version_compare(PHP_VERSION, '5.3.7', '>=')) { + $this->markTestSkipped('Cannot test invalid interface loader with versions less than 5.3.7'); + } + include __DIR__ . '/_files/InvalidInterfaceAutoloader.php'; + AutoloaderFactory::factory(array( + 'InvalidInterfaceAutoloader' => array() + )); + } + + public function testFactoryDoesNotRegisterDuplicateAutoloaders() + { + AutoloaderFactory::factory(array( + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + 'TestNamespace' => __DIR__ . '/TestAsset/TestNamespace', + ), + ), + )); + $this->assertEquals(1, count(AutoloaderFactory::getRegisteredAutoloaders())); + AutoloaderFactory::factory(array( + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + 'ZendTest\Loader\TestAsset\TestPlugins' => __DIR__ . '/TestAsset/TestPlugins', + ), + ), + )); + $this->assertEquals(1, count(AutoloaderFactory::getRegisteredAutoloaders())); + $this->assertTrue(class_exists('TestNamespace\NoDuplicateAutoloadersCase')); + $this->assertTrue(class_exists('ZendTest\Loader\TestAsset\TestPlugins\Foo')); + } + + public function testCanUnregisterAutoloaders() + { + AutoloaderFactory::factory(array( + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + 'TestNamespace' => __DIR__ . '/TestAsset/TestNamespace', + ), + ), + )); + AutoloaderFactory::unregisterAutoloaders(); + $this->assertEquals(0, count(AutoloaderFactory::getRegisteredAutoloaders())); + } + + public function testCanUnregisterAutoloadersByClassName() + { + AutoloaderFactory::factory(array( + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + 'TestNamespace' => __DIR__ . '/TestAsset/TestNamespace', + ), + ), + )); + AutoloaderFactory::unregisterAutoloader('Zend\Loader\StandardAutoloader'); + $this->assertEquals(0, count(AutoloaderFactory::getRegisteredAutoloaders())); + } + + public function testCanGetValidRegisteredAutoloader() + { + AutoloaderFactory::factory(array( + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + 'TestNamespace' => __DIR__ . '/TestAsset/TestNamespace', + ), + ), + )); + $autoloader = AutoloaderFactory::getRegisteredAutoloader('Zend\Loader\StandardAutoloader'); + $this->assertInstanceOf('Zend\Loader\StandardAutoloader', $autoloader); + } + + public function testDefaultAutoloader() + { + AutoloaderFactory::factory(); + $autoloader = AutoloaderFactory::getRegisteredAutoloader('Zend\Loader\StandardAutoloader'); + $this->assertInstanceOf('Zend\Loader\StandardAutoloader', $autoloader); + $this->assertEquals(1, count(AutoloaderFactory::getRegisteredAutoloaders())); + } + + public function testGetInvalidAutoloaderThrowsException() + { + $this->setExpectedException('Zend\Loader\Exception\InvalidArgumentException'); + $loader = AutoloaderFactory::getRegisteredAutoloader('InvalidAutoloader'); + } + + public function testFactoryWithInvalidArgumentThrowsException() + { + $this->setExpectedException('Zend\Loader\Exception\InvalidArgumentException'); + AutoloaderFactory::factory('InvalidArgument'); + } + + public function testFactoryWithInvalidAutoloaderClassThrowsException() + { + $this->setExpectedException('Zend\Loader\Exception\InvalidArgumentException'); + AutoloaderFactory::factory(array('InvalidAutoloader' => array())); + } + + public function testCannotBeInstantiatedViaConstructor() + { + $reflection = new ReflectionClass('Zend\Loader\AutoloaderFactory'); + $constructor = $reflection->getConstructor(); + $this->assertNull($constructor); + } + + public function testPassingNoArgumentsToFactoryInstantiatesAndRegistersStandardAutoloader() + { + AutoloaderFactory::factory(); + $loaders = AutoloaderFactory::getRegisteredAutoloaders(); + $this->assertEquals(1, count($loaders)); + $loader = array_shift($loaders); + $this->assertInstanceOf('Zend\Loader\StandardAutoloader', $loader); + + $test = array($loader, 'autoload'); + $found = false; + foreach (spl_autoload_functions() as $function) { + if ($function === $test) { + $found = true; + break; + } + } + $this->assertTrue($found, 'StandardAutoloader not registered with spl_autoload'); + } +} diff --git a/test/AutoloaderMultiVersionTest.php b/test/AutoloaderMultiVersionTest.php new file mode 100644 index 0000000..a2b1945 --- /dev/null +++ b/test/AutoloaderMultiVersionTest.php @@ -0,0 +1,206 @@ +isEnabled()) { + $this->markTestSkipped('Option TESTS_ZEND_LOADER_AUTOLOADER_MULTIVERSION_ENABLED is not enabled'); + } + + // Store original autoloaders + $this->loaders = spl_autoload_functions(); + if (!is_array($this->loaders)) { + // spl_autoload_functions does not return empty array when no + // autoloaders registered... + $this->loaders = array(); + } + // Store original include_path + $this->includePath = get_include_path(); + + Autoloader::resetInstance(); + $this->path = constant('TESTS_ZEND_LOADER_AUTOLOADER_MULTIVERSION_PATH'); + $this->latest = constant('TESTS_ZEND_LOADER_AUTOLOADER_MULTIVERSION_LATEST'); + $this->latestMajor = constant('TESTS_ZEND_LOADER_AUTOLOADER_MULTIVERSION_LATEST_MAJOR'); + $this->latestMinor = constant('TESTS_ZEND_LOADER_AUTOLOADER_MULTIVERSION_LATEST_MINOR'); + $this->specific = constant('TESTS_ZEND_LOADER_AUTOLOADER_MULTIVERSION_SPECIFIC'); + $this->autoloader = Autoloader::getInstance(); + } + + public function tearDown() + { + if (!$this->isEnabled()) { + return; + } + // Restore original autoloaders + $loaders = spl_autoload_functions(); + foreach ($loaders as $loader) { + spl_autoload_unregister($loader); + } + + foreach ($this->loaders as $loader) { + spl_autoload_register($loader); + } + + // Retore original include_path + set_include_path($this->includePath); + + // Reset autoloader instance so it doesn't affect other tests + Autoloader::resetInstance(); + Autoloader::getInstance(); + } + + public function testZfPathIsNullByDefault() + { + $this->assertNull($this->autoloader->getZfPath()); + } + + /** + * @expectedException Zend\Loader\Exception\ExceptionInterface + */ + public function testSettingZfPathFailsOnInvalidVersionString() + { + $this->autoloader->setZfPath($this->path, 'foo.bar.baz.bat'); + } + + /** + * @expectedException Zend\Loader\Exception\ExceptionInterface + */ + public function testSettingZfPathFailsWhenBasePathDoesNotExist() + { + $this->autoloader->setZfPath('foo.bar.baz.bat', 'latest'); + } + + /** + * @expectedException Zend\Loader\Exception\ExceptionInterface + */ + public function testSettingZfVersionFailsWhenNoValidInstallsDiscovered() + { + $this->autoloader->setZfPath(__DIR__, 'latest'); + } + + public function testAutoloadLatestUsesLatestVersion() + { + $this->autoloader->setZfPath($this->path, 'latest'); + $actual = $this->autoloader->getZfPath(); + $this->assertContains($this->latest, $actual); + } + + public function testAutoloadLatestIncludesLibraryInPath() + { + $this->autoloader->setZfPath($this->path, 'latest'); + $actual = $this->autoloader->getZfPath(); + $this->assertRegexp('#' . preg_quote($this->latest) . '[^/\\\]*/library#', $actual); + } + + public function testAutoloadLatestAddsPathToIncludePath() + { + $this->autoloader->setZfPath($this->path, 'latest'); + $incPath = get_include_path(); + $this->assertRegexp('#' . preg_quote($this->latest) . '[^/\\\]*/library#', $incPath); + } + + public function testAutoloadMajorRevisionShouldUseLatestFromMajorRevision() + { + $this->autoloader->setZfPath($this->path, $this->_getVersion($this->latestMajor, 'major')); + $actual = $this->autoloader->getZfPath(); + $this->assertContains($this->latestMajor, $actual); + } + + public function testAutoloadMajorRevisionIncludesLibraryInPath() + { + $this->autoloader->setZfPath($this->path, $this->_getVersion($this->latestMajor, 'major')); + $actual = $this->autoloader->getZfPath(); + $this->assertRegexp('#' . preg_quote($this->latestMajor) . '[^/\\\]*/library#', $actual); + } + + public function testAutoloadMajorRevisionAddsPathToIncludePath() + { + $this->autoloader->setZfPath($this->path, $this->_getVersion($this->latestMajor, 'major')); + $incPath = get_include_path(); + $this->assertRegexp('#' . preg_quote($this->latestMajor) . '[^/\\\]*/library#', $incPath); + } + + public function testAutoloadMinorRevisionShouldUseLatestFromMinorRevision() + { + $this->autoloader->setZfPath($this->path, $this->_getVersion($this->latestMinor, 'minor')); + $actual = $this->autoloader->getZfPath(); + $this->assertContains($this->latestMinor, $actual); + } + + public function testAutoloadMinorRevisionIncludesLibraryInPath() + { + $this->autoloader->setZfPath($this->path, $this->_getVersion($this->latestMinor, 'minor')); + $actual = $this->autoloader->getZfPath(); + $this->assertRegexp('#' . preg_quote($this->latestMinor) . '[^/\\\]*/library#', $actual); + } + + public function testAutoloadMinorRevisionAddsPathToIncludePath() + { + $this->autoloader->setZfPath($this->path, $this->_getVersion($this->latestMinor, 'minor')); + $incPath = get_include_path(); + $this->assertRegexp('#' . preg_quote($this->latestMinor) . '[^/\\\]*/library#', $incPath); + } + + public function testAutoloadSpecificRevisionShouldUseThatVersion() + { + $this->autoloader->setZfPath($this->path, $this->specific); + $actual = $this->autoloader->getZfPath(); + $this->assertContains($this->specific, $actual); + } + + public function testAutoloadSpecificRevisionIncludesLibraryInPath() + { + $this->autoloader->setZfPath($this->path, $this->specific); + $actual = $this->autoloader->getZfPath(); + $this->assertRegexp('#' . preg_quote($this->specific) . '[^/\\\]*/library#', $actual); + } + + public function testAutoloadSpecificRevisionAddsPathToIncludePath() + { + $this->autoloader->setZfPath($this->path, $this->specific); + $incPath = get_include_path(); + $this->assertRegexp('#' . preg_quote($this->specific) . '[^/\\\]*/library#', $incPath); + } + + protected function _getVersion($version, $type) + { + $parts = explode('.', $version); + switch ($type) { + case 'major': + $value = array_shift($parts); + break; + case 'minor': + $value = array_shift($parts); + $value .= '.' . array_shift($parts); + break; + } + return $value; + } +} diff --git a/test/ClassMapAutoloaderTest.php b/test/ClassMapAutoloaderTest.php new file mode 100644 index 0000000..4872032 --- /dev/null +++ b/test/ClassMapAutoloaderTest.php @@ -0,0 +1,185 @@ +loaders = spl_autoload_functions(); + if (!is_array($this->loaders)) { + // spl_autoload_functions does not return empty array when no + // autoloaders registered... + $this->loaders = array(); + } + + // Store original include_path + $this->includePath = get_include_path(); + + $this->loader = new ClassMapAutoloader(); + } + + public function tearDown() + { + // Restore original autoloaders + $loaders = spl_autoload_functions(); + if (is_array($loaders)) { + foreach ($loaders as $loader) { + spl_autoload_unregister($loader); + } + } + + foreach ($this->loaders as $loader) { + spl_autoload_register($loader); + } + + // Restore original include_path + set_include_path($this->includePath); + } + + public function testRegisteringNonExistentAutoloadMapRaisesInvalidArgumentException() + { + $dir = __DIR__ . '__foobar__'; + $this->setExpectedException('Zend\Loader\Exception\InvalidArgumentException'); + $this->loader->registerAutoloadMap($dir); + } + + public function testValidMapFileNotReturningMapRaisesInvalidArgumentException() + { + $this->setExpectedException('Zend\Loader\Exception\InvalidArgumentException'); + $this->loader->registerAutoloadMap(__DIR__ . '/_files/badmap.php'); + } + + public function testAllowsRegisteringArrayAutoloadMapDirectly() + { + $map = array( + 'Zend\Loader\Exception\ExceptionInterface' => __DIR__ . '/../../../library/Zend/Loader/Exception/ExceptionInterface.php', + ); + $this->loader->registerAutoloadMap($map); + $test = $this->loader->getAutoloadMap(); + $this->assertSame($map, $test); + } + + public function testAllowsRegisteringArrayAutoloadMapViaConstructor() + { + $map = array( + 'Zend\Loader\Exception\ExceptionInterface' => __DIR__ . '/../../../library/Zend/Loader/Exception/ExceptionInterface.php', + ); + $loader = new ClassMapAutoloader(array($map)); + $test = $loader->getAutoloadMap(); + $this->assertSame($map, $test); + } + + public function testRegisteringValidMapFilePopulatesAutoloader() + { + $this->loader->registerAutoloadMap(__DIR__ . '/_files/goodmap.php'); + $map = $this->loader->getAutoloadMap(); + $this->assertTrue(is_array($map)); + $this->assertEquals(2, count($map)); + // Just to make sure nothing changes after loading the same map again + // (loadMapFromFile should just return) + $this->loader->registerAutoloadMap(__DIR__ . '/_files/goodmap.php'); + $map = $this->loader->getAutoloadMap(); + $this->assertTrue(is_array($map)); + $this->assertEquals(2, count($map)); + } + + public function testRegisteringMultipleMapsMergesThem() + { + $map = array( + 'Zend\Loader\Exception\ExceptionInterface' => __DIR__ . '/../../../library/Zend/Loader/Exception/ExceptionInterface.php', + 'ZendTest\Loader\StandardAutoloaderTest' => 'some/bogus/path.php', + ); + $this->loader->registerAutoloadMap($map); + $this->loader->registerAutoloadMap(__DIR__ . '/_files/goodmap.php'); + + $test = $this->loader->getAutoloadMap(); + $this->assertTrue(is_array($test)); + $this->assertEquals(3, count($test)); + $this->assertNotEquals($map['ZendTest\Loader\StandardAutoloaderTest'], $test['ZendTest\Loader\StandardAutoloaderTest']); + } + + public function testCanRegisterMultipleMapsAtOnce() + { + $map = array( + 'Zend\Loader\Exception\ExceptionInterface' => __DIR__ . '/../../../library/Zend/Loader/Exception/ExceptionInterface.php', + 'ZendTest\Loader\StandardAutoloaderTest' => 'some/bogus/path.php', + ); + $maps = array($map, __DIR__ . '/_files/goodmap.php'); + $this->loader->registerAutoloadMaps($maps); + $test = $this->loader->getAutoloadMap(); + $this->assertTrue(is_array($test)); + $this->assertEquals(3, count($test)); + } + + public function testRegisterMapsThrowsExceptionForNonTraversableArguments() + { + $tests = array(true, 'string', 1, 1.0, new \stdClass); + foreach ($tests as $test) { + try { + $this->loader->registerAutoloadMaps($test); + $this->fail('Should not register non-traversable arguments'); + } catch (InvalidArgumentException $e) { + $this->assertContains('array or implement Traversable', $e->getMessage()); + } + } + } + + public function testAutoloadLoadsClasses() + { + $map = array('ZendTest\UnusualNamespace\ClassMappedClass' => __DIR__ . '/TestAsset/ClassMappedClass.php'); + $this->loader->registerAutoloadMap($map); + $this->loader->autoload('ZendTest\UnusualNamespace\ClassMappedClass'); + $this->assertTrue(class_exists('ZendTest\UnusualNamespace\ClassMappedClass', false)); + } + + public function testIgnoresClassesNotInItsMap() + { + $map = array('ZendTest\UnusualNamespace\ClassMappedClass' => __DIR__ . '/TestAsset/ClassMappedClass.php'); + $this->loader->registerAutoloadMap($map); + $this->loader->autoload('ZendTest\UnusualNamespace\UnMappedClass'); + $this->assertFalse(class_exists('ZendTest\UnusualNamespace\UnMappedClass', false)); + } + + public function testRegisterRegistersCallbackWithSplAutoload() + { + $this->loader->register(); + $loaders = spl_autoload_functions(); + $this->assertTrue(count($this->loaders) < count($loaders)); + $test = array_shift($loaders); + $this->assertEquals(array($this->loader, 'autoload'), $test); + } + + public function testCanLoadClassMapFromPhar() + { + $map = 'phar://' . __DIR__ . '/_files/classmap.phar/test/.//../autoload_classmap.php'; + $this->loader->registerAutoloadMap($map); + $this->loader->autoload('some\loadedclass'); + $this->assertTrue(class_exists('some\loadedclass', false)); + + // will not register duplicate, even with a different relative path + $map = 'phar://' . __DIR__ . '/_files/classmap.phar/test/./foo/../../autoload_classmap.php'; + $this->loader->registerAutoloadMap($map); + $test = $this->loader->getAutoloadMap(); + $this->assertEquals(1, count($test)); + } + +} diff --git a/test/ModuleAutoloaderTest.php b/test/ModuleAutoloaderTest.php new file mode 100644 index 0000000..ab50a56 --- /dev/null +++ b/test/ModuleAutoloaderTest.php @@ -0,0 +1,200 @@ +loaders = spl_autoload_functions(); + if (!is_array($this->loaders)) { + // spl_autoload_functions does not return empty array when no + // autoloaders registered... + $this->loaders = array(); + } + + // Store original include_path + $this->includePath = get_include_path(); + } + + public function tearDown() + { + // Restore original autoloaders + $loaders = spl_autoload_functions(); + if (is_array($loaders)) { + foreach ($loaders as $loader) { + spl_autoload_unregister($loader); + } + } + + foreach ($this->loaders as $loader) { + spl_autoload_register($loader); + } + + // Restore original include_path + set_include_path($this->includePath); + } + + public function testCanRegisterPathsFromConstructor() + { + $paths = array(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR); + $loader = new ModuleAutoloader($paths); + $registeredPaths = $loader->getPaths(); + $this->assertSame($paths, $registeredPaths); + } + + public function testPathsNormalizedWithTrailingSlash() + { + $paths = array( + __DIR__ . DIRECTORY_SEPARATOR . '_files', + __DIR__ . DIRECTORY_SEPARATOR . '_files///', + __DIR__ . DIRECTORY_SEPARATOR . '_files\\\\', + ); + $loader = new ModuleAutoloader($paths); + $registeredPaths = $loader->getPaths(); + $this->assertSame(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR, $registeredPaths[0]); + $this->assertSame(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR, $registeredPaths[1]); + $this->assertSame(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR, $registeredPaths[2]); + } + + public function testCanAutoloadModule() + { + $loader = new ModuleAutoloader; + $loader->registerPath(__DIR__ . '/_files/'); + $moduleClass = $loader->autoload('FooModule\Module'); + $this->assertSame('FooModule\Module', $moduleClass); + $module = new \FooModule\Module; + $this->assertInstanceOf('FooModule\Module', $module); + } + + public function testCanAutoloadSubModule() + { + $loader = new ModuleAutoloader; + $loader->registerPath(__DIR__ . '/_files/'); + $loader->register(); + $subModule = new \FooModule\SubModule\Module; + $this->assertInstanceOf('FooModule\SubModule\Module', $subModule); + $loader->unregister(); + } + + public function testCanAutoloadPharModules() + { + $loader = new ModuleAutoloader; + $loader->registerPath(__DIR__ . '/_files/'); + $loader->register(); + + $this->assertTrue(class_exists('PharModule\Module')); + $this->assertTrue(class_exists('PharModuleTar\Module')); + $this->assertTrue(class_exists('PharModulePharTar\Module')); + $this->assertTrue(class_exists('PharModuleNested\Module')); + + // gzip / zip + if (extension_loaded('zlib')) { + // gzip + $this->assertTrue(class_exists('PharModuleGz\Module')); + $this->assertTrue(class_exists('PharModulePharTarGz\Module')); + $this->assertTrue(class_exists('PharModuleTarGz\Module')); + + // zip + $this->assertTrue(class_exists('PharModulePharZip\Module')); + $this->assertTrue(class_exists('PharModuleZip\Module')); + } else { + $this->assertFalse(class_exists('PharModuleGz\Module')); + $this->assertFalse(class_exists('PharModulePharTarGz\Module')); + $this->assertFalse(class_exists('PharModuleTarGz\Module')); + + $this->assertFalse(class_exists('PharModulePharZip\Module')); + $this->assertFalse(class_exists('PharModuleZip\Module')); + } + + // bzip2 + if (extension_loaded('bzip2')) { + $this->assertTrue(class_exists('PharModuleBz2\Module')); + $this->assertTrue(class_exists('PharModulePharTarBz2\Module')); + $this->assertTrue(class_exists('PharModuleTarBz2\Module')); + } else { + $this->assertFalse(class_exists('PharModuleBz2\Module')); + $this->assertFalse(class_exists('PharModulePharTarBz2\Module')); + $this->assertFalse(class_exists('PharModuleTarBz2\Module')); + } + + $loader->unregister(); + } + + public function testProvidesFluidInterface() + { + $loader = new ModuleAutoloader; + $this->assertInstanceOf('Zend\Loader\ModuleAutoloader', $loader->setOptions(array('foo'))); + $this->assertInstanceOf('Zend\Loader\ModuleAutoloader', $loader->registerPaths(array('foo'))); + $this->assertInstanceOf('Zend\Loader\ModuleAutoloader', $loader->registerPath('foo')); + } + + public function testReturnsFalseForNonModuleClass() + { + $loader = new ModuleAutoloader; + $loader->registerPath(__DIR__ . '/_files/'); + $moduleClass = $loader->autoload('FooModule\NotModule'); + $this->assertFalse($moduleClass); + } + + public function testReturnsFalseForNonExistantModuleClass() + { + $loader = new ModuleAutoloader; + $loader->registerPath(__DIR__ . '/_files/'); + $moduleClass = $loader->autoload('NonExistantModule\Module'); + $this->assertFalse($moduleClass); + $loader->registerPath(__DIR__ . '/_files/NonExistantModule', 'NonExistantModule'); + $moduleClass = $loader->autoload('NonExistantModule\Module'); + $this->assertFalse($moduleClass); + $moduleClass = $loader->autoload('NoModuleClassModule\Module'); + $this->assertFalse($moduleClass); + } + + public function testReturnsFalseForNonModulePhar() + { + $loader = new ModuleAutoloader; + $loader->registerPath(__DIR__ . '/_files/'); + $moduleClass = $loader->autoload('PharModuleFake\Module'); + $moduleClass = $loader->autoload('PharModuleNestedFake\Module'); + $this->assertFalse($moduleClass); + } + + public function testInvalidPathThrowsException() + { + $loader = new ModuleAutoloader; + $this->setExpectedException('InvalidArgumentException'); + $loader->registerPath(123); + } + + public function testInvalidPathsThrowsException() + { + $loader = new ModuleAutoloader; + $this->setExpectedException('InvalidArgumentException'); + $loader->registerPaths(123); + } + + public function testCanLoadModulesFromExplicitLocation() + { + $loader = new ModuleAutoloader(array( + 'My\NonmatchingModule' => __DIR__ . '/_files/NonmatchingModule', + 'PharModuleExplicit' => __DIR__ . '/_files/PharModuleExplicit.phar', + )); + $loader->register(); + $this->assertTrue(class_exists('My\NonmatchingModule\Module')); + $this->assertTrue(class_exists('PharModuleExplicit\Module')); + } + +} diff --git a/test/MyLoader.php b/test/MyLoader.php new file mode 100644 index 0000000..da91bae --- /dev/null +++ b/test/MyLoader.php @@ -0,0 +1,24 @@ +loader = new PluginClassLoader(); + } + + public function testPluginClassLoaderHasNoAssociationsByDefault() + { + $plugins = $this->loader->getRegisteredPlugins(); + $this->assertTrue(empty($plugins)); + } + + public function testRegisterPluginRegistersShortNameClassNameAssociation() + { + $this->loader->registerPlugin('loader', __CLASS__); + $plugins = $this->loader->getRegisteredPlugins(); + $this->assertArrayHasKey('loader', $plugins); + $this->assertEquals(__CLASS__, $plugins['loader']); + } + + public function testCallingRegisterPluginWithAnExistingPluginNameOverwritesThatMapAssociation() + { + $this->testRegisterPluginRegistersShortNameClassNameAssociation(); + $this->loader->registerPlugin('loader', 'Zend\Loader\PluginClassLoader'); + $plugins = $this->loader->getRegisteredPlugins(); + $this->assertArrayHasKey('loader', $plugins); + $this->assertEquals('Zend\Loader\PluginClassLoader', $plugins['loader']); + } + + public function testCallingRegisterPluginsWithInvalidStringMapRaisesException() + { + $this->setExpectedException('Zend\Loader\Exception\InvalidArgumentException'); + $this->loader->registerPlugins('__foobar__'); + } + + public function testCallingRegisterPluginsWithStringMapResolvingToNonTraversableClassRaisesException() + { + $this->setExpectedException('Zend\Loader\Exception\InvalidArgumentException'); + $this->loader->registerPlugins('stdClass'); + } + + public function testCallingRegisterPluginsWithValidStringMapResolvingToTraversableClassRegistersPlugins() + { + $this->loader->registerPlugins('ZendTest\Loader\TestAsset\TestPluginMap'); + $pluginMap = new TestAsset\TestPluginMap; + $this->assertEquals($pluginMap->map, $this->loader->getRegisteredPlugins()); + } + + /** + * @dataProvider invalidMaps + */ + public function testCallingRegisterPluginsWithNonArrayNonStringNonTraversableValueRaisesException($arg) + { + $this->setExpectedException('Zend\Loader\Exception\InvalidArgumentException'); + $this->loader->registerPlugins($arg); + } + + public function invalidMaps() + { + return array( + array(null), + array(true), + array(1), + array(1.0), + array(new \stdClass), + ); + } + + public function testCallingRegisterPluginsWithArrayRegistersMap() + { + $map = array('test' => __CLASS__); + $this->loader->registerPlugins($map); + $test = $this->loader->getRegisteredPlugins(); + $this->assertEquals($map, $test); + } + + public function testCallingRegisterPluginsWithTraversableObjectRegistersMap() + { + $map = new TestAsset\TestPluginMap(); + $this->loader->registerPlugins($map); + $test = $this->loader->getRegisteredPlugins(); + $this->assertEquals($map->map, $test); + } + + public function testUnregisterPluginRemovesPluginFromMap() + { + $map = new TestAsset\TestPluginMap(); + $this->loader->registerPlugins($map); + + $this->loader->unregisterPlugin('test'); + + $test = $this->loader->getRegisteredPlugins(); + $this->assertFalse(array_key_exists('test', $test)); + } + + public function testIsLoadedReturnsFalseIfPluginIsNotInMap() + { + $this->assertFalse($this->loader->isLoaded('test')); + } + + public function testIsLoadedReturnsTrueIfPluginIsInMap() + { + $this->loader->registerPlugin('test', __CLASS__); + $this->assertTrue($this->loader->isLoaded('test')); + } + + public function testGetClassNameReturnsFalseIfPluginIsNotInMap() + { + $this->assertFalse($this->loader->getClassName('test')); + } + + public function testGetClassNameReturnsClassNameIfPluginIsInMap() + { + $this->loader->registerPlugin('test', __CLASS__); + $this->assertEquals(__CLASS__, $this->loader->getClassName('test')); + } + + public function testLoadReturnsFalseIfPluginIsNotInMap() + { + $this->assertFalse($this->loader->load('test')); + } + + public function testLoadReturnsClassNameIfPluginIsInMap() + { + $this->loader->registerPlugin('test', __CLASS__); + $this->assertEquals(__CLASS__, $this->loader->load('test')); + } + + public function testIteratingLoaderIteratesPluginMap() + { + $map = new TestAsset\TestPluginMap(); + $this->loader->registerPlugins($map); + $test = array(); + foreach ($this->loader as $name => $class) { + $test[$name] = $class; + } + + $this->assertEquals($map->map, $test); + } + + public function testPluginRegistrationIsCaseInsensitive() + { + $map = array( + 'foo' => __CLASS__, + 'FOO' => __NAMESPACE__ . '\TestAsset\TestPluginMap', + ); + $this->loader->registerPlugins($map); + $this->assertEquals($map['FOO'], $this->loader->getClassName('foo')); + } + + public function testAddingStaticMapDoesNotAffectExistingInstances() + { + PluginClassLoader::addStaticMap(array( + 'test' => __CLASS__, + )); + $this->assertFalse($this->loader->getClassName('test')); + } + + public function testAllowsSettingStaticMapForSeedingInstance() + { + PluginClassLoader::addStaticMap(array( + 'test' => __CLASS__, + )); + $loader = new PluginClassLoader(); + $this->assertEquals(__CLASS__, $loader->getClassName('test')); + } + + public function testPassingNullToStaticMapClearsMap() + { + $this->testAllowsSettingStaticMapForSeedingInstance(); + PluginClassLoader::addStaticMap(null); + $loader = new PluginClassLoader(); + $this->assertFalse($loader->getClassName('test')); + } + + public function testAllowsPassingTraversableObjectToStaticMap() + { + $map = new \ArrayObject(array( + 'test' => __CLASS__, + )); + PluginClassLoader::addStaticMap($map); + $loader = new PluginClassLoader(); + $this->assertEquals(__CLASS__, $loader->getClassName('test')); + } + + public function testMultipleCallsToAddStaticMapMergeMap() + { + PluginClassLoader::addStaticMap(array( + 'test' => __CLASS__, + )); + PluginClassLoader::addStaticMap(array( + 'loader' => 'Zend\Loader\PluginClassLoader', + )); + $loader = new PluginClassLoader(); + $this->assertEquals(__CLASS__, $loader->getClassName('test')); + $this->assertEquals('Zend\Loader\PluginClassLoader', $loader->getClassName('loader')); + } + + public function testStaticMapUsesLateStaticBinding() + { + TestAsset\ExtendedPluginClassLoader::addStaticMap(array('test' => __CLASS__)); + $loader = new PluginClassLoader(); + $this->assertFalse($loader->getClassName('test')); + $loader = new TestAsset\ExtendedPluginClassLoader(); + $this->assertEquals(__CLASS__, $loader->getClassName('test')); + } + + public function testMapPrecedenceIsExplicitTrumpsConstructorTrumpsStaticTrumpsInternal() + { + $loader = new TestAsset\ExtendedPluginClassLoader(); + $this->assertEquals('Zend\Loader\PluginClassLoader', $loader->getClassName('loader')); + + TestAsset\ExtendedPluginClassLoader::addStaticMap(array('loader' => __CLASS__)); + $loader = new TestAsset\ExtendedPluginClassLoader(); + $this->assertEquals(__CLASS__, $loader->getClassName('loader')); + + $loader = new TestAsset\ExtendedPluginClassLoader(array('loader' => 'ZendTest\Loader\TestAsset\ExtendedPluginClassLoader')); + $this->assertEquals('ZendTest\Loader\TestAsset\ExtendedPluginClassLoader', $loader->getClassName('loader')); + + $loader->registerPlugin('loader', __CLASS__); + $this->assertEquals(__CLASS__, $loader->getClassName('loader')); + } + + public function testRegisterPluginsCanAcceptArrayElementWithClassNameProvidingAMap() + { + $pluginMap = new TestAsset\TestPluginMap; + $this->loader->registerPlugins(array('ZendTest\Loader\TestAsset\TestPluginMap')); + $this->assertEquals($pluginMap->map, $this->loader->getRegisteredPlugins()); + } + + public function testRegisterPluginsCanAcceptArrayElementWithObjectProvidingAMap() + { + $pluginMap = new TestAsset\TestPluginMap; + $this->loader->registerPlugins(array($pluginMap)); + $this->assertEquals($pluginMap->map, $this->loader->getRegisteredPlugins()); + } +} diff --git a/test/StandardAutoloaderTest.php b/test/StandardAutoloaderTest.php new file mode 100644 index 0000000..ce4c802 --- /dev/null +++ b/test/StandardAutoloaderTest.php @@ -0,0 +1,197 @@ +loaders = spl_autoload_functions(); + if (!is_array($this->loaders)) { + // spl_autoload_functions does not return empty array when no + // autoloaders registered... + $this->loaders = array(); + } + + // Store original include_path + $this->includePath = get_include_path(); + } + + public function tearDown() + { + // Restore original autoloaders + $loaders = spl_autoload_functions(); + if (is_array($loaders)) { + foreach ($loaders as $loader) { + spl_autoload_unregister($loader); + } + } + + foreach ($this->loaders as $loader) { + spl_autoload_register($loader); + } + + // Restore original include_path + set_include_path($this->includePath); + } + + public function testFallbackAutoloaderFlagDefaultsToFalse() + { + $loader = new StandardAutoloader(); + $this->assertFalse($loader->isFallbackAutoloader()); + } + + public function testFallbackAutoloaderStateIsMutable() + { + $loader = new StandardAutoloader(); + $loader->setFallbackAutoloader(true); + $this->assertTrue($loader->isFallbackAutoloader()); + $loader->setFallbackAutoloader(false); + $this->assertFalse($loader->isFallbackAutoloader()); + } + + public function testPassingNonTraversableOptionsToSetOptionsRaisesException() + { + $loader = new StandardAutoloader(); + + $obj = new \stdClass(); + foreach (array(true, 'foo', $obj) as $arg) { + try { + $loader->setOptions(true); + $this->fail('Setting options with invalid type should fail'); + } catch (InvalidArgumentException $e) { + $this->assertContains('array or Traversable', $e->getMessage()); + } + } + } + + public function testPassingArrayOptionsPopulatesProperties() + { + $options = array( + 'namespaces' => array( + 'Zend\\' => dirname(__DIR__) . DIRECTORY_SEPARATOR, + ), + 'prefixes' => array( + 'Zend_' => dirname(__DIR__) . DIRECTORY_SEPARATOR, + ), + 'fallback_autoloader' => true, + ); + $loader = new TestAsset\StandardAutoloader(); + $loader->setOptions($options); + $this->assertEquals($options['namespaces'], $loader->getNamespaces()); + $this->assertEquals($options['prefixes'], $loader->getPrefixes()); + $this->assertTrue($loader->isFallbackAutoloader()); + } + + public function testPassingTraversableOptionsPopulatesProperties() + { + $namespaces = new \ArrayObject(array( + 'Zend\\' => dirname(__DIR__) . DIRECTORY_SEPARATOR, + )); + $prefixes = new \ArrayObject(array( + 'Zend_' => dirname(__DIR__) . DIRECTORY_SEPARATOR, + )); + $options = new \ArrayObject(array( + 'namespaces' => $namespaces, + 'prefixes' => $prefixes, + 'fallback_autoloader' => true, + )); + $loader = new TestAsset\StandardAutoloader(); + $loader->setOptions($options); + $this->assertEquals((array) $options['namespaces'], $loader->getNamespaces()); + $this->assertEquals((array) $options['prefixes'], $loader->getPrefixes()); + $this->assertTrue($loader->isFallbackAutoloader()); + } + + public function testAutoloadsNamespacedClasses() + { + $loader = new StandardAutoloader(); + $loader->registerNamespace('ZendTest\UnusualNamespace', __DIR__ . '/TestAsset'); + $loader->autoload('ZendTest\UnusualNamespace\NamespacedClass'); + $this->assertTrue(class_exists('ZendTest\UnusualNamespace\NamespacedClass', false)); + } + + public function testAutoloadsVendorPrefixedClasses() + { + $loader = new StandardAutoloader(); + $loader->registerPrefix('ZendTest_UnusualPrefix', __DIR__ . '/TestAsset'); + $loader->autoload('ZendTest_UnusualPrefix_PrefixedClass'); + $this->assertTrue(class_exists('ZendTest_UnusualPrefix_PrefixedClass', false)); + } + + public function testCanActAsFallbackAutoloader() + { + $loader = new StandardAutoloader(); + $loader->setFallbackAutoloader(true); + set_include_path(__DIR__ . '/TestAsset/' . PATH_SEPARATOR . $this->includePath); + $loader->autoload('TestNamespace\FallbackCase'); + $this->assertTrue(class_exists('TestNamespace\FallbackCase', false)); + } + + public function testReturnsFalseForUnresolveableClassNames() + { + $loader = new StandardAutoloader(); + $this->assertFalse($loader->autoload('Some\Fake\Classname')); + } + + public function testReturnsFalseForInvalidClassNames() + { + $loader = new StandardAutoloader(); + $loader->setFallbackAutoloader(true); + $this->assertFalse($loader->autoload('Some\Invalid\Classname\\')); + } + + public function testRegisterRegistersCallbackWithSplAutoload() + { + $loader = new StandardAutoloader(); + $loader->register(); + $loaders = spl_autoload_functions(); + $this->assertTrue(count($this->loaders) < count($loaders)); + $test = array_pop($loaders); + $this->assertEquals(array($loader, 'autoload'), $test); + } + + public function testAutoloadsNamespacedClassesWithUnderscores() + { + $loader = new StandardAutoloader(); + $loader->registerNamespace('ZendTest\UnusualNamespace', __DIR__ . '/TestAsset'); + $loader->autoload('ZendTest\UnusualNamespace\Name_Space\Namespaced_Class'); + $this->assertTrue(class_exists('ZendTest\UnusualNamespace\Name_Space\Namespaced_Class', false)); + } + + public function testZendFrameworkNamespaceIsNotLoadedByDefault() + { + $loader = new StandardAutoloader(); + $expected = array(); + $this->assertAttributeEquals($expected, 'namespaces', $loader); + } + + public function testCanTellAutoloaderToRegisterZendNamespaceAtInstantiation() + { + $loader = new StandardAutoloader(array('autoregister_zf' => true)); + $r = new ReflectionClass($loader); + $file = $r->getFileName(); + $expected = array('Zend\\' => dirname(dirname($file)) . DIRECTORY_SEPARATOR); + $this->assertAttributeEquals($expected, 'namespaces', $loader); + } + +} diff --git a/test/TestAsset/ClassMappedClass.php b/test/TestAsset/ClassMappedClass.php new file mode 100644 index 0000000..6af06e2 --- /dev/null +++ b/test/TestAsset/ClassMappedClass.php @@ -0,0 +1,27 @@ +options = $options; + } +} diff --git a/test/TestAsset/CustomClassLoader.php b/test/TestAsset/CustomClassLoader.php new file mode 100644 index 0000000..af9ef87 --- /dev/null +++ b/test/TestAsset/CustomClassLoader.php @@ -0,0 +1,23 @@ + 'Zend\Loader\PluginClassLoader', + ); + + protected static $staticMap = array(); +} diff --git a/test/TestAsset/Name_Space/Namespaced/Class.php b/test/TestAsset/Name_Space/Namespaced/Class.php new file mode 100644 index 0000000..b49e267 --- /dev/null +++ b/test/TestAsset/Name_Space/Namespaced/Class.php @@ -0,0 +1,21 @@ +options = $options; + } +} diff --git a/test/TestAsset/ServiceLocator.php b/test/TestAsset/ServiceLocator.php new file mode 100644 index 0000000..aed4927 --- /dev/null +++ b/test/TestAsset/ServiceLocator.php @@ -0,0 +1,37 @@ +services[$name])) { + return null; + } + + return $this->services[$name]; + } + + public function has($name) + { + return (isset($this->services[$name])); + } + + public function set($name, $object) + { + $this->services[$name] = $object; + } +} diff --git a/test/TestAsset/StandardAutoloader.php b/test/TestAsset/StandardAutoloader.php new file mode 100644 index 0000000..c006a51 --- /dev/null +++ b/test/TestAsset/StandardAutoloader.php @@ -0,0 +1,42 @@ +namespaces; + } + + /** + * Get registered prefixes + * + * @return array + */ + public function getPrefixes() + { + return $this->prefixes; + } +} diff --git a/test/TestAsset/TestNamespace/FallbackCase.php b/test/TestAsset/TestNamespace/FallbackCase.php new file mode 100644 index 0000000..0e846e4 --- /dev/null +++ b/test/TestAsset/TestNamespace/FallbackCase.php @@ -0,0 +1,21 @@ + __CLASS__, + 'test' => 'ZendTest\Loader\PluginClassLoaderTest', + 'loader' => 'Zend\Loader\PluginClassLoader', + ); + + /** + * Return iterator + * + * @return Traversable + */ + public function getIterator() + { + return new \ArrayIterator($this->map); + } +} diff --git a/test/TestAsset/TestPlugins/Bar.php b/test/TestAsset/TestPlugins/Bar.php new file mode 100644 index 0000000..4450ce4 --- /dev/null +++ b/test/TestAsset/TestPlugins/Bar.php @@ -0,0 +1,21 @@ +#HCUFX+zH1so{z6mCrNmk+4VZRf1kO5lVxLm z?PqyrTYbsCi)SAUT6DX9l=IZ(N&eCg_{&A)LUPZ@pvjNiVBzs`;^cE_soQE~?6YdPodxMcR=>7KF-q~>c?cj~|UL<1^ z$4PJa`t%#cRG~pXXHT&muX;m^ef-GQ4Xv>CPtS%{T_k$d{aI}1>4GD6GxS5AVTog3@72m9!U+1kPaQw(3Vl_2MDw(&ptH@sNRgvda#2}tkk<+M>oL}cv z+}By9K`LkpwvD(@2E}*h(wAB;eUHa2T7qK|su=yynei4aDIb|km`oF`K%DtgsX(&Q z64ZGfN~*{xR)L}h8^~qNn%#Hfvg+$55up70gqP`9&LmmoNqVv*<1vM9-JvU!IKhGM zI=LT5t?TCZ&ZU#Nsh{MeGW0!_9%teCaZ9WvU8=l8j#cgz8B1c0FC{a+_`LOph3{VE zC`R!td9b1gOOi;G$8u9b6`=SOk*v}aPi;Xt6e2=ZqKiicPfJj(0hTY_Pdn< zC-sOOf)a$JLPq*&M{U!=e(Y;%g=Vo`syuYGyX@iaL-sb#*~@qlc@!mg=P|48Q{y@K zeZ=-jg1)f*+|L7kK;wETp@_uT(wzH~*t?M;^Y#H5Xfh#HL-8begVjp%EwBh_B?L8O zxmHRUfe}iVA5CKlQ|+u8s*{n0NyVcKO$(EhwpRy9CkDIM9Nr|n%Sr>Sw3(Xcm`AgG zF1K`w5HtT)=9CK8@rWdC>zx#MNKSq+PDkddC(;$-lH+#mIqLB#Ym>jlIdPUze@U<- z0`+I}0RQvxx_{M4K*erw=l_utKq7(rSh@U+4@Q<_rnpS>1zfJNkILdPN z>K*oZ_qx5iyQ@jh-*p77Q=*+5o&81-AC!m!nt{5CS*70N-dj9*^ytZBbUI50D!(Vfn&@xWYQgnN4Fe{zV0hwl;U)W#){N=&4+l2v;&0~lxqQr48 zZ0j7@SR8eG;zv$;Q=d{1Nuh^?OwAD7`k_Vm+KW*M@Wt`)YC2S_)# zkPbOL7JW>yuQQ2WgV9BeR+}mLAnZstcAhem7$L!~=5)AiZHvePziNUoE{s7|OpA&q z2*dNaZS@9&(?OS^gZfhrN6?>f!l?Oq?8?bl4Yi2J4PTfe<%(h5j4;eKc>fCtJylPI2-Xgt(i> z_?E}CF?6A1wEc4TbtcPtWvP=2hSO=ah+9dvtQ`%%%AHBn6DgDjqfkmZ3Zm+_$Pq5f z?v+Oyb{JlWsEDz_b{{`}++g~aC>$uE6}f@xV6A3L`nmzRgx=S3KIv8}Z>Q=EryO?y zJ`9tWG<9W_Gzt$t@8Y4@vSg8u(duc`EBOL^t(!(0r#u-rl^h@%bwVv=WQEpyhNfi7 znmk}8sTRdbh;1cWBupYM6}85BsAg*IDy5&}x|3-);OGXJiUQUb=ScW6(jAfg`6}2cRn$WsfMQZrCcd7xh<;PXiseQKx71CZJLNE-FX;eqOIoumLENO zM3%)rL*5Wpi$~2|(dE=7LE2UCSV(kjR_iu{0ln-FcK>yMe0qj${qD_Mfcs@*K*$0_ zT{@{Oc^+Nb*6^ecu4hzWrFD0??hykyreJ{yd5VQ}sUBdpC~BxdUy$cVQ%Z6uFA4JX zGg6{-iq55#l7UqRaRI1wK}nZ2lN+RHEm@`6NPtGo%`!gG_pcBe)?fma013d84NPs# zC9q3Ly8RFrFf#y7fh#7xSK6SVP(ULbAkRe2r-V?1f(!~kLy%&COBOn(bVkJr;~n5f z9$4_=+x9kP9L9MBjtyp|85N?kxecRx5Tu!-$B?>@A|G0U^y;vLs}NH(2s0*~Me7(9 zif}sRYqc?MZ=d15%zPDPEmU zZR@KAfy`5c3}RNHvfLE|~;MJZ$nK()I|$S5eVDQ$_KwI-_|p%z{NaE1IT zB&XP@AL@MU;$5_a=CwDGcxA-IJNU>6BpzinA%MDY^JSdCFD~jk#l=Ia+W`$K@j#SC zK0*Zg>bZmVek$$5hN~QY4T*S*S_aa+_(oJm~C4?9A zOsEy!+`a6LtFeZufDzsN?hLB}CCq|&Vq3pL&nJ*D)zu_ss``-wR6$la5j@Y>VHyf} zg+-SgE~3DX=<0}M(Kg?ark_nT%9Oe`K&0skK2l>=o1)PK{p*-Qg{Fg5rP^Ehi38VR z$d1RakB*1q7pEtE{N6GEi9I{`sqy6Ay?Z~x|DUT*eBjT(|K%@5J6Qeq&wqMLpMUxI zuRs2S1n{>{KP@rCAmEhYj?5YTrXuBVOyyexximg}`ui`BKTWoh|NQOWKl|q|^1mK@ Q^nddF$I$ZX`N{MD0c7wRlmGw# literal 0 HcmV?d00001 diff --git a/test/_files/PharModuleBz2.phar.bz2 b/test/_files/PharModuleBz2.phar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..30fc22c4d42d879aa307bdffbc39490fcd7d7492 GIT binary patch literal 2690 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 XU;n)He){ejS-@nfx*Te yD6F8bpO>$YoRe5wtdNmflp5g8$OKb>%|MtOgvMulfHx}}NEIUxdI4#FuoeKaiXJ=w literal 0 HcmV?d00001 diff --git a/test/_files/PharModuleGz.phar.gz b/test/_files/PharModuleGz.phar.gz new file mode 100644 index 0000000000000000000000000000000000000000..6e16c07bb1775403d47a5f2d9f2b1f810318dcdd GIT binary patch literal 2529 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 literal 0 HcmV?d00001 diff --git a/test/_files/PharModuleNestedFake.tar.gz b/test/_files/PharModuleNestedFake.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..9d269d2ce8f1ab2319495f1de27fb57875bce745 GIT binary patch literal 131 zcmb2|=3oE=X6_RnI-kz^Yo7J|>aDBi>09W1#_wu7#|zOE5rY6`35Ld*GbO_c4GfHu z4NOdo4NVQq%}mW$yQHNUZ*sAPY@ExW0o0|#6y?dkn@w@UM)qTyn)dB;ireQ@08~sVZ2$lO literal 0 HcmV?d00001 diff --git a/test/_files/PharModulePharTar.phar.tar b/test/_files/PharModulePharTar.phar.tar new file mode 100644 index 0000000000000000000000000000000000000000..421b63ede72f673e3037f4dd76a1b1b8bd8903b7 GIT binary patch literal 4096 zcmeaxPbtkw)hoy-V4xW=00J{JGYs=V;$UEA%3x?{W@2b+U}|n|!~hgCGc`043 z1A)@wlEfmQl{7GVC>UvD4~%*RF0Q=9+|=TN#N8ocLjxl-gVFk*>M?<7AQMnX1c(CyAF|EN l+OaA8khu}hqr-gJHY_=qsz*geLtr!nMnhmU1cplp002Y3TwMSF literal 0 HcmV?d00001 diff --git a/test/_files/PharModulePharTarBz2.phar.tar.bz2 b/test/_files/PharModulePharTarBz2.phar.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..04944d27d98a5daf04b35b11f77ce8ad87079b4a GIT binary patch literal 318 zcmV-E0m1%4T4*#eL0KkKSw9DC5dZ*)|Gm;01b{^2|BSk3)q(%#-x>h`00BTjA^`#b z2n;X)`qB`IGa(vjrhp9q0iYNV0Bt}cP$bcyG#UZw0MGyc00xGGDMo`30}wO-0j5lY zKmZ1X&Zorl0YRzK7#Sm!&Vy=4A_zrV8d?H(FzO?X0=BMlRhOVj^qzL! zJtHI9=`BRSL1bo-2Ge3t0iRrJAwfaQ;N89XT^1~!eMV3YApny#_!ZtW{22!AN5@;77XM}g8e5m^WK9X60 QCx45%BAh5lAA`0CfGI?RasU7T literal 0 HcmV?d00001 diff --git a/test/_files/PharModulePharTarGz.phar.tar.gz b/test/_files/PharModulePharTarGz.phar.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..cc776967cf574cdee0d38cee2a5aedfbfd49403c GIT binary patch literal 291 zcmV+;0o?u{iwFP!000001M|&KDa}dME66Bdpcya#0y8r+tm0r`X3k(}Xl7z)YG7(^ zZUhoHGc__)Frb~25TLZUB(Vr+B|YpKguuog81)KVTzQGPsl^3}$*Bqf8Hq){;8X!( zg(McaS6Op$CFdj-7b`%-xvFai+S#LkN&uMi6N~hVOG=YyR|XKw|K=v>`QO~g)O=e`ECgZ)jj-W-yxn=>V93SOkb2oFmn} pd!s@UpQtIYt+*z(Pe(U)pxrhKM!_f;1*3p=003Q4HM9T_000L>dkX*n literal 0 HcmV?d00001 diff --git a/test/_files/PharModulePharZip.phar.zip b/test/_files/PharModulePharZip.phar.zip new file mode 100644 index 0000000000000000000000000000000000000000..94361cb01fbb01f1b63b7db45d6139dfc9fa474c GIT binary patch literal 585 zcmWIWW@cdk1M{VJ_ET!IeNBNp5awbKV(`sRDa}dME66CwE9GMd*LG~##t2c(z+ht! z6jtEk%1g{mEiOn*PE`oVNGyWr0I{Mn3#_@gl5-M^ixnWET-CJ!DAvskTU%rUG!KON zfYt#mN-WYZE-6jIXQjTrLRDsgZc<`#YKj6#heBdeazhJX2+Wwt}!Q!sg8Myu^~yqEx-4%sh~f{|nu81gd}n zCLk>W#0I)itTT*H*NVoh-g~g;=*QiQqb~$_GlHbS09#1HJ&+J443 z1A)@wlEfmQl{7GVC>UvD4~%*RF0Q=9+|=TN#N41?M62uWI zDC>R$=U<%)@^?A*EXC~N1*m0XOHov!;Hga}TGcoLU- p_UP0(lOtl*FbFejS-@nfx*Te zD6GK6m6w>CT3nEroT?Czkyr%L5tUhB&Bc|RlUQ7=01@G;t_|>JWP)kNW*JNlLgTYK Sz?+o~q>2#;y?}H!SPKBahAGtm literal 0 HcmV?d00001 diff --git a/test/_files/ZendLoaderAutoloader/Foo.php b/test/_files/ZendLoaderAutoloader/Foo.php new file mode 100644 index 0000000..6c7fa6e --- /dev/null +++ b/test/_files/ZendLoaderAutoloader/Foo.php @@ -0,0 +1,18 @@ + 0) { + foreach ($glob as $file) { + if (!is_dir($file)) { + unlink($file); + } + } + } + $filename = $name . '.phar'; + $phar = new Phar($filename); + switch ($mode) { + case 'normal': + $phar['Module.php'] = "convertToData($format, $compression); + } else { + $phar->setDefaultStub('Module.php', 'Module.php'); + if ($format !== Phar::PHAR || $compression !== Phar::NONE) { + $phar->convertToExecutable($format, $compression); + } + } + if ($format !== Phar::PHAR || $compression !== Phar::NONE) { + unlink($filename); + } + echo "Done!\n"; +} diff --git a/test/_files/badmap.php b/test/_files/badmap.php new file mode 100644 index 0000000..916d122 --- /dev/null +++ b/test/_files/badmap.php @@ -0,0 +1,2 @@ +WJDFr~Khm8Z=TUU0joZ@{@uXC;bZu)|FC@8N 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 $basePath . $ds . 'StandardAutoloaderTest.php', + 'ZendTest\Loader\ClassMapAutoloaderTest' => $basePath . $ds . 'ClassMapAutoloaderTest.php', +); diff --git a/test/bootstrap.php b/test/bootstrap.php new file mode 100644 index 0000000..7a904a5 --- /dev/null +++ b/test/bootstrap.php @@ -0,0 +1,34 @@ +