From 28939c2f7a2a36fa96d230a7bec29c762886a74e Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Fri, 21 Jun 2024 10:05:14 +0200 Subject: [PATCH] feature: allow to create objects in dataProvider thanks to lazy proxy --- src/Persistence/IsProxy.php | 5 + src/Persistence/PersistentObjectFactory.php | 2 +- .../PersistentProxyObjectFactory.php | 10 + src/Persistence/Proxy.php | 5 + src/Persistence/ProxyGenerator.php | 21 +- src/Test/Factories.php | 33 ++- .../Mongo/GenericDocumentFactoryTest.php | 2 +- .../Mongo/GenericDocumentProxyFactoryTest.php | 2 +- .../ORM/GenericEntityFactoryTest.php | 2 +- .../ORM/GenericEntityProxyFactoryTest.php | 4 +- .../Persistence/GenericFactoryTestCase.php | 200 +++++++++--------- .../GenericProxyFactoryTestCase.php | 104 +++++---- 12 files changed, 246 insertions(+), 144 deletions(-) diff --git a/src/Persistence/IsProxy.php b/src/Persistence/IsProxy.php index 809909a53..a1ef6bb77 100644 --- a/src/Persistence/IsProxy.php +++ b/src/Persistence/IsProxy.php @@ -112,6 +112,11 @@ public function _repository(): ProxyRepositoryDecorator return new ProxyRepositoryDecorator(parent::class); } + public function _initializeLazyObject(): void + { + $this->initializeLazyObject(); + } + private function _autoRefresh(): void { if (!$this->_getAutoRefresh()) { diff --git a/src/Persistence/PersistentObjectFactory.php b/src/Persistence/PersistentObjectFactory.php index 2bd83ffd8..36bce3d3a 100644 --- a/src/Persistence/PersistentObjectFactory.php +++ b/src/Persistence/PersistentObjectFactory.php @@ -203,7 +203,7 @@ final public static function truncate(): void static::repository()->truncate(); } - final public function create(callable|array $attributes = []): object + public function create(callable|array $attributes = []): object { $object = parent::create($attributes); diff --git a/src/Persistence/PersistentProxyObjectFactory.php b/src/Persistence/PersistentProxyObjectFactory.php index 06c12e6d8..a17e20f2b 100644 --- a/src/Persistence/PersistentProxyObjectFactory.php +++ b/src/Persistence/PersistentProxyObjectFactory.php @@ -13,6 +13,7 @@ use Doctrine\Persistence\ObjectRepository; use Zenstruck\Foundry\Configuration; +use Zenstruck\Foundry\Exception\FoundryNotBooted; use Zenstruck\Foundry\Factory; use Zenstruck\Foundry\Object\Instantiator; use Zenstruck\Foundry\FactoryCollection; // keep me! @@ -36,6 +37,15 @@ */ abstract class PersistentProxyObjectFactory extends PersistentObjectFactory { + public function create(callable|array $attributes = []): object + { + try { + return parent::create($attributes); + } catch (FoundryNotBooted) { + return ProxyGenerator::wrapFactory($this, $attributes); + } + } + /** * @return class-string */ diff --git a/src/Persistence/Proxy.php b/src/Persistence/Proxy.php index 0dcfb19b8..ee45305ad 100644 --- a/src/Persistence/Proxy.php +++ b/src/Persistence/Proxy.php @@ -49,4 +49,9 @@ public function _real(): object; * @return ProxyRepositoryDecorator> */ public function _repository(): ProxyRepositoryDecorator; + + /** + * @internal + */ + public function _initializeLazyObject(): void; } diff --git a/src/Persistence/ProxyGenerator.php b/src/Persistence/ProxyGenerator.php index b0b1a687f..3c88b8c1b 100644 --- a/src/Persistence/ProxyGenerator.php +++ b/src/Persistence/ProxyGenerator.php @@ -43,6 +43,11 @@ public static function wrap(object $object): Proxy return self::generateClassFor($object)::createLazyProxy(static fn() => $object); // @phpstan-ignore-line } + public static function wrapFactory(PersistentProxyObjectFactory $factory, callable|array $attributes): Proxy + { + return self::generateClassFor($factory)::createLazyProxy(static fn() => $factory->create($attributes)); // @phpstan-ignore-line + } + /** * @template T * @@ -76,8 +81,8 @@ public static function unwrap(mixed $what): mixed */ private static function generateClassFor(object $object): string { - /** @var class-string $class */ - $class = $object instanceof DoctrineProxy ? \get_parent_class($object) : $object::class; + $class = self::extractClassName($object); + $proxyClass = self::proxyClassNameFor($class); /** @var class-string&T> $proxyClass */ @@ -151,4 +156,16 @@ public static function proxyClassNameFor(string $class): string { return \str_replace('\\', '', $class).'Proxy'; } + + /** + * @return class-string + */ + private static function extractClassName(object $object): string + { + if ($object instanceof PersistentProxyObjectFactory) { + return $object::class(); + } + + return $object instanceof DoctrineProxy ? \get_parent_class($object) : $object::class; + } } diff --git a/src/Test/Factories.php b/src/Test/Factories.php index 7c22831b3..453a4d0f5 100644 --- a/src/Test/Factories.php +++ b/src/Test/Factories.php @@ -14,7 +14,10 @@ use PHPUnit\Framework\Attributes\After; use PHPUnit\Framework\Attributes\Before; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\VarExporter\LazyObjectInterface; +use Webmozart\Assert\Assert; use Zenstruck\Foundry\Configuration; +use Zenstruck\Foundry\Persistence\Proxy; /** * @author Kevin Bond @@ -26,7 +29,7 @@ trait Factories * @before */ #[Before] - public static function _bootFoundry(): void + public function _bootFoundry(): void { if (!\is_subclass_of(static::class, KernelTestCase::class)) { // @phpstan-ignore-line // unit test @@ -46,6 +49,34 @@ public static function _bootFoundry(): void }); } + /** + * @internal + * @before + */ + #[Before] + public function _loadDataProvidedProxies(): void + { + if (!\is_subclass_of(static::class, KernelTestCase::class)) { // @phpstan-ignore-line + return; + } + + $providedData = method_exists($this, 'getProvidedData') ? $this->getProvidedData() : $this->providedData(); // @phpstan-ignore method.notFound + + foreach ($providedData as $providedDatum) { + if ($providedDatum instanceof Proxy) { + $providedDatum->_initializeLazyObject(); + } + + if (is_array($providedDatum) && count($providedDatum)) { + foreach ($providedDatum as $itemFromCollection) { + if ($itemFromCollection instanceof Proxy) { + $itemFromCollection->_initializeLazyObject(); + } + } + } + } + } + /** * @internal * @after diff --git a/tests/Integration/Mongo/GenericDocumentFactoryTest.php b/tests/Integration/Mongo/GenericDocumentFactoryTest.php index ab6f5a606..416ed3355 100644 --- a/tests/Integration/Mongo/GenericDocumentFactoryTest.php +++ b/tests/Integration/Mongo/GenericDocumentFactoryTest.php @@ -23,7 +23,7 @@ final class GenericDocumentFactoryTest extends GenericFactoryTestCase { use RequiresMongo; - protected function factory(): GenericModelFactory + protected static function factory(): GenericDocumentFactory { return GenericDocumentFactory::new(); } diff --git a/tests/Integration/Mongo/GenericDocumentProxyFactoryTest.php b/tests/Integration/Mongo/GenericDocumentProxyFactoryTest.php index a3c581e21..6b41ce319 100644 --- a/tests/Integration/Mongo/GenericDocumentProxyFactoryTest.php +++ b/tests/Integration/Mongo/GenericDocumentProxyFactoryTest.php @@ -26,7 +26,7 @@ final class GenericDocumentProxyFactoryTest extends GenericProxyFactoryTestCase { use RequiresMongo; - protected function factory(): PersistentProxyObjectFactory + protected static function factory(): GenericProxyDocumentFactory { return GenericProxyDocumentFactory::new(); } diff --git a/tests/Integration/ORM/GenericEntityFactoryTest.php b/tests/Integration/ORM/GenericEntityFactoryTest.php index 9b7458758..8b512d4ea 100644 --- a/tests/Integration/ORM/GenericEntityFactoryTest.php +++ b/tests/Integration/ORM/GenericEntityFactoryTest.php @@ -23,7 +23,7 @@ final class GenericEntityFactoryTest extends GenericFactoryTestCase { use RequiresORM; - protected function factory(): GenericModelFactory + protected static function factory(): GenericEntityFactory { return GenericEntityFactory::new(); } diff --git a/tests/Integration/ORM/GenericEntityProxyFactoryTest.php b/tests/Integration/ORM/GenericEntityProxyFactoryTest.php index 218c7b518..650b2395f 100644 --- a/tests/Integration/ORM/GenericEntityProxyFactoryTest.php +++ b/tests/Integration/ORM/GenericEntityProxyFactoryTest.php @@ -13,6 +13,8 @@ use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory; use Zenstruck\Foundry\Tests\Fixture\Entity\EdgeCases\EntityWithReadonly\EntityWithReadonly; +use Zenstruck\Foundry\Tests\Fixture\Entity\GenericEntity; +use Zenstruck\Foundry\Tests\Fixture\Factories\Entity\GenericEntityFactory; use Zenstruck\Foundry\Tests\Fixture\Factories\Entity\GenericProxyEntityFactory; use Zenstruck\Foundry\Tests\Integration\Persistence\GenericProxyFactoryTestCase; use Zenstruck\Foundry\Tests\Integration\RequiresORM; @@ -26,7 +28,7 @@ final class GenericEntityProxyFactoryTest extends GenericProxyFactoryTestCase { use RequiresORM; - protected function factory(): PersistentProxyObjectFactory + protected static function factory(): GenericProxyEntityFactory { return GenericProxyEntityFactory::new(); } diff --git a/tests/Integration/Persistence/GenericFactoryTestCase.php b/tests/Integration/Persistence/GenericFactoryTestCase.php index ec3071bc4..7adf3dc9b 100644 --- a/tests/Integration/Persistence/GenericFactoryTestCase.php +++ b/tests/Integration/Persistence/GenericFactoryTestCase.php @@ -43,27 +43,27 @@ abstract class GenericFactoryTestCase extends KernelTestCase */ public function can_create_and_update(): void { - $this->factory()::assert()->empty(); + static::factory()::assert()->empty(); - $object = $this->factory()->create(); + $object = static::factory()->create(); $this->assertNotNull($object->id); $this->assertSame('default1', $object->getProp1()); - $this->factory()::assert() + static::factory()::assert() ->count(1) ->exists(['prop1' => 'default1']) ->notExists(['prop1' => 'invalid']) ; - $this->assertSame($object->id, $this->factory()->first()->id); - $this->assertSame($object->id, $this->factory()->last()->id); + $this->assertSame($object->id, static::factory()->first()->id); + $this->assertSame($object->id, static::factory()->last()->id); $object->setProp1('new value'); save($object); $this->assertSame('new value', $object->getProp1()); - $this->factory()::assert()->exists(['prop1' => 'new value']); + static::factory()::assert()->exists(['prop1' => 'new value']); } /** @@ -71,18 +71,18 @@ public function can_create_and_update(): void */ public function can_disable_auto_persist(): void { - $this->factory()->repository()->assert()->empty(); + static::factory()->repository()->assert()->empty(); - $object = $this->factory()->withoutPersisting()->create(); + $object = static::factory()->withoutPersisting()->create(); $this->assertNull($object->id); $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->empty(); + static::factory()->repository()->assert()->empty(); save($object); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); } /** @@ -90,16 +90,16 @@ public function can_disable_auto_persist(): void */ public function can_refresh(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); // initial data $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); self::ensureKernelShutdown(); // modify and save title "externally" - $ext = $this->factory()->first(); + $ext = static::factory()->first(); $ext->setProp1('external'); save($ext); @@ -109,7 +109,7 @@ public function can_refresh(): void $this->assertSame($refreshed, $object); $this->assertSame('external', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'external']); + static::factory()->repository()->assert()->exists(['prop1' => 'external']); } /** @@ -117,18 +117,18 @@ public function can_refresh(): void */ public function cannot_refresh_if_there_are_unsaved_changes(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); // initial data $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); $object->setProp1('new'); try { refresh($object); } catch (\RuntimeException) { - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); return; } @@ -141,13 +141,13 @@ public function cannot_refresh_if_there_are_unsaved_changes(): void */ public function can_delete(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); delete($object); - $this->factory()->repository()->assert()->empty(); + static::factory()->repository()->assert()->empty(); } /** @@ -170,9 +170,9 @@ public function repository_and_create_function(): void */ public function create_many(): void { - $models = $this->factory()->createMany(3, fn(int $i) => ['prop1' => "value{$i}"]); + $models = static::factory()->createMany(3, fn(int $i) => ['prop1' => "value{$i}"]); - $this->factory()::repository()->assert()->count(3); + static::factory()::repository()->assert()->count(3); $this->assertSame('value1', $models[0]->getProp1()); $this->assertSame('value2', $models[1]->getProp1()); @@ -184,10 +184,10 @@ public function create_many(): void */ public function find(): void { - $object = $this->factory()->create(['prop1' => 'foo']); + $object = static::factory()->create(['prop1' => 'foo']); - $this->assertSame($object->id, $this->factory()::find($object->id)->id); - $this->assertSame($object->id, $this->factory()::find(['prop1' => 'foo'])->id); + $this->assertSame($object->id, static::factory()::find($object->id)->id); + $this->assertSame($object->id, static::factory()::find(['prop1' => 'foo'])->id); } /** @@ -197,7 +197,7 @@ public function find_must_return_object(): void { $this->expectException(\RuntimeException::class); - $this->factory()::find(1); + static::factory()::find(1); } /** @@ -205,12 +205,12 @@ public function find_must_return_object(): void */ public function find_by(): void { - $this->factory()->create(['prop1' => 'a']); - $this->factory()->create(['prop1' => 'b']); - $this->factory()->create(['prop1' => 'b']); + static::factory()->create(['prop1' => 'a']); + static::factory()->create(['prop1' => 'b']); + static::factory()->create(['prop1' => 'b']); - $this->assertCount(1, $this->factory()::findBy(['prop1' => 'a'])); - $this->assertCount(2, $this->factory()::findBy(['prop1' => 'b'])); + $this->assertCount(1, static::factory()::findBy(['prop1' => 'a'])); + $this->assertCount(2, static::factory()::findBy(['prop1' => 'b'])); } /** @@ -218,15 +218,15 @@ public function find_by(): void */ public function find_or_create(): void { - $this->factory()->create(['prop1' => 'a']); + static::factory()->create(['prop1' => 'a']); - $this->assertSame('a', $this->factory()::findOrCreate(['prop1' => 'a'])->getProp1()); + $this->assertSame('a', static::factory()::findOrCreate(['prop1' => 'a'])->getProp1()); - $this->factory()::repository()->assert()->count(1); + static::factory()::repository()->assert()->count(1); - $this->assertSame('b', $this->factory()::findOrCreate(['prop1' => 'b'])->getProp1()); + $this->assertSame('b', static::factory()::findOrCreate(['prop1' => 'b'])->getProp1()); - $this->factory()::repository()->assert()->count(2); + static::factory()::repository()->assert()->count(2); } /** @@ -234,12 +234,12 @@ public function find_or_create(): void */ public function random(): void { - $this->factory()->create(['prop1' => 'a']); - $this->factory()->create(['prop1' => 'b']); - $this->factory()->create(['prop1' => 'c']); + static::factory()->create(['prop1' => 'a']); + static::factory()->create(['prop1' => 'b']); + static::factory()->create(['prop1' => 'c']); - $this->assertContains($this->factory()::random()->getProp1(), ['a', 'b', 'c']); - $this->assertSame('b', $this->factory()::random(['prop1' => 'b'])->getProp1()); + $this->assertContains(static::factory()::random()->getProp1(), ['a', 'b', 'c']); + $this->assertSame('b', static::factory()::random(['prop1' => 'b'])->getProp1()); } /** @@ -249,7 +249,7 @@ public function random_must_return_an_object(): void { $this->expectException(NotEnoughObjects::class); - $this->factory()::random(); + static::factory()::random(); } /** @@ -257,16 +257,16 @@ public function random_must_return_an_object(): void */ public function random_or_create(): void { - $this->factory()->create(['prop1' => 'a']); + static::factory()->create(['prop1' => 'a']); - $this->assertSame('a', $this->factory()::randomOrCreate()->getProp1()); - $this->assertSame('a', $this->factory()::randomOrCreate(['prop1' => 'a'])->getProp1()); + $this->assertSame('a', static::factory()::randomOrCreate()->getProp1()); + $this->assertSame('a', static::factory()::randomOrCreate(['prop1' => 'a'])->getProp1()); - $this->factory()::repository()->assert()->count(1); + static::factory()::repository()->assert()->count(1); - $this->assertSame('b', $this->factory()::randomOrCreate(['prop1' => 'b'])->getProp1()); + $this->assertSame('b', static::factory()::randomOrCreate(['prop1' => 'b'])->getProp1()); - $this->factory()::repository()->assert()->count(2); + static::factory()::repository()->assert()->count(2); } /** @@ -274,17 +274,17 @@ public function random_or_create(): void */ public function random_set(): void { - $this->factory()->create(['prop1' => 'a']); - $this->factory()->create(['prop1' => 'b']); - $this->factory()->create(['prop1' => 'b']); + static::factory()->create(['prop1' => 'a']); + static::factory()->create(['prop1' => 'b']); + static::factory()->create(['prop1' => 'b']); - $set = $this->factory()::randomSet(2); + $set = static::factory()::randomSet(2); $this->assertCount(2, $set); $this->assertContains($set[0]->getProp1(), ['a', 'b']); $this->assertContains($set[1]->getProp1(), ['a', 'b']); - $set = $this->factory()::randomSet(2, ['prop1' => 'b']); + $set = static::factory()::randomSet(2, ['prop1' => 'b']); $this->assertCount(2, $set); $this->assertSame('b', $set[0]->getProp1()); @@ -296,11 +296,11 @@ public function random_set(): void */ public function random_set_requires_at_least_the_number_available(): void { - $this->factory()::createMany(3); + static::factory()::createMany(3); $this->expectException(NotEnoughObjects::class); - $this->factory()::randomSet(4); + static::factory()::randomSet(4); } /** @@ -308,12 +308,12 @@ public function random_set_requires_at_least_the_number_available(): void */ public function random_range(): void { - $this->factory()->create(['prop1' => 'a']); - $this->factory()->create(['prop1' => 'b']); - $this->factory()->create(['prop1' => 'b']); - $this->factory()->create(['prop1' => 'b']); + static::factory()->create(['prop1' => 'a']); + static::factory()->create(['prop1' => 'b']); + static::factory()->create(['prop1' => 'b']); + static::factory()->create(['prop1' => 'b']); - $range = $this->factory()::randomRange(0, 3); + $range = static::factory()::randomRange(0, 3); $this->assertGreaterThanOrEqual(0, \count($this)); $this->assertLessThanOrEqual(3, \count($this)); @@ -322,7 +322,7 @@ public function random_range(): void $this->assertContains($object->getProp1(), ['a', 'b']); } - $range = $this->factory()::randomRange(0, 3, ['prop1' => 'b']); + $range = static::factory()::randomRange(0, 3, ['prop1' => 'b']); $this->assertGreaterThanOrEqual(0, \count($this)); $this->assertLessThanOrEqual(3, \count($this)); @@ -337,11 +337,11 @@ public function random_range(): void */ public function random_range_requires_at_least_the_max_available(): void { - $this->factory()::createMany(3); + static::factory()::createMany(3); $this->expectException(NotEnoughObjects::class); - $this->factory()::randomRange(1, 5); + static::factory()::randomRange(1, 5); } /** @@ -349,12 +349,12 @@ public function random_range_requires_at_least_the_max_available(): void */ public function factory_count(): void { - $this->factory()::createOne(['prop1' => 'a']); - $this->factory()::createOne(['prop1' => 'b']); - $this->factory()::createOne(['prop1' => 'b']); + static::factory()::createOne(['prop1' => 'a']); + static::factory()::createOne(['prop1' => 'b']); + static::factory()::createOne(['prop1' => 'b']); - $this->assertSame(3, $this->factory()::count()); - $this->assertSame(2, $this->factory()::count(['prop1' => 'b'])); + $this->assertSame(3, static::factory()::count()); + $this->assertSame(2, static::factory()::count(['prop1' => 'b'])); } /** @@ -362,12 +362,12 @@ public function factory_count(): void */ public function truncate(): void { - $this->factory()::createMany(3); - $this->factory()::repository()->assert()->count(3); + static::factory()::createMany(3); + static::factory()::repository()->assert()->count(3); - $this->factory()::truncate(); + static::factory()::truncate(); - $this->factory()::repository()->assert()->empty(); + static::factory()::repository()->assert()->empty(); } /** @@ -375,9 +375,9 @@ public function truncate(): void */ public function factory_all(): void { - $this->factory()::createMany(3); + static::factory()::createMany(3); - $this->assertCount(3, $this->factory()::all()); + $this->assertCount(3, static::factory()::all()); } /** @@ -385,14 +385,14 @@ public function factory_all(): void */ public function repository_assertions(): void { - $assert = $this->factory()::repository()->assert(); + $assert = static::factory()::repository()->assert(); $assert->empty(); $assert->empty(['prop1' => 'a']); - $this->factory()::createOne(['prop1' => 'a']); - $this->factory()::createOne(['prop1' => 'b']); - $this->factory()::createOne(['prop1' => 'b']); + static::factory()::createOne(['prop1' => 'a']); + static::factory()::createOne(['prop1' => 'b']); + static::factory()::createOne(['prop1' => 'b']); $assert->notEmpty(); $assert->notEmpty(['prop1' => 'a']); @@ -415,9 +415,9 @@ public function repository_assertions(): void */ public function repository_is_lazy(): void { - $this->factory()::createOne(); + static::factory()::createOne(); - $repository = $this->factory()::repository(); + $repository = static::factory()::repository(); $object = $repository->random(); $object->setProp1('new value'); @@ -433,18 +433,18 @@ public function repository_is_lazy(): void */ public function flush_after(): void { - $this->factory()::repository()->assert()->empty(); + static::factory()::repository()->assert()->empty(); flush_after(function() { - $object = $this->factory()::createOne(); + $object = static::factory()::createOne(); // ensure auto-refresh does not break when in flush_after $object->getProp1(); - $this->factory()::repository()->assert()->empty(); + static::factory()::repository()->assert()->empty(); }); - $this->factory()::repository()->assert()->count(1); + static::factory()::repository()->assert()->count(1); } /** @@ -452,19 +452,19 @@ public function flush_after(): void */ public function can_disable_and_enable_persisting_globally(): void { - $this->factory()::repository()->assert()->empty(); + static::factory()::repository()->assert()->empty(); disable_persisting(); - $this->factory()::createOne(); - $this->factory()::new()->create(); + static::factory()::createOne(); + static::factory()::new()->create(); persistent_factory($this->modelClass())->create(['prop1' => 'foo']); persist($this->modelClass(), ['prop1' => 'foo']); enable_persisting(); - $this->factory()::createOne(); - $this->factory()::repository()->assert()->count(1); + static::factory()::createOne(); + static::factory()::repository()->assert()->count(1); } /** @@ -476,19 +476,19 @@ public function cannot_access_repository_method_when_persist_disabled(): void $countErrors = 0; try { - $this->factory()::assert(); + static::factory()::assert(); } catch (PersistenceDisabled) { ++$countErrors; } try { - $this->factory()::repository(); + static::factory()::repository(); } catch (PersistenceDisabled) { ++$countErrors; } try { - $this->factory()::findBy([]); + static::factory()::findBy([]); } catch (PersistenceDisabled) { ++$countErrors; } @@ -501,11 +501,11 @@ public function cannot_access_repository_method_when_persist_disabled(): void */ public function can_persist_object_with_sequence(): void { - $this->factory()->sequence([['prop1' => 'foo'], ['prop1' => 'bar']])->create(); + static::factory()->sequence([['prop1' => 'foo'], ['prop1' => 'bar']])->create(); - $this->factory()::assert()->count(2); - $this->factory()::assert()->exists(['prop1' => 'foo']); - $this->factory()::assert()->exists(['prop1' => 'bar']); + static::factory()::assert()->count(2); + static::factory()::assert()->exists(['prop1' => 'foo']); + static::factory()::assert()->exists(['prop1' => 'bar']); } /** @@ -519,7 +519,7 @@ public function assert_persist_is_re_enabled_automatically(): void self::assertTrue($configuration->persistence()->isEnabled()); persist($this->modelClass(), ['prop1' => 'value']); - $this->factory()::assert()->count(1); + static::factory()::assert()->count(1); } /** @@ -527,7 +527,7 @@ public function assert_persist_is_re_enabled_automatically(): void */ public function assert_it_ca_create_object_with_dates(): void { - $object = $this->factory()->create(['date' => $date = new \DateTimeImmutable()]); + $object = static::factory()->create(['date' => $date = new \DateTimeImmutable()]); self::assertSame($date->format(\DateTimeInterface::ATOM), $object->getDate()?->format(\DateTimeInterface::ATOM)); } @@ -545,11 +545,11 @@ public function it_should_not_create_proxy_for_not_persistable_objects(): void */ protected function modelClass(): string { - return $this->factory()::class(); + return static::factory()::class(); } /** * @return PersistentObjectFactory */ - abstract protected function factory(): PersistentObjectFactory; + abstract protected static function factory(): PersistentObjectFactory; } diff --git a/tests/Integration/Persistence/GenericProxyFactoryTestCase.php b/tests/Integration/Persistence/GenericProxyFactoryTestCase.php index e95976388..c41b15b30 100644 --- a/tests/Integration/Persistence/GenericProxyFactoryTestCase.php +++ b/tests/Integration/Persistence/GenericProxyFactoryTestCase.php @@ -30,32 +30,32 @@ abstract class GenericProxyFactoryTestCase extends GenericFactoryTestCase */ public function can_update_and_delete_via_proxy(): void { - $this->factory()->repository()->assert()->empty(); + static::factory()->repository()->assert()->empty(); - $object = $this->factory()->create(); + $object = static::factory()->create(); $this->assertNotNull($object->id); $this->assertSame('default1', $object->getProp1()); $this->assertSame('default1', $object->_refresh()->getProp1()); - $this->factory()->repository()->assert() + static::factory()->repository()->assert() ->count(1) ->exists(['prop1' => 'default1']) ->notExists(['prop1' => 'invalid']) ; - $this->assertSame($object->id, $this->factory()->first()->id); - $this->assertSame($object->id, $this->factory()->last()->id); + $this->assertSame($object->id, static::factory()->first()->id); + $this->assertSame($object->id, static::factory()->last()->id); $object->setProp1('new value'); $object->_save(); $this->assertSame('new value', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'new value']); + static::factory()->repository()->assert()->exists(['prop1' => 'new value']); $object->_delete(); - $this->factory()->repository()->assert()->empty(); + static::factory()->repository()->assert()->empty(); } /** @@ -63,18 +63,18 @@ public function can_update_and_delete_via_proxy(): void */ public function can_disable_persisting_by_factory_and_save_proxy(): void { - $this->factory()->repository()->assert()->empty(); + static::factory()->repository()->assert()->empty(); - $object = $this->factory()->withoutPersisting()->create()->_disableAutoRefresh(); + $object = static::factory()->withoutPersisting()->create()->_disableAutoRefresh(); $this->assertNull($object->id); $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->empty(); + static::factory()->repository()->assert()->empty(); $object->_save(); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); } /** @@ -82,11 +82,11 @@ public function can_disable_persisting_by_factory_and_save_proxy(): void */ public function can_disable_and_enable_proxy_auto_refreshing(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); // initial data $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); $object->_disableAutoRefresh(); $object->setProp1('new'); @@ -95,7 +95,7 @@ public function can_disable_and_enable_proxy_auto_refreshing(): void $object->_save(); $this->assertSame('new 2', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'new 2']); + static::factory()->repository()->assert()->exists(['prop1' => 'new 2']); } /** @@ -103,11 +103,11 @@ public function can_disable_and_enable_proxy_auto_refreshing(): void */ public function can_disable_and_enable_proxy_auto_refreshing_with_callback(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); // initial data $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); $object->_withoutAutoRefresh(function(GenericModel&Proxy $object) { $object->setProp1('new'); @@ -116,7 +116,7 @@ public function can_disable_and_enable_proxy_auto_refreshing_with_callback(): vo }); $this->assertSame('new 2', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'new 2']); + static::factory()->repository()->assert()->exists(['prop1' => 'new 2']); } /** @@ -124,16 +124,16 @@ public function can_disable_and_enable_proxy_auto_refreshing_with_callback(): vo */ public function can_manually_refresh_via_proxy(): void { - $object = $this->factory()->create()->_disableAutoRefresh(); + $object = static::factory()->create()->_disableAutoRefresh(); // initial data $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); self::ensureKernelShutdown(); // modify and save title "externally" - $ext = $this->factory()::first(); + $ext = static::factory()::first(); $ext->setProp1('external'); $ext->_save(); @@ -143,7 +143,7 @@ public function can_manually_refresh_via_proxy(): void // "calling method" triggers auto-refresh $this->assertSame('external', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'external']); + static::factory()->repository()->assert()->exists(['prop1' => 'external']); } /** @@ -151,16 +151,16 @@ public function can_manually_refresh_via_proxy(): void */ public function proxy_auto_refreshes(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); // initial data $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); self::ensureKernelShutdown(); // modify and save title "externally" - $ext = $this->factory()::first(); + $ext = static::factory()::first(); $ext->setProp1('external'); $ext->_save(); @@ -168,7 +168,7 @@ public function proxy_auto_refreshes(): void // "calling method" triggers auto-refresh $this->assertSame('external', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'external']); + static::factory()->repository()->assert()->exists(['prop1' => 'external']); } /** @@ -176,21 +176,21 @@ public function proxy_auto_refreshes(): void */ public function cannot_auto_refresh_proxy_if_changes(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); // initial data $this->assertSame('default1', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); $object->setProp1('new'); try { $object->setProp1('new 1'); } catch (\RuntimeException) { - $this->factory()->repository()->assert()->exists(['prop1' => 'default1']); + static::factory()->repository()->assert()->exists(['prop1' => 'default1']); $object->_save(); $this->assertSame('new', $object->getProp1()); - $this->factory()->repository()->assert()->exists(['prop1' => 'new']); + static::factory()->repository()->assert()->exists(['prop1' => 'new']); return; } @@ -203,11 +203,11 @@ public function cannot_auto_refresh_proxy_if_changes(): void */ public function can_access_repository_from_proxy(): void { - $object = $this->factory()::createOne(); + $object = static::factory()::createOne(); $object = $object->_repository()->findOneBy(['prop1' => 'default1']); - $this->assertInstanceOf($this->factory()::class(), $object); + $this->assertInstanceOf(static::factory()::class(), $object); } /** @@ -215,7 +215,7 @@ public function can_access_repository_from_proxy(): void */ public function can_force_set_and_get_proxy(): void { - $object = $this->factory()::createOne(); + $object = static::factory()::createOne(); $this->assertSame('default1', $object->_get('prop1')); @@ -229,7 +229,7 @@ public function can_force_set_and_get_proxy(): void */ public function can_get_real_object_even_if_modified(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); $object->setProp1('foo'); self::assertInstanceOf(GenericModel::class, $real = $object->_real()); @@ -259,7 +259,7 @@ public function can_create_object_with_readonly_properties(): void */ public function can_delete_proxified_object_and_still_access_its_methods(): void { - $object = $this->factory()->create(); + $object = static::factory()->create(); $object->_delete(); $this->assertSame('default1', $object->getProp1()); @@ -270,7 +270,7 @@ public function can_delete_proxified_object_and_still_access_its_methods(): void */ public function can_use_after_persist_with_attributes(): void { - $object = $this->factory() + $object = static::factory() ->instantiateWith(Instantiator::withConstructor()->allowExtra('extra')) ->afterPersist(function (GenericModel $object, array $attributes) { $object->setProp1($attributes['extra']); @@ -280,10 +280,42 @@ public function can_use_after_persist_with_attributes(): void $this->assertSame($value, $object->getProp1()); } + /** + * @test + * @dataProvider createOneObjectInDataProvider + */ + public function assert_it_can_create_one_object_in_data_provider(GenericModel $entity): void + { + static::factory()::assert()->count(1); + self::assertSame('value set in data provider', $entity->getProp1()); + } + + public static function createOneObjectInDataProvider(): iterable + { + yield [static::factory()::createOne(['prop1' => 'value set in data provider'])]; + } + + /** + * @test + * @dataProvider createManyObjectsInDataProvider + * @param list $entities + */ + public function assert_it_can_create_many_objects_in_data_provider(array $entities): void + { + static::factory()::assert()->count(2); + self::assertSame('value 1 set in data provider', $entities[0]->getProp1()); + self::assertSame('value 2 set in data provider', $entities[1]->getProp1()); + } + + public static function createManyObjectsInDataProvider(): iterable + { + yield [static::factory()::createMany(2, fn(int $i) => ['prop1' => "value {$i} set in data provider"])]; + } + /** * @return PersistentProxyObjectFactory */ - abstract protected function factory(): PersistentProxyObjectFactory; // @phpstan-ignore-line + abstract protected static function factory(): PersistentProxyObjectFactory; // @phpstan-ignore-line /** * @return PersistentProxyObjectFactory