diff --git a/.laminas-ci.json b/.laminas-ci.json index bce3fa21..b76cebb6 100644 --- a/.laminas-ci.json +++ b/.laminas-ci.json @@ -1,5 +1,15 @@ { "ignore_php_platform_requirements": { "8.1": true - } + }, + "additional_checks": [ + { + "name": "Psalm for psr/container v1", + "job": { + "php": "@lowest", + "dependencies": "locked", + "command": "composer require -W psr/container:^1 && vendor/bin/psalm --stats --output-format=github --no-cache" + } + } + ] } diff --git a/composer.json b/composer.json index 0582510b..289670db 100644 --- a/composer.json +++ b/composer.json @@ -26,21 +26,18 @@ }, "sort-packages": true, "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true, - "composer/package-versions-deprecated": true, - "laminas/laminas-dependency-plugin": true + "dealerdirect/phpcodesniffer-composer-installer": true } }, "require": { "php": "~7.4.0 || ~8.0.0 || ~8.1.0", + "composer-plugin-api": "^2.0", "laminas/laminas-stdlib": "^3.2.1", - "psr/container": "^1.0" + "psr/container": "^1.1 || ^2.0.2" }, "require-dev": { - "composer/package-versions-deprecated": "^1.0", "laminas/laminas-coding-standard": "~2.3.0", "laminas/laminas-container-config-test": "^0.6", - "laminas/laminas-dependency-plugin": "^2.1.2", "mikey179/vfsstream": "^1.6.10@alpha", "ocramius/proxy-manager": "^2.11", "phpbench/phpbench": "^1.1", @@ -50,7 +47,7 @@ "vimeo/psalm": "^4.8" }, "provide": { - "psr/container-implementation": "^1.0" + "psr/container-implementation": "^1.1 || ^2.0" }, "conflict": { "ext-psr": "*", diff --git a/composer.lock b/composer.lock index 4b13efd2..f2d02622 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3c3716ae3129e05fa4378e1889b98dbe", + "content-hash": "95886a4e7c8b9e7fbe376b2094639f27", "packages": [ { "name": "laminas/laminas-stdlib", @@ -67,22 +67,27 @@ }, { "name": "psr/container", - "version": "1.1.2", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { "php": ">=7.4.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -109,9 +114,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2021-11-05T16:47:00+00:00" } ], "packages-dev": [ @@ -1190,59 +1195,6 @@ ], "time": "2022-03-21T11:08:05+00:00" }, - { - "name": "laminas/laminas-dependency-plugin", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-dependency-plugin.git", - "reference": "73cfb63ddca9d6bfedad5e0a038f6d55063975a3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-dependency-plugin/zipball/73cfb63ddca9d6bfedad5e0a038f6d55063975a3", - "reference": "73cfb63ddca9d6bfedad5e0a038f6d55063975a3", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1 || ^2.0", - "php": "^7.3 || ~8.0.0 || ~8.1.0" - }, - "require-dev": { - "composer/composer": "^1.9 || ^2.0", - "laminas/laminas-coding-standard": "^2.2.1", - "mikey179/vfsstream": "^1.6.10@alpha", - "phpunit/phpunit": "^9.5.5", - "psalm/plugin-phpunit": "^0.15.1", - "roave/security-advisories": "dev-master", - "vimeo/psalm": "^4.5" - }, - "type": "composer-plugin", - "extra": { - "class": "Laminas\\DependencyPlugin\\DependencyRewriterPluginDelegator" - }, - "autoload": { - "psr-4": { - "Laminas\\DependencyPlugin\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Replace zendframework and zfcampus packages with their Laminas Project equivalents.", - "support": { - "issues": "https://github.com/laminas/laminas-dependency-plugin/issues", - "source": "https://github.com/laminas/laminas-dependency-plugin/tree/2.2.0" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2021-09-08T17:51:35+00:00" - }, { "name": "mikey179/vfsstream", "version": "v1.6.11-alpha.0", @@ -4871,37 +4823,29 @@ }, { "name": "symfony/service-contracts", - "version": "v2.5.2", + "version": "v1.1.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + "reference": "191afdcb5804db960d26d8566b7e9a2843cab3a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/191afdcb5804db960d26d8566b7e9a2843cab3a0", + "reference": "191afdcb5804db960d26d8566b7e9a2843cab3a0", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" - }, - "conflict": { - "ext-psr": "<1.1|>=2" + "php": "^7.1.3" }, "suggest": { + "psr/container": "", "symfony/service-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "dev-master": "1.1-dev" } }, "autoload": { @@ -4934,23 +4878,9 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/service-contracts/tree/v1.1.2" }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-05-30T19:17:29+00:00" + "time": "2019-05-28T07:50:59+00:00" }, { "name": "symfony/string", @@ -5427,7 +5357,8 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~7.4.0 || ~8.0.0 || ~8.1.0" + "php": "~7.4.0 || ~8.0.0 || ~8.1.0", + "composer-plugin-api": "^2.0" }, "platform-dev": [], "platform-overrides": { diff --git a/phpcs.xml.dist b/phpcs.xml.dist index a8083863..021c54c3 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -16,6 +16,8 @@ bin src test + + src/AbstractUntypedContainerImplementation.php test/TestAsset/laminas-code/*.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 8ea35319..cd08d409 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -141,10 +141,6 @@ $config['services'] $config['shared'] - - $name - $name - (bool) $flag (bool) $flag diff --git a/psalm.xml.dist b/psalm.xml.dist index d71e2eec..05e6a1b7 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -47,6 +47,22 @@ + + + + + + + + + + + + + + + + diff --git a/src/AbstractPluginManager.php b/src/AbstractPluginManager.php index fe8a85d4..53fc86e7 100644 --- a/src/AbstractPluginManager.php +++ b/src/AbstractPluginManager.php @@ -174,8 +174,7 @@ public function get($name, ?array $options = null) } /** - * {@inheritDoc} - * + * @param mixed $instance * @psalm-assert InstanceType $instance */ public function validate($instance) diff --git a/src/AbstractTypedContainerImplementation.php b/src/AbstractTypedContainerImplementation.php new file mode 100644 index 00000000..fe7db2c0 --- /dev/null +++ b/src/AbstractTypedContainerImplementation.php @@ -0,0 +1,63 @@ +hasService($id); + } + + /** + * Finds an entry of the container by its identifier and returns it. + * + * @param string $id Identifier of the entry to look for. + * @psalm-param string|class-string $id + * @throws NotFoundExceptionInterface No entry was found for **this** identifier. + * @throws ContainerExceptionInterface Error while retrieving the entry. + * @return mixed Entry. + */ + public function get(string $id) + { + return $this->getService($id); + } + + /** + * @internal + * + * @psalm-param string|class-string $name + */ + abstract protected function hasService(string $name): bool; + + /** + * @internal + * + * @psalm-param string|class-string $name + * @throws NotFoundExceptionInterface No entry was found for **this** identifier. + * @throws ContainerExceptionInterface Error while retrieving the entry. + * @return mixed + */ + abstract protected function getService(string $name); +} diff --git a/src/AbstractUntypedContainerImplementation.php b/src/AbstractUntypedContainerImplementation.php new file mode 100644 index 00000000..22a62f13 --- /dev/null +++ b/src/AbstractUntypedContainerImplementation.php @@ -0,0 +1,72 @@ +hasService($id); + } + + /** + * Finds an entry of the container by its identifier and returns it. + * + * @param string $id Identifier of the entry to look for. + * @psalm-param string|class-string $id + * + * @throws NotFoundExceptionInterface No entry was found for **this** identifier. + * @throws ContainerExceptionInterface Error while retrieving the entry. + * + * @return mixed Entry. + */ + public function get($id) + { + return $this->getService($id); + } + + /** + * @internal + * + * @psalm-param string|class-string $name + */ + abstract protected function hasService(string $name): bool; + + /** + * @internal + * + * @psalm-param string|class-string $name + * @throws NotFoundExceptionInterface No entry was found for **this** identifier. + * @throws ContainerExceptionInterface Error while retrieving the entry. + * @return mixed + */ + abstract protected function getService(string $name); +} diff --git a/src/ServiceManager.php b/src/ServiceManager.php index c87879c1..e0fb69fe 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -19,6 +19,7 @@ use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use function array_intersect; use function array_key_exists; @@ -61,8 +62,9 @@ * @psalm-import-type InitializersConfigurationType from ConfigInterface * @psalm-import-type LazyServicesConfigurationType from ConfigInterface * @psalm-type ServiceManagerConfiguration = array{shared_by_default?:bool}&ServiceManagerConfigurationType + * phpcs:disable WebimpressCodingStandard.PHP.CorrectClassNameCase.Invalid */ -class ServiceManager implements ServiceLocatorInterface +class ServiceManager extends AbstractContainerImplementation implements ServiceLocatorInterface { /** @var Factory\AbstractFactoryInterface[] */ protected $abstractFactories = []; @@ -187,9 +189,25 @@ public function getServiceLocator() } /** - * {@inheritDoc} + * @internal + * + * @psalm-param string|class-string $name + */ + protected function hasService(string $name): bool + { + // Check static services and factories first to speedup the most common requests. + return $this->staticServiceOrFactoryCanCreate($name) || $this->abstractFactoryCanCreate($name); + } + + /** + * @internal + * + * @psalm-param string|class-string $name + * @throws NotFoundExceptionInterface No entry was found for **this** identifier. + * @throws ContainerExceptionInterface Error while retrieving the entry. + * @return mixed */ - public function get($name) + protected function getService(string $name) { // We start by checking if we have cached the requested service; // this is the fastest method. @@ -257,18 +275,6 @@ public function build($name, ?array $options = null) return $this->doCreate($name, $options); } - /** - * {@inheritDoc} - * - * @param string|class-string $name - * @return bool - */ - public function has($name) - { - // Check static services and factories first to speedup the most common requests. - return $this->staticServiceOrFactoryCanCreate($name) || $this->abstractFactoryCanCreate($name); - } - /** * Indicate whether or not the instance is immutable. * diff --git a/src/autoload.php b/src/autoload.php index 76bd64e0..1e5fbfc1 100644 --- a/src/autoload.php +++ b/src/autoload.php @@ -3,6 +3,9 @@ declare(strict_types=1); +namespace Laminas\ServiceManager; + +use Composer\InstalledVersions; use Interop\Container\Containerinterface as InteropContainerInterface; use Interop\Container\Exception\ContainerException as InteropContainerException; use Interop\Container\Exception\NotFoundException as InteropNotFoundException; @@ -10,6 +13,11 @@ use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; +use function assert; +use function class_alias; +use function interface_exists; +use function version_compare; + if (! interface_exists(InteropContainerInterface::class, false)) { class_alias(ContainerInterface::class, InteropContainerInterface::class); } @@ -19,3 +27,16 @@ class_alias(ContainerExceptionInterface::class, InteropContainerException::class if (! interface_exists(InteropNotFoundException::class, false)) { class_alias(NotFoundExceptionInterface::class, InteropNotFoundException::class); } + +$installedContainerVersion = InstalledVersions::getVersion('psr/container'); + +assert( + $installedContainerVersion !== null, + 'psr/container is required by `composer.json` and therefore this method should not return `null`.' +); + +if (version_compare($installedContainerVersion, '2', '<')) { + class_alias(AbstractUntypedContainerImplementation::class, AbstractContainerImplementation::class); +} else { + class_alias(AbstractTypedContainerImplementation::class, AbstractContainerImplementation::class); +} diff --git a/test/AbstractFactory/ReflectionBasedAbstractFactoryTest.php b/test/AbstractFactory/ReflectionBasedAbstractFactoryTest.php index 015d0668..b406e333 100644 --- a/test/AbstractFactory/ReflectionBasedAbstractFactoryTest.php +++ b/test/AbstractFactory/ReflectionBasedAbstractFactoryTest.php @@ -7,23 +7,20 @@ use ArrayAccess; use Laminas\ServiceManager\AbstractFactory\ReflectionBasedAbstractFactory; use Laminas\ServiceManager\Exception\ServiceNotFoundException; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Psr\Container\ContainerInterface; use function sprintf; class ReflectionBasedAbstractFactoryTest extends TestCase { - use ProphecyTrait; - - /** @var ObjectProphecy */ - private ObjectProphecy $container; + /** @var MockObject&ContainerInterface */ + private ContainerInterface $container; public function setUp(): void { - $this->container = $this->prophesize(ContainerInterface::class); + $this->container = $this->createMock(ContainerInterface::class); } public function nonClassRequestedNames(): array @@ -39,14 +36,14 @@ public function nonClassRequestedNames(): array public function testCanCreateReturnsFalseForNonClassRequestedNames(string $requestedName): void { $factory = new ReflectionBasedAbstractFactory(); - $this->assertFalse($factory->canCreate($this->container->reveal(), $requestedName)); + $this->assertFalse($factory->canCreate($this->container, $requestedName)); } public function testCanCreateReturnsFalseWhenConstructorIsPrivate(): void { $this->assertFalse( (new ReflectionBasedAbstractFactory())->canCreate( - $this->container->reveal(), + $this->container, TestAsset\ClassWithPrivateConstructor::class ), 'ReflectionBasedAbstractFactory should not be able to instantiate a class with a private constructor' @@ -57,7 +54,7 @@ public function testCanCreateReturnsTrueWhenClassHasNoConstructor(): void { $this->assertTrue( (new ReflectionBasedAbstractFactory())->canCreate( - $this->container->reveal(), + $this->container, TestAsset\ClassWithNoConstructor::class ), 'ReflectionBasedAbstractFactory should be able to instantiate a class without a constructor' @@ -67,21 +64,24 @@ public function testCanCreateReturnsTrueWhenClassHasNoConstructor(): void public function testFactoryInstantiatesClassDirectlyIfItHasNoConstructor(): void { $factory = new ReflectionBasedAbstractFactory(); - $instance = $factory($this->container->reveal(), TestAsset\ClassWithNoConstructor::class); + $instance = $factory($this->container, TestAsset\ClassWithNoConstructor::class); $this->assertInstanceOf(TestAsset\ClassWithNoConstructor::class, $instance); } public function testFactoryInstantiatesClassDirectlyIfConstructorHasNoArguments(): void { $factory = new ReflectionBasedAbstractFactory(); - $instance = $factory($this->container->reveal(), TestAsset\ClassWithEmptyConstructor::class); + $instance = $factory($this->container, TestAsset\ClassWithEmptyConstructor::class); $this->assertInstanceOf(TestAsset\ClassWithEmptyConstructor::class, $instance); } public function testFactoryRaisesExceptionWhenUnableToResolveATypeHintedService(): void { - $this->container->has(TestAsset\SampleInterface::class)->willReturn(false); - $this->container->has('config')->willReturn(false); + $this->container + ->method('has') + ->withConsecutive(['config'], [TestAsset\SampleInterface::class]) + ->willReturn(false); + $factory = new ReflectionBasedAbstractFactory(); $this->expectException(ServiceNotFoundException::class); $this->expectExceptionMessage(sprintf( @@ -89,7 +89,7 @@ public function testFactoryRaisesExceptionWhenUnableToResolveATypeHintedService( TestAsset\ClassWithTypeHintedConstructorParameter::class, TestAsset\SampleInterface::class )); - $factory($this->container->reveal(), TestAsset\ClassWithTypeHintedConstructorParameter::class); + $factory($this->container, TestAsset\ClassWithTypeHintedConstructorParameter::class); } public function testFactoryRaisesExceptionForScalarParameters(): void @@ -100,45 +100,57 @@ public function testFactoryRaisesExceptionForScalarParameters(): void 'Unable to create service "%s"; unable to resolve parameter "foo" to a class, interface, or array type', TestAsset\ClassWithScalarParameters::class )); - $factory($this->container->reveal(), TestAsset\ClassWithScalarParameters::class); + $factory($this->container, TestAsset\ClassWithScalarParameters::class); } public function testFactoryInjectsConfigServiceForConfigArgumentsTypeHintedAsArray(): void { $config = ['foo' => 'bar']; - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn($config); + $this->container->method('has')->with('config')->willReturn(true); + $this->container->method('get')->with('config')->willReturn($config); $factory = new ReflectionBasedAbstractFactory(); - $instance = $factory($this->container->reveal(), TestAsset\ClassAcceptingConfigToConstructor::class); + $instance = $factory($this->container, TestAsset\ClassAcceptingConfigToConstructor::class); $this->assertInstanceOf(TestAsset\ClassAcceptingConfigToConstructor::class, $instance); $this->assertEquals($config, $instance->config); } public function testFactoryCanInjectKnownTypeHintedServices(): void { - $sample = $this->prophesize(TestAsset\SampleInterface::class)->reveal(); - $this->container->has('config')->willReturn(false); - $this->container->has(TestAsset\SampleInterface::class)->willReturn(true); - $this->container->get(TestAsset\SampleInterface::class)->willReturn($sample); + $sample = $this->createStub(TestAsset\SampleInterface::class); + $this->container + ->method('has') + ->withConsecutive(['config'], [TestAsset\SampleInterface::class]) + ->willReturnOnConsecutiveCalls(false, true); + + $this->container + ->expects(self::once()) + ->method('get') + ->with(TestAsset\SampleInterface::class) + ->willReturn($sample); $factory = new ReflectionBasedAbstractFactory(); - $instance = $factory($this->container->reveal(), TestAsset\ClassWithTypeHintedConstructorParameter::class); + $instance = $factory($this->container, TestAsset\ClassWithTypeHintedConstructorParameter::class); $this->assertInstanceOf(TestAsset\ClassWithTypeHintedConstructorParameter::class, $instance); $this->assertSame($sample, $instance->sample); } public function testFactoryResolvesTypeHintsForServicesToWellKnownServiceNames(): void { - $this->container->has('config')->willReturn(false); + $this->container + ->method('has') + ->withConsecutive(['config'], ['ValidatorManager']) + ->willReturnOnConsecutiveCalls(false, true); - $validators = $this->prophesize(TestAsset\ValidatorPluginManager::class)->reveal(); - $this->container->has('ValidatorManager')->willReturn(true); - $this->container->get('ValidatorManager')->willReturn($validators); + $validators = $this->createStub(TestAsset\ValidatorPluginManager::class); + $this->container + ->method('get') + ->with('ValidatorManager') + ->willReturn($validators); $factory = new ReflectionBasedAbstractFactory([TestAsset\ValidatorPluginManager::class => 'ValidatorManager']); $instance = $factory( - $this->container->reveal(), + $this->container, TestAsset\ClassAcceptingWellKnownServicesAsConstructorParameters::class ); $this->assertInstanceOf( @@ -150,20 +162,22 @@ public function testFactoryResolvesTypeHintsForServicesToWellKnownServiceNames() public function testFactoryCanSupplyAMixOfParameterTypes(): void { - $validators = $this->prophesize(TestAsset\ValidatorPluginManager::class)->reveal(); - $this->container->has('ValidatorManager')->willReturn(true); - $this->container->get('ValidatorManager')->willReturn($validators); - - $sample = $this->prophesize(TestAsset\SampleInterface::class)->reveal(); - $this->container->has(TestAsset\SampleInterface::class)->willReturn(true); - $this->container->get(TestAsset\SampleInterface::class)->willReturn($sample); + $validators = $this->createStub(TestAsset\ValidatorPluginManager::class); + $this->container + ->method('has') + ->withConsecutive(['config'], [TestAsset\SampleInterface::class], ['ValidatorManager']) + ->willReturn(true); + $sample = $this->createStub(TestAsset\SampleInterface::class); $config = ['foo' => 'bar']; - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn($config); + + $this->container + ->method('get') + ->withConsecutive([TestAsset\SampleInterface::class], ['ValidatorManager'], ['config']) + ->willReturnOnConsecutiveCalls($sample, $validators, $config); $factory = new ReflectionBasedAbstractFactory([TestAsset\ValidatorPluginManager::class => 'ValidatorManager']); - $instance = $factory($this->container->reveal(), TestAsset\ClassWithMixedConstructorParameters::class); + $instance = $factory($this->container, TestAsset\ClassWithMixedConstructorParameters::class); $this->assertInstanceOf(TestAsset\ClassWithMixedConstructorParameters::class, $instance); $this->assertEquals($config, $instance->config); @@ -174,10 +188,10 @@ public function testFactoryCanSupplyAMixOfParameterTypes(): void public function testFactoryWillUseDefaultValueWhenPresentForScalarArgument(): void { - $this->container->has('config')->willReturn(false); + $this->container->method('has')->with('config')->willReturn(false); $factory = new ReflectionBasedAbstractFactory(); $instance = $factory( - $this->container->reveal(), + $this->container, TestAsset\ClassWithScalarDependencyDefiningDefaultValue::class ); $this->assertInstanceOf(TestAsset\ClassWithScalarDependencyDefiningDefaultValue::class, $instance); @@ -189,11 +203,13 @@ public function testFactoryWillUseDefaultValueWhenPresentForScalarArgument(): vo */ public function testFactoryWillUseDefaultValueForTypeHintedArgument(): void { - $this->container->has('config')->willReturn(false); - $this->container->has(ArrayAccess::class)->willReturn(false); + $this->container + ->method('has') + ->withConsecutive(['config'], [ArrayAccess::class]) + ->willReturn(false); $factory = new ReflectionBasedAbstractFactory(); $instance = $factory( - $this->container->reveal(), + $this->container, TestAsset\ClassWithTypehintedDefaultValue::class ); $this->assertInstanceOf(TestAsset\ClassWithTypehintedDefaultValue::class, $instance); diff --git a/test/AbstractPluginManagerTest.php b/test/AbstractPluginManagerTest.php index 15801d83..4dfe9c43 100644 --- a/test/AbstractPluginManagerTest.php +++ b/test/AbstractPluginManagerTest.php @@ -17,7 +17,6 @@ use LaminasTest\ServiceManager\TestAsset\SimplePluginManager; use LaminasTest\ServiceManager\TestAsset\V2v3PluginManager; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; use Psr\Container\ContainerInterface; use stdClass; @@ -33,7 +32,6 @@ class AbstractPluginManagerTest extends TestCase { use CommonServiceLocatorBehaviorsTrait; - use ProphecyTrait; public function createContainer(array $config = []): ServiceManager { @@ -43,8 +41,7 @@ public function createContainer(array $config = []): ServiceManager public function testInjectCreationContextInFactories(): void { - $invokableFactory = $this->getMockBuilder(FactoryInterface::class) - ->getMock(); + $invokableFactory = $this->createMock(FactoryInterface::class); $config = [ 'factories' => [ @@ -52,8 +49,7 @@ public function testInjectCreationContextInFactories(): void ], ]; - $container = $this->getMockBuilder(ContainerInterface::class) - ->getMock(); + $container = $this->createStub(ContainerInterface::class); $pluginManager = new SimplePluginManager($container, $config); $invokableFactory->expects($this->once()) @@ -75,8 +71,7 @@ public function testValidateInstance(): void ], ]; - $container = $this->getMockBuilder(ContainerInterface::class) - ->getMock(); + $container = $this->createStub(ContainerInterface::class); $pluginManager = new SimplePluginManager($container, $config); // Assert no exception is triggered because the plugin manager validate ObjectWithOptions @@ -95,8 +90,7 @@ public function testCachesInstanceByDefaultIfNoOptionsArePassed(): void ], ]; - $container = $this->getMockBuilder(ContainerInterface::class) - ->getMock(); + $container = $this->createStub(ContainerInterface::class); $pluginManager = new SimplePluginManager($container, $config); $first = $pluginManager->get(InvokableObject::class); @@ -128,8 +122,7 @@ public function testReturnsDiscreteInstancesIfOptionsAreProvidedRegardlessOfShar ]; $options = ['foo' => 'bar']; - $container = $this->getMockBuilder(ContainerInterface::class) - ->getMock(); + $container = $this->createStub(ContainerInterface::class); $pluginManager = new SimplePluginManager($container, $config); $first = $pluginManager->get(InvokableObject::class, $options); @@ -235,13 +228,13 @@ public function testPassingNoInitialConstructorArgumentSetsPluginManagerAsCreati */ public function testCanPassConfigInterfaceAsFirstConstructorArgumentWithDeprecationNotice(): void { - $config = $this->prophesize(ConfigInterface::class); - $config->toArray()->willReturn([]); + $config = $this->createStub(ConfigInterface::class); + $config->method('toArray')->willReturn([]); set_error_handler(function ($errno, $errstr) { $this->assertEquals(E_USER_DEPRECATED, $errno); }, E_USER_DEPRECATED); - $pluginManager = new TestAsset\LenientPluginManager($config->reveal()); + $pluginManager = new TestAsset\LenientPluginManager($config); restore_error_handler(); $this->assertSame($pluginManager, $pluginManager->getCreationContext()); @@ -278,13 +271,15 @@ public function testPassingNonContainerNonConfigNonNullFirstConstructorArgumentR */ public function testPassingConfigInstanceAsFirstConstructorArgumentSkipsSecondArgumentWithDeprecationNotice(): void { - $config = $this->prophesize(ConfigInterface::class); - $config->toArray()->willReturn(['services' => [self::class => $this]]); + $config = $this->createMock(ConfigInterface::class); + $config + ->method('toArray') + ->willReturn(['services' => [self::class => $this]]); set_error_handler(function ($errno, $errstr) { $this->assertEquals(E_USER_DEPRECATED, $errno); }, E_USER_DEPRECATED); - $pluginManager = new TestAsset\LenientPluginManager($config->reveal(), ['services' => [self::class => []]]); + $pluginManager = new TestAsset\LenientPluginManager($config, ['services' => [self::class => []]]); restore_error_handler(); $this->assertSame($this, $pluginManager->get(self::class)); @@ -378,12 +373,18 @@ public function testAbstractFactoryGetsCreationContext(): void { $serviceManager = new ServiceManager(); $pluginManager = new SimplePluginManager($serviceManager); - $abstractFactory = $this->prophesize(AbstractFactoryInterface::class); - $abstractFactory->canCreate($serviceManager, 'foo') + $abstractFactory = $this->createMock(AbstractFactoryInterface::class); + $abstractFactory + ->method('canCreate') + ->with($serviceManager, 'foo') ->willReturn(true); - $abstractFactory->__invoke($serviceManager, 'foo', null) + + $abstractFactory + ->method('__invoke') + ->with($serviceManager, 'foo', null) ->willReturn(new InvokableObject()); - $pluginManager->addAbstractFactory($abstractFactory->reveal()); + + $pluginManager->addAbstractFactory($abstractFactory); $this->assertInstanceOf(InvokableObject::class, $pluginManager->get('foo')); } diff --git a/test/ConfigTest.php b/test/ConfigTest.php index 1e456005..a157f791 100644 --- a/test/ConfigTest.php +++ b/test/ConfigTest.php @@ -7,15 +7,12 @@ use Laminas\ServiceManager\Config; use Laminas\ServiceManager\ServiceManager; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; /** * @covers Laminas\ServiceManager\Config */ class ConfigTest extends TestCase { - use ProphecyTrait; - public function testMergeArrays(): void { $config = [ @@ -103,12 +100,12 @@ public function testPassesKnownServiceConfigKeysToServiceManagerWithConfigMethod 'baz' => 'bat', ]; - $services = $this->prophesize(ServiceManager::class); - $services->configure($expected)->willReturn('CALLED'); + $services = $this->createMock(ServiceManager::class); + $services->method('configure')->with($expected)->willReturn('CALLED'); /** @psalm-suppress InvalidArgument Keeping this invalid configuration to ensure BC compatibility. */ $configuration = new Config($config); - $this->assertEquals('CALLED', $configuration->configureServiceManager($services->reveal())); + $this->assertEquals('CALLED', $configuration->configureServiceManager($services)); return [ 'array' => $expected,