diff --git a/.gitattributes b/.gitattributes index 7325c690..85dc9a8c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,6 @@ /test export-ignore /vendor export-ignore -.coveralls.yml export-ignore .gitattributes export-ignore .gitignore export-ignore .travis.yml export-ignore .php_cs export-ignore -phpunit.xml.dist export-ignore diff --git a/.gitignore b/.gitignore index a7fc91d6..4cac0a21 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ nbproject tmp/ clover.xml -composer.lock coveralls-upload.json phpunit.xml vendor diff --git a/.php_cs b/.php_cs index 8f4dd5aa..bf4b799f 100644 --- a/.php_cs +++ b/.php_cs @@ -1,7 +1,5 @@ in('src') - ->in('test') ->notPath('TestAsset') ->notPath('_files') ->filter(function (SplFileInfo $file) { @@ -31,8 +29,8 @@ $config->fixers( 'method_argument_space', 'object_operator', 'php_closing_tag', + 'psr0', 'remove_lines_between_uses', - 'short_array_syntax', 'short_tag', 'standardize_not_equal', 'trailing_spaces', diff --git a/.travis.yml b/.travis.yml index 73f4c148..cdbfa468 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,28 +2,17 @@ sudo: false language: php -branches: - except: - - /^release-.*$/ - - /^ghgfk-.*$/ - -cache: - directories: - - $HOME/.composer/cache - matrix: fast_finish: true include: - php: 5.5 - env: - - EXECUTE_CS_CHECK=true - php: 5.6 env: - EXECUTE_TEST_COVERALLS=true + - EXECUTE_CS_CHECK=true - php: 7 - php: hhvm allow_failures: - - php: 7 - php: hhvm notifications: @@ -31,12 +20,12 @@ notifications: email: false before_install: - - if [[ $EXECUTE_TEST_COVERALLS != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi + - if [[ $EXECUTE_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi - composer self-update - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then composer require --dev --no-update satooshi/php-coveralls ; fi install: - - travis_retry composer install --no-interaction --ignore-platform-reqs + - composer install --no-interaction --prefer-source script: - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/phpunit --coverage-clover clover.xml ; fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 533a8360..67437159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,206 @@ -# Changelog +# CHANGELOG -All notable changes to this project will be documented in this file, in reverse chronological order by release. +## v3.O.0 - TBD -## 2.5.2 - TBD +### 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. + +### Deprecated + +* Nothing + +### Removed + +* 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. + +* `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 + ] + ] +]; +``` + +* `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. + +### Changed/Fixed + +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. + +* 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. + +* 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. + +* It's so fast now that your app will fly. + +## 2.5.2 ### Added @@ -21,4 +219,4 @@ All notable changes to this project will be documented in this file, in reverse - [#3](https://github.com/zendframework/zend-servicemanager/pull/3) properly updates the codebase to PHP 5.5, by taking advantage of the default closure binding (`$this` in a closure is the invoking object when created within a method). It - also removes several `@requires PHP 5.4.0` annotations. + also removes several `@requires PHP 5.4.0` annotations. \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index dbb1b49c..8e6efbde 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -25,4 +25,4 @@ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md index d5d6535f..7c8a5f17 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ # zend-servicemanager -[![Build Status](https://secure.travis-ci.org/zendframework/zend-servicemanager.svg?branch=master)](https://secure.travis-ci.org/zendframework/zend-servicemanager) -[![Coverage Status](https://coveralls.io/repos/zendframework/zend-servicemanager/badge.svg?branch=master)](https://coveralls.io/r/zendframework/zend-servicemanager?branch=master) - The Service Locator design pattern is implemented by the `Zend\ServiceManager` component. The Service Locator is a service/object locator, tasked with retrieving other objects. diff --git a/composer.json b/composer.json index 7e37bd0f..d66826a3 100644 --- a/composer.json +++ b/composer.json @@ -1,41 +1,38 @@ { - "name": "zendframework/zend-servicemanager", - "description": " ", - "license": "BSD-3-Clause", - "keywords": [ - "zf2", - "servicemanager" - ], - "homepage": "https://github.com/zendframework/zend-servicemanager", - "autoload": { - "psr-4": { - "Zend\\ServiceManager\\": "src/" - } - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "zendframework/zend-di": "~2.5", - "zendframework/zend-mvc": "~2.5", - "fabpot/php-cs-fixer": "1.7.*", - "phpunit/PHPUnit": "~4.0" - }, - "suggest": { - "ocramius/proxy-manager": "ProxyManager 0.5.* to handle lazy initialization of services", - "zendframework/zend-di": "Zend\\Di component" - }, - "minimum-stability": "dev", - "prefer-stable": true, - "extra": { - "branch-alias": { - "dev-master": "2.5-dev", - "dev-develop": "2.6-dev" - } - }, - "autoload-dev": { - "psr-4": { - "ZendTest\\ServiceManager\\": "test/" - } + "name": "zendframework/zend-servicemanager", + "description": " ", + "license": "BSD-3-Clause", + "keywords": [ + "zf", + "servicemanager", + "service-manager" + ], + "homepage": "https://github.com/zendframework/zend-servicemanager", + "autoload": { + "psr-4": { + "Zend\\ServiceManager\\": "src/" } + }, + "require": { + "php": ">=5.5", + "container-interop/container-interop": "1.*" + }, + "require-dev": { + "phpunit/phpunit": "~4.6", + "ocramius/proxy-manager": "~1.0" + }, + "suggest": { + "ocramius/proxy-manager": "ProxyManager 1.* to handle lazy initialization of services" + }, + "extra": { + "branch-alias": { + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" + } + }, + "autoload-dev": { + "psr-4": { + "ZendTest\\ServiceManager\\": "test/" + } + } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..eec88ad4 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1289 @@ +{ + "_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": "126c9ae82a70261c55bac0ccef34e0d3", + "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": "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.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "6044546998c7627ab997501a3d0db972b3db9790" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6044546998c7627ab997501a3d0db972b3db9790", + "reference": "6044546998c7627ab997501a3d0db972b3db9790", + "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-07-13 11:25:58" + }, + { + "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.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "9b97f9d807b862c2de2a36e86690000801c85724" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9b97f9d807b862c2de2a36e86690000801c85724", + "reference": "9b97f9d807b862c2de2a36e86690000801c85724", + "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-07-13 11:28:34" + }, + { + "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": "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": "squizlabs/php_codesniffer", + "version": "2.3.3", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "c1a26c729508f73560c1a4f767f60b8ab6b4a666" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/c1a26c729508f73560c1a4f767f60b8ab6b4a666", + "reference": "c1a26c729508f73560c1a4f767f60b8ab6b4a666", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.1.2" + }, + "bin": [ + "scripts/phpcs", + "scripts/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Fixer.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2015-06-24 03:16:23" + }, + { + "name": "symfony/yaml", + "version": "v2.7.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "4bfbe0ed3909bfddd75b70c094391ec1f142f860" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/4bfbe0ed3909bfddd75b70c094391ec1f142f860", + "reference": "4bfbe0ed3909bfddd75b70c094391ec1f142f860", + "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-07-01 11:25:50" + }, + { + "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": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.5" + }, + "platform-dev": [] +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9ef98aeb..544e5159 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ @@ -28,7 +28,7 @@ functionality works as expected. Such tests include those for Zend\Soap and Zend\Session, which require that headers not be sent in order to work. --> - + diff --git a/src/AbstractFactoryInterface.php b/src/AbstractFactoryInterface.php deleted file mode 100644 index 96bffea8..00000000 --- a/src/AbstractFactoryInterface.php +++ /dev/null @@ -1,33 +0,0 @@ -addInitializer(function ($instance) { - if ($instance instanceof ServiceLocatorAwareInterface) { - $instance->setServiceLocator($this); - } - }); + 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 - * - * @throws Exception\ServiceNotFoundException - * @throws Exception\ServiceNotCreatedException - * @throws Exception\RuntimeException + * {@inheritDoc} */ - public function get($name, $options = [], $usePeeringServiceManagers = true) + public function get($name, array $options = []) { - $isAutoInvokable = false; - - // Allow specifying a class name directly; registers as an invokable class - if (!$this->has($name) && $this->autoAddInvokableClass && class_exists($name)) { - $isAutoInvokable = true; - - $this->setInvokableClass($name, $name); - } - - $this->creationOptions = $options; - - try { - $instance = parent::get($name, $usePeeringServiceManagers); - } catch (Exception\ServiceNotFoundException $exception) { - $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception); - } catch (Exception\ServiceNotCreatedException $exception) { - $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception); - } - - $this->creationOptions = null; - - try { - $this->validatePlugin($instance); - } catch (Exception\RuntimeException $exception) { - $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception); - } + $instance = parent::get($name, $options); + $this->validate($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 + * {@inheritDoc} */ - public function setServiceLocator(ServiceLocatorInterface $serviceLocator) + public function validate($instance) { - $this->serviceLocator = $serviceLocator; - - return $this; - } - - /** - * Get the main plugin manager. Useful for fetching dependencies from within factories. - * - * @return ServiceLocatorInterface - */ - 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 - */ - 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', - get_class($this) . '::' . __FUNCTION__, - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : ''), - $invokable - )); - } - - if (null === $this->creationOptions - || (is_array($this->creationOptions) && empty($this->creationOptions)) - ) { - $instance = new $invokable(); - } else { - $instance = new $invokable($this->creationOptions); - } - - return $instance; - } - - /** - * Attempt to create an instance via a factory class - * - * Overrides parent implementation by passing $creationOptions to the - * constructor, if non-null. - * - * @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]; - $hasCreationOptions = !(null === $this->creationOptions || (is_array($this->creationOptions) && empty($this->creationOptions))); - - if (is_string($factory) && class_exists($factory, true)) { - if (!$hasCreationOptions) { - $factory = new $factory(); - } else { - $factory = new $factory($this->creationOptions); - } - - $this->factories[$canonicalName] = $factory; - } - - if ($factory instanceof FactoryInterface) { - $instance = $this->createServiceViaCallback([$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; - } - - /** - * Create service via callback - * - * @param callable $callable - * @param string $cName - * @param string $rName - * @throws Exception\ServiceNotCreatedException - * @throws Exception\ServiceNotFoundException - * @throws Exception\CircularDependencyFoundException - * @return object - */ - protected function createServiceViaCallback($callable, $cName, $rName) - { - if (is_object($callable)) { - $factory = $callable; - } elseif (is_array($callable)) { - // reset both rewinds and returns the value of the first array element - $factory = reset($callable); - } - - if (isset($factory) - && ($factory instanceof MutableCreationOptionsInterface) - && is_array($this->creationOptions) - && !empty($this->creationOptions) - ) { - $factory->setCreationOptions($this->creationOptions); - } - - return parent::createServiceViaCallback($callable, $cName, $rName); - } - - /** - * @param string $serviceName - * @param bool $isAutoInvokable - * @param BaseException $exception - * - * @throws BaseException - * @throws Exception\ServiceLocatorUsageException - */ - private function tryThrowingServiceLocatorUsageException( - $serviceName, - $isAutoInvokable, - BaseException $exception - ) { - if ($isAutoInvokable) { - $this->unregisterService($this->canonicalizeName($serviceName)); - } - - $serviceLocator = $this->getServiceLocator(); - - if ($serviceLocator && $serviceLocator->has($serviceName)) { - throw Exception\ServiceLocatorUsageException::fromInvalidPluginManagerRequestedServiceName( - $this, - $serviceLocator, - $serviceName, - $exception - ); + if (empty($this->instanceOf) || $instance instanceof $this->instanceOf) { + return; } - throw $exception; + 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 d506f266..00000000 --- a/src/Config.php +++ /dev/null @@ -1,166 +0,0 @@ -config = $config; - } - - /** - * Get allow override - * - * @return null|bool - */ - public function getAllowOverride() - { - return (isset($this->config['allow_override'])) ? $this->config['allow_override'] : null; - } - - /** - * Get factories - * - * @return array - */ - public function getFactories() - { - return (isset($this->config['factories'])) ? $this->config['factories'] : []; - } - - /** - * Get abstract factories - * - * @return array - */ - public function getAbstractFactories() - { - return (isset($this->config['abstract_factories'])) ? $this->config['abstract_factories'] : []; - } - - /** - * Get invokables - * - * @return array - */ - public function getInvokables() - { - return (isset($this->config['invokables'])) ? $this->config['invokables'] : []; - } - - /** - * Get services - * - * @return array - */ - public function getServices() - { - return (isset($this->config['services'])) ? $this->config['services'] : []; - } - - /** - * Get aliases - * - * @return array - */ - public function getAliases() - { - return (isset($this->config['aliases'])) ? $this->config['aliases'] : []; - } - - /** - * Get initializers - * - * @return array - */ - public function getInitializers() - { - return (isset($this->config['initializers'])) ? $this->config['initializers'] : []; - } - - /** - * Get shared - * - * @return array - */ - public function getShared() - { - return (isset($this->config['shared'])) ? $this->config['shared'] : []; - } - - /** - * Get the delegator services map, with keys being the services acting as delegates, - * and values being the delegator factories names - * - * @return array - */ - public function getDelegators() - { - return (isset($this->config['delegators'])) ? $this->config['delegators'] : []; - } - - /** - * Configure service manager - * - * @param ServiceManager $serviceManager - * @return void - */ - public function configureServiceManager(ServiceManager $serviceManager) - { - if (($allowOverride = $this->getAllowOverride()) !== null) { - $serviceManager->setAllowOverride($allowOverride); - } - - 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); - } - - foreach ($this->getDelegators() as $originalServiceName => $delegators) { - foreach ($delegators as $delegator) { - $serviceManager->addDelegator($originalServiceName, $delegator); - } - } - } -} diff --git a/src/ConfigInterface.php b/src/ConfigInterface.php deleted file mode 100644 index d55bc0e5..00000000 --- a/src/ConfigInterface.php +++ /dev/null @@ -1,21 +0,0 @@ -di = $di; - if (in_array($useServiceLocator, [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, $name, $requestedName) - { - $this->serviceLocator = $serviceLocator; - if ($requestedName) { - return $this->get($requestedName, []); - } - - return $this->get($name, []); - } - - /** - * {@inheritDoc} - */ - public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) - { - if ($this->instanceManager->hasSharedInstance($requestedName) - || $this->instanceManager->hasAlias($requestedName) - || $this->instanceManager->hasConfig($requestedName) - || $this->instanceManager->hasTypePreferences($requestedName) - ) { - return true; - } - - if (! $this->definitions->hasClass($requestedName) || interface_exists($requestedName)) { - return false; - } - - return true; - } -} diff --git a/src/Di/DiInstanceManagerProxy.php b/src/Di/DiInstanceManagerProxy.php deleted file mode 100644 index 87b10a39..00000000 --- a/src/Di/DiInstanceManagerProxy.php +++ /dev/null @@ -1,71 +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; - } - - /** - * Determine if we have a shared instance by class or alias - * - * @param $classOrAlias - * @return bool - */ - public function hasSharedInstance($classOrAlias) - { - return ($this->serviceLocator->has($classOrAlias) || $this->diInstanceManager->hasSharedInstance($classOrAlias)); - } - - /** - * Get shared instance - * - * @param $classOrAlias - * @return mixed - */ - public function getSharedInstance($classOrAlias) - { - if ($this->serviceLocator->has($classOrAlias)) { - return $this->serviceLocator->get($classOrAlias); - } - - return $this->diInstanceManager->getSharedInstance($classOrAlias); - } -} diff --git a/src/Di/DiServiceFactory.php b/src/Di/DiServiceFactory.php deleted file mode 100644 index e1e73935..00000000 --- a/src/Di/DiServiceFactory.php +++ /dev/null @@ -1,118 +0,0 @@ -di = $di; - $this->name = $name; - $this->parameters = $parameters; - if (in_array($useServiceLocator, [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; - } - - /** - * Create service - * - * @param ServiceLocatorInterface $serviceLocator - * @return object - */ - public function createService(ServiceLocatorInterface $serviceLocator) - { - $this->serviceLocator = $serviceLocator; - return $this->get($this->name, $this->parameters); - } - - /** - * Override, as we want it to use the functionality defined in the proxy - * - * @param string $name - * @param array $params - * @return object - * @throws Exception\ServiceNotFoundException - */ - public function get($name, array $params = []) - { - // 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 66760f06..00000000 --- a/src/Di/DiServiceInitializer.php +++ /dev/null @@ -1,66 +0,0 @@ -di = $di; - $this->serviceLocator = $serviceLocator; - $this->diInstanceManagerProxy = ($diImProxy) ?: new DiInstanceManagerProxy($di->instanceManager(), $serviceLocator); - } - - /** - * Initialize - * - * @param $instance - * @param ServiceLocatorInterface $serviceLocator - * @throws \Exception - */ - 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 280ff9d1..00000000 --- a/src/Exception/CircularDependencyFoundException.php +++ /dev/null @@ -1,14 +0,0 @@ -getServiceLocator() in your factory code?', - $serviceName, - get_class($pluginManager), - get_class($previousException), - $serviceName, - get_class($parentLocator) - ), - 0, - $previousException - ); - } -} diff --git a/src/Exception/ServiceNotCreatedException.php b/src/Exception/ServiceNotCreatedException.php index a8b08e0f..585b60c0 100644 --- a/src/Exception/ServiceNotCreatedException.php +++ b/src/Exception/ServiceNotCreatedException.php @@ -9,6 +9,11 @@ namespace Zend\ServiceManager\Exception; -class ServiceNotCreatedException extends RuntimeException +use RuntimeException as SplRuntimeException; + +/** + * ServiceNotCreatedException + */ +class ServiceNotCreatedException extends SplRuntimeException implements ExceptionInterface { -} +} \ No newline at end of file diff --git a/src/Exception/ServiceNotFoundException.php b/src/Exception/ServiceNotFoundException.php index 478f4ee0..610721e3 100644 --- a/src/Exception/ServiceNotFoundException.php +++ b/src/Exception/ServiceNotFoundException.php @@ -9,6 +9,12 @@ namespace Zend\ServiceManager\Exception; -class ServiceNotFoundException extends InvalidArgumentException +use Interop\Container\Exception\NotFoundException; +use InvalidArgumentException as SplInvalidArgumentException; + +/** + * ServiceNotFoundException + */ +class ServiceNotFoundException extends SplInvalidArgumentException implements ExceptionInterface, NotFoundException { -} +} \ No newline at end of file diff --git a/src/Factory/AbstractFactoryInterface.php b/src/Factory/AbstractFactoryInterface.php new file mode 100644 index 00000000..b3f6f72a --- /dev/null +++ b/src/Factory/AbstractFactoryInterface.php @@ -0,0 +1,29 @@ +get('Config'); @@ -41,7 +38,7 @@ public function createService(ServiceLocatorInterface $serviceLocator) throw new Exception\InvalidArgumentException('Missing "class_map" config key in "lazy_services"'); } - $factoryConfig = new Configuration(); + $factoryConfig = new ProxyConfiguration(); if (isset($lazyServices['proxies_namespace'])) { $factoryConfig->setProxiesNamespace($lazyServices['proxies_namespace']); @@ -51,7 +48,7 @@ public function createService(ServiceLocatorInterface $serviceLocator) $factoryConfig->setProxiesTargetDir($lazyServices['proxies_target_dir']); } - if (!isset($lazyServices['write_proxy_files']) || ! $lazyServices['write_proxy_files']) { + if (!isset($lazyServices['write_proxy_files']) || !$lazyServices['write_proxy_files']) { $factoryConfig->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); } @@ -59,4 +56,4 @@ public function createService(ServiceLocatorInterface $serviceLocator) 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 0a65d655..00000000 --- a/src/FactoryInterface.php +++ /dev/null @@ -1,21 +0,0 @@ -creationOptions = $creationOptions; - } - - /** - * Get creation options - * - * @return array - */ - public function getCreationOptions() - { - return $this->creationOptions; - } -} diff --git a/src/PluginManagerInterface.php b/src/PluginManagerInterface.php new file mode 100644 index 00000000..e7931a48 --- /dev/null +++ b/src/PluginManagerInterface.php @@ -0,0 +1,29 @@ +setProxyInitializer(null); - - $wrappedInstance = call_user_func($callback); + $wrappedInstance = $callback(); return true; }; - if (isset($this->servicesMap[$requestedName])) { - return $this->proxyFactory->createProxy($this->servicesMap[$requestedName], $initializer); - } elseif (isset($this->servicesMap[$name])) { + if (isset($this->servicesMap[$name])) { return $this->proxyFactory->createProxy($this->servicesMap[$name], $initializer); } - throw new Exception\InvalidServiceNameException( - sprintf('The requested service "%s" was not found in the provided services map', $requestedName) + 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 1058042c..00000000 --- a/src/ServiceLocatorAwareInterface.php +++ /dev/null @@ -1,27 +0,0 @@ -serviceLocator = $serviceLocator; - - return $this; - } - - /** - * Get service locator - * - * @return ServiceLocatorInterface - */ - public function getServiceLocator() - { - return $this->serviceLocator; - } -} diff --git a/src/ServiceLocatorInterface.php b/src/ServiceLocatorInterface.php index 4df3c5fc..88ad5931 100644 --- a/src/ServiceLocatorInterface.php +++ b/src/ServiceLocatorInterface.php @@ -10,24 +10,24 @@ namespace Zend\ServiceManager; /** - * Service locator interface + * Interface for service locator */ interface ServiceLocatorInterface { /** - * Retrieve a registered instance + * Retrieve a service by its name, with optional options * - * @param string $name - * @throws Exception\ServiceNotFoundException - * @return object|array + * @param string $name + * @param array $options + * @return object */ - public function get($name); + public function get($name, array $options = []); /** - * Check for a registered instance + * Check if the service locator has a registered service for the given name * - * @param string|array $name + * @param string $name * @return bool */ public function has($name); -} +} \ No newline at end of file diff --git a/src/ServiceManager.php b/src/ServiceManager.php index 90a23ee9..04c5beab 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -9,34 +9,24 @@ namespace Zend\ServiceManager; -class ServiceManager implements ServiceLocatorInterface -{ - /**@#+ - * Constants - */ - const SCOPE_PARENT = 'parent'; - const SCOPE_CHILD = 'child'; - /**@#-*/ +use Exception; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Exception\InvalidArgumentException; +use Zend\ServiceManager\Exception\ServiceNotCreatedException; +use Zend\ServiceManager\Factory\AbstractFactoryInterface; +use Zend\ServiceManager\Factory\DelegatorFactoryInterface; +use Zend\ServiceManager\Exception\ServiceNotFoundException; +use Zend\ServiceManager\Initializer\InitializerInterface; +/** + * Service Manager + */ +class ServiceManager implements ServiceLocatorInterface, ContainerInterface +{ /** - * Lookup for canonicalized names. + * A list of factories (either as string name or callable) * - * @var array - */ - protected $canonicalNames = []; - - /** - * @var bool - */ - protected $allowOverride = false; - - /** - * @var array - */ - protected $invokableClasses = []; - - /** - * @var string|callable|\Closure|FactoryInterface[] + * @var string[]|callable[] */ protected $factories = []; @@ -46,1224 +36,273 @@ class ServiceManager implements ServiceLocatorInterface protected $abstractFactories = []; /** - * @var array[] + * @var string[]|DelegatorFactoryInterface[] */ protected $delegators = []; /** - * @var array - */ - protected $pendingAbstractFactoryRequests = []; - - /** - * @var integer + * @var InitializerInterface[] */ - protected $nestedContextCounter = -1; - - /** - * @var array - */ - protected $nestedContext = []; - - /** - * @var array - */ - protected $shared = []; + protected $initializers = []; /** - * Registered services and cached values + * A list of aliases + * + * Should map one alias to a service name, or another alias (aliases are recursively resolved) * - * @var array - */ - protected $instances = []; - - /** * @var array */ protected $aliases = []; /** + * A list of already loaded services (this act as a local cache) + * * @var array */ - protected $initializers = []; + protected $services = []; /** - * @var ServiceManager[] - */ - protected $peeringServiceManagers = []; - - /** - * Whether or not to share by default + * Should the services be shared by default? * * @var bool */ - protected $shareByDefault = true; - - /** - * @var bool - */ - protected $retrieveFromPeeringManagerFirst = false; + protected $sharedByDefault = true; /** - * @var bool Track whether not to throw exceptions during create() - */ - protected $throwExceptionInCreate = true; - - /** - * @var array map of characters to be replaced through strtr - */ - protected $canonicalNamesReplacements = ['-' => '', '_' => '', ' ' => '', '\\' => '', '/' => '']; - - /** - * @var ServiceLocatorInterface - */ - protected $serviceManagerCaller; - - /** - * Constructor + * Allow to activate/deactivate shared per service name * - * @param ConfigInterface $config - */ - public function __construct(ConfigInterface $config = null) - { - if ($config) { - $config->configureServiceManager($this); - } - } - - /** - * Set allow override - * - * @param $allowOverride - * @return ServiceManager - */ - public function setAllowOverride($allowOverride) - { - $this->allowOverride = (bool) $allowOverride; - return $this; - } - - /** - * Get allow override - * - * @return bool - */ - public function getAllowOverride() - { - return $this->allowOverride; - } - - /** - * Set flag indicating whether services are shared by default - * - * @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)', - get_class($this) . '::' . __FUNCTION__ - )); - } - $this->shareByDefault = (bool) $shareByDefault; - return $this; - } - - /** - * Are services shared by default? - * - * @return bool - */ - public function shareByDefault() - { - return $this->shareByDefault; - } - - /** - * Set throw exceptions in create - * - * @param bool $throwExceptionInCreate - * @return ServiceManager - */ - public function setThrowExceptionInCreate($throwExceptionInCreate) - { - $this->throwExceptionInCreate = $throwExceptionInCreate; - return $this; - } - - /** - * Get throw exceptions in create + * Example configuration: * - * @return bool - */ - public function getThrowExceptionInCreate() - { - return $this->throwExceptionInCreate; - } - - /** - * Set flag indicating whether to pull from peering manager before attempting creation + * 'shared' => [ + * MyService::class => true, // will be shared, even if "sharedByDefault" is false + * MyOtherService::class => false // won't be shared, even if "sharedByDefault" is true + * ] * - * @param bool $retrieveFromPeeringManagerFirst - * @return ServiceManager + * @var array */ - public function setRetrieveFromPeeringManagerFirst($retrieveFromPeeringManagerFirst = true) - { - $this->retrieveFromPeeringManagerFirst = (bool) $retrieveFromPeeringManagerFirst; - return $this; - } + protected $shared = []; /** - * Should we retrieve from the peering manager prior to attempting to create a service? - * - * @return bool + * @var ServiceLocatorInterface */ - public function retrieveFromPeeringManagerFirst() - { - return $this->retrieveFromPeeringManagerFirst; - } + protected $creationContext; /** - * Set invokable class - * - * @param string $name - * @param string $invokableClass - * @param bool $shared - * @return ServiceManager - * @throws Exception\InvalidServiceNameException + * @param array $config */ - public function setInvokableClass($name, $invokableClass, $shared = null) + public function __construct(array $config) { - $cName = $this->canonicalizeName($name); - - if ($this->has([$cName, $name], 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', - $name - )); - } - $this->unregisterService($cName); - } - - if ($shared === null) { - $shared = $this->shareByDefault; - } - - $this->invokableClasses[$cName] = $invokableClass; - $this->shared[$cName] = (bool) $shared; - - return $this; + $this->creationContext = $this; + $this->configure($config); } /** - * Set factory + * {@inheritDoc} * - * @param string $name - * @param string|FactoryInterface|callable $factory - * @param bool $shared - * @return ServiceManager - * @throws Exception\InvalidArgumentException - * @throws Exception\InvalidServiceNameException + * This is a highly performance sensitive method, do not modify if you have not benchmarked it carefully */ - public function setFactory($name, $factory, $shared = null) + public function get($name, array $options = []) { - $cName = $this->canonicalizeName($name); + $name = $this->resolveAlias($name); - if (!($factory instanceof FactoryInterface || is_string($factory) || 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.' - ); + // 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]; } - if ($this->has([$cName, $name], 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', - $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); } - $this->unregisterService($cName); - } - - if ($shared === null) { - $shared = $this->shareByDefault; + } catch (Exception $exception) { + throw new ServiceNotCreatedException(sprintf( + 'Service with name "%s" could not be created. Reason: %s', + $name, + $exception->getMessage() + )); } - $this->factories[$cName] = $factory; - $this->shared[$cName] = (bool) $shared; - - return $this; - } - - /** - * Add abstract factory - * - * @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 (!$factory instanceof AbstractFactoryInterface && is_string($factory)) { - $factory = new $factory(); + foreach ($this->initializers as $initializer) { + $initializer($this->creationContext, $object); } - if (!$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 (($this->sharedByDefault && !isset($this->shared[$name])) + || (isset($this->shared[$name]) && $this->shared[$name])) { + $this->services[$name] = $object; } - if ($topOfStack) { - array_unshift($this->abstractFactories, $factory); - } else { - array_push($this->abstractFactories, $factory); - } - return $this; + return $object; } /** - * Sets the given service name as to be handled by a delegator factory - * - * @param string $serviceName name of the service being the delegate - * @param string $delegatorFactoryName name of the service being the delegator factory - * - * @return ServiceManager + * {@inheritDoc} */ - public function addDelegator($serviceName, $delegatorFactoryName) + public function has($name, $checkAbstractFactories = false) { - $cName = $this->canonicalizeName($serviceName); + $name = $this->resolveAlias($name); + $found = isset($this->services[$name]) || isset($this->factories[$name]); - if (!isset($this->delegators[$cName])) { - $this->delegators[$cName] = []; + if ($found || !$checkAbstractFactories) { + return $found; } - $this->delegators[$cName][] = $delegatorFactoryName; - - return $this; - } - - /** - * Add initializer - * - * @param callable|InitializerInterface $initializer - * @param bool $topOfStack - * @return ServiceManager - * @throws Exception\InvalidArgumentException - */ - public function addInitializer($initializer, $topOfStack = true) - { - if (!($initializer instanceof InitializerInterface || is_callable($initializer))) { - if (is_string($initializer)) { - $initializer = new $initializer; - } - - if (!($initializer instanceof InitializerInterface || is_callable($initializer))) { - throw new Exception\InvalidArgumentException('$initializer should be callable.'); + // Check abstract factories + foreach ($this->abstractFactories as $abstractFactory) { + if ($abstractFactory->canCreateServiceWithName($name)) { + return true; } } - if ($topOfStack) { - array_unshift($this->initializers, $initializer); - } else { - array_push($this->initializers, $initializer); - } - return $this; + return false; } /** - * Register a service with the locator + * Get a factory for the given service name * - * @param string $name - * @param mixed $service - * @return ServiceManager - * @throws Exception\InvalidServiceNameException - */ - public function setService($name, $service) - { - $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.', - get_class($this) . '::' . __FUNCTION__, - $name - )); - } - $this->unregisterService($cName); - } - - $this->instances[$cName] = $service; - - return $this; - } - - /** * @param string $name - * @param bool $isShared - * @return ServiceManager - * @throws Exception\ServiceNotFoundException - */ - public function setShared($name, $isShared) - { - $cName = $this->canonicalizeName($name); - - if ( - !isset($this->invokableClasses[$cName]) - && !isset($this->factories[$cName]) - && !$this->canCreateFromAbstractFactory($cName, $name) - ) { - throw new Exception\ServiceNotFoundException(sprintf( - '%s: A service by the name "%s" was not found and could not be marked as shared', - get_class($this) . '::' . __FUNCTION__, - $name - )); - } - - $this->shared[$cName] = (bool) $isShared; - return $this; - } - - /** - * @param string $name - * @return bool - * @throws Exception\ServiceNotFoundException + * @return callable + * @throws ServiceNotFoundException */ - public function isShared($name) + protected function getFactory($name) { - $cName = $this->canonicalizeName($name); + $factory = isset($this->factories[$name]) ? $this->factories[$name] : null; - if (!$this->has($name)) { - throw new Exception\ServiceNotFoundException(sprintf( - '%s: A service by the name "%s" was not found', - get_class($this) . '::' . __FUNCTION__, - $name - )); + if (is_string($factory)) { + $this->factories[$name] = $factory = new $factory(); } - if (!isset($this->shared[$cName])) { - return $this->shareByDefault(); + if (is_callable($factory)) { + return $factory; } - return $this->shared[$cName]; - } - - /** - * Resolve the alias for the given canonical name - * - * @param string $cName The canonical name to resolve - * @return string The resolved canonical name - */ - protected function resolveAlias($cName) - { - $stack = []; - - while ($this->hasAlias($cName)) { - if (isset($stack[$cName])) { - throw new Exception\CircularReferenceException(sprintf( - 'Circular alias reference: %s -> %s', - implode(' -> ', $stack), - $cName - )); + // Check abstract factories + foreach ($this->abstractFactories as $abstractFactory) { + if ($abstractFactory->canCreateServiceWithName($name)) { + return $abstractFactory; } - - $stack[$cName] = $cName; - $cName = $this->aliases[$cName]; } - return $cName; + 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 + )); } /** - * Retrieve a registered instance - * - * @param string $name - * @param bool $usePeeringServiceManagers - * @throws Exception\ServiceNotFoundException - * @return object|array + * @param string $name + * @param array $options + * @return object */ - public function get($name, $usePeeringServiceManagers = true) + protected function createDelegatorFromName($name, array $options = []) { - // inlined code from ServiceManager::canonicalizeName for performance - if (isset($this->canonicalNames[$name])) { - $cName = $this->canonicalNames[$name]; - } else { - $cName = $this->canonicalizeName($name); - } - - $isAlias = false; - - if ($this->hasAlias($cName)) { - $isAlias = true; - $cName = $this->resolveAlias($cName); - } - - $instance = null; - - if ($usePeeringServiceManagers && $this->retrieveFromPeeringManagerFirst) { - $instance = $this->retrieveFromPeeringManager($name); - - if (null !== $instance) { - return $instance; - } - } - - if (isset($this->instances[$cName])) { - return $this->instances[$cName]; - } - - if (!$instance) { - $this->checkNestedContextStart($cName); - if ( - isset($this->invokableClasses[$cName]) - || isset($this->factories[$cName]) - || isset($this->aliases[$cName]) - || $this->canCreateFromAbstractFactory($cName, $name) - ) { - $instance = $this->create([$cName, $name]); - } elseif ($isAlias && $this->canCreateFromAbstractFactory($name, $cName)) { - /* - * case of an alias leading to an abstract factory : - * 'my-alias' => 'my-abstract-defined-service' - * $name = 'my-alias' - * $cName = 'my-abstract-defined-service' - */ - $instance = $this->create([$name, $cName]); - } elseif ($usePeeringServiceManagers && !$this->retrieveFromPeeringManagerFirst) { - $instance = $this->retrieveFromPeeringManager($name); - } - $this->checkNestedContextStop(); - } - - // Still no instance? raise an exception - if ($instance === null) { - $this->checkNestedContextStop(true); - if ($isAlias) { - throw new Exception\ServiceNotFoundException(sprintf( - 'An alias "%s" was requested but no service could be found.', - $name - )); - } - - throw new Exception\ServiceNotFoundException(sprintf( - '%s was unable to fetch or create an instance for %s', - get_class($this) . '::' . __FUNCTION__, - $name - )); - } - - if ( - ($this->shareByDefault && !isset($this->shared[$cName])) - || (isset($this->shared[$cName]) && $this->shared[$cName] === true) - ) { - $this->instances[$cName] = $instance; - } - - return $instance; - } + $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); + }; - /** - * Create an instance of the requested service - * - * @param string|array $name - * - * @return bool|object - */ - public function create($name) - { - if (is_array($name)) { - list($cName, $rName) = $name; - } else { - $rName = $name; + for ($i = 0 ; $i < $delegatorsCount ; ++$i) { + $delegatorFactory = $this->delegators[$name][$i]; - // inlined code from ServiceManager::canonicalizeName for performance - if (isset($this->canonicalNames[$rName])) { - $cName = $this->canonicalNames[$name]; - } else { - $cName = $this->canonicalizeName($name); + if (is_string($delegatorFactory)) { + $delegatorFactory = $this->delegators[$name][$i] = new $delegatorFactory(); } - } - if (isset($this->delegators[$cName])) { - return $this->createDelegatorFromFactory($cName, $rName); + $creationCallback = function() use ($delegatorFactory, $name, $creationCallback, $options) { + return $delegatorFactory($this->creationContext, $name, $creationCallback, $options); + }; } - return $this->doCreate($rName, $cName); + return $creationCallback($this->creationContext, $name, $creationCallback, $options); } /** - * Creates a callback that uses a delegator to create a service - * - * @param DelegatorFactoryInterface|callable $delegatorFactory the delegator factory - * @param string $rName requested service name - * @param string $cName canonical service name - * @param callable $creationCallback callback for instantiating the real service + * Configure the service manager * - * @return callable - */ - private function createDelegatorCallback($delegatorFactory, $rName, $cName, $creationCallback) - { - return function () use ($delegatorFactory, $rName, $cName, $creationCallback) { - return $delegatorFactory instanceof DelegatorFactoryInterface - ? $delegatorFactory->createDelegatorWithName($this, $cName, $rName, $creationCallback) - : $delegatorFactory($this, $cName, $rName, $creationCallback); - }; - } - - /** - * Actually creates the service - * - * @param string $rName real service name - * @param string $cName canonicalized service name - * - * @return bool|mixed|null|object - * @throws Exception\ServiceNotFoundException - * - */ - protected function doCreate($rName, $cName) - { - $instance = null; - - if (isset($this->factories[$cName])) { - $instance = $this->createFromFactory($cName, $rName); - } - - if ($instance === null && isset($this->invokableClasses[$cName])) { - $instance = $this->createFromInvokable($cName, $rName); - } - $this->checkNestedContextStart($cName); - if ($instance === null && $this->canCreateFromAbstractFactory($cName, $rName)) { - $instance = $this->createFromAbstractFactory($cName, $rName); - } - $this->checkNestedContextStop(); - - if ($instance === null && $this->throwExceptionInCreate) { - $this->checkNestedContextStop(true); - throw new Exception\ServiceNotFoundException(sprintf( - 'No valid instance was found for %s%s', - $cName, - ($rName ? '(alias: ' . $rName . ')' : '') - )); - } - - // Do not call initializers if we do not have an instance - if ($instance === null) { - return $instance; - } - - foreach ($this->initializers as $initializer) { - if ($initializer instanceof InitializerInterface) { - $initializer->initialize($instance, $this); - } else { - call_user_func($initializer, $instance, $this); - } - } - - return $instance; - } - - /** - * Determine if we can create an instance. - * Proxies to has() + * Valid top keys are: * - * @param string|array $name - * @param bool $checkAbstractFactories - * @return bool - * @deprecated this method is being deprecated as of zendframework 2.3, and may be removed in future major versions - */ - public function canCreate($name, $checkAbstractFactories = true) - { - trigger_error(sprintf('%s is deprecated; please use %s::has', __METHOD__, __CLASS__), E_USER_DEPRECATED); - return $this->has($name, $checkAbstractFactories, false); - } - - /** - * Determine if an instance exists. + * - 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 + * - delegators: a list of services map to one or more delegators + * - shared: a list of key value that map a service name to a boolean + * - aliases: a list of key value that map an alias to a service name (or to another alias) + * - shared_by_default: boolean * - * @param string|array $name An array argument accepts exactly two values. - * Example: array('canonicalName', 'requestName') - * @param bool $checkAbstractFactories - * @param bool $usePeeringServiceManagers - * @return bool + * @param array $config + * @return void */ - public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = true) + protected function configure(array $config) { - if (is_string($name)) { - $rName = $name; - - // inlined code from ServiceManager::canonicalizeName for performance - if (isset($this->canonicalNames[$rName])) { - $cName = $this->canonicalNames[$rName]; - } else { - $cName = $this->canonicalizeName($name); - } - } elseif (is_array($name) && count($name) >= 2) { - list($cName, $rName) = $name; - } else { - return false; - } + $this->factories = (isset($config['factories']) ? $config['factories'] : []) + $this->factories; + $this->delegators = array_merge_recursive($this->delegators, isset($config['delegators']) ? $config['delegators'] : []); + $this->shared = (isset($config['shared']) ? $config['shared'] : []) + $this->shared; + $this->aliases = (isset($config['aliases']) ? $config['aliases'] : []) + $this->aliases; + $this->sharedByDefault = isset($config['shared_by_default']) ? $config['shared_by_default'] : $this->sharedByDefault; - if (isset($this->invokableClasses[$cName]) - || isset($this->factories[$cName]) - || isset($this->aliases[$cName]) - || isset($this->instances[$cName]) - || ($checkAbstractFactories && $this->canCreateFromAbstractFactory($cName, $rName)) - ) { - return true; - } - - if ($usePeeringServiceManagers) { - $caller = $this->serviceManagerCaller; - foreach ($this->peeringServiceManagers as $peeringServiceManager) { - // ignore peering service manager if they are the same instance - if ($caller === $peeringServiceManager) { - continue; + // 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(); } - $peeringServiceManager->serviceManagerCaller = $this; - - if ($peeringServiceManager->has($name)) { - $peeringServiceManager->serviceManagerCaller = null; - return true; + if (is_callable($abstractFactory)) { + $this->abstractFactories[] = $abstractFactory; + continue; } - $peeringServiceManager->serviceManagerCaller = null; - } - } - - return false; - } - - /** - * Determine if we can create an instance from an abstract factory. - * - * @param string $cName - * @param string $rName - * @return bool - */ - public function canCreateFromAbstractFactory($cName, $rName) - { - if (array_key_exists($cName, $this->nestedContext)) { - $context = $this->nestedContext[$cName]; - if ($context === false) { - return false; - } elseif (is_object($context)) { - return !isset($this->pendingAbstractFactoryRequests[get_class($context).$cName]); + 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) + )); } } - $this->checkNestedContextStart($cName); - // check abstract factories - $result = false; - $this->nestedContext[$cName] = false; - foreach ($this->abstractFactories as $abstractFactory) { - $pendingKey = get_class($abstractFactory).$cName; - if (isset($this->pendingAbstractFactoryRequests[$pendingKey])) { - $result = false; - break; - } - if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) { - $this->nestedContext[$cName] = $abstractFactory; - $result = true; - break; - } - } - $this->checkNestedContextStop(); - return $result; - } + if (isset($config['initializers'])) { + foreach ($config['initializers'] as $initializer) { + if (is_string($initializer)) { + $initializer = new $initializer(); + } - /** - * Ensure the alias definition will not result in a circular reference - * - * @param string $alias - * @param string $nameOrAlias - * @throws Exception\CircularReferenceException - * @return self - */ - protected function checkForCircularAliasReference($alias, $nameOrAlias) - { - $aliases = $this->aliases; - $aliases[$alias] = $nameOrAlias; - $stack = []; + if (is_callable($initializer)) { + $this->initializers[] = $initializer; + continue; + } - while (isset($aliases[$alias])) { - if (isset($stack[$alias])) { - throw new Exception\CircularReferenceException(sprintf( - 'The alias definition "%s" : "%s" results in a circular reference: "%s" -> "%s"', - $alias, - $nameOrAlias, - implode('" -> "', $stack), - $alias + 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) )); } - - $stack[$alias] = $alias; - $alias = $aliases[$alias]; } - - return $this; } /** - * @param string $alias - * @param string $nameOrAlias - * @return ServiceManager - * @throws Exception\ServiceNotFoundException - * @throws Exception\InvalidServiceNameException - */ - public function setAlias($alias, $nameOrAlias) - { - if (!is_string($alias) || !is_string($nameOrAlias)) { - throw new Exception\InvalidServiceNameException('Service or alias names must be strings.'); - } - - $cAlias = $this->canonicalizeName($alias); - $nameOrAlias = $this->canonicalizeName($nameOrAlias); - - if ($alias == '' || $nameOrAlias == '') { - throw new Exception\InvalidServiceNameException('Invalid service name alias'); - } - - if ($this->allowOverride === false && $this->has([$cAlias, $alias], false)) { - throw new Exception\InvalidServiceNameException(sprintf( - 'An alias by the name "%s" or "%s" already exists', - $cAlias, - $alias - )); - } - - if ($this->hasAlias($alias)) { - $this->checkForCircularAliasReference($cAlias, $nameOrAlias); - } - - $this->aliases[$cAlias] = $nameOrAlias; - return $this; - } - - /** - * Determine if we have an alias + * Recursively resolve an alias name to a service name * * @param string $alias - * @return bool - */ - public function hasAlias($alias) - { - return isset($this->aliases[$this->canonicalizeName($alias)]); - } - - /** - * Create scoped service manager - * - * @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; - } - 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; - } - - /** - * Canonicalize name - * - * @param string $name * @return string */ - protected function canonicalizeName($name) + private function resolveAlias($alias) { - if (isset($this->canonicalNames[$name])) { - return $this->canonicalNames[$name]; - } + $name = $alias; - // this is just for performance instead of using str_replace - return $this->canonicalNames[$name] = strtolower(strtr($name, $this->canonicalNamesReplacements)); - } + do { + $canBeResolved = isset($this->aliases[$name]); + $name = $canBeResolved ? $this->aliases[$name] : $name; + } while ($canBeResolved); - /** - * Create service via callback - * - * @param callable $callable - * @param string $cName - * @param string $rName - * @throws Exception\ServiceNotCreatedException - * @throws Exception\ServiceNotFoundException - * @throws Exception\CircularDependencyFoundException - * @return object - */ - protected function createServiceViaCallback($callable, $cName, $rName) - { - static $circularDependencyResolver = []; - $depKey = spl_object_hash($this) . '-' . $cName; - - if (isset($circularDependencyResolver[$depKey])) { - $circularDependencyResolver = []; - throw new Exception\CircularDependencyFoundException('Circular dependency for LazyServiceLoader was found for instance ' . $rName); - } - - 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.'); - } - - return $instance; - } - - /** - * Retrieve a keyed list of all registered services. Handy for debugging! - * - * @return array - */ - public function getRegisteredServices() - { - return [ - '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! - * - * @return array - */ - public function getCanonicalNames() - { - return $this->canonicalNames; - } - - /** - * Allows to override the canonical names lookup map with predefined - * values. - * - * @param array $canonicalNames - * @return ServiceManager - */ - public function setCanonicalNames($canonicalNames) - { - $this->canonicalNames = $canonicalNames; - - return $this; - } - - /** - * Attempt to retrieve an instance via a peering manager - * - * @param string $name - * @return mixed - */ - protected function retrieveFromPeeringManager($name) - { - if (null !== ($service = $this->loopPeeringServiceManagers($name))) { - return $service; - } - - $name = $this->canonicalizeName($name); - - if ($this->hasAlias($name)) { - do { - $name = $this->aliases[$name]; - } while ($this->hasAlias($name)); - } - - if (null !== ($service = $this->loopPeeringServiceManagers($name))) { - return $service; - } - - return; - } - - /** - * Loop over peering service managers. - * - * @param string $name - * @return mixed - */ - protected function loopPeeringServiceManagers($name) - { - $caller = $this->serviceManagerCaller; - - foreach ($this->peeringServiceManagers as $peeringServiceManager) { - // ignore peering service manager if they are the same instance - if ($caller === $peeringServiceManager) { - continue; - } - - // pass this instance to peering service manager - $peeringServiceManager->serviceManagerCaller = $this; - - if ($peeringServiceManager->has($name)) { - $this->shared[$name] = $peeringServiceManager->isShared($name); - $instance = $peeringServiceManager->get($name); - $peeringServiceManager->serviceManagerCaller = null; - return $instance; - } - - $peeringServiceManager->serviceManagerCaller = null; - } - - return; - } - - /** - * Attempt to create an instance via an invokable class - * - * @param string $canonicalName - * @param string $requestedName - * @return null|\stdClass - * @throws Exception\ServiceNotFoundException 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', - get_class($this) . '::' . __FUNCTION__, - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : ''), - $invokable - )); - } - $instance = new $invokable; - return $instance; - } - - /** - * 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([$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; - } - - /** - * 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) - { - if (isset($this->nestedContext[$canonicalName])) { - $abstractFactory = $this->nestedContext[$canonicalName]; - $pendingKey = get_class($abstractFactory).$canonicalName; - try { - $this->pendingAbstractFactoryRequests[$pendingKey] = true; - $instance = $this->createServiceViaCallback( - [$abstractFactory, 'createServiceWithName'], - $canonicalName, - $requestedName - ); - unset($this->pendingAbstractFactoryRequests[$pendingKey]); - return $instance; - } catch (\Exception $e) { - unset($this->pendingAbstractFactoryRequests[$pendingKey]); - $this->checkNestedContextStop(true); - throw new Exception\ServiceNotCreatedException( - sprintf( - 'An abstract factory could not create an instance of %s%s.', - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : '') - ), - $e->getCode(), - $e - ); - } - } - return; - } - - /** - * - * @param string $cName - * @return self - */ - protected function checkNestedContextStart($cName) - { - if ($this->nestedContextCounter === -1 || !isset($this->nestedContext[$cName])) { - $this->nestedContext[$cName] = null; - } - $this->nestedContextCounter++; - return $this; - } - - /** - * - * @param bool $force - * @return self - */ - protected function checkNestedContextStop($force = false) - { - if ($force) { - $this->nestedContextCounter = -1; - $this->nestedContext = []; - return $this; - } - - $this->nestedContextCounter--; - if ($this->nestedContextCounter === -1) { - $this->nestedContext = []; - } - return $this; - } - - /** - * @param $canonicalName - * @param $requestedName - * @return mixed - * @throws Exception\ServiceNotCreatedException - */ - protected function createDelegatorFromFactory($canonicalName, $requestedName) - { - $delegatorsCount = count($this->delegators[$canonicalName]); - $creationCallback = function () use ($requestedName, $canonicalName) { - return $this->doCreate($requestedName, $canonicalName); - }; - - for ($i = 0; $i < $delegatorsCount; $i += 1) { - $delegatorFactory = $this->delegators[$canonicalName][$i]; - - if (is_string($delegatorFactory)) { - $delegatorFactory = !$this->has($delegatorFactory) && class_exists($delegatorFactory, true) ? - new $delegatorFactory - : $this->get($delegatorFactory); - $this->delegators[$canonicalName][$i] = $delegatorFactory; - } - - if (!$delegatorFactory instanceof DelegatorFactoryInterface && !is_callable($delegatorFactory)) { - throw new Exception\ServiceNotCreatedException(sprintf( - 'While attempting to create %s%s an invalid factory was registered for this instance type.', - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : '') - )); - } - - $creationCallback = $this->createDelegatorCallback( - $delegatorFactory, - $requestedName, - $canonicalName, - $creationCallback - ); - } - - return $creationCallback($this, $canonicalName, $requestedName, $creationCallback); - } - - /** - * Checks if the object has this class as one of its parents - * - * @see https://bugs.php.net/bug.php?id=53727 - * @see https://github.com/zendframework/zf2/pull/1807 - * - * @deprecated since zf 2.3 requires PHP >= 5.3.23 - * - * @param string $className - * @param string $type - * @return bool - * - * @deprecated this method is being deprecated as of zendframework 2.2, and may be removed in future major versions - */ - protected static function isSubclassOf($className, $type) - { - return is_subclass_of($className, $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 - */ - protected function unregisterService($canonical) - { - $types = ['invokableClasses', 'factories', 'aliases']; - foreach ($types as $type) { - if (isset($this->{$type}[$canonical])) { - unset($this->{$type}[$canonical]); - break; - } - } - - if (isset($this->instances[$canonical])) { - unset($this->instances[$canonical]); - } - - if (isset($this->shared[$canonical])) { - unset($this->shared[$canonical]); - } + return $name; } -} +} \ No newline at end of file diff --git a/test/AbstractPluginManagerTest.php b/test/AbstractPluginManagerTest.php index 0837e9b5..8aec6816 100644 --- a/test/AbstractPluginManagerTest.php +++ b/test/AbstractPluginManagerTest.php @@ -9,278 +9,56 @@ namespace ZendTest\ServiceManager; -use ReflectionClass; -use ReflectionObject; -use Zend\ServiceManager\Config; -use Zend\ServiceManager\Exception\RuntimeException; -use Zend\ServiceManager\ServiceManager; -use ZendTest\ServiceManager\TestAsset\FooPluginManager; -use ZendTest\ServiceManager\TestAsset\MockSelfReturningDelegatorFactory; +use stdClass; +use Zend\ServiceManager\Exception\InvalidServiceException; +use Zend\ServiceManager\Factory\FactoryInterface; +use Zend\ServiceManager\Factory\InvokableFactory; +use Zend\ServiceManager\ServiceLocatorInterface; +use ZendTest\ServiceManager\Asset\InvokableObject; +use ZendTest\ServiceManager\Asset\SimplePluginManager; class AbstractPluginManagerTest extends \PHPUnit_Framework_TestCase { - /** - * @var ServiceManager - */ - protected $serviceManager; - - /** - * @var FooPluginManager - */ - protected $pluginManager; - - public function setup() + public function testInjectCreationContextInFactories() { - $this->serviceManager = new ServiceManager(); - $this->pluginManager = new FooPluginManager(new Config([ - 'factories' => [ - 'Foo' => 'ZendTest\ServiceManager\TestAsset\FooFactory', - ], - 'shared' => [ - 'Foo' => false, - ], - ])); - } + $invokableFactory = $this->getMock(FactoryInterface::class); - public function testSetMultipleCreationOptions() - { - $pluginManager = new FooPluginManager(new Config([ + $config = [ 'factories' => [ - 'Foo' => 'ZendTest\ServiceManager\TestAsset\FooFactory' - ], - 'shared' => [ - 'Foo' => false + InvokableObject::class => $invokableFactory ] - ])); - - $refl = new ReflectionClass($pluginManager); - $reflProperty = $refl->getProperty('factories'); - $reflProperty->setAccessible(true); - - $value = $reflProperty->getValue($pluginManager); - $this->assertInternalType('string', $value['foo']); - - $pluginManager->get('Foo', ['key1' => 'value1']); - - $value = $reflProperty->getValue($pluginManager); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\FooFactory', $value['foo']); - $this->assertEquals(['key1' => 'value1'], $value['foo']->getCreationOptions()); - - $pluginManager->get('Foo', ['key2' => 'value2']); - - $value = $reflProperty->getValue($pluginManager); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\FooFactory', $value['foo']); - $this->assertEquals(['key2' => 'value2'], $value['foo']->getCreationOptions()); - } - - /** - * @group issue-4208 - */ - public function testGetFaultyRegisteredInvokableThrowsException() - { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - - $pluginManager = new FooPluginManager(); - $pluginManager->setInvokableClass('helloWorld', 'IDoNotExist'); - $pluginManager->get('helloWorld'); - } - - public function testAbstractFactoryWithMutableCreationOptions() - { - $creationOptions = ['key1' => 'value1']; - $mock = 'ZendTest\ServiceManager\TestAsset\AbstractFactoryWithMutableCreationOptions'; - $abstractFactory = $this->getMock($mock, ['setCreationOptions']); - $abstractFactory->expects($this->once()) - ->method('setCreationOptions') - ->with($creationOptions); - - $this->pluginManager->addAbstractFactory($abstractFactory); - $instance = $this->pluginManager->get('classnoexists', $creationOptions); - $this->assertInternalType('object', $instance); - } - - public function testMutableMethodNeverCalledWithoutCreationOptions() - { - $mock = 'ZendTest\ServiceManager\TestAsset\CallableWithMutableCreationOptions'; - $callable = $this->getMock($mock, ['setCreationOptions']); - $callable->expects($this->never()) - ->method('setCreationOptions'); - - $ref = new ReflectionObject($this->pluginManager); - - $method = $ref->getMethod('createServiceViaCallback'); - $method->setAccessible(true); - $method->invoke($this->pluginManager, $callable, 'foo', 'bar'); - } - - public function testCallableObjectWithMutableCreationOptions() - { - $creationOptions = ['key1' => 'value1']; - $mock = 'ZendTest\ServiceManager\TestAsset\CallableWithMutableCreationOptions'; - $callable = $this->getMock($mock, ['setCreationOptions']); - $callable->expects($this->once()) - ->method('setCreationOptions') - ->with($creationOptions); - - $ref = new ReflectionObject($this->pluginManager); - - $property = $ref->getProperty('creationOptions'); - $property->setAccessible(true); - $property->setValue($this->pluginManager, $creationOptions); - - $method = $ref->getMethod('createServiceViaCallback'); - $method->setAccessible(true); - $method->invoke($this->pluginManager, $callable, 'foo', 'bar'); - } - - public function testValidatePluginIsCalledWithDelegatorFactoryIfItsAService() - { - $pluginManager = $this->getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager'); - $delegatorFactory = $this->getMock('Zend\\ServiceManager\\DelegatorFactoryInterface'); - - $pluginManager->setService('delegator-factory', $delegatorFactory); - $pluginManager->addDelegator('foo-service', 'delegator-factory'); + ]; - $pluginManager->expects($this->once()) - ->method('validatePlugin') - ->with($delegatorFactory); + $serviceLocator = $this->getMock(ServiceLocatorInterface::class); + $pluginManager = new SimplePluginManager($serviceLocator, $config); - $pluginManager->create('foo-service'); - } - - public function testSingleDelegatorUsage() - { - $delegatorFactory = $this->getMock('Zend\\ServiceManager\\DelegatorFactoryInterface'); - /* @var $pluginManager \Zend\ServiceManager\AbstractPluginManager|\PHPUnit_Framework_MockObject_MockObject */ - $pluginManager = $this->getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager'); - $realService = $this->getMock('stdClass', [], [], 'RealService'); - $delegator = $this->getMock('stdClass', [], [], 'Delegator'); - - $delegatorFactory - ->expects($this->once()) - ->method('createDelegatorWithName') - ->with( - $pluginManager, - 'fooservice', - 'foo-service', - $this->callback(function ($callback) use ($realService) { - if (!is_callable($callback)) { - return false; - } - - return call_user_func($callback) === $realService; - }) - ) - ->will($this->returnValue($delegator)); - - $pluginManager->setFactory('foo-service', function () use ($realService) { - return $realService; - }); - $pluginManager->addDelegator('foo-service', $delegatorFactory); - - $pluginManager->expects($this->once()) - ->method('validatePlugin') - ->with($delegator); - - $this->assertSame($delegator, $pluginManager->get('foo-service')); - } - - public function testMultipleDelegatorsUsage() - { - /* @var $pluginManager \Zend\ServiceManager\AbstractPluginManager|\PHPUnit_Framework_MockObject_MockObject */ - $pluginManager = $this->getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager'); - - $fooDelegator = new MockSelfReturningDelegatorFactory(); - $barDelegator = new MockSelfReturningDelegatorFactory(); - - $pluginManager->addDelegator('foo-service', $fooDelegator); - $pluginManager->addDelegator('foo-service', $barDelegator); - $pluginManager->setInvokableClass('foo-service', 'stdClass'); - - $pluginManager->expects($this->once()) - ->method('validatePlugin') - ->with($barDelegator); - - $this->assertSame($barDelegator, $pluginManager->get('foo-service')); - $this->assertCount(1, $barDelegator->instances); - $this->assertCount(1, $fooDelegator->instances); - $this->assertInstanceOf('stdClass', array_shift($fooDelegator->instances)); - $this->assertSame($fooDelegator, array_shift($barDelegator->instances)); - } - - /** - * @group 6833 - */ - public function testCanCheckInvalidServiceManagerIsUsed() - { - $sm = new ServiceManager(); - $sm->setService('bar', new \stdClass()); - - /** @var \Zend\ServiceManager\AbstractPluginManager $pluginManager */ - $pluginManager = new FooPluginManager(); - $pluginManager->setServiceLocator($sm); - - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceLocatorUsageException'); + $invokableFactory->expects($this->once()) + ->method('__invoke') + ->with($serviceLocator, InvokableObject::class) + ->will($this->returnValue(new InvokableObject())); - $pluginManager->get('bar'); + $object = $pluginManager->get(InvokableObject::class); - $this->fail('A Zend\ServiceManager\Exception\ServiceNotCreatedException is expected'); + $this->assertInstanceOf(InvokableObject::class, $object); } - /** - * @group 6833 - */ - public function testWillRethrowOnNonValidatedPlugin() + public function testValidateInstance() { - $sm = new ServiceManager(); - - $sm->setInvokableClass('stdClass', 'stdClass'); - - /** @var \Zend\ServiceManager\AbstractPluginManager|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager'); - - $pluginManager - ->expects($this->once()) - ->method('validatePlugin') - ->with($this->isInstanceOf('stdClass')) - ->will($this->throwException(new RuntimeException())); - - $pluginManager->setServiceLocator($sm); - - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceLocatorUsageException'); - - $pluginManager->get('stdClass'); - } - - /** - * @group 6833 - */ - public function testWillResetAutoInvokableServiceIfNotValid() - { - /** @var \Zend\ServiceManager\AbstractPluginManager|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager'); - - $pluginManager - ->expects($this->any()) - ->method('validatePlugin') - ->will($this->throwException(new RuntimeException())); - - $pluginManager->setInvokableClass(__CLASS__, __CLASS__); - - try { - $pluginManager->get('stdClass'); + $config = [ + 'factories' => [ + InvokableObject::class => new InvokableFactory(), + stdClass::class => new InvokableFactory() + ] + ]; - $this->fail('Expected the plugin manager to throw a RuntimeException, none thrown'); - } catch (RuntimeException $exception) { - $this->assertFalse($pluginManager->has('stdClass')); - } + $serviceLocator = $this->getMock(ServiceLocatorInterface::class); + $pluginManager = new SimplePluginManager($serviceLocator, $config); - try { - $pluginManager->get(__CLASS__); + // Assert no exception is triggered because the plugin manager validate ObjectWithOptions + $pluginManager->get(InvokableObject::class); - $this->fail('Expected the plugin manager to throw a RuntimeException, none thrown'); - } catch (RuntimeException $exception) { - $this->assertTrue($pluginManager->has(__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/GlobIteratorService.php b/test/Asset/FactoryObject.php similarity index 65% rename from test/TestAsset/GlobIteratorService.php rename to test/Asset/FactoryObject.php index c0c16ecd..405ab569 100644 --- a/test/TestAsset/GlobIteratorService.php +++ b/test/Asset/FactoryObject.php @@ -7,11 +7,14 @@ * @license http://framework.zend.com/license/new-bsd New BSD License */ -namespace ZendTest\ServiceManager\TestAsset; +namespace ZendTest\ServiceManager\Asset; -class GlobIteratorService extends \GlobIterator +class FactoryObject { - public function __construct() + public $dependency; + + public function __construct($dependency) { + $this->dependency = $dependency; } -} +} \ No newline at end of file diff --git a/test/Asset/FailingFactory.php b/test/Asset/FailingFactory.php new file mode 100644 index 00000000..a84697c3 --- /dev/null +++ b/test/Asset/FailingFactory.php @@ -0,0 +1,23 @@ +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..e72234fd --- /dev/null +++ b/test/Asset/SimpleAbstractFactory.php @@ -0,0 +1,36 @@ + InvokableFactory::class + ]; +} \ No newline at end of file diff --git a/test/Di/DiAbstractServiceFactoryTest.php b/test/Di/DiAbstractServiceFactoryTest.php deleted file mode 100644 index 10b8d044..00000000 --- a/test/Di/DiAbstractServiceFactoryTest.php +++ /dev/null @@ -1,125 +0,0 @@ -addSharedInstance($this->fooInstance = new \stdClass(), 'foo'); - $this->mockDi = $this->getMock('Zend\Di\Di', [], [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); - } - - /** - * @group 6021 - * - * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::createServiceWithName - * @covers Zend\ServiceManager\Di\DiAbstractServiceFactory::get - */ - public function testCreateServiceWithNameAndWithoutRequestName() - { - $foo = $this->diAbstractServiceFactory->createServiceWithName($this->mockServiceLocator, 'foo', null); - $this->assertEquals($this->fooInstance, $foo); - } - - /** - * @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', ['parameters' => ['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', [__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)); - $classDefinition - ->expects($this->any()) - ->method('getClasses') - ->will($this->returnValue([__NAMESPACE__ . '\Other\Non\Existing'])); - $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 23d528eb..00000000 --- a/test/Di/DiServiceFactoryTest.php +++ /dev/null @@ -1,72 +0,0 @@ -addSharedInstanceWithParameters( - $this->fooInstance = new \stdClass(), - 'foo', - ['bar' => 'baz'] - ); - $this->mockDi = $this->getMock('Zend\Di\Di', [], [null, $instanceManager]); - $this->mockServiceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); - $this->diServiceFactory = new DiServiceFactory( - $this->mockDi, - 'foo', - ['bar' => 'baz'] - ); - } - - /** - * @covers Zend\ServiceManager\Di\DiServiceFactory::__construct - */ - public function testConstructor() - { - $instance = new DiServiceFactory( - $this->getMock('Zend\Di\Di'), - 'string', - ['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 08d79da0..00000000 --- a/test/Di/DiServiceInitializerTest.php +++ /dev/null @@ -1,74 +0,0 @@ -mockDi = $this->getMock('Zend\Di\Di', ['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/Exception/ServiceLocatorUsageExceptionTest.php b/test/Exception/ServiceLocatorUsageExceptionTest.php deleted file mode 100644 index 6f7c693d..00000000 --- a/test/Exception/ServiceLocatorUsageExceptionTest.php +++ /dev/null @@ -1,54 +0,0 @@ -getMockForAbstractClass('Zend\ServiceManager\AbstractPluginManager'); - /* @var $serviceLocator \Zend\ServiceManager\ServiceLocatorInterface */ - $serviceLocator = $this->getMockForAbstractClass('Zend\ServiceManager\ServiceLocatorInterface'); - $previousException = new Exception(); - - $exception = ServiceLocatorUsageException::fromInvalidPluginManagerRequestedServiceName( - $pluginManager, - $serviceLocator, - 'the-service', - $previousException - ); - - $this->assertInstanceOf('Zend\ServiceManager\Exception\ServiceLocatorUsageException', $exception); - $this->assertInstanceOf( - 'Zend\ServiceManager\Exception\ServiceNotFoundException', - $exception, - 'Must be a ServiceNotFoundException for BC compatibility with older try-catch logic' - ); - $this->assertSame($previousException, $exception->getPrevious()); - - $expectedMessageFormat = <<<'MESSAGE' -Service "the-service" has been requested to plugin manager of type "%a", but couldn't be retrieved. -A previous exception of type "Exception" has been raised in the process. -By the way, a service with the name "the-service" has been found in the parent service locator "%a": did you forget to use $parentLocator = $serviceLocator->getServiceLocator() in your factory code? -MESSAGE; - - $this->assertStringMatchesFormat($expectedMessageFormat, $exception->getMessage()); - } -} 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/MutableCreationOptionsTraitTest.php b/test/MutableCreationOptionsTraitTest.php deleted file mode 100644 index 93e64cdc..00000000 --- a/test/MutableCreationOptionsTraitTest.php +++ /dev/null @@ -1,58 +0,0 @@ -markTestSkipped('Requires PHP >=5.4.0'); - } - $this->stub = $this->getObjectForTrait('Zend\ServiceManager\MutableCreationOptionsTrait'); - } - - public function tearDown() - { - unset($this->stub); - } - - public function testCreationOptionsInitiallyIsArray() - { - $this->assertAttributeEquals([], 'creationOptions', $this->stub); - } - - public function testTraitProvidesSetter() - { - $this->assertTrue( - method_exists($this->stub, 'setCreationOptions') - ); - } - - public function testTraitProvidesGetter() - { - $this->assertTrue( - method_exists($this->stub, 'getCreationOptions') - ); - } - - public function testTraitAcceptsCreationOptionsArray() - { - $creationOptions = [ - 'foo' => 'bar' - ]; - $this->stub->setCreationOptions($creationOptions); - $this->assertEquals($creationOptions, $this->stub->getCreationOptions()); - } -} diff --git a/test/Proxy/LazyServiceFactoryFactoryTest.php b/test/Proxy/LazyServiceFactoryFactoryTest.php deleted file mode 100644 index 0ff04444..00000000 --- a/test/Proxy/LazyServiceFactoryFactoryTest.php +++ /dev/null @@ -1,154 +0,0 @@ -markTestSkipped('Please install `ocramius/proxy-manager` to run these tests'); - } - } - - /** - * @dataProvider invalidConfigProvider - */ - public function testInvalidConfiguration($config) - { - $locator = $this->getMock('Zend\\ServiceManager\\ServiceLocatorInterface'); - $factory = new LazyServiceFactoryFactory(); - - $locator->expects($this->any())->method('get')->with('Config')->will($this->returnValue($config)); - $this->setExpectedException('Zend\\ServiceManager\\Exception\\InvalidArgumentException'); - - $factory->createService($locator); - } - - public function testAutoGenerateProxyFiles() - { - $serviceManager = new ServiceManager(); - $namespace = 'ZendTestProxy' . uniqid(); - - $serviceManager->setService( - 'Config', - [ - 'lazy_services' => [ - 'class_map' => ['foo' => __CLASS__], - 'proxies_namespace' => $namespace, - 'write_proxy_files' => true, - ], - ] - ); - $serviceManager->setFactory('foo-delegator', 'Zend\ServiceManager\Proxy\LazyServiceFactoryFactory'); - $serviceManager->setInvokableClass('foo', __CLASS__); - $serviceManager->addDelegator('foo', 'foo-delegator'); - - /* @var $proxy self|\ProxyManager\Proxy\ValueHolderInterface|\ProxyManager\Proxy\LazyLoadingInterface */ - $proxy = $serviceManager->create('foo'); - $proxyClassName = get_class($proxy); - - $this->assertInstanceOf('ProxyManager\\Proxy\\LazyLoadingInterface', $proxy); - $this->assertInstanceOf(__CLASS__, $proxy); - $this->assertStringMatchesFormat( - $namespace . '\__PM__\ZendTest\ServiceManager\Proxy\LazyServiceFactoryFactoryTest%s', - $proxyClassName - ); - $this->assertFileExists(sys_get_temp_dir() . '/' . str_replace('\\', '', $proxyClassName) . '.php'); - $this->assertFalse($proxy->isProxyInitialized()); - $this->assertEquals($this->invalidConfigProvider(), $proxy->invalidConfigProvider()); - $this->assertTrue($proxy->isProxyInitialized()); - } - - public function testAutoGenerateAndEvaluateProxies() - { - $serviceManager = new ServiceManager(); - $namespace = 'ZendTestProxy' . uniqid(); - - $serviceManager->setService( - 'Config', - [ - 'lazy_services' => [ - 'class_map' => ['foo' => __CLASS__], - 'proxies_namespace' => $namespace, - ], - ] - ); - $serviceManager->setFactory('foo-delegator', 'Zend\ServiceManager\Proxy\LazyServiceFactoryFactory'); - $serviceManager->setInvokableClass('foo', __CLASS__); - $serviceManager->addDelegator('foo', 'foo-delegator'); - - /* @var $proxy self|\ProxyManager\Proxy\ValueHolderInterface|\ProxyManager\Proxy\LazyLoadingInterface */ - $proxy = $serviceManager->create('foo'); - $proxyClassName = get_class($proxy); - - $this->assertInstanceOf('ProxyManager\\Proxy\\LazyLoadingInterface', $proxy); - $this->assertInstanceOf(__CLASS__, $proxy); - $this->assertStringMatchesFormat( - $namespace . '\__PM__\ZendTest\ServiceManager\Proxy\LazyServiceFactoryFactoryTest%s', - $proxyClassName - ); - $this->assertFileNotExists(sys_get_temp_dir() . '/' . str_replace('\\', '', $proxyClassName) . '.php'); - $this->assertFalse($proxy->isProxyInitialized()); - $this->assertEquals($this->invalidConfigProvider(), $proxy->invalidConfigProvider()); - $this->assertTrue($proxy->isProxyInitialized()); - } - - public function testRegistersAutoloader() - { - $autoloaders = spl_autoload_functions(); - $serviceManager = new ServiceManager(); - $namespace = 'ZendTestProxy' . uniqid(); - - $serviceManager->setService( - 'Config', - [ - 'lazy_services' => [ - 'class_map' => ['foo' => __CLASS__], - 'proxies_namespace' => $namespace, - ], - ] - ); - $serviceManager->setFactory('foo-delegator', 'Zend\ServiceManager\Proxy\LazyServiceFactoryFactory'); - $serviceManager->create('foo-delegator'); - - $currentAutoloaders = spl_autoload_functions(); - $proxyAutoloader = end($currentAutoloaders); - - $this->assertCount(count($autoloaders) + 1, $currentAutoloaders); - $this->assertInstanceOf('ProxyManager\\Autoloader\\AutoloaderInterface', $proxyAutoloader); - - spl_autoload_unregister($proxyAutoloader); - } - - /** - * Provides invalid configuration - * - * @return array - */ - public function invalidConfigProvider() - { - return [ - [[]], - [['lazy_services' => []]] - ]; - } -} diff --git a/test/Proxy/LazyServiceFactoryTest.php b/test/Proxy/LazyServiceFactoryTest.php deleted file mode 100644 index 683915ee..00000000 --- a/test/Proxy/LazyServiceFactoryTest.php +++ /dev/null @@ -1,87 +0,0 @@ -markTestSkipped('Please install `ocramius/proxy-manager` to run these tests'); - } - - $this->locator = $this->getMock('Zend\\ServiceManager\\ServiceLocatorInterface'); - $this->proxyFactory = $this - ->getMockBuilder('ProxyManager\\Factory\\LazyLoadingValueHolderFactory') - ->disableOriginalConstructor() - ->getMock(); - } - - public function testCreateDelegatorWithRequestedName() - { - $instance = new \stdClass(); - $callback = function () {}; - $factory = new LazyServiceFactory($this->proxyFactory, ['foo' => 'bar']); - - $this - ->proxyFactory - ->expects($this->once()) - ->method('createProxy') - ->with('bar', $callback) - ->will($this->returnValue($instance)); - - $this->assertSame($instance, $factory->createDelegatorWithName($this->locator, 'baz', 'foo', $callback)); - } - - public function testCreateDelegatorWithCanonicalName() - { - $instance = new \stdClass(); - $callback = function () {}; - $factory = new LazyServiceFactory($this->proxyFactory, ['foo' => 'bar']); - - $this - ->proxyFactory - ->expects($this->once()) - ->method('createProxy') - ->with('bar', $callback) - ->will($this->returnValue($instance)); - - $this->assertSame($instance, $factory->createDelegatorWithName($this->locator, 'foo', 'baz', $callback)); - } - - public function testCannotCreateDelegatorWithNoMappedServiceClass() - { - $factory = new LazyServiceFactory($this->proxyFactory, []); - - $this->setExpectedException('Zend\\ServiceManager\\Exception\\InvalidServiceNameException'); - - $factory->createDelegatorWithName($this->locator, 'foo', 'baz', function () {}); - } -} diff --git a/test/ServiceLocatorAwareTraitTest.php b/test/ServiceLocatorAwareTraitTest.php deleted file mode 100644 index 8bdae845..00000000 --- a/test/ServiceLocatorAwareTraitTest.php +++ /dev/null @@ -1,45 +0,0 @@ -getObjectForTrait('\Zend\ServiceManager\ServiceLocatorAwareTrait'); - - $this->assertAttributeEquals(null, 'serviceLocator', $object); - - $serviceLocator = new ServiceManager; - - $object->setServiceLocator($serviceLocator); - - $this->assertAttributeEquals($serviceLocator, 'serviceLocator', $object); - } - - public function testGetServiceLocator() - { - $object = $this->getObjectForTrait('\Zend\ServiceManager\ServiceLocatorAwareTrait'); - - $this->assertNull($object->getServiceLocator()); - - $serviceLocator = new ServiceManager; - - $object->setServiceLocator($serviceLocator); - - $this->assertEquals($serviceLocator, $object->getServiceLocator()); - } -} diff --git a/test/ServiceManagerTest.php b/test/ServiceManagerTest.php index c0cd7af7..e6c7f8b3 100644 --- a/test/ServiceManagerTest.php +++ b/test/ServiceManagerTest.php @@ -9,1215 +9,248 @@ namespace ZendTest\ServiceManager; -use PHPUnit_Framework_TestCase as TestCase; -use Zend\Di\Di; -use Zend\Mvc\Service\DiFactory; -use Zend\ServiceManager\Di\DiAbstractServiceFactory; -use Zend\ServiceManager\Exception; +use DateTime; +use stdClass; +use Zend\ServiceManager\Exception\ServiceNotCreatedException; +use Zend\ServiceManager\Factory\FactoryInterface; +use Zend\ServiceManager\Initializer\InitializerInterface; +use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\InvokableFactory; use Zend\ServiceManager\ServiceManager; -use Zend\ServiceManager\Config; -use ZendTest\ServiceManager\TestAsset\FooCounterAbstractFactory; -use ZendTest\ServiceManager\TestAsset\MockSelfReturningDelegatorFactory; +use ZendTest\ServiceManager\Asset\FailingFactory; +use ZendTest\ServiceManager\Asset\InvokableObject; +use ZendTest\ServiceManager\Asset\SimpleAbstractFactory; +use ZendTest\ServiceManager\Asset\SimpleServiceManager; -/** - * @group Zend_ServiceManager - */ -class ServiceManagerTest extends TestCase +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(['services' => ['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 testSetSharedAbstractFactory() - { - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - $ret = $this->serviceManager->setShared('foo', false); - $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', []); - $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 testGetUsesIndivualSharedSettingWhenSetAndDeviatesFromShareByDefaultSetting() - { - $this->serviceManager->setAllowOverride(true); - $this->serviceManager->setShareByDefault(false); - $this->serviceManager->setInvokableClass('foo', 'ZendTest\ServiceManager\TestAsset\Foo'); - $this->serviceManager->setShared('foo', true); - $this->assertSame($this->serviceManager->get('foo'), $this->serviceManager->get('foo')); - - $this->serviceManager->setShareByDefault(true); - $this->serviceManager->setInvokableClass('foo', 'ZendTest\ServiceManager\TestAsset\Foo'); - $this->serviceManager->setShared('foo', false); - $this->assertNotSame($this->serviceManager->get('foo'), $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 testGetAbstractFactoryWithAlias() + public function testIsSharedByDefault() { - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - $this->serviceManager->setAlias('foo', 'ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); - } - - /** - * @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')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::create - */ - public function testCreateWithMultipleAbstractFactories() - { - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\BarAbstractFactory'); - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $this->serviceManager->get('bar')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::create - */ - public function testCreateTheSameServiceWithMultipleAbstractFactories() - { - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooFakeAbstractFactory'); - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $this->serviceManager->get('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::create - */ - public function testCreateTheSameServiceWithMultipleAbstractFactoriesReversePriority() - { - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooFakeAbstractFactory'); - - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\FooFake', $this->serviceManager->get('foo')); - } - - public function testCreateWithInitializerObject() - { - $this->serviceManager->addInitializer(new TestAsset\FooInitializer(['foo' => 'bar'])); - $this->serviceManager->setFactory('foo', function () { - return new \stdClass(); - }); - $obj = $this->serviceManager->get('foo'); - $this->assertEquals('bar', $obj->foo); - } - - public function testHasReturnsFalseOnNonStringsAndArrays() - { - $obj = new \stdClass(); - $this->assertFalse($this->serviceManager->has($obj)); - } - - public function testHasAcceptsArrays() - { - $this->serviceManager->setInvokableClass('foobar', 'foo'); - $this->assertTrue($this->serviceManager->has(['foobar', 'foo_bar'])); - } - - /** - * @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() - { - $this->serviceManager->setService('foo', 'bar'); - $this->serviceManager->setAlias('baz', 'foo'); - - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); - $this->serviceManager->setAlias('baz', 'foo'); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setAlias - */ - public function testSetAliasDoesNotThrowExceptionOnServiceNotFound() - { - $this->serviceManager->setAlias('foo', 'bar'); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::get - */ - public function testGetServiceThrowsExceptionOnAliasWithNoSetService() - { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->serviceManager->setAlias('foo', 'bar'); - $this->serviceManager->get('foo'); - } - - /** - * @cover Zend\ServiceManager\ServiceManager::get - */ - public function testGetServiceThrowsExceptionOnMultipleAliasesWithNoSetService() - { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->serviceManager->setAlias('foo', 'bar'); - $this->serviceManager->setAlias('baz', 'foo'); - $this->serviceManager->get('foo'); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::hasAlias - */ - public function testHasAlias() - { - $this->assertFalse($this->serviceManager->hasAlias('foo')); - - $this->serviceManager->setService('bar', 'baz'); - $this->serviceManager->setAlias('foo', 'bar'); - $this->assertTrue($this->serviceManager->hasAlias('foo')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::createScopedServiceManager - */ - public function testCreateScopedServiceManager() - { - $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 + ] + ]); - $this->assertContains($this->serviceManager, $this->readAttribute($scopedServiceManager, 'peeringServiceManagers')); + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class); - // test child scoped - $childScopedServiceManager = $this->serviceManager->createScopedServiceManager(ServiceManager::SCOPE_CHILD); - $this->assertContains($childScopedServiceManager, $this->readAttribute($this->serviceManager, 'peeringServiceManagers')); + $this->assertSame($object1, $object2); } - public function testConfigureWithInvokableClass() + public function testCanDisableSharedByDefault() { - $config = new Config([ - 'invokables' => [ - 'foo' => 'ZendTest\ServiceManager\TestAsset\Foo', + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class ], + 'shared_by_default' => false ]); - $serviceManager = new ServiceManager($config); - $foo = $serviceManager->get('foo'); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Foo', $foo); - } - - public function testPeeringService() - { - $di = new Di(); - $di->instanceManager()->setParameters('ZendTest\ServiceManager\TestAsset\Bar', ['foo' => ['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); - } - - public function testDiAbstractServiceFactory() - { - $di = $this->getMock('Zend\Di\Di'); - $factory = new DiAbstractServiceFactory($di); - $factory->instanceManager()->setConfig('ZendTest\ServiceManager\TestAsset\Bar', ['parameters' => ['foo' => ['a']]]); - $this->serviceManager->addAbstractFactory($factory); - $this->assertTrue($this->serviceManager->has('ZendTest\ServiceManager\TestAsset\Bar', true)); + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class); - $bar = $this->serviceManager->get('ZendTest\ServiceManager\TestAsset\Bar', true); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $bar); + $this->assertNotSame($object1, $object2); } - public function testExceptionThrowingFactory() + public function testCanDisableSharedForSingleService() { - $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()); - } - } - - /** - * @expectedException Zend\ServiceManager\Exception\ServiceNotFoundException - */ - public function testCannotUseUnknownServiceNameForAbstractFactory() - { - $config = new Config([ - 'abstract_factories' => [ - 'ZendTest\ServiceManager\TestAsset\FooAbstractFactory', + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class ], + 'shared' => [ + stdClass::class => false + ] ]); - $serviceManager = new ServiceManager($config); - $serviceManager->setFactory('foo', 'ZendTest\ServiceManager\TestAsset\FooFactory'); - $foo = $serviceManager->get('unknownObject'); - } - - /** - * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException - */ - public function testDoNotFallbackToAbstractFactory() - { - $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', ['foo' => ['a']]); - $serviceManager->addAbstractFactory(new DiAbstractServiceFactory($di)); - $bar = $serviceManager->get('ZendTest\ServiceManager\TestAsset\Bar'); - } - - /** - * @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(['a']); - }); - $this->serviceManager->setAllowOverride(false); - // should throw an exception because 'foo' already exists in the service manager - $this->serviceManager->setAlias('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); - } - - /** - * When failing, this test will trigger a fatal error: Allowed memory size of # bytes exhausted - */ - public function testCallingANonExistingServiceFromAnAbstractServiceDoesNotMakeTheServerExhaustTheAllowedMemoryByCallingItselfForTheGivenService() - { - $abstractFactory = new TestAsset\TrollAbstractFactory; - $this->serviceManager->addAbstractFactory($abstractFactory); - - $this->assertSame($abstractFactory->inexistingServiceCheckResult, null); - - // By doing this the Service Manager will rely on the Abstract Service Factory - $service = $this->serviceManager->get('SomethingThatCanBeCreated'); - $this->assertSame(false, $abstractFactory->inexistingServiceCheckResult); + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class); - $this->assertInstanceOf('stdClass', $service); + $this->assertNotSame($object1, $object2); } - public function testMultipleAbstractFactoriesWithOneLookingForANonExistingServiceDuringCanCreate() + public function testCanEnableSharedForSingleService() { - $abstractFactory = new TestAsset\TrollAbstractFactory; - $anotherAbstractFactory = $this->getMock('Zend\ServiceManager\AbstractFactoryInterface'); - $anotherAbstractFactory - ->expects($this->exactly(2)) - ->method('canCreateServiceWithName') - ->with( - $this->serviceManager, - $this->logicalOr('somethingthatcanbecreated', 'nonexistingservice'), - $this->logicalOr('SomethingThatCanBeCreated', 'NonExistingService') - ) - ->will($this->returnValue(false)); - - $this->serviceManager->addAbstractFactory($abstractFactory); - $this->serviceManager->addAbstractFactory($anotherAbstractFactory); - - $this->assertTrue($this->serviceManager->has('SomethingThatCanBeCreated')); - $this->assertFalse($abstractFactory->inexistingServiceCheckResult); - } - - public function testWaitingAbstractFactory() - { - $abstractFactory = new TestAsset\WaitingAbstractFactory; - $this->serviceManager->addAbstractFactory($abstractFactory); - - $abstractFactory->waitingService = null; - $abstractFactory->canCreateCallCount = 0; - $this->assertFalse($this->serviceManager->has('SomethingThatCanBeCreated')); - $this->assertEquals(1, $abstractFactory->canCreateCallCount); - - $abstractFactory->waitingService = 'SomethingThatCanBeCreated'; - $abstractFactory->canCreateCallCount = 0; - $this->assertTrue($this->serviceManager->has('SomethingThatCanBeCreated')); - $this->assertEquals(1, $abstractFactory->canCreateCallCount); - - $abstractFactory->canCreateCallCount = 0; - $this->assertInstanceOf('stdClass', $this->serviceManager->get('SomethingThatCanBeCreated')); - $this->assertEquals(1, $abstractFactory->canCreateCallCount); - } - - public function testWaitingAbstractFactoryNestedContextCounterWhenThrowException() - { - $abstractFactory = new TestAsset\WaitingAbstractFactory; - $this->serviceManager->addAbstractFactory($abstractFactory); - - $contextCounter = new \ReflectionProperty($this->serviceManager, 'nestedContextCounter'); - $contextCounter->setAccessible(true); - $contextCounter->getValue($this->serviceManager); - - $abstractFactory->waitName = 'SomethingThatCanBeCreated'; - $abstractFactory->createNullService = true; - $this->assertEquals(-1, $contextCounter->getValue($this->serviceManager)); - try { - $this->serviceManager->get('SomethingThatCanBeCreated'); - $this->fail('serviceManager shoud throw Zend\ServiceManager\Exception\ServiceNotFoundException'); - } catch (\Exception $e) { - if (stripos(get_class($e), 'PHPUnit') !== false) { - throw $e; - } - $this->assertEquals(-1, $contextCounter->getValue($this->serviceManager)); - } - - $abstractFactory->createNullService = false; - $abstractFactory->throwExceptionWhenCreate = true; - try { - $this->serviceManager->get('SomethingThatCanBeCreated'); - $this->fail('serviceManager shoud throw Zend\ServiceManager\Exception\ServiceNotCreatedException'); - } catch (\Exception $e) { - if (stripos(get_class($e), 'PHPUnit') !== false) { - throw $e; - } - $this->assertEquals(-1, $contextCounter->getValue($this->serviceManager)); - } - } - - public function testShouldAllowAddingInitializersAsClassNames() - { - $result = $this->serviceManager->addInitializer('ZendTest\ServiceManager\TestAsset\FooInitializer'); - $this->assertSame($this->serviceManager, $result); - } - - public function testShouldRaiseExceptionIfInitializerClassIsNotAnInitializerInterfaceImplementation() - { - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidArgumentException'); - $result = $this->serviceManager->addInitializer(get_class($this)); - } - - public function testGetGlobIteratorServiceWorksProperly() - { - $config = new Config([ - 'invokables' => [ - 'foo' => 'ZendTest\ServiceManager\TestAsset\GlobIteratorService', + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class ], + 'shared_by_default' => false, + 'shared' => [ + stdClass::class => true + ] ]); - $serviceManager = new ServiceManager($config); - $foo = $serviceManager->get('foo'); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\GlobIteratorService', $foo); - } - - public function duplicateService() - { - return [ - [ - 'setFactory', - function ($services) { - return $this; - }, - $this, - 'assertSame', - ], - [ - 'setInvokableClass', - 'stdClass', - 'stdClass', - 'assertInstanceOf', - ], - [ - 'setService', - $this, - $this, - 'assertSame', - ], - ]; - } - - /** - * @dataProvider duplicateService - */ - public function testWithAllowOverrideOnRegisteringAServiceDuplicatingAnExistingAliasShouldInvalidateTheAlias($method, $service, $expected, $assertion = 'assertSame') - { - $this->serviceManager->setAllowOverride(true); - $sm = $this->serviceManager; - $this->serviceManager->setFactory('http.response', function () use ($sm) { - return $sm; - }); - $this->serviceManager->setAlias('response', 'http.response'); - $this->assertSame($sm, $this->serviceManager->get('response')); - - $this->serviceManager->{$method}('response', $service); - $this->{$assertion}($expected, $this->serviceManager->get('response')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::canonicalizeName - */ - public function testCanonicalizeName() - { - $this->serviceManager->setService('foo_bar', new \stdClass()); - $this->assertEquals(true, $this->serviceManager->has('foo_bar')); - $this->assertEquals(true, $this->serviceManager->has('foobar')); - $this->assertEquals(true, $this->serviceManager->has('foo-bar')); - $this->assertEquals(true, $this->serviceManager->has('foo/bar')); - $this->assertEquals(true, $this->serviceManager->has('foo bar')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::canCreateFromAbstractFactory - */ - public function testWanCreateFromAbstractFactoryWillNotInstantiateAbstractFactoryOnce() - { - $count = FooCounterAbstractFactory::$instantiationCount; - $this->serviceManager->addAbstractFactory(__NAMESPACE__ . '\TestAsset\FooCounterAbstractFactory'); - - $this->serviceManager->canCreateFromAbstractFactory('foo', 'foo'); - $this->serviceManager->canCreateFromAbstractFactory('foo', 'foo'); - - $this->assertSame($count + 1, FooCounterAbstractFactory::$instantiationCount); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::canCreateFromAbstractFactory - * @covers Zend\ServiceManager\ServiceManager::create - */ - public function testAbstractFactoryNotUsedIfNotAbleToCreate() - { - $service = new \stdClass; - $af1 = $this->getMock('Zend\ServiceManager\AbstractFactoryInterface'); - $af1->expects($this->any())->method('canCreateServiceWithName')->will($this->returnValue(true)); - $af1->expects($this->any())->method('createServiceWithName')->will($this->returnValue($service)); + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class); - $af2 = $this->getMock('Zend\ServiceManager\AbstractFactoryInterface'); - $af2->expects($this->any())->method('canCreateServiceWithName')->will($this->returnValue(false)); - $af2->expects($this->never())->method('createServiceWithName'); - - $this->serviceManager->addAbstractFactory($af1); - $this->serviceManager->addAbstractFactory($af2); - - $this->assertSame($service, $this->serviceManager->create('test')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setAlias - * @covers Zend\ServiceManager\ServiceManager::get - * @covers Zend\ServiceManager\ServiceManager::retrieveFromPeeringManager - */ - public function testCanGetAliasedServicesFromPeeringServiceManagers() - { - $service = new \stdClass(); - $peeringSm = new ServiceManager(); - - $peeringSm->setService('actual-service-name', $service); - $this->serviceManager->addPeeringServiceManager($peeringSm); - - $this->serviceManager->setAlias('alias-name', 'actual-service-name'); - - $this->assertSame($service, $this->serviceManager->get('alias-name')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::get - */ - public function testDuplicateNewInstanceMultipleAbstractFactories() - { - $this->serviceManager->setAllowOverride(true); - $this->serviceManager->setShareByDefault(false); - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\BarAbstractFactory'); - $this->serviceManager->addAbstractFactory('ZendTest\ServiceManager\TestAsset\FooAbstractFactory'); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $this->serviceManager->get('bar')); - $this->assertInstanceOf('ZendTest\ServiceManager\TestAsset\Bar', $this->serviceManager->get('bar')); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::setService - * @covers Zend\ServiceManager\ServiceManager::get - * @covers Zend\ServiceManager\ServiceManager::retrieveFromPeeringManagerFirst - * @covers Zend\ServiceManager\ServiceManager::setRetrieveFromPeeringManagerFirst - * @covers Zend\ServiceManager\ServiceManager::addPeeringServiceManager - */ - public function testRetrieveServiceFromPeeringServiceManagerIfretrieveFromPeeringManagerFirstSetToTrueAndServiceNamesAreSame() - { - $foo1 = "foo1"; - $boo1 = "boo1"; - $boo2 = "boo2"; - - $this->serviceManager->setService($foo1, $boo1); - $this->assertEquals($this->serviceManager->get($foo1), $boo1); - - $serviceManagerChild = new ServiceManager(); - $serviceManagerChild->setService($foo1, $boo2); - $this->assertEquals($serviceManagerChild->get($foo1), $boo2); - - $this->assertFalse($this->serviceManager->retrieveFromPeeringManagerFirst()); - $this->serviceManager->setRetrieveFromPeeringManagerFirst(true); - $this->assertTrue($this->serviceManager->retrieveFromPeeringManagerFirst()); - - $this->serviceManager->addPeeringServiceManager($serviceManagerChild); - - $this->assertContains($serviceManagerChild, $this->readAttribute($this->serviceManager, 'peeringServiceManagers')); - - $this->assertEquals($serviceManagerChild->get($foo1), $boo2); - $this->assertEquals($this->serviceManager->get($foo1), $boo2); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::create - * @covers Zend\ServiceManager\ServiceManager::createDelegatorFromFactory - * @covers Zend\ServiceManager\ServiceManager::createDelegatorCallback - * @covers Zend\ServiceManager\ServiceManager::addDelegator - */ - public function testUsesDelegatorWhenAvailable() - { - $delegator = $this->getMock('Zend\\ServiceManager\\DelegatorFactoryInterface'); - - $this->serviceManager->setService('foo-delegator', $delegator); - $this->serviceManager->addDelegator('foo-service', 'foo-delegator'); - $this->serviceManager->setInvokableClass('foo-service', 'stdClass'); - - $delegator - ->expects($this->once()) - ->method('createDelegatorWithName') - ->with( - $this->serviceManager, - 'fooservice', - 'foo-service', - $this->callback(function ($callback) { - if (!is_callable($callback)) { - return false; - } - - $service = call_user_func($callback); - - return $service instanceof \stdClass; - }) - ) - ->will($this->returnValue($delegator)); - - $this->assertSame($delegator, $this->serviceManager->create('foo-service')); + $this->assertSame($object1, $object2); } - /** - * @covers Zend\ServiceManager\ServiceManager::create - * @covers Zend\ServiceManager\ServiceManager::createDelegatorFromFactory - * @covers Zend\ServiceManager\ServiceManager::createDelegatorCallback - * @covers Zend\ServiceManager\ServiceManager::addDelegator - */ - public function testUsesMultipleDelegates() + public function testCanCreateObjectWithInvokableFactory() { - $fooDelegator = new MockSelfReturningDelegatorFactory(); - $barDelegator = new MockSelfReturningDelegatorFactory(); - - $this->serviceManager->setService('foo-delegate', $fooDelegator); - $this->serviceManager->setService('bar-delegate', $barDelegator); - $this->serviceManager->addDelegator('foo-service', 'foo-delegate'); - $this->serviceManager->addDelegator('foo-service', 'bar-delegate'); - $this->serviceManager->setInvokableClass('foo-service', 'stdClass'); - - $this->assertSame($barDelegator, $this->serviceManager->create('foo-service')); - $this->assertCount(1, $barDelegator->instances); - $this->assertCount(1, $fooDelegator->instances); - $this->assertInstanceOf('stdClass', array_shift($fooDelegator->instances)); - $this->assertSame($fooDelegator, array_shift($barDelegator->instances)); - } - - /** - * @covers Zend\ServiceManager\ServiceManager::resolveAlias - */ - public function testSetCircularAliasReferenceThrowsException() - { - $this->setExpectedException('Zend\ServiceManager\Exception\CircularReferenceException'); + $serviceManager = new ServiceManager([ + 'factories' => [ + InvokableObject::class => InvokableFactory::class + ] + ]); - // Only affects service managers that allow overwriting definitions - $this->serviceManager->setAllowOverride(true); - $this->serviceManager->setInvokableClass('foo-service', 'stdClass'); - $this->serviceManager->setAlias('foo-alias', 'foo-service'); - $this->serviceManager->setAlias('bar-alias', 'foo-alias'); - $this->serviceManager->setAlias('baz-alias', 'bar-alias'); + $object = $serviceManager->get(InvokableObject::class, ['foo' => 'bar']); - // This will now cause a cyclic reference and should throw an exception - $this->serviceManager->setAlias('foo-alias', 'bar-alias'); + $this->assertInstanceOf(InvokableObject::class, $object); + $this->assertEquals(['foo' => 'bar'], $object->options); } - /** - * @covers Zend\ServiceManager\ServiceManager::checkForCircularAliasReference - */ - public function testResolveCircularAliasReferenceThrowsException() + public function testCanCreateObjectWithClosureFactory() { - $this->setExpectedException('Zend\ServiceManager\Exception\CircularReferenceException'); - - // simulate an inconsistent state of $servicemanager->aliases as it could be - // caused by derived classes - $cyclicAliases = [ - 'fooalias' => 'bazalias', - 'baralias' => 'fooalias', - 'bazalias' => 'baralias' - ]; - - $reflection = new \ReflectionObject($this->serviceManager); - $propertyReflection = $reflection->getProperty('aliases'); - $propertyReflection->setAccessible(true); - $propertyReflection->setValue($this->serviceManager, $cyclicAliases); + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => function(ServiceLocatorInterface $serviceLocator, $className) { + $this->assertEquals(stdClass::class, $className); + return new stdClass(); + } + ] + ]); - // This should throw the exception - $this->serviceManager->get('baz-alias'); + $object = $serviceManager->get(stdClass::class); + $this->assertInstanceOf(stdClass::class, $object); } - /** - * @covers Zend\ServiceManager\ServiceManager::createDelegatorFromFactory - */ - public function testDelegatorFactoryWhenNotRegisteredAsService() + public function testCanCreateServiceWithAbstractFactory() { - $delegator = $this->getMock('Zend\\ServiceManager\\DelegatorFactoryInterface'); - - $this->serviceManager->addDelegator('foo-service', $delegator); - $this->serviceManager->setInvokableClass('foo-service', 'stdClass'); - - $delegator - ->expects($this->once()) - ->method('createDelegatorWithName') - ->with( - $this->serviceManager, - 'fooservice', - 'foo-service', - $this->callback(function ($callback) { - if (!is_callable($callback)) { - return false; - } - - $service = call_user_func($callback); - - return $service instanceof \stdClass; - }) - ) - ->will($this->returnValue($delegator)); + $serviceManager = new ServiceManager([ + 'abstract_factories' => [ + new SimpleAbstractFactory() + ] + ]); - $this->assertSame($delegator, $this->serviceManager->create('foo-service')); + $serviceManager->get(DateTime::class); } - /** - * @covers Zend\ServiceManager\ServiceManager::create - * @covers Zend\ServiceManager\ServiceManager::createDelegatorFromFactory - * @covers Zend\ServiceManager\ServiceManager::createDelegatorCallback - * @covers Zend\ServiceManager\ServiceManager::addDelegator - */ - public function testMultipleDelegatorFactoriesWhenNotRegisteredAsServices() + public function testCanCreateServiceWithAlias() { - $fooDelegator = new MockSelfReturningDelegatorFactory(); - $barDelegator = new MockSelfReturningDelegatorFactory(); - - $this->serviceManager->addDelegator('foo-service', $fooDelegator); - $this->serviceManager->addDelegator('foo-service', $barDelegator); - $this->serviceManager->setInvokableClass('foo-service', 'stdClass'); - - $this->assertSame($barDelegator, $this->serviceManager->create('foo-service')); - $this->assertCount(1, $barDelegator->instances); - $this->assertCount(1, $fooDelegator->instances); - $this->assertInstanceOf('stdClass', array_shift($fooDelegator->instances)); - $this->assertSame($fooDelegator, array_shift($barDelegator->instances)); - } + $serviceManager = new ServiceManager([ + 'factories' => [ + InvokableObject::class => InvokableFactory::class + ], + 'aliases' => [ + 'foo' => InvokableObject::class, + 'bar' => 'foo' + ] + ]); - public function testInvalidDelegatorFactoryThrowsException() - { - $delegatorFactory = new \stdClass; - $this->serviceManager->addDelegator('foo-service', $delegatorFactory); + $object = $serviceManager->get('bar'); - try { - $this->serviceManager->create('foo-service'); - $this->fail('Expected exception was not raised'); - } catch (Exception\ServiceNotCreatedException $expected) { - $this->assertRegExp('/invalid factory/', $expected->getMessage()); - return; - } + $this->assertInstanceOf(InvokableObject::class, $object); + $this->assertTrue($serviceManager->has('bar')); + $this->assertFalse($serviceManager->has('baz')); } - public function testInvalidDelegatorFactoryAmongMultipleOnesThrowsException() + public function testCanCheckServiceExistenceWithoutCheckingAbstractFactories() { - $this->serviceManager->addDelegator('foo-service', new MockSelfReturningDelegatorFactory()); - $this->serviceManager->addDelegator('foo-service', new MockSelfReturningDelegatorFactory()); - $this->serviceManager->addDelegator('foo-service', 'stdClass'); + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ] + ]); - try { - $this->serviceManager->create('foo-service'); - $this->fail('Expected exception was not raised'); - } catch (Exception\ServiceNotCreatedException $expected) { - $this->assertRegExp('/invalid factory/', $expected->getMessage()); - return; - } + $this->assertTrue($serviceManager->has(stdClass::class)); + $this->assertFalse($serviceManager->has(DateTime::class)); } - public function testDelegatorFromCallback() + public function testCanCheckServiceExistenceWithCheckingAbstractFactories() { - $realService = $this->getMock('stdClass', [], [], 'RealService'); - $delegator = $this->getMock('stdClass', [], [], 'Delegator'); - - $delegatorFactoryCallback = function ($serviceManager, $cName, $rName, $callback) use ($delegator) { - $delegator->real = call_user_func($callback); - return $delegator; - }; - - $this->serviceManager->setFactory('foo-service', function () use ($realService) { return $realService; }); - $this->serviceManager->addDelegator('foo-service', $delegatorFactoryCallback); - - $service = $this->serviceManager->create('foo-service'); + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ], + 'abstract_factories' => [ + new SimpleAbstractFactory() // This one always return true + ] + ]); - $this->assertSame($delegator, $service); - $this->assertSame($realService, $service->real); + $this->assertTrue($serviceManager->has(stdClass::class, true)); + $this->assertTrue($serviceManager->has(DateTime::class, true)); } - /** - * @dataProvider getServiceOfVariousTypes - * @param $service - */ - public function testAbstractFactoriesCanReturnAnyTypeButNull($service) + public function testNeverShareIfOptionsArePassed() { - $abstractFactory = $this->getMock('Zend\ServiceManager\AbstractFactoryInterface'); - $abstractFactory - ->expects($this->any()) - ->method('canCreateServiceWithName') - ->with($this->serviceManager, 'something', 'something') - ->will($this->returnValue(true)); - - $abstractFactory - ->expects($this->any()) - ->method('createServiceWithName') - ->with($this->serviceManager, 'something', 'something') - ->will($this->returnValue($service)); + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ], + 'shared' => [ + stdClass::class => true + ] + ]); - $this->serviceManager->addAbstractFactory($abstractFactory); + $object1 = $serviceManager->get(stdClass::class); + $object2 = $serviceManager->get(stdClass::class, ['foo' => 'bar']); - if ($service === null) { - try { - $this->serviceManager->get('something'); - $this->fail('ServiceManager::get() successfully returned null'); - } catch (\Exception $e) { - $this->assertInstanceOf('Zend\ServiceManager\Exception\ServiceNotCreatedException', $e); - } - } else { - $this->assertSame($service, $this->serviceManager->get('something')); - } + $this->assertNotSame($object1, $object2); } - /** - * @dataProvider getServiceOfVariousTypes - * @param $service - */ - public function testFactoriesCanReturnAnyTypeButNull($service) + public function testInitializersAreRunAfterCreation() { - $factory = function () use ($service) { - return $service; - }; - $this->serviceManager->setFactory('something', $factory); + $initializer = $this->getMock(InitializerInterface::class); - if ($service === null) { - try { - $this->serviceManager->get('something'); - $this->fail('ServiceManager::get() successfully returned null'); - } catch (\Exception $e) { - $this->assertInstanceOf('Zend\ServiceManager\Exception\ServiceNotCreatedException', $e); - } - } else { - $this->assertSame($service, $this->serviceManager->get('something')); - } - } + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => InvokableFactory::class + ], + 'initializers' => [ + $initializer + ] + ]); - /** - * @dataProvider getServiceOfVariousTypes - * @param $service - */ - public function testServicesCanBeOfAnyTypeButNull($service) - { - $this->serviceManager->setService('something', $service); + $initializer->expects($this->once()) + ->method('__invoke') + ->with($serviceManager, $this->isInstanceOf(stdClass::class)); - if ($service === null) { - try { - $this->serviceManager->get('something'); - $this->fail('ServiceManager::get() successfully returned null'); - } catch (\Exception $e) { - $this->assertInstanceOf('Zend\ServiceManager\Exception\ServiceNotFoundException', $e); - } - } else { - $this->assertSame($service, $this->serviceManager->get('something')); - } - } + // We call it twice to make sure that the initializer is only called once - public function getServiceOfVariousTypes() - { - return [ - [null], - ['string'], - [1], - [1.2], - [[]], - [function () {}], - [false], - [new \stdClass()], - [tmpfile()] - ]; + $serviceManager->get(stdClass::class); + $serviceManager->get(stdClass::class); } - /** - * @group ZF2-4377 - */ - public function testServiceManagerRespectsSharedFlagWhenRetrievingFromPeeredServiceManager() + public function testThrowExceptionIfServiceCannotBeCreated() { - $this->serviceManager->setInvokableClass('foo', 'ZendTest\ServiceManager\TestAsset\Foo'); - $this->serviceManager->setShared('foo', false); + $serviceManager = new ServiceManager([ + 'factories' => [ + stdClass::class => FailingFactory::class + ] + ]); - $childManager = new ServiceManager(new Config()); - $childManager->addPeeringServiceManager($this->serviceManager); - $childManager->setRetrieveFromPeeringManagerFirst(false); + $this->setExpectedException(ServiceNotCreatedException::class); - $this->assertNotSame($childManager->get('foo'), $childManager->get('foo')); + $serviceManager->get(stdClass::class); } - /** - * @group ZF2-4377 - */ - public function testIsSharedThrowsExceptionWhenPassedNameWhichDoesNotExistAnywhere() + public function testConfigurationCanBeMerged() { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->serviceManager->isShared('foobarbazbat'); - } + $serviceManager = new SimpleServiceManager([ + 'factories' => [ + DateTime::class => InvokableFactory::class + ] + ]); - public function testPeeringServiceManagersInBothDirectionsDontRunIntoInfiniteLoop() - { - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $peeredServiceManager = $this->serviceManager->createScopedServiceManager(ServiceManager::SCOPE_CHILD); - $peeredServiceManager->addPeeringServiceManager($this->serviceManager); - $this->serviceManager->get('foobarbazbat'); + $this->assertTrue($serviceManager->has(DateTime::class)); + $this->assertTrue($serviceManager->has(stdClass::class)); } - public function testServiceCanBeFoundFromPeeringServicesManagers() + public function testConfigurationTakesPrecedenceWhenMerged() { - $peeredServiceManager = new ServiceManager(); - $peeredServiceManager->addPeeringServiceManager($this->serviceManager); - $this->serviceManager->addPeeringServiceManager($peeredServiceManager); + $factory = $this->getMock(FactoryInterface::class); - $secondParentServiceManager = new ServiceManager(); - $secondParentServiceManager->addPeeringServiceManager($peeredServiceManager); - $peeredServiceManager->addPeeringServiceManager($secondParentServiceManager); + $factory->expects($this->once())->method('__invoke'); - $expectedService = new \stdClass(); - $secondParentServiceManager->setService('peered_service', $expectedService); - - // check if service is direct child of secong parent service manager - $this->assertFalse($this->serviceManager->has('peered_service', true, false)); - $this->assertFalse($peeredServiceManager->has('peered_service', true, false)); - $this->assertTrue($secondParentServiceManager->has('peered_service', true, false)); + $serviceManager = new SimpleServiceManager([ + 'factories' => [ + stdClass::class => $factory + ] + ]); - // check if we can receive service from peered service managers - $this->assertTrue($this->serviceManager->has('peered_service')); - $this->assertTrue($peeredServiceManager->has('peered_service')); - $this->assertTrue($secondParentServiceManager->has('peered_service')); - $this->assertSame($expectedService, $this->serviceManager->get('peered_service')); - $this->assertSame($expectedService, $peeredServiceManager->get('peered_service')); - $this->assertSame($expectedService, $secondParentServiceManager->get('peered_service')); + $serviceManager->get(stdClass::class); } -} +} \ No newline at end of file diff --git a/test/TestAsset/AbstractFactoryWithMutableCreationOptions.php b/test/TestAsset/AbstractFactoryWithMutableCreationOptions.php deleted file mode 100644 index ac6b555c..00000000 --- a/test/TestAsset/AbstractFactoryWithMutableCreationOptions.php +++ /dev/null @@ -1,38 +0,0 @@ -options = $options; - } -} diff --git a/test/TestAsset/Bar.php b/test/TestAsset/Bar.php deleted file mode 100644 index 4598b6cb..00000000 --- a/test/TestAsset/Bar.php +++ /dev/null @@ -1,20 +0,0 @@ -options = $options; - } - - public function __invoke(ServiceLocatorInterface $serviceLocator, $cName, $rName) - { - return new stdClass; - } -} diff --git a/test/TestAsset/CircularDependencyAbstractFactory.php b/test/TestAsset/CircularDependencyAbstractFactory.php deleted file mode 100644 index 1d2ce25c..00000000 --- a/test/TestAsset/CircularDependencyAbstractFactory.php +++ /dev/null @@ -1,41 +0,0 @@ -has($name)) { - return $serviceLocator->get($name); - } - - return $this->expectedInstance; - } -} diff --git a/test/TestAsset/FooAbstractFactory.php b/test/TestAsset/FooAbstractFactory.php deleted file mode 100644 index 381fe5c4..00000000 --- a/test/TestAsset/FooAbstractFactory.php +++ /dev/null @@ -1,27 +0,0 @@ -creationOptions = $creationOptions; - } - - public function setCreationOptions(array $creationOptions) - { - $this->creationOptions = $creationOptions; - } - - public function getCreationOptions() - { - return $this->creationOptions; - } - - public function createService(ServiceLocatorInterface $serviceLocator) - { - return new Foo; - } -} diff --git a/test/TestAsset/FooFake.php b/test/TestAsset/FooFake.php deleted file mode 100644 index 1781d9aa..00000000 --- a/test/TestAsset/FooFake.php +++ /dev/null @@ -1,15 +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/TestAsset/MockSelfReturningDelegatorFactory.php b/test/TestAsset/MockSelfReturningDelegatorFactory.php deleted file mode 100644 index 603090c6..00000000 --- a/test/TestAsset/MockSelfReturningDelegatorFactory.php +++ /dev/null @@ -1,34 +0,0 @@ -instances[] = call_user_func($callback); - - return $this; - } -} diff --git a/test/TestAsset/TrollAbstractFactory.php b/test/TestAsset/TrollAbstractFactory.php deleted file mode 100644 index b0b8e1d4..00000000 --- a/test/TestAsset/TrollAbstractFactory.php +++ /dev/null @@ -1,36 +0,0 @@ -inexistingServiceCheckResult = $serviceLocator->has('NonExistingService'); - - if ($requestedName === 'SomethingThatCanBeCreated') { - return true; - } - - return false; - } - - public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) - { - return new stdClass; - } -} diff --git a/test/TestAsset/WaitingAbstractFactory.php b/test/TestAsset/WaitingAbstractFactory.php deleted file mode 100644 index 9c215841..00000000 --- a/test/TestAsset/WaitingAbstractFactory.php +++ /dev/null @@ -1,42 +0,0 @@ -canCreateCallCount++; - return $requestedName === $this->waitingService; - } - - public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) - { - if ($this->throwExceptionWhenCreate) { - throw new FooException('E'); - } - if ($this->createNullService) { - return null; - } - return new stdClass; - } -} 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 @@ -