diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..eab5706e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,195 @@ +# CHANGELOG + +## v3.O.0 + +### Changed + +v3 of the ServiceManager component is a completely rewritten, more efficient implementation of the service locator +pattern. It includes a number of breaking changes, that are outlined in this section. + +- Peering has been removed. It was a complex and rarely used feature that was misunderstood most of the time. + +- Integration with `Zend\Di` has been removed. It may be re-integrated later as part of another component. + +- You no longer need a `Zend\ServiceManager\Config` object to configure the service manager, but you instead need to +simply pass an array. + +In ZF 2.x: + +```php +$config = new \Zend\ServiceManager\Config([ + 'factories' => [...] +]); + +$sm = new \Zend\ServiceManager\ServiceManager($config); +``` + +In ZF 3.x: + +```php +$sm = new \Zend\ServiceManager\ServiceManager([ + 'factories' => [...] +]); +``` + +- Service manager is now immutable. Once configured, it cannot be altered. You need to create a new service manager +if you need to change the configuration. This allow to ensure safer and more aggressive caching. + +- `invokables` key no longer exists. It has been replaced by a built-in factory. + +In ZF 2.x: + +```php +return [ + 'service_manager' => [ + 'invokables' => [ + MyClass::class => MyClass:class + ] + ] +]; +``` + +In ZF 3.x: + +```php +return [ + 'service_manager' => [ + 'factories' => [ + MyClass::class => \Zend\ServiceManager\Factory\InvokableFactory:class + ] + ] +]; +``` + +- Interfaces for `FactoryInterface`, `DelegatorFactoryInterface` and `AbstractFactoryInterface` have changed. Now, +they are all callable. This allow to optimize performance. Most of the time, rewriting a factory to match new interface +implies replacing the method name by `__invoke`. + +For instance, here is a simple ZF 2.x factory: + +```php +class MyFactory implements FactoryInterface +{ + function createService(ServiceLocatorInterface $sl) + { + // ... + } +} +``` + +The equivalent ZF 3.x factory: + +```php +class MyFactory implements FactoryInterface +{ + function __invoke(ServiceLocatorInterface $sl, $requestedName) + { + // ... + } +} +``` + +As you can see, factories also receive a second parameter enforce through interface, that allows to easily map multiple +service names to the same factory. + +- Plugin managers will now receive the parent service locator instead of itself in factories. In ZF 2.x, you needed +to call the method `getServiceLocator` to retrieve the main service locator. This was confusing, and was not IDE friendly +as this method was not enforced through interface. + +In ZF 2.x, if a factory was set to a service name defined in a plugin manager: + +```php +class MyFactory implements FactoryInterface +{ + function createService(ServiceLocatorInterface $sl) + { + // $sl is actually a plugin manager + + $parentLocator = $sl->getServiceLocator(); + + // ... + } +} +``` + +In ZF 3.x: + +```php +class MyFactory implements FactoryInterface +{ + function __invoke(ServiceLocatorInterface $sl, $requestedName) + { + // $sl is already the main, parent service locator. If you need to retrieve the plugin manager again, you + // can retrieve it through the SL + $pluginManager = $sl->get(MyPluginManager::class); + // ... + } +} +``` + +In practice, this should reduce code as dependencies often come from the main service locator, and not the plugin +manager itself. + +- `PluginManager` now enforce the need for the main service locator in their constructor. In ZF2, people often forgot +to set the parent locator, which leads to bugs in factories trying to fetch dependencies from the parent locator. + +- `MutableCreationOptionsInterface` has been removed, as options can now be passed directly through factories. (??) + +- `ServiceLocatorAwareInterface` and its associated trait has been removed. It was an anti-pattern, and you are encouraged +to inject your dependencies in factories instead of injecting the whole service locator. + +- It's so fast now that your app will fly. + +### Added + +- You can now map multiple key names to the same factory. It was previously possible in ZF2 but it was not enforced +by the `FactoryInterface` interface. Now, this interface receives the `$requestedName` as second parameter. + +Example: + +```php +$sm = new \Zend\ServiceManager\ServiceManager([ + 'factories' => [ + MyClassA::class => MyFactory::class, + MyClassB::class => MyFactory::class + ] +]); + +$sm->get(MyClassA::class); // MyFactory will receive MyClassA::class as second parameter +``` + +- Writing a plugin manager has been simplified. If you have simple needs, you no longer need to implement the complete +`validate` method. + +In ZF 2.x, if your plugin manager only accepts to create instances that implement `Zend\Validator\ValidatorInterface`, +you needed to write this code: + +```php +class MyPluginManager extends AbstractPluginManager +{ + public function validate($instance) + { + if ($instance instanceof \Zend\Validator\ValidatorInterface) { + return; + } + + throw new InvalidServiceException(sprintf( + 'Plugin manager "%s" expected an instance of type "%s", but "%s" was received', + __CLASS__, + \Zend\Validator\ValidatorInterface::class, + is_object($instance) ? get_class($instance) : gettype($instance) + )); + } +} +``` + +In ZF 3.x: + +```php +class MyPluginManager extends AbstractPluginManager +{ + protected $instanceOf = \Zend\Validator\ValidatorInterface::class; +} +``` + +Of course, you can still override `validate` method if your logic is more complex. \ No newline at end of file diff --git a/composer.json b/composer.json index edbaf75a..04e1852b 100644 --- a/composer.json +++ b/composer.json @@ -3,29 +3,38 @@ "description": " ", "license": "BSD-3-Clause", "keywords": [ - "zf2", - "servicemanager" + "zf", + "servicemanager", + "service-manager" ], + "homepage": "https://github.com/zendframework/zend-servicemanager", "autoload": { "psr-4": { - "Zend\\ServiceManager": "src/" + "Zend\\ServiceManager\\": "src/" } }, "require": { - "php": ">=5.3.3" + "php": ">=5.5", + "container-interop/container-interop": "*" + }, + "require-dev": { + "phpunit/phpunit": "~4.6", + "ocramius/proxy-manager": "~1.0", + "fabpot/php-cs-fixer": "1.7.*", + "satooshi/php-coveralls": "dev-master" }, "suggest": { - "zendframework/zend-di": "Zend\\Di component" + "ocramius/proxy-manager": "ProxyManager 1.* to handle lazy initialization of services" + }, + "extra": { + "branch-alias": { + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" + } }, - "homepage": "https://github.com/zendframework/zend-service-manager", "autoload-dev": { "psr-4": { "ZendTest\\ServiceManager\\": "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/composer.lock b/composer.lock new file mode 100644 index 00000000..2223ffb6 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1840 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "4a81fdcda2ed3080af3981c96346d49b", + "packages": [ + { + "name": "container-interop/container-interop", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "time": "2014-12-30 15:22:37" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "fabpot/php-cs-fixer", + "version": "v1.7.1", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "8785276c44a36ca5235a3b6133e3ffbe989ee431" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/8785276c44a36ca5235a3b6133e3ffbe989ee431", + "reference": "8785276c44a36ca5235a3b6133e3ffbe989ee431", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.6", + "sebastian/diff": "~1.1", + "symfony/console": "~2.3", + "symfony/event-dispatcher": "~2.1", + "symfony/filesystem": "~2.1", + "symfony/finder": "~2.1", + "symfony/process": "~2.3", + "symfony/stopwatch": "~2.5" + }, + "require-dev": { + "satooshi/php-coveralls": "0.7.*@dev" + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "Symfony\\CS\\": "Symfony/CS/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dariusz RumiƄski", + "email": "dariusz.ruminski@gmail.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "A script to automatically fix Symfony Coding Standard", + "time": "2015-05-04 16:56:09" + }, + { + "name": "guzzle/guzzle", + "version": "v3.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-03-18 18:23:50" + }, + { + "name": "ocramius/proxy-manager", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/ProxyManager.git", + "reference": "a80a39fac4fbd771aea7d3871929933a3a1bbf3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/a80a39fac4fbd771aea7d3871929933a3a1bbf3e", + "reference": "a80a39fac4fbd771aea7d3871929933a3a1bbf3e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "zendframework/zend-code": ">2.2.5,<3.0" + }, + "require-dev": { + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "1.5.*" + }, + "suggest": { + "ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects", + "zendframework/zend-json": "To have the JsonRpc adapter (Remote Object feature)", + "zendframework/zend-soap": "To have the Soap adapter (Remote Object feature)", + "zendframework/zend-stdlib": "To use the hydrator proxy", + "zendframework/zend-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "ProxyManager\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A library providing utilities to generate, instantiate and generally operate with Object Proxies", + "homepage": "https://github.com/Ocramius/ProxyManager", + "keywords": [ + "aop", + "lazy loading", + "proxy", + "proxy pattern", + "service proxies" + ], + "time": "2014-12-12 10:59:05" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, + { + "name": "phpspec/prophecy", + "version": "v1.4.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373", + "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "phpdocumentor/reflection-docblock": "~2.0", + "sebastian/comparator": "~1.1" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2015-04-27 22:15:08" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.1.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "07e27765596d72c378a6103e80da5d84e802f1e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/07e27765596d72c378a6103e80da5d84e802f1e4", + "reference": "07e27765596d72c378a6103e80da5d84e802f1e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "~1.0", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-06-30 06:52:35" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb", + "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-04-02 05:19:05" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "83fe1bdc5d47658b727595c14da140da92b3d66d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/83fe1bdc5d47658b727595c14da140da92b3d66d", + "reference": "83fe1bdc5d47658b727595c14da140da92b3d66d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2015-06-13 07:35:30" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "7a9b0969488c3c54fd62b4d504b3ec758fd005d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/7a9b0969488c3c54fd62b4d504b3ec758fd005d9", + "reference": "7a9b0969488c3c54fd62b4d504b3ec758fd005d9", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-06-19 03:43:16" + }, + { + "name": "phpunit/phpunit", + "version": "4.7.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "0ebabb4cda7d066be8391dfdbaf57fe70ac9a99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0ebabb4cda7d066be8391dfdbaf57fe70ac9a99b", + "reference": "0ebabb4cda7d066be8391dfdbaf57fe70ac9a99b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "~1.3,>=1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": ">=1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.2", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-06-30 06:53:57" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "1c330b1b6e1ea8fd15f2fbea46770576e366855c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/1c330b1b6e1ea8fd15f2fbea46770576e366855c", + "reference": "1c330b1b6e1ea8fd15f2fbea46770576e366855c", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-07-04 05:41:32" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "satooshi/php-coveralls", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/satooshi/php-coveralls.git", + "reference": "2fbf803803d179ab1082807308a67bbd5a760c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/2fbf803803d179ab1082807308a67bbd5a760c70", + "reference": "2fbf803803d179ab1082807308a67bbd5a760c70", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-simplexml": "*", + "guzzle/guzzle": ">=2.7", + "php": ">=5.3", + "psr/log": "1.0.0", + "symfony/config": ">=2.0", + "symfony/console": ">=2.0", + "symfony/stopwatch": ">=2.2", + "symfony/yaml": ">=2.0" + }, + "require-dev": { + "apigen/apigen": "2.8.*@stable", + "pdepend/pdepend": "dev-master as 2.0.0", + "phpmd/phpmd": "dev-master", + "phpunit/php-invoker": ">=1.1.0,<1.2.0", + "phpunit/phpunit": "3.7.*@stable", + "sebastian/finder-facade": "dev-master", + "sebastian/phpcpd": "1.4.*@stable", + "squizlabs/php_codesniffer": "1.4.*@stable", + "theseer/fdomdocument": "dev-master" + }, + "suggest": { + "symfony/http-kernel": "Allows Symfony integration" + }, + "bin": [ + "composer/bin/coveralls" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.7-dev" + } + }, + "autoload": { + "psr-0": { + "Satooshi\\Component": "src/", + "Satooshi\\Bundle": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kitamura Satoshi", + "email": "with.no.parachute@gmail.com", + "homepage": "https://www.facebook.com/satooshi.jp" + } + ], + "description": "PHP client library for Coveralls API", + "homepage": "https://github.com/satooshi/php-coveralls", + "keywords": [ + "ci", + "coverage", + "github", + "test" + ], + "time": "2014-11-11 15:35:34" + }, + { + "name": "sebastian/comparator", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-01-29 16:28:08" + }, + { + "name": "sebastian/diff", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-02-22 15:13:53" + }, + { + "name": "sebastian/environment", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e", + "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2015-01-01 10:01:08" + }, + { + "name": "sebastian/exporter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "84839970d05254c73cde183a721c7af13aede943" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-01-27 07:23:06" + }, + { + "name": "sebastian/global-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2014-10-06 09:23:50" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-01-24 09:48:32" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21 13:59:46" + }, + { + "name": "symfony/config", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Config.git", + "reference": "58ded81f1f582a87c528ef3dae9a859f78b5f374" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Config/zipball/58ded81f1f582a87c528ef3dae9a859f78b5f374", + "reference": "58ded81f1f582a87c528ef3dae9a859f78b5f374", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/filesystem": "~2.3" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2015-06-11 14:06:56" + }, + { + "name": "symfony/console", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Console.git", + "reference": "564398bc1f33faf92fc2ec86859983d30eb81806" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Console/zipball/564398bc1f33faf92fc2ec86859983d30eb81806", + "reference": "564398bc1f33faf92fc2ec86859983d30eb81806", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/phpunit-bridge": "~2.7", + "symfony/process": "~2.1" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2015-06-10 15:30:22" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "be3c5ff8d503c46768aeb78ce6333051aa6f26d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/be3c5ff8d503c46768aeb78ce6333051aa6f26d9", + "reference": "be3c5ff8d503c46768aeb78ce6333051aa6f26d9", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/phpunit-bridge": "~2.7", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2015-06-08 09:37:21" + }, + { + "name": "symfony/filesystem", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Filesystem.git", + "reference": "a0d43eb3e17d4f4c6990289805a488a0482a07f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/a0d43eb3e17d4f4c6990289805a488a0482a07f3", + "reference": "a0d43eb3e17d4f4c6990289805a488a0482a07f3", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2015-06-08 09:37:21" + }, + { + "name": "symfony/finder", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Finder.git", + "reference": "c13a40d638aeede1e8400f8c956c7f9246c05f75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Finder/zipball/c13a40d638aeede1e8400f8c956c7f9246c05f75", + "reference": "c13a40d638aeede1e8400f8c956c7f9246c05f75", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2015-06-04 20:11:48" + }, + { + "name": "symfony/process", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process.git", + "reference": "552d8efdc80980cbcca50b28d626ac8e36e3cdd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Process/zipball/552d8efdc80980cbcca50b28d626ac8e36e3cdd1", + "reference": "552d8efdc80980cbcca50b28d626ac8e36e3cdd1", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2015-06-08 09:37:21" + }, + { + "name": "symfony/stopwatch", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Stopwatch.git", + "reference": "c653f1985f6c2b7dbffd04d48b9c0a96aaef814b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/c653f1985f6c2b7dbffd04d48b9c0a96aaef814b", + "reference": "c653f1985f6c2b7dbffd04d48b9c0a96aaef814b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "time": "2015-06-04 20:11:48" + }, + { + "name": "symfony/yaml", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "9808e75c609a14f6db02f70fccf4ca4aab53c160" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/9808e75c609a14f6db02f70fccf4ca4aab53c160", + "reference": "9808e75c609a14f6db02f70fccf4ca4aab53c160", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2015-06-10 15:30:22" + }, + { + "name": "zendframework/zend-code", + "version": "2.5.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-code.git", + "reference": "5d998f261ec2a55171c71da57a11622745680153" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-code/zipball/5d998f261ec2a55171c71da57a11622745680153", + "reference": "5d998f261ec2a55171c71da57a11622745680153", + "shasum": "" + }, + "require": { + "php": ">=5.3.23", + "zendframework/zend-eventmanager": "~2.5" + }, + "require-dev": { + "doctrine/common": ">=2.1", + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-stdlib": "~2.5", + "zendframework/zend-version": "~2.5" + }, + "suggest": { + "doctrine/common": "Doctrine\\Common >=2.1 for annotation features", + "zendframework/zend-stdlib": "Zend\\Stdlib component" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev", + "dev-develop": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Code\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides facilities to generate arbitrary code using an object oriented interface", + "homepage": "https://github.com/zendframework/zend-code", + "keywords": [ + "code", + "zf2" + ], + "time": "2015-06-03 15:31:59" + }, + { + "name": "zendframework/zend-eventmanager", + "version": "2.5.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-eventmanager.git", + "reference": "d94a16039144936f107f906896349900fd634443" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/d94a16039144936f107f906896349900fd634443", + "reference": "d94a16039144936f107f906896349900fd634443", + "shasum": "" + }, + "require": { + "php": ">=5.3.23", + "zendframework/zend-stdlib": "~2.5" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev", + "dev-develop": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\EventManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-eventmanager", + "keywords": [ + "eventmanager", + "zf2" + ], + "time": "2015-06-03 15:32:01" + }, + { + "name": "zendframework/zend-stdlib", + "version": "2.5.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-stdlib.git", + "reference": "cc8e90a60dd5d44b9730b77d07b97550091da1ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/cc8e90a60dd5d44b9730b77d07b97550091da1ae", + "reference": "cc8e90a60dd5d44b9730b77d07b97550091da1ae", + "shasum": "" + }, + "require": { + "php": ">=5.3.23" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-config": "~2.5", + "zendframework/zend-eventmanager": "~2.5", + "zendframework/zend-filter": "~2.5", + "zendframework/zend-inputfilter": "~2.5", + "zendframework/zend-serializer": "~2.5", + "zendframework/zend-servicemanager": "~2.5" + }, + "suggest": { + "zendframework/zend-eventmanager": "To support aggregate hydrator usage", + "zendframework/zend-filter": "To support naming strategy hydrator usage", + "zendframework/zend-serializer": "Zend\\Serializer component", + "zendframework/zend-servicemanager": "To support hydrator plugin manager usage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev", + "dev-develop": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Stdlib\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-stdlib", + "keywords": [ + "stdlib", + "zf2" + ], + "time": "2015-06-03 15:32:03" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "satooshi/php-coveralls": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.5" + }, + "platform-dev": [] +} diff --git a/src/AbstractFactoryInterface.php b/src/AbstractFactoryInterface.php deleted file mode 100644 index fe1f1b58..00000000 --- a/src/AbstractFactoryInterface.php +++ /dev/null @@ -1,17 +0,0 @@ -addInitializer(function ($instance) use ($self) { - if ($instance instanceof ServiceLocatorAwareInterface) { - $instance->setServiceLocator($self); - } - if ($instance instanceof ServiceManagerAwareInterface) { - $instance->setServiceManager($self); - } - }); + parent::__construct($config); + $this->creationContext = $parentLocator; } /** - * Validate the plugin - * - * Checks that the filter loaded is either a valid callback or an instance - * of FilterInterface. - * - * @param mixed $plugin - * @return void - * @throws Exception\RuntimeException if invalid - */ - abstract public function validatePlugin($plugin); - - /** - * Retrieve a service from the manager by name - * - * Allows passing an array of options to use when creating the instance. - * createFromInvokable() will use these and pass them to the instance - * constructor if not null and a non-empty array. - * - * @param string $name - * @param array $options - * @param bool $usePeeringServiceManagers - * @return object + * {@inheritDoc} */ - public function get($name, $options = array(), $usePeeringServiceManagers = true) + public function get($name, array $options = []) { - // Allow specifying a class name directly; registers as an invokable class - if (!$this->has($name) && $this->autoAddInvokableClass && class_exists($name)) { - $this->setInvokableClass($name, $name); - } + $instance = parent::get($name, $options); + $this->validate($instance); - $this->creationOptions = $options; - $instance = parent::get($name, $usePeeringServiceManagers); - $this->creationOptions = null; - $this->validatePlugin($instance); return $instance; } /** - * Register a service with the locator. - * - * Validates that the service object via validatePlugin() prior to - * attempting to register it. - * - * @param string $name - * @param mixed $service - * @param bool $shared - * @return AbstractPluginManager - * @throws Exception\InvalidServiceNameException - */ - public function setService($name, $service, $shared = true) - { - if ($service) { - $this->validatePlugin($service); - } - parent::setService($name, $service, $shared); - return $this; - } - - /** - * Set the main service locator so factories can have access to it to pull deps - * - * @param ServiceLocatorInterface $serviceLocator - * @return AbstractPluginManager - */ - public function setServiceLocator(ServiceLocatorInterface $serviceLocator) - { - $this->serviceLocator = $serviceLocator; - return $this; - } - - /** - * Get the main plugin manager. Useful for fetching dependencies from within factories. - * - * @return mixed - */ - public function getServiceLocator() - { - return $this->serviceLocator; - } - - /** - * Attempt to create an instance via an invokable class - * - * Overrides parent implementation by passing $creationOptions to the - * constructor, if non-null. - * - * @param string $canonicalName - * @param string $requestedName - * @return null|\stdClass - * @throws Exception\ServiceNotCreatedException If resolved class does not exist + * {@inheritDoc} */ - protected function createFromInvokable($canonicalName, $requestedName) + public function validate($instance) { - $invokable = $this->invokableClasses[$canonicalName]; - - if (null === $this->creationOptions - || (is_array($this->creationOptions) && empty($this->creationOptions)) - ) { - $instance = new $invokable(); - } else { - $instance = new $invokable($this->creationOptions); + if (empty($this->instanceOf) || $instance instanceof $this->instanceOf) { + return; } - return $instance; + throw new InvalidServiceException(sprintf( + 'Plugin manager "%s" expected an instance of type "%s", but "%s" was received', + __CLASS__, + $this->instanceOf, + is_object($instance) ? get_class($instance) : gettype($instance) + )); } -} +} \ No newline at end of file diff --git a/src/Config.php b/src/Config.php deleted file mode 100644 index 3518e4cd..00000000 --- a/src/Config.php +++ /dev/null @@ -1,96 +0,0 @@ -config = $config; - } - - public function getAllowOverride() - { - return (isset($this->config['allow_override'])) ? $this->config['allow_override'] : null; - } - - public function getFactories() - { - return (isset($this->config['factories'])) ? $this->config['factories'] : array(); - } - - public function getAbstractFactories() - { - return (isset($this->config['abstract_factories'])) ? $this->config['abstract_factories'] : array(); - } - - public function getInvokables() - { - return (isset($this->config['invokables'])) ? $this->config['invokables'] : array(); - } - - public function getServices() - { - return (isset($this->config['services'])) ? $this->config['services'] : array(); - } - - public function getAliases() - { - return (isset($this->config['aliases'])) ? $this->config['aliases'] : array(); - } - - public function getInitializers() - { - return (isset($this->config['initializers'])) ? $this->config['initializers'] : array(); - } - - public function getShared() - { - return (isset($this->config['shared'])) ? $this->config['shared'] : array(); - } - - public function configureServiceManager(ServiceManager $serviceManager) - { - $allowOverride = $this->getAllowOverride(); - isset($allowOverride) ? $serviceManager->setAllowOverride($allowOverride) : null; - - foreach ($this->getFactories() as $name => $factory) { - $serviceManager->setFactory($name, $factory); - } - - foreach ($this->getAbstractFactories() as $factory) { - $serviceManager->addAbstractFactory($factory); - } - - foreach ($this->getInvokables() as $name => $invokable) { - $serviceManager->setInvokableClass($name, $invokable); - } - - foreach ($this->getServices() as $name => $service) { - $serviceManager->setService($name, $service); - } - - foreach ($this->getAliases() as $alias => $nameOrAlias) { - $serviceManager->setAlias($alias, $nameOrAlias); - } - - foreach ($this->getInitializers() as $initializer) { - $serviceManager->addInitializer($initializer); - } - - foreach ($this->getShared() as $name => $isShared) { - $serviceManager->setShared($name, $isShared); - } - } - -} diff --git a/src/ConfigInterface.php b/src/ConfigInterface.php deleted file mode 100644 index 2c4fa89f..00000000 --- a/src/ConfigInterface.php +++ /dev/null @@ -1,16 +0,0 @@ -di = $di; - if (in_array($useServiceLocator, array(self::USE_SL_BEFORE_DI, self::USE_SL_AFTER_DI, self::USE_SL_NONE))) { - $this->useServiceLocator = $useServiceLocator; - } - - // since we are using this in a proxy-fashion, localize state - $this->definitions = $this->di->definitions; - $this->instanceManager = $this->di->instanceManager; - } - - /** - * {@inheritDoc} - */ - public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $serviceName, $requestedName) - { - $this->serviceLocator = $serviceLocator; - if ($requestedName) { - return $this->get($requestedName, array(), true); - } else { - return $this->get($serviceName, array(), true); - } - - } - - /** - * {@inheritDoc} - */ - public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) - { - return $this->instanceManager->hasSharedInstance($requestedName) - || $this->instanceManager->hasAlias($requestedName) - || $this->instanceManager->hasConfig($requestedName) - || $this->instanceManager->hasTypePreferences($requestedName) - || $this->definitions->hasClass($requestedName); - } -} diff --git a/src/Di/DiInstanceManagerProxy.php b/src/Di/DiInstanceManagerProxy.php deleted file mode 100644 index 45e34794..00000000 --- a/src/Di/DiInstanceManagerProxy.php +++ /dev/null @@ -1,66 +0,0 @@ -diInstanceManager = $diInstanceManager; - $this->serviceLocator = $serviceLocator; - - // localize state - $this->aliases = &$diInstanceManager->aliases; - $this->sharedInstances = &$diInstanceManager->sharedInstances; - $this->sharedInstancesWithParams = &$diInstanceManager->sharedInstancesWithParams; - $this->configurations = &$diInstanceManager->configurations; - $this->typePreferences = &$diInstanceManager->typePreferences; - } - - /** - * @param $classOrAlias - * @return bool - */ - public function hasSharedInstance($classOrAlias) - { - return ($this->serviceLocator->has($classOrAlias) || $this->diInstanceManager->hasSharedInstance($classOrAlias)); - } - - /** - * @param $classOrAlias - * @return mixed - */ - public function getSharedInstance($classOrAlias) - { - if ($this->serviceLocator->has($classOrAlias)) { - return $this->serviceLocator->get($classOrAlias); - } else { - return $this->diInstanceManager->getSharedInstance($classOrAlias); - } - } -} diff --git a/src/Di/DiServiceFactory.php b/src/Di/DiServiceFactory.php deleted file mode 100644 index 4a341aba..00000000 --- a/src/Di/DiServiceFactory.php +++ /dev/null @@ -1,120 +0,0 @@ -di = $di; - $this->name = $name; - $this->parameters = $parameters; - if (in_array($useServiceLocator, array(self::USE_SL_BEFORE_DI, self::USE_SL_AFTER_DI, self::USE_SL_NONE))) { - $this->useServiceLocator = $useServiceLocator; - } - - // since we are using this in a proxy-fashion, localize state - $this->definitions = $this->di->definitions; - $this->instanceManager = $this->di->instanceManager; - } - - /** - * @param ServiceLocatorInterface $serviceLocator - * @return object - */ - public function createService(ServiceLocatorInterface $serviceLocator) - { - $this->serviceLocator = $serviceLocator; - return $this->get($this->name, $this->parameters, true); - } - - /** - * Override, as we want it to use the functionality defined in the proxy - * - * @param string $name - * @param array $params - * @return object - * @throws Exception\InvalidServiceNameException - */ - public function get($name, array $params = array()) - { - // allow this di service to get dependencies from the service locator BEFORE trying di - if ($this->useServiceLocator == self::USE_SL_BEFORE_DI && $this->serviceLocator->has($name)) { - return $this->serviceLocator->get($name); - } - - try { - - $service = parent::get($name, $params); - return $service; - - } catch (DiClassNotFoundException $e) { - - // allow this di service to get dependencies from the service locator AFTER trying di - if ($this->useServiceLocator == self::USE_SL_AFTER_DI && $this->serviceLocator->has($name)) { - return $this->serviceLocator->get($name); - } else { - throw new Exception\ServiceNotFoundException( - sprintf('Service %s was not found in this DI instance', $name), - null, - $e - ); - } - } - - } - -} diff --git a/src/Di/DiServiceInitializer.php b/src/Di/DiServiceInitializer.php deleted file mode 100644 index 3480703c..00000000 --- a/src/Di/DiServiceInitializer.php +++ /dev/null @@ -1,64 +0,0 @@ -di = $di; - $this->serviceLocator = $serviceLocator; - $this->diInstanceManagerProxy = ($diImProxy) ?: new DiInstanceManagerProxy($di->instanceManager(), $serviceLocator); - } - - /** - * @param $instance - */ - public function initialize($instance, ServiceLocatorInterface $serviceLocator) - { - $instanceManager = $this->di->instanceManager; - $this->di->instanceManager = $this->diInstanceManagerProxy; - try { - $this->di->injectDependencies($instance); - $this->di->instanceManager = $instanceManager; - } catch (\Exception $e) { - $this->di->instanceManager = $instanceManager; - throw $e; - } - } - -} diff --git a/src/Exception/CircularDependencyFoundException.php b/src/Exception/CircularDependencyFoundException.php deleted file mode 100644 index 3e394fdf..00000000 --- a/src/Exception/CircularDependencyFoundException.php +++ /dev/null @@ -1,19 +0,0 @@ -get('Config'); + + if (!isset($config['lazy_services'])) { + throw new Exception\InvalidArgumentException('Missing "lazy_services" config key'); + } + + $lazyServices = $config['lazy_services']; + + if (!isset($lazyServices['class_map'])) { + throw new Exception\InvalidArgumentException('Missing "class_map" config key in "lazy_services"'); + } + + $factoryConfig = new ProxyConfiguration(); + + if (isset($lazyServices['proxies_namespace'])) { + $factoryConfig->setProxiesNamespace($lazyServices['proxies_namespace']); + } + + if (isset($lazyServices['proxies_target_dir'])) { + $factoryConfig->setProxiesTargetDir($lazyServices['proxies_target_dir']); + } + + if (!isset($lazyServices['write_proxy_files']) || !$lazyServices['write_proxy_files']) { + $factoryConfig->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); + } + + spl_autoload_register($factoryConfig->getProxyAutoloader()); + + return new LazyServiceFactory(new LazyLoadingValueHolderFactory($factoryConfig), $lazyServices['class_map']); + } +} \ No newline at end of file diff --git a/src/FactoryInterface.php b/src/FactoryInterface.php deleted file mode 100644 index 6fc8c05c..00000000 --- a/src/FactoryInterface.php +++ /dev/null @@ -1,16 +0,0 @@ -proxyFactory = $proxyFactory; + $this->servicesMap = $servicesMap; + } + + /** + * {@inheritDoc} + * + * @return object|\ProxyManager\Proxy\LazyLoadingInterface|\ProxyManager\Proxy\ValueHolderInterface + */ + public function __invoke(ServiceLocatorInterface $serviceLocator, $name, callable $callback) + { + $initializer = function (&$wrappedInstance, LazyLoadingInterface $proxy) use ($callback) { + $proxy->setProxyInitializer(null); + $wrappedInstance = $callback(); + + return true; + }; + + if (isset($this->servicesMap[$name])) { + return $this->proxyFactory->createProxy($this->servicesMap[$name], $initializer); + } + + throw new Exception\ServiceNotFoundException( + sprintf('The requested service "%s" was not found in the provided services map', $name) + ); + } +} \ No newline at end of file diff --git a/src/ServiceLocatorAwareInterface.php b/src/ServiceLocatorAwareInterface.php deleted file mode 100644 index 40ffde2d..00000000 --- a/src/ServiceLocatorAwareInterface.php +++ /dev/null @@ -1,17 +0,0 @@ - '', '_' => '', ' ' => '', '\\' => '', '/' => ''); + protected $sharedByDefault = true; /** - * @param ConfigInterface $config - */ - public function __construct(ConfigInterface $config = null) - { - if ($config) { - $config->configureServiceManager($this); - } - } - - /** - * @param $allowOverride - * @return ServiceManager - */ - public function setAllowOverride($allowOverride) - { - $this->allowOverride = (bool) $allowOverride; - return $this; - } - - /** - * @return bool - */ - public function getAllowOverride() - { - return $this->allowOverride; - } - - /** - * Set flag indicating whether services are shared by default + * Allow to activate/deactivate shared per service name * - * @param bool $shareByDefault - * @return ServiceManager - * @throws Exception\RuntimeException if allowOverride is false - */ - public function setShareByDefault($shareByDefault) - { - if ($this->allowOverride === false) { - throw new Exception\RuntimeException(sprintf( - '%s: cannot alter default shared service setting; container is marked immutable (allow_override is false)', - __METHOD__ - )); - } - $this->shareByDefault = (bool) $shareByDefault; - return $this; - } - - /** - * Are services shared by default? - * - * @return bool - */ - public function shareByDefault() - { - return $this->shareByDefault; - } - - /** - * @param bool $throwExceptionInCreate - * @return ServiceManager - */ - public function setThrowExceptionInCreate($throwExceptionInCreate) - { - $this->throwExceptionInCreate = $throwExceptionInCreate; - return $this; - } - - /** - * @return bool - */ - public function getThrowExceptionInCreate() - { - return $this->throwExceptionInCreate; - } - - /** - * Set flag indicating whether to pull from peering manager before attempting creation + * Example configuration: * - * @param bool $retrieveFromPeeringManagerFirst - * @return ServiceManager - */ - public function setRetrieveFromPeeringManagerFirst($retrieveFromPeeringManagerFirst = true) - { - $this->retrieveFromPeeringManagerFirst = (bool) $retrieveFromPeeringManagerFirst; - return $this; - } - - /** - * Should we retrieve from the peering manager prior to attempting to create a service? + * 'shared' => [ + * MyService::class => true, // will be shared, even if "sharedByDefault" is false + * MyOtherService::class => false // won't be shared, even if "sharedByDefault" is true + * ] * - * @return bool - */ - public function retrieveFromPeeringManagerFirst() - { - return $this->retrieveFromPeeringManagerFirst; - } - - /** - * @param string $name - * @param string $invokableClass - * @param bool $shared - * @return ServiceManager - * @throws Exception\InvalidServiceNameException - */ - public function setInvokableClass($name, $invokableClass, $shared = true) - { - $cName = $this->canonicalizeName($name); - $rName = $name; - - if ($this->has(array($cName, $rName), false)) { - if ($this->allowOverride === false) { - throw new Exception\InvalidServiceNameException(sprintf( - 'A service by the name or alias "%s" already exists and cannot be overridden; please use an alternate name', - $cName - )); - } - $this->unregisterService($cName); - } - - $this->invokableClasses[$cName] = $invokableClass; - $this->shared[$cName] = (bool) $shared; - - return $this; - } - - /** - * @param string $name - * @param string|FactoryInterface|callable $factory - * @param bool $shared - * @return ServiceManager - * @throws Exception\InvalidServiceNameException - */ - public function setFactory($name, $factory, $shared = true) - { - $cName = $this->canonicalizeName($name); - $rName = $name; - - if (!is_string($factory) && !$factory instanceof FactoryInterface && !is_callable($factory)) { - throw new Exception\InvalidArgumentException( - 'Provided abstract factory must be the class name of an abstract factory or an instance of an AbstractFactoryInterface.' - ); - } - - if ($this->has(array($cName, $rName), false)) { - if ($this->allowOverride === false) { - throw new Exception\InvalidServiceNameException(sprintf( - 'A service by the name or alias "%s" already exists and cannot be overridden, please use an alternate name', - $cName - )); - } - $this->unregisterService($cName); - } - - $this->factories[$cName] = $factory; - $this->shared[$cName] = (bool) $shared; - - return $this; - } - - /** - * @param AbstractFactoryInterface|string $factory - * @param bool $topOfStack - * @return ServiceManager - * @throws Exception\InvalidArgumentException if the abstract factory is invalid - */ - public function addAbstractFactory($factory, $topOfStack = true) - { - if (!is_string($factory) && !$factory instanceof AbstractFactoryInterface) { - throw new Exception\InvalidArgumentException( - 'Provided abstract factory must be the class name of an abstract factory or an instance of an AbstractFactoryInterface.' - ); - } - if (is_string($factory)) { - if (!class_exists($factory, true)) { - throw new Exception\InvalidArgumentException( - 'Provided abstract factory must be the class name of an abstract factory or an instance of an AbstractFactoryInterface.' - ); - } - $refl = new ReflectionClass($factory); - if (!$refl->implementsInterface(__NAMESPACE__ . '\\AbstractFactoryInterface')) { - throw new Exception\InvalidArgumentException( - 'Provided abstract factory must be the class name of an abstract factory or an instance of an AbstractFactoryInterface.' - ); - } - } - - if ($topOfStack) { - array_unshift($this->abstractFactories, $factory); - } else { - array_push($this->abstractFactories, $factory); - } - return $this; - } - - /** - * @param callable|InitializerInterface $initializer - * @return ServiceManager - * @throws Exception\InvalidArgumentException + * @var array */ - public function addInitializer($initializer, $topOfStack = true) - { - if (!is_callable($initializer) && !$initializer instanceof InitializerInterface) { - if (!is_string($initializer) - || !$this->isSubclassOf($initializer, __NAMESPACE__ . '\InitializerInterface') - ) { - throw new Exception\InvalidArgumentException('$initializer should be callable.'); - } - $initializer = new $initializer; - } - - if ($topOfStack) { - array_unshift($this->initializers, $initializer); - } else { - array_push($this->initializers, $initializer); - } - return $this; - } + protected $shared = []; /** - * Register a service with the locator - * - * @param string $name - * @param mixed $service - * @param bool $shared - * @return ServiceManager - * @throws Exception\InvalidServiceNameException + * @var ServiceLocatorInterface */ - public function setService($name, $service, $shared = true) - { - $cName = $this->canonicalizeName($name); - - if ($this->has($cName, false)) { - if ($this->allowOverride === false) { - throw new Exception\InvalidServiceNameException(sprintf( - '%s: A service by the name "%s" or alias already exists and cannot be overridden, please use an alternate name.', - __METHOD__, - $name - )); - } - $this->unregisterService($cName); - } - - $this->instances[$cName] = $service; - $this->shared[$cName] = (bool) $shared; - return $this; - } + protected $creationContext; /** - * @param string $name - * @param bool $isShared - * @return ServiceManager - * @throws Exception\ServiceNotFoundException + * @param array $config */ - public function setShared($name, $isShared) + public function __construct(array $config) { - $cName = $this->canonicalizeName($name); - - if (!isset($this->invokableClasses[$cName]) && !isset($this->factories[$cName])) { - throw new Exception\ServiceNotFoundException(sprintf( - '%s: A service by the name "%s" was not found and could not be marked as shared', - __METHOD__, - $name - )); - } - - $this->shared[$cName] = (bool) $isShared; - return $this; + $this->creationContext = $this; + $this->configure($config); } /** - * Retrieve a registered instance + * {@inheritDoc} * - * @param string $cName - * @param bool $usePeeringServiceManagers - * @return object|array + * This is a highly performance sensitive method, do not modify if you have not benchmarked it carefully */ - public function get($name, $usePeeringServiceManagers = true) + public function get($name, array $options = []) { - $cName = $this->canonicalizeName($name); - $rName = $name; - - if ($this->hasAlias($cName)) { - do { - $cName = $this->aliases[$cName]; - } while ($this->hasAlias($cName)); - - if (!$this->has(array($cName, $rName))) { - throw new Exception\ServiceNotFoundException(sprintf( - 'An alias "%s" was requested but no service could be found.', - $name - )); - } - } + $name = $this->resolveAlias($name); - if (isset($this->instances[$cName])) { - return $this->instances[$cName]; + // We start by checking if the service is cached (this is the fastest method). If options is not empty, we + // never "share" because this could create unexpected behaviour + if (empty($options) && isset($this->services[$name])) { + return $this->services[$name]; } - $instance = null; - $retrieveFromPeeringManagerFirst = $this->retrieveFromPeeringManagerFirst(); - - if ($usePeeringServiceManagers && $retrieveFromPeeringManagerFirst) { - $instance = $this->retrieveFromPeeringManager($name); - } - if (!$instance) { - if ($this->canCreate(array($cName, $rName))) { - $instance = $this->create(array($cName, $rName)); - } elseif ($usePeeringServiceManagers && !$retrieveFromPeeringManagerFirst) { - $instance = $this->retrieveFromPeeringManager($name); + try { + if (!isset($this->delegators[$name])) { + // Let's create the service by fetching the factory + $factory = $this->getFactory($name); + $object = $factory($this->creationContext, $name, $options); + } else { + $object = $this->createDelegatorFromName($name, $options); } - } - - // Still no instance? raise an exception - if (!$instance && !is_array($instance)) { - throw new Exception\ServiceNotFoundException(sprintf( - '%s was unable to fetch or create an instance for %s', - __METHOD__, - $name - ) - ); - } - - if ($this->shareByDefault() && (!isset($this->shared[$cName]) || $this->shared[$cName] === true) - ) { - $this->instances[$cName] = $instance; - } - - return $instance; - } - - /** - * @param string|array $name - * @return false|object - * @throws Exception\ServiceNotCreatedException - * @throws Exception\InvalidServiceNameException - */ - public function create($name) - { - $instance = false; - - if (is_array($name)) { - list($cName, $rName) = $name; - } else { - $rName = $name; - $cName = $this->canonicalizeName($rName); - } - - - if (isset($this->factories[$cName])) { - $instance = $this->createFromFactory($cName, $rName); - } - - if (!$instance && isset($this->invokableClasses[$cName])) { - $instance = $this->createFromInvokable($cName, $rName); - } - - if (!$instance && $this->canCreateFromAbstractFactory($cName, $rName)) { - $instance = $this->createFromAbstractFactory($cName, $rName); - } - - if ($this->throwExceptionInCreate == true && $instance === false) { - throw new Exception\ServiceNotFoundException(sprintf( - 'No valid instance was found for %s%s', - $cName, - ($rName ? '(alias: ' . $rName . ')' : '') + } catch (Exception $exception) { + throw new ServiceNotCreatedException(sprintf( + 'Service with name "%s" could not be created. Reason: %s', + $name, + $exception->getMessage() )); } foreach ($this->initializers as $initializer) { - if ($initializer instanceof InitializerInterface) { - $initializer->initialize($instance, $this); - } elseif (is_object($initializer) && is_callable($initializer)) { - $initializer($instance, $this); - } else { - call_user_func($initializer, $instance, $this); - } - } - - return $instance; - } - - /** - * Determine if we can create an instance. - * - * @param string|array $name - * @return bool - */ - public function canCreate($name, $checkAbstractFactories = true) - { - if (is_array($name)) { - list($cName, $rName) = $name; - } else { - $rName = $name; - $cName = $this->canonicalizeName($rName); + $initializer($this->creationContext, $object); } - if ( - isset($this->invokableClasses[$cName]) - || isset($this->factories[$cName]) - || isset($this->aliases[$cName]) - || isset($this->instances[$cName]) - ) { - return true; + if (($this->sharedByDefault && !isset($this->shared[$name])) + || (isset($this->shared[$name]) && $this->shared[$name])) { + $this->services[$name] = $object; } - if ($checkAbstractFactories && $this->canCreateFromAbstractFactory($cName, $rName)) { - return true; - } - - return false; + return $object; } /** - * @param string|array $name - * @param bool $checkAbstractFactories - * @param bool $usePeeringServiceManagers - * @return bool + * {@inheritDoc} */ - public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = true) + public function has($name, $checkAbstractFactories = false) { - if (is_array($name)) { - list($cName, $rName) = $name; - } else { - $rName = $name; - $cName = $this->canonicalizeName($rName); - } + $name = $this->resolveAlias($name); + $found = isset($this->services[$name]) || isset($this->factories[$name]); - if ($this->canCreate(array($cName, $rName), $checkAbstractFactories)) { - return true; + if ($found || !$checkAbstractFactories) { + return $found; } - if ($usePeeringServiceManagers) { - foreach ($this->peeringServiceManagers as $peeringServiceManager) { - if ($peeringServiceManager->has($rName)) { - return true; - } + // Check abstract factories + foreach ($this->abstractFactories as $abstractFactory) { + if ($abstractFactory->canCreateServiceWithName($name)) { + return true; } } @@ -546,369 +161,145 @@ public function has($name, $checkAbstractFactories = true, $usePeeringServiceMan } /** - * Determine if we can create an instance from an abstract factory. + * Get a factory for the given service name * - * @param string $cName - * @param string $rName - * @return bool - */ - public function canCreateFromAbstractFactory($cName, $rName) - { - // check abstract factories - foreach ($this->abstractFactories as $index => $abstractFactory) { - // Support string abstract factory class names - if (is_string($abstractFactory) && class_exists($abstractFactory, true)) { - $this->abstractFactory[$index] = $abstractFactory = new $abstractFactory(); - } - - if ( - isset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)]) - && $this->pendingAbstractFactoryRequests[get_class($abstractFactory)] == $rName - ) { - return false; - } - - if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) { - return true; - } - } - return false; - } - - /** - * @param string $alias - * @param string $nameOrAlias - * @return ServiceManager - * @throws Exception\ServiceNotFoundException - * @throws Exception\InvalidServiceNameException + * @param string $name + * @return callable + * @throws ServiceNotFoundException */ - public function setAlias($alias, $nameOrAlias) + protected function getFactory($name) { - if (!is_string($alias) || !is_string($nameOrAlias)) { - throw new Exception\InvalidServiceNameException('Service or alias names must be strings.'); - } + $factory = isset($this->factories[$name]) ? $this->factories[$name] : null; - $cAlias = $this->canonicalizeName($alias); - $nameOrAlias = $this->canonicalizeName($nameOrAlias); - - if ($alias == '' || $nameOrAlias == '') { - throw new Exception\InvalidServiceNameException('Invalid service name alias'); + if (is_string($factory)) { + $this->factories[$name] = $factory = new $factory(); } - if ($this->allowOverride === false && $this->has(array($cAlias, $alias), false)) { - throw new Exception\InvalidServiceNameException('An alias by this name already exists'); + if (is_callable($factory)) { + return $factory; } - $this->aliases[$cAlias] = $nameOrAlias; - return $this; - } - - /** - * @param string $alias - * @return bool - */ - public function hasAlias($alias) - { - $alias = $this->canonicalizeName($alias); - return (isset($this->aliases[$alias])); - } - - /** - * @param string $peering - * @return ServiceManager - */ - public function createScopedServiceManager($peering = self::SCOPE_PARENT) - { - $scopedServiceManager = new ServiceManager(); - if ($peering == self::SCOPE_PARENT) { - $scopedServiceManager->peeringServiceManagers[] = $this; - } - if ($peering == self::SCOPE_CHILD) { - $this->peeringServiceManagers[] = $scopedServiceManager; + // Check abstract factories + foreach ($this->abstractFactories as $abstractFactory) { + if ($abstractFactory->canCreateServiceWithName($name)) { + return $abstractFactory; + } } - return $scopedServiceManager; - } - /** - * Add a peering relationship - * - * @param ServiceManager $manager - * @param string $peering - * @return ServiceManager - */ - public function addPeeringServiceManager(ServiceManager $manager, $peering = self::SCOPE_PARENT) - { - if ($peering == self::SCOPE_PARENT) { - $this->peeringServiceManagers[] = $manager; - } - if ($peering == self::SCOPE_CHILD) { - $manager->peeringServiceManagers[] = $this; - } - return $this; + throw new ServiceNotFoundException(sprintf( + 'An invalid or missing factory was given for creating service "%s". Did you make sure you added the service + into the service manager configuration?', + $name + )); } /** * @param string $name - * @return string - */ - protected function canonicalizeName($name) - { - if (isset($this->canonicalNames[$name])) { - return $this->canonicalNames[$name]; - } - - // this is just for performance instead of using str_replace - return $this->canonicalNames[$name] = strtolower(strtr($name, $this->canonicalNamesReplacements)); - } - - /** - * @param callable $callable - * @param string $cName - * @param string $rName - * @throws Exception\ServiceNotCreatedException - * @throws Exception\CircularDependencyFoundException + * @param array $options * @return object */ - protected function createServiceViaCallback($callable, $cName, $rName) + protected function createDelegatorFromName($name, array $options = []) { - static $circularDependencyResolver = array(); - $depKey = spl_object_hash($this) . '-' . $cName; + $delegatorsCount = count($this->delegators[$name]); + $creationCallback = function() use ($name, $options) { + // Code is inlined for performance reason, instead of abstracting the creation + $factory = $this->getFactory($name); + return $factory($this->creationContext, $name, $options); + }; - if (isset($circularDependencyResolver[$depKey])) { - $circularDependencyResolver = array(); - throw new Exception\CircularDependencyFoundException('Circular dependency for LazyServiceLoader was found for instance ' . $rName); - } + for ($i = 0 ; $i < $delegatorsCount ; ++$i) { + $delegatorFactory = $this->delegators[$name][$i]; - try { - $circularDependencyResolver[$depKey] = true; - $instance = call_user_func($callable, $this, $cName, $rName); - unset($circularDependencyResolver[$depKey]); - } catch (Exception\ServiceNotFoundException $e) { - unset($circularDependencyResolver[$depKey]); - throw $e; - } catch (\Exception $e) { - unset($circularDependencyResolver[$depKey]); - throw new Exception\ServiceNotCreatedException( - sprintf('An exception was raised while creating "%s"; no instance returned', $rName), - $e->getCode(), - $e - ); - } - if ($instance === null) { - throw new Exception\ServiceNotCreatedException('The factory was called but did not return an instance.'); + if (is_string($delegatorFactory)) { + $delegatorFactory = $this->delegators[$name][$i] = new $delegatorFactory(); + } + + $creationCallback = function() use ($delegatorFactory, $name, $creationCallback, $options) { + return $delegatorFactory($this->creationContext, $name, $creationCallback, $options); + }; } - return $instance; + return $creationCallback($this->creationContext, $name, $creationCallback, $options); } /** - * Retrieve a keyed list of all registered services. Handy for debugging! + * Configure the service manager * - * @return array - */ - public function getRegisteredServices() - { - return array( - 'invokableClasses' => array_keys($this->invokableClasses), - 'factories' => array_keys($this->factories), - 'aliases' => array_keys($this->aliases), - 'instances' => array_keys($this->instances), - ); - } - - /** - * Retrieve a keyed list of all canonical names. Handy for debugging! + * Valid top keys are: * - * @return array - */ - public function getCanonicalNames() - { - return $this->canonicalNames; - } - - /** - * Allows to override the canonical names lookup map with predefined - * values. + * - factories: a list of key value that map a service name with a factory + * - abstract_factories: a list of object or string of abstract factories + * - shared: a list of key value that map a service name to a boolean + * - shared_by_default: boolean * - * @return array $canonicalNames - * @return ServiceManager + * @param array $config + * @return void */ - public function setCanonicalNames($canonicalNames) + protected function configure(array $config) { - $this->canonicalNames = $canonicalNames; + $this->factories = isset($config['factories']) ? $config['factories'] : []; + $this->delegators = isset($config['delegators']) ? $config['delegators'] : []; + $this->shared = isset($config['shared']) ? $config['shared'] : []; + $this->aliases = isset($config['aliases']) ? $config['aliases'] : []; + $this->sharedByDefault = isset($config['shared_by_default']) ? $config['shared_by_default'] : $this->sharedByDefault; - return $this; - } + // For abstract factories and initializers, we always directly instantiate them to avoid checks during construction + if (isset($config['abstract_factories'])) { + foreach ($config['abstract_factories'] as $abstractFactory) { + if (is_string($abstractFactory)) { + $abstractFactory = new $abstractFactory(); + } - /** - * Attempt to retrieve an instance via a peering manager - * - * @param string $name - * @return mixed - */ - protected function retrieveFromPeeringManager($name) - { - foreach ($this->peeringServiceManagers as $peeringServiceManager) { - if ($peeringServiceManager->has($name)) { - return $peeringServiceManager->get($name); + if (is_callable($abstractFactory)) { + $this->abstractFactories[] = $abstractFactory; + continue; + } + + throw new InvalidArgumentException(sprintf( + 'An invalid abstract factory was registered. A callable or an instance of "%s" was expected, but + "%s" was received', + AbstractFactoryInterface::class, + is_object($abstractFactory) ? get_class($abstractFactory) : gettype($abstractFactory) + )); } } - return null; - } - /** - * Attempt to create an instance via an invokable class - * - * @param string $canonicalName - * @param string $requestedName - * @return null|\stdClass - * @throws Exception\ServiceNotCreatedException If resolved class does not exist - */ - protected function createFromInvokable($canonicalName, $requestedName) - { - $invokable = $this->invokableClasses[$canonicalName]; - if (!class_exists($invokable)) { - throw new Exception\ServiceNotFoundException(sprintf( - '%s: failed retrieving "%s%s" via invokable class "%s"; class does not exist', - __METHOD__, - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : ''), - $canonicalName - )); - } - $instance = new $invokable; - return $instance; - } + if (isset($config['initializers'])) { + foreach ($config['initializers'] as $initializer) { + if (is_string($initializer)) { + $initializer = new $initializer(); + } - /** - * Attempt to create an instance via a factory - * - * @param string $canonicalName - * @param string $requestedName - * @return mixed - * @throws Exception\ServiceNotCreatedException If factory is not callable - */ - protected function createFromFactory($canonicalName, $requestedName) - { - $factory = $this->factories[$canonicalName]; - if (is_string($factory) && class_exists($factory, true)) { - $factory = new $factory; - $this->factories[$canonicalName] = $factory; - } - if ($factory instanceof FactoryInterface) { - $instance = $this->createServiceViaCallback(array($factory, 'createService'), $canonicalName, $requestedName); - } elseif (is_callable($factory)) { - $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName); - } else { - throw new Exception\ServiceNotCreatedException(sprintf( - 'While attempting to create %s%s an invalid factory was registered for this instance type.', - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : '') - )); - } - return $instance; - } + if (is_callable($initializer)) { + $this->initializers[] = $initializer; + continue; + } - /** - * Attempt to create an instance via an abstract factory - * - * @param string $canonicalName - * @param string $requestedName - * @return object|null - * @throws Exception\ServiceNotCreatedException If abstract factory is not callable - */ - protected function createFromAbstractFactory($canonicalName, $requestedName) - { - foreach ($this->abstractFactories as $index => $abstractFactory) { - // support factories as strings - if (is_string($abstractFactory) && class_exists($abstractFactory, true)) { - $this->abstractFactories[$index] = $abstractFactory = new $abstractFactory; - } elseif (!$abstractFactory instanceof AbstractFactoryInterface) { - throw new Exception\ServiceNotCreatedException(sprintf( - 'While attempting to create %s%s an abstract factory could not produce a valid instance.', - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : '') + throw new InvalidArgumentException(sprintf( + 'An invalid initializer was registered. A callable or an instance of "%s" was expected, but + "%s" was received', + InitializerInterface::class, + is_object($initializer) ? get_class($initializer) : gettype($initializer) )); } - try { - $this->pendingAbstractFactoryRequests[get_class($abstractFactory)] = $requestedName; - $instance = $this->createServiceViaCallback( - array($abstractFactory, 'createServiceWithName'), - $canonicalName, - $requestedName - ); - unset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)]); - } catch (\Exception $e) { - unset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)]); - throw new Exception\ServiceNotCreatedException( - sprintf( - 'An abstract factory could not create an instance of %s%s.', - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : '') - ), - $e->getCode(), - $e - ); - } - if (is_object($instance)) { - break; - } } - - return $instance; } /** - * Checks if the object has this class as one of its parents + * Recursively resolve an alias name to a service name * - * @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); - } - - /** - * Unregister a service - * - * Called when $allowOverride is true and we detect that a service being - * added to the instance already exists. This will remove the duplicate - * entry, and also any shared flags previously registered. - * - * @param string $canonical - * @return void + * @param string $alias + * @return string */ - protected function unregisterService($canonical) + private function resolveAlias($alias) { - $types = array('invokableClasses', 'factories', 'aliases'); - foreach ($types as $type) { - if (isset($this->{$type}[$canonical])) { - unset($this->{$type}[$canonical]); - break; - } - } + $name = $alias; - if (isset($this->instances[$canonical])) { - unset($this->instances[$canonical]); - } + do { + $canBeResolved = isset($this->aliases[$name]); + $name = $canBeResolved ? $this->aliases[$name] : $name; + } while ($canBeResolved); - if (isset($this->shared[$canonical])) { - unset($this->shared[$canonical]); - } + return $name; } -} +} \ No newline at end of file diff --git a/src/ServiceManagerAwareInterface.php b/src/ServiceManagerAwareInterface.php deleted file mode 100644 index 5b7f970f..00000000 --- a/src/ServiceManagerAwareInterface.php +++ /dev/null @@ -1,16 +0,0 @@ - [ + InvokableObject::class => InvokableFactory::class + ], + 'aliases' => [ + 'foo' => InvokableObject::class, + 'bar' => 'foo' + ] + ]; + + $serviceLocator = $this->getMock(ServiceLocatorInterface::class); + $this->pluginManager = $this->getMockForAbstractClass( + AbstractAliasedPluginManager::class, + [$serviceLocator, $config] + ); + } + + public function testCreateObjectWithAlias() + { + $object = $this->pluginManager->get('bar'); + $this->assertInstanceOf(InvokableObject::class, $object); + } + + public function testCheckObjectExistanceWithAlias() + { + $this->assertTrue($this->pluginManager->has('bar')); + $this->assertFalse($this->pluginManager->has('baz')); + } +} \ No newline at end of file diff --git a/test/AbstractPluginManagerTest.php b/test/AbstractPluginManagerTest.php new file mode 100644 index 00000000..42a4745c --- /dev/null +++ b/test/AbstractPluginManagerTest.php @@ -0,0 +1,64 @@ +getMock(FactoryInterface::class); + + $config = [ + 'factories' => [ + InvokableObject::class => $invokableFactory + ] + ]; + + $serviceLocator = $this->getMock(ServiceLocatorInterface::class); + $pluginManager = new SimplePluginManager($serviceLocator, $config); + + $invokableFactory->expects($this->once()) + ->method('__invoke') + ->with($serviceLocator, InvokableObject::class) + ->will($this->returnValue(new InvokableObject())); + + $object = $pluginManager->get(InvokableObject::class); + + $this->assertInstanceOf(InvokableObject::class, $object); + } + + public function testValidateInstance() + { + $config = [ + 'factories' => [ + InvokableObject::class => new InvokableFactory(), + stdClass::class => new InvokableFactory() + ] + ]; + + $serviceLocator = $this->getMock(ServiceLocatorInterface::class); + $pluginManager = new SimplePluginManager($serviceLocator, $config); + + // Assert no exception is triggered because the plugin manager validate ObjectWithOptions + $pluginManager->get(InvokableObject::class); + + // Assert it throws an exception for anything else + $this->setExpectedException(InvalidServiceException::class); + $pluginManager->get(stdClass::class); + } +} \ No newline at end of file diff --git a/test/TestAsset/Bar.php b/test/Asset/FactoryObject.php similarity index 52% rename from test/TestAsset/Bar.php rename to test/Asset/FactoryObject.php index d6e74142..405ab569 100644 --- a/test/TestAsset/Bar.php +++ b/test/Asset/FactoryObject.php @@ -3,16 +3,18 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @package Zend_ServiceManager */ -namespace ZendTest\ServiceManager\TestAsset; +namespace ZendTest\ServiceManager\Asset; -class Bar +class FactoryObject { - public function __construct(array $foo) + public $dependency; + + public function __construct($dependency) { + $this->dependency = $dependency; } -} +} \ No newline at end of file diff --git a/test/Asset/InvokableObject.php b/test/Asset/InvokableObject.php new file mode 100644 index 00000000..dd3d5a95 --- /dev/null +++ b/test/Asset/InvokableObject.php @@ -0,0 +1,26 @@ +options = $options; + } +} \ No newline at end of file diff --git a/test/Asset/SimpleAbstractFactory.php b/test/Asset/SimpleAbstractFactory.php new file mode 100644 index 00000000..dc774965 --- /dev/null +++ b/test/Asset/SimpleAbstractFactory.php @@ -0,0 +1,32 @@ +addSharedInstance($this->fooInstance = new \stdClass(), 'foo'); - $this->mockDi = $this->getMock('Zend\Di\Di', array(), array(null, $instanceManager)); - $this->mockServiceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); - $this->diAbstractServiceFactory = new DiAbstractServiceFactory( - $this->mockDi - ); - } - - - /** - * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::__construct - */ - public function testConstructor() - { - $instance = new DiAbstractServiceFactory( - $this->getMock('Zend\Di\Di') - ); - $this->assertInstanceOf('Zend\ServiceManager\Di\DiAbstractServiceFactory', $instance); - } - - /** - * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::createServiceWithName - * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::get - */ - public function testCreateServiceWithName() - { - $foo = $this->diAbstractServiceFactory->createServiceWithName($this->mockServiceLocator, 'foo', 'foo'); - $this->assertEquals($this->fooInstance, $foo); - } - - /** - * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::canCreateServiceWithName - */ - public function testCanCreateServiceWithName() - { - $instance = new DiAbstractServiceFactory($this->getMock('Zend\Di\Di')); - $im = $instance->instanceManager(); - - $locator = new ServiceManager(); - - // will check shared instances - $this->assertFalse($instance->canCreateServiceWithName($locator, 'a-shared-instance-alias', 'a-shared-instance-alias')); - $im->addSharedInstance(new \stdClass(), 'a-shared-instance-alias'); - $this->assertTrue($instance->canCreateServiceWithName($locator, 'a-shared-instance-alias', 'a-shared-instance-alias')); - - // will check aliases - $this->assertFalse($instance->canCreateServiceWithName($locator, 'an-alias', 'an-alias')); - $im->addAlias('an-alias', 'stdClass'); - $this->assertTrue($instance->canCreateServiceWithName($locator, 'an-alias', 'an-alias')); - - // will check instance configurations - $this->assertFalse($instance->canCreateServiceWithName($locator, __NAMESPACE__ . '\Non\Existing', __NAMESPACE__ . '\Non\Existing')); - $im->setConfig(__NAMESPACE__ . '\Non\Existing', array('parameters' => array('a' => 'b'))); - $this->assertTrue($instance->canCreateServiceWithName($locator, __NAMESPACE__ . '\Non\Existing', __NAMESPACE__ . '\Non\Existing')); - - // will check preferences for abstract types - $this->assertFalse($instance->canCreateServiceWithName($locator, __NAMESPACE__ . '\AbstractClass', __NAMESPACE__ . '\AbstractClass')); - $im->setTypePreference(__NAMESPACE__ . '\AbstractClass', array(__NAMESPACE__ . '\Non\Existing')); - $this->assertTrue($instance->canCreateServiceWithName($locator, __NAMESPACE__ . '\AbstractClass', __NAMESPACE__ . '\AbstractClass')); - - // will check definitions - $def = $instance->definitions(); - $this->assertFalse($instance->canCreateServiceWithName($locator, __NAMESPACE__ . '\Other\Non\Existing', __NAMESPACE__ . '\Other\Non\Existing')); - $classDefinition = $this->getMock('Zend\Di\Definition\DefinitionInterface'); - $classDefinition - ->expects($this->any()) - ->method('hasClass') - ->with($this->equalTo(__NAMESPACE__ . '\Other\Non\Existing')) - ->will($this->returnValue(true)); - $def->addDefinition($classDefinition); - $this->assertTrue($instance->canCreateServiceWithName($locator, __NAMESPACE__ . '\Other\Non\Existing', __NAMESPACE__ . '\Other\Non\Existing')); - } -} diff --git a/test/Di/DiServiceFactoryTest.php b/test/Di/DiServiceFactoryTest.php deleted file mode 100644 index cf06afc7..00000000 --- a/test/Di/DiServiceFactoryTest.php +++ /dev/null @@ -1,75 +0,0 @@ -addSharedInstanceWithParameters( - $this->fooInstance = new \stdClass(), - 'foo', - array('bar' => 'baz') - ); - $this->mockDi = $this->getMock('Zend\Di\Di', array(), array(null, $instanceManager)); - $this->mockServiceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); - $this->diServiceFactory = new DiServiceFactory( - $this->mockDi, - 'foo', - array('bar' => 'baz') - ); - } - - /** - * @covers Zend\ServiceManager\Di\DiServiceFactory::__construct - */ - public function testConstructor() - { - $instance = new DiServiceFactory( - $this->getMock('Zend\Di\Di'), - 'string', - array('foo' => 'bar') - ); - $this->assertInstanceOf('Zend\ServiceManager\Di\DiServiceFactory', $instance); - } - - /** - * @covers Zend\ServiceManager\Di\DiServiceFactory::createService - * @covers Zend\ServiceManager\Di\DiServiceFactory::get - */ - public function testCreateService() - { - $foo = $this->diServiceFactory->createService($this->mockServiceLocator); - $this->assertEquals($this->fooInstance, $foo); - } -} diff --git a/test/Di/DiServiceInitializerTest.php b/test/Di/DiServiceInitializerTest.php deleted file mode 100644 index 9cabd777..00000000 --- a/test/Di/DiServiceInitializerTest.php +++ /dev/null @@ -1,74 +0,0 @@ -mockDi = $this->getMock('Zend\Di\Di', array('injectDependencies')); - $this->mockServiceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); - $this->mockDiInstanceManagerProxy = new DiInstanceManagerProxy( - $this->mockDiInstanceManager = $this->getMock('Zend\Di\InstanceManager'), - $this->mockServiceLocator - ); - $this->diServiceInitializer = new DiServiceInitializer( - $this->mockDi, - $this->mockServiceLocator, - $this->mockDiInstanceManagerProxy - ); - - } - - /** - * @covers Zend\ServiceManager\Di\DiServiceInitializer::initialize - */ - public function testInitialize() - { - $instance = new \stdClass(); - - // test di is called with proper instance - $this->mockDi->expects($this->once())->method('injectDependencies')->with($instance); - - $this->diServiceInitializer->initialize($instance, $this->mockServiceLocator); - } - - /** - * @covers Zend\ServiceManager\Di\DiServiceInitializer::initialize - * @todo this needs to be moved into its own class - */ - public function testProxyInstanceManagersStayInSync() - { - $instanceManager = new \Zend\Di\InstanceManager(); - $proxy = new DiInstanceManagerProxy($instanceManager, $this->mockServiceLocator); - $instanceManager->addAlias('foo', 'bar'); - - $this->assertEquals($instanceManager->getAliases(), $proxy->getAliases()); - } - -} diff --git a/test/Factory/InvokableFactoryTest.php b/test/Factory/InvokableFactoryTest.php new file mode 100644 index 00000000..aa5fbebd --- /dev/null +++ b/test/Factory/InvokableFactoryTest.php @@ -0,0 +1,28 @@ +getMock(ServiceLocatorInterface::class); + $factory = new InvokableFactory(); + + $object = $factory($serviceLocator, InvokableObject::class, ['foo' => 'bar']); + + $this->assertInstanceOf(InvokableObject::class, $object); + $this->assertEquals(['foo' => 'bar'], $object->options); + } +} \ No newline at end of file diff --git a/test/Factory/LazyServiceFactoryFactoryTest.php b/test/Factory/LazyServiceFactoryFactoryTest.php new file mode 100644 index 00000000..cff7485b --- /dev/null +++ b/test/Factory/LazyServiceFactoryFactoryTest.php @@ -0,0 +1,51 @@ +getMock(ServiceLocatorInterface::class); + $factory = new LazyServiceFactoryFactory(); + + $this->setExpectedException( + InvalidArgumentException::class, + 'Missing "lazy_services" config key' + ); + + $object = $factory($serviceLocator, InvokableObject::class); + } + + public function testExceptionThrownWhenLazyServiceConfigMissingClassMap() + { + $serviceLocator = $this->getMock(ServiceLocatorInterface::class); + $serviceLocator->expects($this->once()) + ->method('get') + ->with('Config') + ->will($this->returnValue([ + 'lazy_services' => [] + ])); + + $factory = new LazyServiceFactoryFactory(); + + $this->setExpectedException( + InvalidArgumentException::class, + 'Missing "class_map" config key in "lazy_services"' + ); + + $object = $factory($serviceLocator, InvokableObject::class); + } +} diff --git a/test/ServiceManagerTest.php b/test/ServiceManagerTest.php index 63c18416..f9382404 100644 --- a/test/ServiceManagerTest.php +++ b/test/ServiceManagerTest.php @@ -3,567 +3,128 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @package Zend_ServiceManager */ namespace ZendTest\ServiceManager; -use Zend\Di\Di; -use Zend\Mvc\Service\DiFactory; -use Zend\ServiceManager\Di\DiAbstractServiceFactory; -use Zend\ServiceManager\Exception; +use stdClass; +use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\InvokableFactory; use Zend\ServiceManager\ServiceManager; -use Zend\ServiceManager\Config; +use ZendTest\ServiceManager\Asset\InvokableObject; +use ZendTest\ServiceManager\Asset\SimpleAbstractFactory; class ServiceManagerTest extends \PHPUnit_Framework_TestCase { - - /** - * @var ServiceManager - */ - protected $serviceManager = null; - - public function setup() - { - $this->serviceManager = new ServiceManager; - } - - /** - * @covers Zend\ServiceManager\ServiceManager::__construct - */ - public function testConstructorConfig() - { - $config = new Config(array('services' => array('foo' => 'bar'))); - $serviceManager = new ServiceManager($config); - $this->assertEquals('bar', $serviceManager->get('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setAllowOverride - * @covers Zend\ServiceManager\ServiceManager::getAllowOverride - */ - public function testAllowOverride() - { - $this->assertFalse($this->serviceManager->getAllowOverride()); - $ret = $this->serviceManager->setAllowOverride(true); - $this->assertSame($this->serviceManager, $ret); - $this->assertTrue($this->serviceManager->getAllowOverride()); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setThrowExceptionInCreate - * @covers Zend\ServiceManager\ServiceManager::getThrowExceptionInCreate - */ - public function testThrowExceptionInCreate() - { - $this->assertTrue($this->serviceManager->getThrowExceptionInCreate()); - $ret = $this->serviceManager->setThrowExceptionInCreate(false); - $this->assertSame($this->serviceManager, $ret); - $this->assertFalse($this->serviceManager->getThrowExceptionInCreate()); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setInvokableClass - */ - public function testSetInvokableClass() - { - $ret = $this->serviceManager->setInvokableClass('foo', 'bar'); - $this->assertSame($this->serviceManager, $ret); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setFactory - */ - public function testSetFactory() - { - $ret = $this->serviceManager->setFactory('foo', 'bar'); - $this->assertSame($this->serviceManager, $ret); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setFactory - */ - public function testSetFactoryThrowsExceptionOnDuplicate() - { - $this->serviceManager->setFactory('foo', 'bar'); - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); - $this->serviceManager->setFactory('foo', 'bar'); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::addAbstractFactory - */ - public function testAddAbstractFactory() - { - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - - $ret = $this->serviceManager->addAbstractFactory(new TestAsset\FooAbstractFactory()); - $this->assertSame($this->serviceManager, $ret); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::addAbstractFactory - */ - public function testAddAbstractFactoryThrowsExceptionOnInvalidFactory() - { - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidArgumentException'); - $this->serviceManager->addAbstractFactory(10); - } - - public function testServiceManagerIsPassedToInitializer() - { - $initializer = new TestAsset\FooInitializer(); - $this->serviceManager->addInitializer($initializer); - $this->serviceManager->setFactory('foo', function () { - return new \stdClass(); - }); - $obj = $this->serviceManager->get('foo'); - $this->assertSame($this->serviceManager, $initializer->sm); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::addInitializer - */ - public function testAddInitializer() - { - $ret = $this->serviceManager->addInitializer(new TestAsset\FooInitializer()); - $this->assertSame($this->serviceManager, $ret); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::addInitializer - */ - public function testAddInitializerThrowsExceptionOnInvalidInitializer() - { - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidArgumentException'); - $this->serviceManager->addInitializer(5); - } - - - /** - * @covers Zend\ServiceManager\ServiceManager::setService - */ - public function testSetService() - { - $ret = $this->serviceManager->setService('foo', 'bar'); - $this->assertSame($this->serviceManager, $ret); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setShared - */ - public function testSetShared() - { - $this->serviceManager->setInvokableClass('foo', 'bar'); - $ret = $this->serviceManager->setShared('foo', true); - $this->assertSame($this->serviceManager, $ret); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setShared - */ - public function testSetSharedThrowsExceptionOnUnregisteredService() - { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->serviceManager->setShared('foo', true); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::get - */ - public function testGet() - { - $this->serviceManager->setService('foo', 'bar'); - $this->assertEquals('bar', $this->serviceManager->get('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::get - */ - public function testGetDoesNotThrowExceptionOnEmptyArray() - { - $this->serviceManager->setService('foo', array()); - $this->serviceManager->get('foo'); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::get - */ - public function testGetThrowsExceptionOnUnknownService() - { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->assertEquals('bar', $this->serviceManager->get('foo')); - } - - - /** - * @covers Zend\ServiceManager\ServiceManager::get - */ - public function testGetWithAlias() - { - $this->serviceManager->setService('foo', 'bar'); - $this->serviceManager->setAlias('baz', 'foo'); - $this->assertEquals('bar', $this->serviceManager->get('baz')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::get - */ - public function testGetWithScopedContainer() - { - $this->serviceManager->setService('foo', 'bar'); - $scopedServiceManager = $this->serviceManager->createScopedServiceManager(); - $this->assertEquals('bar', $scopedServiceManager->get('foo')); - } - - public function testCanRetrieveFromParentPeeringManager() - { - $parent = new ServiceManager(); - $parent->setService('foo', 'bar'); - $child = new ServiceManager(); - $child->addPeeringServiceManager($parent, ServiceManager::SCOPE_PARENT); - $this->assertEquals('bar', $child->get('foo')); - } - - public function testCanRetrieveFromChildPeeringManager() - { - $parent = new ServiceManager(); - $child = new ServiceManager(); - $child->addPeeringServiceManager($parent, ServiceManager::SCOPE_CHILD); - $child->setService('foo', 'bar'); - $this->assertEquals('bar', $parent->get('foo')); - } - - public function testAllowsRetrievingFromPeeringContainerFirst() - { - $parent = new ServiceManager(); - $parent->setFactory('foo', function($sm) { - return 'bar'; - }); - $child = new ServiceManager(); - $child->setFactory('foo', function($sm) { - return 'baz'; - }); - $child->addPeeringServiceManager($parent, ServiceManager::SCOPE_PARENT); - $child->setRetrieveFromPeeringManagerFirst(true); - $this->assertEquals('bar', $child->get('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::create - */ - public function testCreateWithInvokableClass() - { - $this->serviceManager->setInvokableClass('foo', 'ZendTest\ServiceManager\TestAsset\Foo'); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::create - */ - public function testCreateWithFactoryInstance() - { - $this->serviceManager->setFactory('foo', 'ZendTest\ServiceManager\TestAsset\FooFactory'); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::create - */ - public function testCreateWithCallableFactory() - { - $this->serviceManager->setFactory('foo', function () { return new TestAsset\Foo; }); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::create - */ - public function testCreateWithAbstractFactory() - { - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); - } - - public function testCreateWithInitializerObject() - { - $this->serviceManager->addInitializer(new TestAsset\FooInitializer(array('foo' => 'bar'))); - $this->serviceManager->setFactory('foo', function () { - return new \stdClass(); - }); - $obj = $this->serviceManager->get('foo'); - $this->assertEquals('bar', $obj->foo); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::has - */ - public function testHas() - { - $this->assertFalse($this->serviceManager->has('foo')); - $this->serviceManager->setInvokableClass('foo', 'bar'); - $this->assertTrue($this->serviceManager->has('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setAlias - */ - public function testSetAlias() - { - $this->serviceManager->setInvokableClass('foo', 'bar'); - $ret = $this->serviceManager->setAlias('bar', 'foo'); - $this->assertSame($this->serviceManager, $ret); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setAlias - */ - public function testSetAliasThrowsExceptionOnInvalidAliasName() - { - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); - $this->serviceManager->setAlias(5, 10); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setAlias - */ - public function testSetAliasThrowsExceptionOnEmptyAliasName() - { - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); - $this->serviceManager->setAlias('', 'foo'); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setAlias - */ - public function testSetAliasThrowsExceptionOnDuplicateAlias() + public function testIsSharedByDefault() { - $this->serviceManager->setService('foo', 'bar'); - $this->serviceManager->setAlias('baz', 'foo'); - - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); - $this->serviceManager->setAlias('baz', 'foo'); - } + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ] + ]); - /** - * @covers Zend\ServiceManager\ServiceManager::setAlias - */ - public function testSetAliasDoesNotThrowExceptionOnServiceNotFound() - { - $this->serviceManager->setAlias('foo', 'bar'); - } + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class); - /** - * @covers Zend\ServiceManager\ServiceManager::get - */ - public function testGetServiceThrowsExceptionOnAliasWithNoSetService() - { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->serviceManager->setAlias('foo', 'bar'); - $this->serviceManager->get('foo'); + $this->assertSame($object1, $object2); } - /** - * @cover Zend\ServiceManager\ServiceManager::get - */ - public function testGetServiceThrowsExceptionOnMultipleAliasesWithNoSetService() + public function testCanDisableSharedByDefault() { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->serviceManager->setAlias('foo', 'bar'); - $this->serviceManager->setAlias('baz', 'foo'); - $this->serviceManager->get('foo'); - } + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ], + 'shared_by_default' => false + ]); - /** - * @covers Zend\ServiceManager\ServiceManager::hasAlias - */ - public function testHasAlias() - { - $this->assertFalse($this->serviceManager->hasAlias('foo')); + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class); - $this->serviceManager->setService('bar', 'baz'); - $this->serviceManager->setAlias('foo', 'bar'); - $this->assertTrue($this->serviceManager->hasAlias('foo')); + $this->assertNotSame($object1, $object2); } - /** - * @covers Zend\ServiceManager\ServiceManager::createScopedServiceManager - */ - public function testCreateScopedServiceManager() + public function testCanDisableSharedForSingleService() { - $this->serviceManager->setService('foo', 'bar'); - $scopedServiceManager = $this->serviceManager->createScopedServiceManager(); - $this->assertNotSame($this->serviceManager, $scopedServiceManager); - $this->assertFalse($scopedServiceManager->has('foo', true, false)); + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ], + 'shared' => [ + stdClass::class => false + ] + ]); - $this->assertContains($this->serviceManager, $this->readAttribute($scopedServiceManager, 'peeringServiceManagers')); - - // test child scoped - $childScopedServiceManager = $this->serviceManager->createScopedServiceManager(ServiceManager::SCOPE_CHILD); - $this->assertContains($childScopedServiceManager, $this->readAttribute($this->serviceManager, 'peeringServiceManagers')); - } - - public function testConfigureWithInvokableClass() - { - $config = new Config(array( - 'invokables' => array( - 'foo' => 'ZendTest\ServiceManager\TestAsset\Foo', - ), - )); - $serviceManager = new ServiceManager($config); - $foo = $serviceManager->get('foo'); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $foo); - } + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class); - public function testPeeringService() - { - $di = new Di(); - $di->instanceManager()->setParameters('ZendTest\ServiceManager\TestAsset\Bar', array('foo' => array('a'))); - $this->serviceManager->addAbstractFactory(new DiAbstractServiceFactory($di)); - $sm = $this->serviceManager->createScopedServiceManager(ServiceManager::SCOPE_PARENT); - $sm->setFactory('di', new DiFactory()); - $bar = $sm->get('ZendTest\ServiceManager\TestAsset\Bar', true); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $bar); + $this->assertNotSame($object1, $object2); } - public function testDiAbstractServiceFactory() + public function testCanEnableSharedForSingleService() { - $di = $this->getMock('Zend\Di\Di'); - $factory = new DiAbstractServiceFactory($di); - $factory->instanceManager()->setConfig('ZendTest\ServiceManager\TestAsset\Bar', array('parameters' => array('foo' => array('a')))); - $this->serviceManager->addAbstractFactory($factory); - - $this->assertTrue($this->serviceManager->has('ZendTest\ServiceManager\TestAsset\Bar', true)); - - $bar = $this->serviceManager->get('ZendTest\ServiceManager\TestAsset\Bar', true); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $bar); - } + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ], + 'shared_by_default' => false, + 'shared' => [ + stdClass::class => true + ] + ]); - public function testExceptionThrowingFactory() - { - $this->serviceManager->setFactory('foo', 'ZendTest\ServiceManager\TestAsset\ExceptionThrowingFactory'); - try { - $this->serviceManager->get('foo'); - $this->fail("No exception thrown"); - } catch (Exception\ServiceNotCreatedException $e) { - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\FooException', $e->getPrevious()); - } - } + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class); - /** - * @expectedException Zend\ServiceManager\Exception\ServiceNotFoundException - */ - public function testCannotUseUnknownServiceNameForAbstractFactory() - { - $config = new Config(array( - 'abstract_factories' => array( - 'ZendTest\ServiceManager\TestAsset\FooAbstractFactory', - ), - )); - $serviceManager = new ServiceManager($config); - $serviceManager->setFactory('foo', 'ZendTest\ServiceManager\TestAsset\FooFactory'); - $foo = $serviceManager->get('unknownObject'); + $this->assertSame($object1, $object2); } - /** - * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException - */ - public function testDoNotFallbackToAbstractFactory() + public function testCanCreateObjectWithInvokableFactory() { - $factory = function ($sm) { - return new TestAsset\Bar(); - }; - $serviceManager = new ServiceManager(); - $serviceManager->setFactory('ZendTest\ServiceManager\TestAsset\Bar', $factory); - $di = new Di(); - $di->instanceManager()->setParameters('ZendTest\ServiceManager\TestAsset\Bar', array('foo' => array('a'))); - $serviceManager->addAbstractFactory(new DiAbstractServiceFactory($di)); - $bar = $serviceManager->get('ZendTest\ServiceManager\TestAsset\Bar'); - } + $serviceManager = new ServiceManager([ + 'factories' => [ + InvokableObject::class => InvokableFactory::class + ] + ]); - /** - * @expectedException Zend\ServiceManager\Exception\InvalidServiceNameException - */ - public function testAssignAliasWithExistingServiceName() - { - $this->serviceManager->setFactory('foo', 'ZendTest\ServiceManager\TestAsset\FooFactory'); - $this->serviceManager->setFactory('bar', function ($sm) { - return new Bar(array('a')); - }); - $this->serviceManager->setAllowOverride(false); - // should throw an exception because 'foo' already exists in the service manager - $this->serviceManager->setAlias('foo', 'bar'); - } + $object = $serviceManager->get(InvokableObject::class, ['foo' => 'bar']); - /** - * @covers Zend\ServiceManager\ServiceManager::createFromAbstractFactory - * @covers Zend\ServiceManager\ServiceManager::has - */ - public function testWillNotCreateCircularReferences() - { - $abstractFactory = new TestAsset\CircularDependencyAbstractFactory(); - $sm = new ServiceManager(); - $sm->addAbstractFactory($abstractFactory); - $foo = $sm->get('foo'); - $this->assertSame($abstractFactory->expectedInstance, $foo); + $this->assertInstanceOf(InvokableObject::class, $object); + $this->assertEquals(['foo' => 'bar'], $object->options); } - public function testShouldAllowAddingInitializersAsClassNames() + public function testCanCreateObjectWithClosureFactory() { - $result = $this->serviceManager->addInitializer('ZendTest\ServiceManager\TestAsset\FooInitializer'); - $this->assertSame($this->serviceManager, $result); - } + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => function(ServiceLocatorInterface $serviceLocator, $className) { + $this->assertEquals(stdClass::class, $className); + return new stdClass(); + } + ] + ]); - public function testShouldRaiseExceptionIfInitializerClassIsNotAnInitializerInterfaceImplementation() - { - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidArgumentException'); - $result = $this->serviceManager->addInitializer(get_class($this)); + $object = $serviceManager->get(stdClass::class); + $this->assertInstanceOf(stdClass::class, $object); } - public function duplicateService() + public function testNeverShareIfOptionsArePassed() { - $self = $this; - return array( - array( - 'setFactory', - function ($services) use ($self) { - return $self; - }, - $self, - 'assertSame', - ), - array( - 'setInvokableClass', - 'stdClass', - 'stdClass', - 'assertInstanceOf', - ), - array( - 'setService', - $self, - $self, - 'assertSame', - ), - ); - } + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ], + 'shared' => [ + stdClass::class => true + ] + ]); - /** - * @dataProvider duplicateService - */ - public function testWithAllowOverrideOnRegisteringAServiceDuplicatingAnExistingAliasShouldInvalidateTheAlias($method, $service, $expected, $assertion = 'assertSame') - { - $this->serviceManager->setAllowOverride(true); - $sm = $this->serviceManager; - $this->serviceManager->setFactory('http.response', function ($services) use ($sm) { - return $sm; - }); - $this->serviceManager->setAlias('response', 'http.response'); - $this->assertSame($sm, $this->serviceManager->get('response')); + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class, ['foo' => 'bar']); - $self = $this; - $this->serviceManager->{$method}('response', $service); - $this->{$assertion}($expected, $this->serviceManager->get('response')); + $this->assertNotSame($object1, $object2); } -} +} \ No newline at end of file diff --git a/test/TestAsset/CircularDependencyAbstractFactory.php b/test/TestAsset/CircularDependencyAbstractFactory.php deleted file mode 100644 index 869e0b1f..00000000 --- a/test/TestAsset/CircularDependencyAbstractFactory.php +++ /dev/null @@ -1,42 +0,0 @@ -has($name)) { - return $serviceLocator->get($name); - } - - return $this->expectedInstance; - } -} diff --git a/test/TestAsset/ExceptionThrowingFactory.php b/test/TestAsset/ExceptionThrowingFactory.php deleted file mode 100644 index 653cf8db..00000000 --- a/test/TestAsset/ExceptionThrowingFactory.php +++ /dev/null @@ -1,23 +0,0 @@ -var = $var; - } - } - - public function initialize($instance, ServiceLocatorInterface $serviceLocator) - { - $this->sm = $serviceLocator; - if ($this->var) { - list($key, $value) = each($this->var); - $instance->{$key} = $value; - } - } -} diff --git a/test/bootstrap.php b/test/bootstrap.php deleted file mode 100644 index 2ab1230e..00000000 --- a/test/bootstrap.php +++ /dev/null @@ -1,34 +0,0 @@ -