diff --git a/.coveralls.yml b/.coveralls.yml index 53bda829..bc71b62f 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1,3 +1,2 @@ coverage_clover: clover.xml json_path: coveralls-upload.json -src_dir: src diff --git a/.travis.yml b/.travis.yml index 2948647d..764a0a1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,6 @@ matrix: - php: 7 - php: hhvm allow_failures: - - php: 7 - php: hhvm notifications: @@ -45,10 +44,10 @@ notifications: before_install: - if [[ $EXECUTE_TEST_COVERALLS != '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 + - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then composer require --dev --no-update satooshi/php-coveralls:^1.0 ; fi install: - - travis_retry composer install --no-interaction --ignore-platform-reqs + - travis_retry composer install --no-interaction script: - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/phpunit --coverage-clover clover.xml ; fi @@ -60,4 +59,4 @@ after_success: - if [[ $DEPLOY_DOCS == "true" ]]; then echo "Preparing to build and deploy documentation" ; ./zf-mkdoc-theme/deploy.sh ; echo "Completed deploying documentation" ; fi after_script: - - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/coveralls ; fi + - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/coveralls -v ; fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c3ddbdc..9ea10320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,37 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 3.1.0 - 2016-06-01 + +### Added + +- [#103](https://github.com/zendframework/zend-servicemanager/pull/103) Allowing + installation of `ocramius/proxy-manager` `^2.0` together with + `zendframework/zend-servicemanager`. +- [#103](https://github.com/zendframework/zend-servicemanager/pull/103) Disallowing + test failures when running tests against PHP `7.0.*`. +- [#113](https://github.com/zendframework/zend-servicemanager/pull/113) Improved performance + when dealing with registering aliases and factories via `ServiceManager#setFactory()` and + `ServiceManager#setAlias()` +- [#120](https://github.com/zendframework/zend-servicemanager/pull/120) The + `zendframework/zend-servicemanager` component now provides a + `container-interop/container-interop-implementation` implementation + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- [#97](https://github.com/zendframework/zend-servicemanager/pull/97) Typo corrections + in the delegator factories documentation. +- [#98](https://github.com/zendframework/zend-servicemanager/pull/98) Using coveralls ^1.0 + for tracking test code coverage changes. + ## 3.0.4 - TBD ### Added diff --git a/benchmarks/SetNewServicesBench.php b/benchmarks/SetNewServicesBench.php new file mode 100644 index 00000000..b3c2c011 --- /dev/null +++ b/benchmarks/SetNewServicesBench.php @@ -0,0 +1,77 @@ + [ + 'factory1' => BenchAsset\FactoryFoo::class, + ], + 'invokables' => [ + 'invokable1' => BenchAsset\Foo::class, + ], + 'services' => [ + 'service1' => new \stdClass(), + ], + 'aliases' => [ + 'factoryAlias1' => 'factory1', + 'recursiveFactoryAlias1' => 'factoryAlias1', + 'recursiveFactoryAlias2' => 'recursiveFactoryAlias1', + ], + 'abstract_factories' => [ + BenchAsset\AbstractFactoryFoo::class + ], + ]; + + for ($i = 0; $i <= self::NUM_SERVICES; $i++) { + $config['factories']["factory_$i"] = BenchAsset\FactoryFoo::class; + $config['aliases']["alias_$i"] = "service_$i"; + } + + $this->sm = new ServiceManager($config); + } + + public function benchSetFactory() + { + // @todo @link https://github.com/phpbench/phpbench/issues/304 + $sm = clone $this->sm; + + $sm->setFactory('factory2', BenchAsset\FactoryFoo::class); + } + + public function benchSetAlias() + { + // @todo @link https://github.com/phpbench/phpbench/issues/304 + $sm = clone $this->sm; + + $sm->setAlias('factoryAlias2', 'factory1'); + } + + public function benchSetAliasOverrided() + { + // @todo @link https://github.com/phpbench/phpbench/issues/304 + $sm = clone $this->sm; + + $sm->setAlias('recursiveFactoryAlias1', 'factory1'); + } +} diff --git a/composer.json b/composer.json index 65e7a7d8..d63debfe 100644 --- a/composer.json +++ b/composer.json @@ -18,9 +18,9 @@ "container-interop/container-interop": "~1.0" }, "require-dev": { - "phpunit/phpunit": "~4.6", - "ocramius/proxy-manager": "~1.0", - "squizlabs/php_codesniffer": "^2.0@dev", + "phpunit/phpunit": "^4.6 || ^5.2.10", + "ocramius/proxy-manager": "^1.0 || ^2.0", + "squizlabs/php_codesniffer": "^2.5.1", "phpbench/phpbench": "^0.10.0" }, "suggest": { @@ -40,5 +40,8 @@ "ZendTest\\ServiceManager\\": "test/", "ZendBench\\ServiceManager\\": "benchmarks/" } + }, + "provide": { + "container-interop/container-interop-implementation": "^1.1" } } diff --git a/doc/book/delegators.md b/doc/book/delegators.md index 359afd3b..2cb779ae 100644 --- a/doc/book/delegators.md +++ b/doc/book/delegators.md @@ -29,8 +29,7 @@ The parameters passed to the delegator factory are the following: - `$container` is the service locator that is used while creating the delegator for the requested service. - `$name` is the name of the service being requested. -- `$callback` is a -- [callable](http://www.php.net/manual/en/language.types.callable.php) that is +- `$callback` is a [callable](http://www.php.net/manual/en/language.types.callable.php) that is responsible for instantiating the delegated service (the real service instance). - `$options` is an array of options to use when creating the instance; these are typically used only during `build()` operations. diff --git a/src/ServiceManager.php b/src/ServiceManager.php index 8e5b6bee..8f626c79 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -14,7 +14,9 @@ use Interop\Container\Exception\ContainerException; use ProxyManager\Configuration as ProxyConfiguration; use ProxyManager\Factory\LazyLoadingValueHolderFactory; +use ProxyManager\FileLocator\FileLocator; use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy; +use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy; use Zend\ServiceManager\Exception\ContainerModificationsNotAllowedException; use Zend\ServiceManager\Exception\CyclicAliasException; use Zend\ServiceManager\Exception\InvalidArgumentException; @@ -341,10 +343,8 @@ public function configure(array $config) } if (isset($config['aliases'])) { - $this->aliases = $config['aliases'] + $this->aliases; - } - - if (! empty($this->aliases)) { + $this->configureAliases($config['aliases']); + } elseif (! $this->configured && ! empty($this->aliases)) { $this->resolveAliases($this->aliases); } @@ -374,6 +374,35 @@ public function configure(array $config) return $this; } + /** + * @param string[] $aliases + * + * @return void + */ + private function configureAliases(array $aliases) + { + if (! $this->configured) { + $this->aliases = $aliases + $this->aliases; + + $this->resolveAliases($this->aliases); + + return; + } + + // Performance optimization. If there are no collisions, then we don't need to recompute loops + $intersecting = $this->aliases && \array_intersect_key($this->aliases, $aliases); + $this->aliases = $this->aliases ? \array_merge($this->aliases, $aliases) : $aliases; + + if ($intersecting) { + $this->resolveAliases($this->aliases); + + return; + } + + $this->resolveAliases($aliases); + $this->resolveNewAliasesWithPreviouslyResolvedAliases($aliases); + } + /** * Add an alias. * @@ -568,7 +597,11 @@ private function resolveInitializers(array $initializers) } /** - * Resolve all aliases to their canonical service names. + * Resolve aliases to their canonical service names. + * + * @param string[] $aliases + * + * @returns void */ private function resolveAliases(array $aliases) { @@ -589,6 +622,23 @@ private function resolveAliases(array $aliases) } } + /** + * Rewrites the map of aliases by resolving the given $aliases with the existing resolved ones. + * This is mostly done for performance reasons. + * + * @param string[] $aliases + * + * @return void + */ + private function resolveNewAliasesWithPreviouslyResolvedAliases(array $aliases) + { + foreach ($this->resolvedAliases as $name => $target) { + if (isset($aliases[$target])) { + $this->resolvedAliases[$name] = $this->resolvedAliases[$target]; + } + } + } + /** * Get a factory for the given service name * @@ -750,6 +800,10 @@ private function createLazyServiceDelegatorFactory() if (! isset($this->lazyServices['write_proxy_files']) || ! $this->lazyServices['write_proxy_files']) { $factoryConfig->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); + } else { + $factoryConfig->setGeneratorStrategy(new FileWriterGeneratorStrategy( + new FileLocator($factoryConfig->getProxiesTargetDir()) + )); } spl_autoload_register($factoryConfig->getProxyAutoloader()); diff --git a/test/ServiceManagerTest.php b/test/ServiceManagerTest.php index 44666433..580e0db3 100644 --- a/test/ServiceManagerTest.php +++ b/test/ServiceManagerTest.php @@ -236,4 +236,29 @@ public function testAliasToAnExplicitServiceShouldWork() $this->assertSame($service, $alias); } + + /** + * @depends testAliasToAnExplicitServiceShouldWork + */ + public function testSetAliasShouldWorkWithRecursiveAlias() + { + $config = [ + 'aliases' => [ + 'Alias' => 'TailInvokable', + ], + 'services' => [ + InvokableObject::class => new InvokableObject(), + ], + ]; + $serviceManager = new ServiceManager($config); + $serviceManager->setAlias('HeadAlias', 'Alias'); + $serviceManager->setAlias('TailInvokable', InvokableObject::class); + + $service = $serviceManager->get(InvokableObject::class); + $alias = $serviceManager->get('Alias'); + $headAlias = $serviceManager->get('HeadAlias'); + + $this->assertSame($service, $alias); + $this->assertSame($service, $headAlias); + } }