From 60cecdb8fc0a7d8bfef2c7f3faa1d5b3190b549d Mon Sep 17 00:00:00 2001 From: Bl00D4NGEL Date: Fri, 22 Dec 2023 11:02:50 +0100 Subject: [PATCH 1/2] fix: clear caching when setting container --- src/Facade.php | 6 ++++-- tests/Unit/FacadeTest.php | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Facade.php b/src/Facade.php index d4e85ba..9668750 100644 --- a/src/Facade.php +++ b/src/Facade.php @@ -136,13 +136,13 @@ public static function swapMock(): Mockery\MockInterface { $accessor = static::getFacadeAccessor(); $mock = static::createMock(); - self::$resolvedInstances[$accessor] = $mock; + static::$resolvedInstances[$accessor] = $mock; return $mock; } /** - * Set the container instance. + * Set the container instance. Reset any cache instances in the process. * * @codeCoverageIgnore * @@ -151,6 +151,8 @@ public static function swapMock(): Mockery\MockInterface */ public static function setContainer(ContainerInterface $container): void { + static::clear(); + static::$container = $container; } diff --git a/tests/Unit/FacadeTest.php b/tests/Unit/FacadeTest.php index 0c5c6bc..32408c9 100644 --- a/tests/Unit/FacadeTest.php +++ b/tests/Unit/FacadeTest.php @@ -161,4 +161,21 @@ public function testSwapMock(): void $result = ServiceFacade::greeting('World'); // @phpstan-ignore-line $this->assertEquals('Hello World!', $result); } + + public function testSettingContainerClearsFacadeCache(): void + { + $firstService = new Service(); + $firstContainer = new Container($firstService); + ServiceFacade::setContainer($firstContainer); + $firstRoot = ServiceFacade::getFacadeRoot(); + $this->assertSame($firstRoot, $firstService); + + $secondService = new Service(); + $secondContainer = new Container($secondService); + ServiceFacade::setContainer($secondContainer); + $secondRoot = ServiceFacade::getFacadeRoot(); + $this->assertSame($secondRoot, $secondService); + + $this->assertNotSame($firstRoot, $secondRoot); + } } From fb3e098e3574ded8408d1046a0857776edd94719 Mon Sep 17 00:00:00 2001 From: Bl00D4NGEL Date: Fri, 22 Dec 2023 11:26:37 +0100 Subject: [PATCH 2/2] feat: remove dependency on mockery, replace swapMock with swap --- composer.json | 4 +-- composer.lock | 47 ++++++++++++++++++------------ src/Facade.php | 60 +++++++-------------------------------- tests/Unit/FacadeTest.php | 45 +++++++++-------------------- 4 files changed, 55 insertions(+), 101 deletions(-) diff --git a/composer.json b/composer.json index 87a6035..09f2172 100644 --- a/composer.json +++ b/composer.json @@ -23,9 +23,9 @@ "require-dev": { "phpstan/phpstan": "^1.9", "friendsofphp/php-cs-fixer": "^3.14", - "mockery/mockery": "^1.5", "phpstan/phpstan-mockery": "^1.1", - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^10.0", + "mockery/mockery": "^1.6" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 9c2cc67..841fe94 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": "e9fbb38995010710e0b756b06a59f611", + "content-hash": "8afddd9541270acbf3778054ee1d3f73", "packages": [ { "name": "psr/container", @@ -575,38 +575,38 @@ }, { "name": "mockery/mockery", - "version": "1.5.1", + "version": "1.6.7", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e" + "reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/e92dcc83d5a51851baf5f5591d32cb2b16e3684e", - "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e", + "url": "https://api.github.com/repos/mockery/mockery/zipball/0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06", + "reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06", "shasum": "" }, "require": { "hamcrest/hamcrest-php": "^2.0.1", "lib-pcre": ">=7.0", - "php": "^7.3 || ^8.0" + "php": ">=7.3" }, "conflict": { "phpunit/phpunit": "<8.0" }, "require-dev": { - "phpunit/phpunit": "^8.5 || ^9.3" + "phpunit/phpunit": "^8.5 || ^9.6.10", + "symplify/easy-coding-standard": "^12.0.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, "autoload": { - "psr-0": { - "Mockery": "library/" + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" } }, "notification-url": "https://packagist.org/downloads/", @@ -617,12 +617,20 @@ { "name": "Pádraic Brady", "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" + "homepage": "https://github.com/padraic", + "role": "Author" }, { "name": "Dave Marshall", "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" } ], "description": "Mockery is a simple yet flexible PHP mock object framework", @@ -640,10 +648,13 @@ "testing" ], "support": { + "docs": "https://docs.mockery.io/", "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/1.5.1" + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" }, - "time": "2022-09-07T15:32:08+00:00" + "time": "2023-12-10T02:24:34+00:00" }, { "name": "myclabs/deep-copy", diff --git a/src/Facade.php b/src/Facade.php index 9668750..f01ccea 100644 --- a/src/Facade.php +++ b/src/Facade.php @@ -4,7 +4,6 @@ namespace GeekCell\Facade; -use Mockery; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; @@ -24,7 +23,7 @@ abstract class Facade /** * @var array */ - protected static array $resolvedInstances = []; + protected static array $swappedInstances = []; /** * Return the underlying instance behind the facade. @@ -39,8 +38,8 @@ abstract class Facade public static function getFacadeRoot(): object { $accessor = static::getFacadeAccessor(); - if (isset(static::$resolvedInstances[$accessor])) { - return static::$resolvedInstances[$accessor]; + if (isset(static::$swappedInstances[$accessor])) { + return static::$swappedInstances[$accessor]; } if (!isset(static::$container)) { @@ -50,12 +49,10 @@ public static function getFacadeRoot(): object $instance = static::$container->get($accessor); if (!is_object($instance)) { throw new \UnexpectedValueException( - sprintf('The entry for "%s" must return an object.', $accessor), + sprintf('The entry for "%s" must return an object. Got: %s', $accessor, get_debug_type($instance)), ); } - self::$resolvedInstances[$accessor] = $instance; - return $instance; } @@ -88,57 +85,22 @@ public static function __callStatic(string $method, array $args): mixed */ public static function clear(): void { - static::$resolvedInstances = []; + static::$swappedInstances = []; static::$container = null; } /** - * Return the class name for the underlying instance behind the facade. - * - * @return string - */ - public static function getMockableClass(): string - { - $instance = static::getFacadeRoot(); - return get_class($instance); - } - - /** - * Return a Mockery mock instance of the underlying instance behind the facade. - * - * @return Mockery\MockInterface - * - * @throws NotFoundExceptionInterface - * @throws ContainerExceptionInterface - * @throws \LogicException - * @throws \UnexpectedValueException - */ - public static function createMock(): Mockery\MockInterface - { - $classToMock = static::getMockableClass(); - return Mockery::mock($classToMock); - } - - /** - * Return a Mockery mock instance, but also swap the underlying instance behind the facade - * so consecutive calls to the facade will use the mock. + * @template T of object * - * This behavior can be reset by calling Facade::clear(). - * - * @return Mockery\MockInterface - * - * @throws NotFoundExceptionInterface - * @throws ContainerExceptionInterface - * @throws \LogicException - * @throws \UnexpectedValueException + * @param T $newInstance + * @return T */ - public static function swapMock(): Mockery\MockInterface + public static function swap($newInstance) { $accessor = static::getFacadeAccessor(); - $mock = static::createMock(); - static::$resolvedInstances[$accessor] = $mock; + static::$swappedInstances[$accessor] = $newInstance; - return $mock; + return $newInstance; } /** diff --git a/tests/Unit/FacadeTest.php b/tests/Unit/FacadeTest.php index 32408c9..1d58e5e 100644 --- a/tests/Unit/FacadeTest.php +++ b/tests/Unit/FacadeTest.php @@ -117,49 +117,30 @@ public function testCallStaticWithMissingMethod(): void ServiceFacade::invalid(); // @phpstan-ignore-line } - public function testGetMockableClass(): void + public function testGetFacadeRootUsesSwappedValueWithoutContainer(): void { - // Given - ServiceFacade::setContainer($this->container); - - // When - $result = ServiceFacade::getMockableClass(); - - // Then - $this->assertSame(Service::class, $result); - } - - public function testCreateMock(): void - { - // Given - ServiceFacade::setContainer($this->container); + $service = new Service(); + ServiceFacade::swap($service); - // When - $mock = ServiceFacade::createMock(); + $root = ServiceFacade::getFacadeRoot(); - // Then - $this->assertInstanceOf(Mockery\MockInterface::class, $mock); + $this->assertSame($root, $service); } - public function testSwapMock(): void + public function testSwap(): void { // Given ServiceFacade::setContainer($this->container); - // When - $mock = ServiceFacade::swapMock(); - $mock->shouldReceive('greeting')->andReturn('Hello Mock!'); - - // Then - $this->assertInstanceOf(Mockery\MockInterface::class, $mock); + $root = ServiceFacade::getFacadeRoot(); + $this->assertSame($this->service, $root); - $result = ServiceFacade::greeting('World'); // @phpstan-ignore-line - $this->assertEquals('Hello Mock!', $result); + $otherService = new Service(); + ServiceFacade::swap($otherService); - ServiceFacade::clear(); - ServiceFacade::setContainer($this->container); - $result = ServiceFacade::greeting('World'); // @phpstan-ignore-line - $this->assertEquals('Hello World!', $result); + $otherRoot = ServiceFacade::getFacadeRoot(); + $this->assertSame($otherRoot, $otherService); + $this->assertNotSame($root, $otherRoot); } public function testSettingContainerClearsFacadeCache(): void