diff --git a/UPGRADE-0.8.md b/UPGRADE-0.8.md index 34e38741..d7bd3f77 100644 --- a/UPGRADE-0.8.md +++ b/UPGRADE-0.8.md @@ -6,6 +6,8 @@ - Updated `DomainMessageBusInterface::dispatch()` to return `void` - Updated `DomainCollectionInterface::map()` to return `DomainCollectionInterface` - Renamed `TreeBuilder` to `TreeBuilderHelper` +- Removed `ChainObjectFactory` and `ClassMappingObjectFactory` +- Added `DomainObjectFactoryInterface::getClass()` ## UserEav diff --git a/composer.json b/composer.json index 48f52724..7177fad7 100644 --- a/composer.json +++ b/composer.json @@ -1,14 +1,14 @@ { "description": "Composer configuration for bulk CI testing of packages", + "prefer-stable": true, + "minimum-stability": "dev", "require-dev": { "wikimedia/composer-merge-plugin": "^1.4", "phpstan/phpstan-shim": "^0.10", "phpstan/phpstan-phpunit": "^0.10", "phpunit/phpunit": "^7.4", "ro0nl/link": "^1.0", - "symfony/config": "@dev", - "symfony/messenger": "@dev", - "symfony/var-dumper": "^4.1", + "symfony/config": "^4.2", "twig/twig": "^2.5" }, "autoload-dev": { diff --git a/docs/ddd/factory/entity-aware.md b/docs/ddd/factory/entity-aware.md index 70cba70f..937232fa 100644 --- a/docs/ddd/factory/entity-aware.md +++ b/docs/ddd/factory/entity-aware.md @@ -33,12 +33,11 @@ value might be considered empty if it's not capable to calculate one upfront. ### `MsgPhp\Domain\Factory\EntityAwareFactory` -A generic entity factory. It decorates any object factory and uses the [domain identity mapping](../identity-mapping.md) -as well as a known entity to identifier class mapping. +A generic entity factory. -- `__construct(DomainObjectFactoryInterface $factory, DomainIdentityMappingInterface $identityMapping, array $identifierMapping = [])` - - `$factory`: The decorated object factory - - `$identityMapping`: The identity mapping +- `__construct(DomainObjectFactoryInterface $factory, DomainIdentityHelper $identityHelper, array $identifierMapping = [])` + - `$factory`: The decorated [object factory](object.md) + - `$identityHelper`: The [identity helper](../identities.md) - `$identifierMapping`: The identifier class mapping (`['EntityType' => 'IdType']`) #### Basic example @@ -46,7 +45,7 @@ as well as a known entity to identifier class mapping. ```php 'id', - ]), + ])), [ MyEntity::class => DomainId::class, ] @@ -83,8 +82,14 @@ $id = $factory->identify(MyEntity::class, 1); /** @var DomainId $id */ $id = $factory->nextIdentifier(MyEntity::class); ``` + +!!! note + `EntityAwareFactory::reference()` requires [symfony/var-exporter] + ### `MsgPhp\Domain\Infra\Doctrine\EntityAwareFactory` A Doctrine tailored entity aware factory. - [Read more](../../infrastructure/doctrine-orm.md#entity-aware-factory) + +[symfony/var-exporter]: https://packagist.org/packages/symfony/var-exporter diff --git a/docs/ddd/factory/object.md b/docs/ddd/factory/object.md index e056df2e..18c46e03 100644 --- a/docs/ddd/factory/object.md +++ b/docs/ddd/factory/object.md @@ -9,6 +9,10 @@ any domain object based on a given class name and context. Returns a factorized domain object by class name. Optionally a context can be provided for the factory to act upon. +### `getClass(string $class, array $context = []): string` + +Returns the actual class name the factory will create and equalizes `get_class($factory->create($class, $context))`. + ## Implementations ### `MsgPhp\Domain\Factory\DomainObjectFactory` @@ -21,9 +25,12 @@ higher precedence. In case the context key is numeric its value will be provided Any sub class of `MsgPhp\Domain\DomainIdInterface` or `MsgPhp\Domain\DomainCollectionInterface` will be initialized using `$class::fromValue()` by default, otherwise initialization happens regularly (i.e. `new $class(...$arguments)`). +A class mapping can be provided and is usually used to map abstracts to concretes. + Nested objects (e.g. `MyObject $myArgument`) can be provided as nested context (thus nested array). - `setNestedFactory(?DomainObjectFactoryInterface $factory): void` + - `$classMapping`: The class mapping (`['SourceType' => 'TargetType']`)` - `$factory`: The optional factory to use for nested objects. If not set the current factory will be used instead. #### Basic example @@ -35,7 +42,11 @@ use MsgPhp\Domain\Factory\DomainObjectFactory; // --- SETUP --- -class Some +interface KnownInterface +{ +} + +class Some implements KnownInterface { public function __construct(int $a, ?int $b, ?int $c) { @@ -44,15 +55,21 @@ class Some class Subject { - public function __construct(string $argument, Some $some, Subject $otherSubject = null) + public function __construct(string $argument, KnownInterface $some, Subject $otherSubject = null) { } } -$factory = new DomainObjectFactory(); +$factory = new DomainObjectFactory([ + KnownInterface::class => Some::class, +]); // --- USAGE --- +/** @var Some $object */ +$object = $factory->create(KnownInterface::class, ['a' => 1]); +$factory->getClass(KnownInterface::class); // "Some" + /** @var Subject $object */ $object = $factory->create(Subject::class, [ 'argument' => 'value', @@ -63,67 +80,3 @@ $object = $factory->create(Subject::class, [ ], ]); ``` - -### `MsgPhp\Domain\Factory\ChainObjectFactory` - -A chain object factory. It holds many object factories and returns a domain object from the first supporting factory. - -- `__construct(iterable $factories)` - - `$factories`: Available object factories - -#### Basic example - -```php - 'TargetType']`) - -#### Basic example - -```php - Subject::class] -); - -// --- USAGE --- - -/** @var Subject $object */ -$object = $factory->create(KnownInterface::class); -``` diff --git a/src/Domain/Factory/ChainObjectFactory.php b/src/Domain/Factory/ChainObjectFactory.php deleted file mode 100644 index b26b7463..00000000 --- a/src/Domain/Factory/ChainObjectFactory.php +++ /dev/null @@ -1,35 +0,0 @@ - - */ -final class ChainObjectFactory implements DomainObjectFactoryInterface -{ - private $factories; - - /** - * @param DomainObjectFactoryInterface[] $factories - */ - public function __construct(iterable $factories) - { - $this->factories = $factories; - } - - public function create(string $entity, array $context = []) - { - foreach ($this->factories as $factory) { - try { - return $factory->create($entity, $context); - } catch (InvalidClassException $e) { - } - } - - throw InvalidClassException::create($entity); - } -} diff --git a/src/Domain/Factory/ClassMappingObjectFactory.php b/src/Domain/Factory/ClassMappingObjectFactory.php deleted file mode 100644 index 2d865b28..00000000 --- a/src/Domain/Factory/ClassMappingObjectFactory.php +++ /dev/null @@ -1,25 +0,0 @@ - - */ -final class ClassMappingObjectFactory implements DomainObjectFactoryInterface -{ - private $factory; - private $mapping; - - public function __construct(DomainObjectFactoryInterface $factory, array $mapping) - { - $this->factory = $factory; - $this->mapping = $mapping; - } - - public function create(string $class, array $context = []) - { - return $this->factory->create($this->mapping[$class] ?? $class, $context); - } -} diff --git a/src/Domain/Factory/DomainObjectFactory.php b/src/Domain/Factory/DomainObjectFactory.php index dfe94206..b9191e62 100644 --- a/src/Domain/Factory/DomainObjectFactory.php +++ b/src/Domain/Factory/DomainObjectFactory.php @@ -12,8 +12,14 @@ */ final class DomainObjectFactory implements DomainObjectFactoryInterface { + private $classMapping; private $factory; + public function __construct(array $classMapping = []) + { + $this->classMapping = $classMapping; + } + public function setNestedFactory(?DomainObjectFactoryInterface $factory): void { $this->factory = $factory; @@ -21,6 +27,8 @@ public function setNestedFactory(?DomainObjectFactoryInterface $factory): void public function create(string $class, array $context = []) { + $class = $this->getClass($class, $context); + if (is_subclass_of($class, DomainIdInterface::class) || is_subclass_of($class, DomainCollectionInterface::class)) { return $class::fromValue(...$this->resolveArguments($class, 'fromValue', $context)); } @@ -32,6 +40,11 @@ public function create(string $class, array $context = []) return new $class(...$this->resolveArguments($class, '__construct', $context)); } + public function getClass(string $class, array $context = []): string + { + return $this->classMapping[$class] ?? $class; + } + private function resolveArguments(string $class, string $method, array $context): array { $arguments = []; diff --git a/src/Domain/Factory/DomainObjectFactoryInterface.php b/src/Domain/Factory/DomainObjectFactoryInterface.php index 7f45afbd..9b1bdc2a 100644 --- a/src/Domain/Factory/DomainObjectFactoryInterface.php +++ b/src/Domain/Factory/DomainObjectFactoryInterface.php @@ -13,4 +13,6 @@ interface DomainObjectFactoryInterface * @return object */ public function create(string $class, array $context = []); + + public function getClass(string $class, array $context = []): string; } diff --git a/src/Domain/Factory/EntityAwareFactory.php b/src/Domain/Factory/EntityAwareFactory.php index ad30816d..f77aa432 100644 --- a/src/Domain/Factory/EntityAwareFactory.php +++ b/src/Domain/Factory/EntityAwareFactory.php @@ -4,8 +4,10 @@ namespace MsgPhp\Domain\Factory; -use MsgPhp\Domain\{DomainIdentityMappingInterface, DomainIdInterface}; +use MsgPhp\Domain\{DomainIdentityHelper, DomainIdInterface}; use MsgPhp\Domain\Exception\InvalidClassException; +use Symfony\Component\VarExporter\Exception\ClassNotFoundException; +use Symfony\Component\VarExporter\Instantiator; /** * @author Roland Franssen @@ -13,13 +15,13 @@ final class EntityAwareFactory implements EntityAwareFactoryInterface { private $factory; - private $identityMapping; + private $identityHelper; private $identifierMapping; - public function __construct(DomainObjectFactoryInterface $factory, DomainIdentityMappingInterface $identityMapping, array $identifierMapping = []) + public function __construct(DomainObjectFactoryInterface $factory, DomainIdentityHelper $identityHelper, array $identifierMapping = []) { $this->factory = $factory; - $this->identityMapping = $identityMapping; + $this->identityHelper = $identityHelper; $this->identifierMapping = $identifierMapping; } @@ -28,15 +30,38 @@ public function create(string $class, array $context = []) return $this->factory->create($class, $context); } + public function getClass(string $class, array $context = []): string + { + return $this->factory->getClass($class, $context); + } + public function reference(string $class, $id) { - $idFields = $this->identityMapping->getIdentifierFieldNames($class); + if (!class_exists(Instantiator::class)) { + throw new \LogicException(sprintf('Method "%s()" requires "symfony/var-exporter".', __METHOD__)); + } + + $class = $this->factory->getClass($class); - if (!\is_array($id)) { - $id = [array_shift($idFields) => $id]; + if (!$this->identityHelper->isIdentity($class, $id)) { + throw new \LogicException(sprintf('Invalid identity %s for class "%s".', (string) json_encode($id), $class)); } - return $this->factory->create($class, $id + array_fill_keys($idFields, null)); + $properties = []; + foreach ($this->identityHelper->toIdentity($class, $id) as $field => $value) { + if (property_exists($class, $field)) { + $properties[$field] = $value; + continue; + } + + $properties[lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $field))))] = $value; + } + + try { + return Instantiator::instantiate($class, $properties); + } catch (ClassNotFoundException $e) { + throw InvalidClassException::create($class); + } } public function identify(string $class, $value): DomainIdInterface diff --git a/src/Domain/Infra/DependencyInjection/BundleHelper.php b/src/Domain/Infra/DependencyInjection/BundleHelper.php index e1e49df0..9904dea3 100644 --- a/src/Domain/Infra/DependencyInjection/BundleHelper.php +++ b/src/Domain/Infra/DependencyInjection/BundleHelper.php @@ -6,7 +6,7 @@ use Doctrine\ORM\Events as DoctrineOrmEvents; use MsgPhp\Domain\{DomainIdentityHelper, DomainIdentityMappingInterface}; -use MsgPhp\Domain\Factory\{ClassMappingObjectFactory, DomainObjectFactory, DomainObjectFactoryInterface, EntityAwareFactory, EntityAwareFactoryInterface}; +use MsgPhp\Domain\Factory\{DomainObjectFactory, DomainObjectFactoryInterface, EntityAwareFactory, EntityAwareFactoryInterface}; use MsgPhp\Domain\Infra\{Console as ConsoleInfra, Doctrine as DoctrineInfra, InMemory as InMemoryInfra, Messenger as MessengerInfra, SimpleBus as SimpleBusInfra}; use MsgPhp\Domain\Message\{DomainMessageBus, DomainMessageBusInterface}; use Symfony\Component\Console\ConsoleEvents; @@ -90,16 +90,11 @@ private static function initObjectFactory(ContainerBuilder $container): void { $container->register(DomainObjectFactory::class) ->setPublic(false) + ->setArgument('$classMapping', '%msgphp.domain.class_mapping%') ->addMethodCall('setNestedFactory', [new Reference(DomainObjectFactoryInterface::class)]); $container->setAlias(DomainObjectFactoryInterface::class, new Alias(DomainObjectFactory::class, false)); - $container->register(ClassMappingObjectFactory::class) - ->setPublic(false) - ->setDecoratedService(DomainObjectFactory::class) - ->setArgument('$factory', new Reference(ClassMappingObjectFactory::class.'.inner')) - ->setArgument('$mapping', '%msgphp.domain.class_mapping%'); - $container->autowire(EntityAwareFactory::class) ->setPublic(false) ->setDecoratedService(DomainObjectFactory::class) @@ -113,8 +108,7 @@ private static function initObjectFactory(ContainerBuilder $container): void ->setPublic(false) ->setDecoratedService(EntityAwareFactory::class) ->setArgument('$factory', new Reference(DoctrineInfra\EntityAwareFactory::class.'.inner')) - ->setArgument('$em', new Reference('msgphp.doctrine.entity_manager')) - ->setArgument('$classMapping', '%msgphp.domain.class_mapping%'); + ->setArgument('$em', new Reference('msgphp.doctrine.entity_manager')); } } diff --git a/src/Domain/Infra/Doctrine/EntityAwareFactory.php b/src/Domain/Infra/Doctrine/EntityAwareFactory.php index b6b1a33a..6278fda7 100644 --- a/src/Domain/Infra/Doctrine/EntityAwareFactory.php +++ b/src/Domain/Infra/Doctrine/EntityAwareFactory.php @@ -4,6 +4,7 @@ namespace MsgPhp\Domain\Infra\Doctrine; +use Doctrine\Common\Persistence\Mapping\MappingException; use Doctrine\ORM\EntityManagerInterface; use MsgPhp\Domain\DomainIdInterface; use MsgPhp\Domain\Exception\InvalidClassException; @@ -16,35 +17,38 @@ final class EntityAwareFactory implements EntityAwareFactoryInterface { private $factory; private $em; - private $classMapping; - public function __construct(EntityAwareFactoryInterface $factory, EntityManagerInterface $em, array $classMapping = []) + public function __construct(EntityAwareFactoryInterface $factory, EntityManagerInterface $em) { $this->factory = $factory; $this->em = $em; - $this->classMapping = $classMapping; } public function create(string $class, array $context = []) { - $class = $this->classMapping[$class] ?? $class; - - if ($this->isManaged($class)) { - $class = $this->getDiscriminatorClass($class, $context); - } + return $this->factory->create($this->resolveDiscriminatorClass($class, $context), $context); + } - return $this->factory->create($class, $context); + public function getClass(string $class, array $context = []): string + { + return $this->resolveDiscriminatorClass($class, $context); } public function reference(string $class, $id) { - if (!$this->isManaged($class = $this->classMapping[$class] ?? $class)) { - throw InvalidClassException::create($class); - } if (\is_array($id)) { - $class = $this->getDiscriminatorClass($class, $id, true); + $class = $this->resolveDiscriminatorClass($class, $id, true); + } else { + $class = $this->factory->getClass($class); + } + + try { + $ref = $this->em->getReference($class, $id); + } catch (MappingException $e) { + $ref = null; } - if (null === $ref = $this->em->getReference($class, $id)) { + + if (null === $ref) { throw InvalidClassException::create($class); } @@ -53,29 +57,22 @@ public function reference(string $class, $id) public function identify(string $class, $value): DomainIdInterface { - if (!$this->isManaged($class = $this->classMapping[$class] ?? $class)) { - throw InvalidClassException::create($class); - } - return $this->factory->identify($class, $value); } public function nextIdentifier(string $class): DomainIdInterface { - if (!$this->isManaged($class = $this->classMapping[$class] ?? $class)) { - throw InvalidClassException::create($class); - } - return $this->factory->nextIdentifier($class); } - private function isManaged(string $class): bool + private function resolveDiscriminatorClass(string $class, array &$context, bool $clear = false): string { - return class_exists($class) && !$this->em->getMetadataFactory()->isTransient($class); - } + $class = $this->factory->getClass($class, $context); + + if ($this->em->getMetadataFactory()->isTransient($class)) { + return $class; + } - private function getDiscriminatorClass(string $class, array &$context, bool $clear = false): string - { $metadata = $this->em->getClassMetadata($class); if (isset($metadata->discriminatorColumn['fieldName'], $context[$metadata->discriminatorColumn['fieldName']])) { diff --git a/src/Domain/Tests/Factory/ChainObjectFactoryTest.php b/src/Domain/Tests/Factory/ChainObjectFactoryTest.php deleted file mode 100644 index 307ffb3f..00000000 --- a/src/Domain/Tests/Factory/ChainObjectFactoryTest.php +++ /dev/null @@ -1,35 +0,0 @@ -createMock(DomainObjectFactoryInterface::class); - $factory1->expects(self::any()) - ->method('create') - ->willThrowException(InvalidClassException::create('some')); - $factory2 = $this->createMock(DomainObjectFactoryInterface::class); - $factory2->expects(self::any()) - ->method('create') - ->willReturn($object = new \stdClass()); - - self::assertSame($object, (new ChainObjectFactory([$factory1, $factory2]))->create('some')); - } - - public function testCreateWithoutFactories(): void - { - $factory = new ChainObjectFactory([]); - - $this->expectException(InvalidClassException::class); - - $factory->create('some'); - } -} diff --git a/src/Domain/Tests/Factory/ClassMappingObjectFactoryTest.php b/src/Domain/Tests/Factory/ClassMappingObjectFactoryTest.php deleted file mode 100644 index 5ce63ee3..00000000 --- a/src/Domain/Tests/Factory/ClassMappingObjectFactoryTest.php +++ /dev/null @@ -1,29 +0,0 @@ -createMock(DomainObjectFactoryInterface::class); - $innerFactory->expects(self::any()) - ->method('create') - ->willReturnCallback(function ($class, $context) { - $o = new \stdClass(); - $o->class = $class; - $o->context = $context; - - return $o; - }); - $factory = new ClassMappingObjectFactory($innerFactory, ['foo' => 'bar']); - - self::assertSame(['class' => 'bar', 'context' => []], (array) $factory->create('foo')); - self::assertSame(['class' => 'Foo', 'context' => ['context']], (array) $factory->create('Foo', ['context'])); - } -} diff --git a/src/Domain/Tests/Factory/DomainObjectFactoryTest.php b/src/Domain/Tests/Factory/DomainObjectFactoryTest.php index 5e0d79eb..dd09dd5d 100644 --- a/src/Domain/Tests/Factory/DomainObjectFactoryTest.php +++ b/src/Domain/Tests/Factory/DomainObjectFactoryTest.php @@ -20,6 +20,13 @@ public function testCreate(): void self::assertSame('foo', $object->b); } + public function testCreateWithAlias(): void + { + $object = (new DomainObjectFactory(['alias' => \stdClass::class]))->create('alias'); + + self::assertInstanceOf(\stdClass::class, $object); + } + public function testCreateWithDomainId(): void { self::assertInstanceOf(DomainId::class, (new DomainObjectFactory())->create(DomainId::class, [1])); @@ -137,6 +144,15 @@ public function testNestedCreateWithInvalidNestedFactory(): void $factory->create(NestedTestObject::class, [['a', 'b']]); } + + public function testGetClass(): void + { + $factory = new DomainObjectFactory(['alias' => \stdClass::class]); + + self::assertSame('foo', $factory->getClass('foo')); + self::assertSame(\stdClass::class, $factory->getClass('alias')); + self::assertSame(\stdClass::class, $factory->getClass(\stdClass::class)); + } } class TestObject diff --git a/src/Domain/Tests/Factory/EntityAwareFactoryTest.php b/src/Domain/Tests/Factory/EntityAwareFactoryTest.php index c0168093..6562738f 100644 --- a/src/Domain/Tests/Factory/EntityAwareFactoryTest.php +++ b/src/Domain/Tests/Factory/EntityAwareFactoryTest.php @@ -4,8 +4,7 @@ namespace MsgPhp\Domain\Tests\Factory; -use MsgPhp\Domain\DomainIdentityMappingInterface; -use MsgPhp\Domain\DomainIdInterface; +use MsgPhp\Domain\{DomainIdentityHelper, DomainIdentityMappingInterface, DomainIdInterface}; use MsgPhp\Domain\Exception\InvalidClassException; use MsgPhp\Domain\Factory\{DomainObjectFactoryInterface, EntityAwareFactory}; use PHPUnit\Framework\TestCase; @@ -36,13 +35,16 @@ protected function setUp(): void return $o; }); + $innerFactory->expects(self::any()) + ->method('getClass') + ->willReturnArgument(0); $identityMapping = $this->createMock(DomainIdentityMappingInterface::class); $identityMapping->expects(self::any()) ->method('getIdentifierFieldNames') ->willReturn(['id_field', 'id_field2']); - $this->factory = new EntityAwareFactory($innerFactory, $identityMapping, ['alias_id' => 'id']); + $this->factory = new EntityAwareFactory($innerFactory, new DomainIdentityHelper($identityMapping), ['alias_id' => 'id']); } public function testCreate(): void @@ -53,12 +55,33 @@ public function testCreate(): void self::assertSame(['class' => 'bar', 'context' => ['context']], (array) $object); } + public function testGetClass(): void + { + self::assertSame('foo', $this->factory->getClass('foo')); + self::assertSame('bar', $this->factory->getClass('bar', ['context'])); + } + public function testReference(): void { - self::assertInstanceOf(\stdClass::class, $object = $this->factory->reference('foo', 1)); - self::assertSame(['class' => 'foo', 'context' => ['id_field' => 1, 'id_field2' => null]], (array) $object); - self::assertInstanceOf(\stdClass::class, $object = $this->factory->reference('foo', ['id_field2' => 2, 'foo' => 'bar'])); - self::assertSame(['class' => 'foo', 'context' => ['id_field2' => 2, 'foo' => 'bar', 'id_field' => null]], (array) $object); + /** @var TestReferencedEntity $reference */ + $reference = $this->factory->reference(TestReferencedEntity::class, ['id_field' => 1, 'id_field2' => 2]); + + self::assertInstanceOf(TestReferencedEntity::class, $reference); + self::assertSame([1, 2], $reference->get()); + } + + public function testReferenceWithUnknownClass(): void + { + $this->expectException(InvalidClassException::class); + + $this->factory->reference('foo', ['id_field' => 1, 'id_field2' => 2]); + } + + public function testReferenceWithInvalidIdentity(): void + { + $this->expectException(\LogicException::class); + + $this->factory->reference(TestReferencedEntity::class, 1); } public function testIdentify(): void @@ -67,7 +90,10 @@ public function testIdentify(): void self::assertSame('1', $this->factory->identify('alias_id', '1')->toString()); self::assertSame($id = $this->createMock(DomainIdInterface::class), $this->factory->identify('id', $id)); self::assertSame($id = $this->createMock(DomainIdInterface::class), $this->factory->identify('alias_id', $id)); + } + public function testIdentifyWithUnknownClass(): void + { $this->expectException(InvalidClassException::class); $this->factory->identify('foo', '1'); @@ -77,9 +103,28 @@ public function testNextIdentifier(): void { self::assertSame('new', $this->factory->nextIdentifier('id')->toString()); self::assertSame('new', $this->factory->nextIdentifier('alias_id')->toString()); + } + public function testNextIdentifierWithUnknownClass(): void + { $this->expectException(InvalidClassException::class); $this->factory->nextIdentifier('foo'); } } + +class TestReferencedEntity +{ + private $idField; + private $idField2 = 'foo'; + + public function __construct() + { + throw new \BadMethodCallException(); + } + + public function get(): array + { + return [$this->idField, $this->idField2]; + } +} diff --git a/src/Domain/Tests/Infra/Doctrine/EntityAwareFactoryTest.php b/src/Domain/Tests/Infra/Doctrine/EntityAwareFactoryTest.php index 849896bc..a4b2436a 100644 --- a/src/Domain/Tests/Infra/Doctrine/EntityAwareFactoryTest.php +++ b/src/Domain/Tests/Infra/Doctrine/EntityAwareFactoryTest.php @@ -25,9 +25,12 @@ public function testCreate(): void ->method('create') ->with(Entities\TestEntity::class, ['foo' => 'bar']) ->willReturn($obj = new \stdClass()); - $factory = new EntityAwareFactory($innerFactory, self::$em, ['alias' => Entities\TestEntity::class]); + $innerFactory->expects(self::once()) + ->method('getClass') + ->willReturnArgument(0); + $factory = new EntityAwareFactory($innerFactory, self::$em); - self::assertSame($obj, $factory->create('alias', ['foo' => 'bar'])); + self::assertSame($obj, $factory->create(Entities\TestEntity::class, ['foo' => 'bar'])); } public function testCreateWithDiscriminator(): void @@ -37,6 +40,9 @@ public function testCreateWithDiscriminator(): void ->method('create') ->with(Entities\TestChildEntity::class, ['foo' => 'bar', 'discriminator' => 'child']) ->willReturn($obj = new \stdClass()); + $innerFactory->expects(self::once()) + ->method('getClass') + ->willReturnArgument(0); $factory = new EntityAwareFactory($innerFactory, self::$em); self::assertSame($obj, $factory->create(Entities\TestParentEntity::class, ['foo' => 'bar', 'discriminator' => 'child'])); @@ -49,6 +55,9 @@ public function testCreateWithObject(): void ->method('create') ->with(\stdClass::class) ->willReturn($obj = new \stdClass()); + $innerFactory->expects(self::once()) + ->method('getClass') + ->willReturnArgument(0); $factory = new EntityAwareFactory($innerFactory, self::$em); @@ -57,19 +66,24 @@ public function testCreateWithObject(): void public function testReference(): void { - $factory = new EntityAwareFactory($this->createMock(EntityAwareFactoryInterface::class), self::$em, ['alias' => Entities\TestEntity::class]); + $innerFactory = $this->createMock(EntityAwareFactoryInterface::class); + $innerFactory->expects(self::once()) + ->method('getClass') + ->willReturnArgument(0); + $factory = new EntityAwareFactory($innerFactory, self::$em); self::assertInstanceOf(Proxy::class, $ref = $factory->reference(Entities\TestEntity::class, $id = $this->createMock(DomainIdInterface::class))); self::assertInstanceOf(Entities\TestEntity::class, $ref); self::assertSame($id, $ref->getId()); - self::assertInstanceOf(Proxy::class, $ref = $factory->reference('alias', $id)); - self::assertInstanceOf(Entities\TestEntity::class, $ref); - self::assertSame($id, $ref->getId()); } public function testReferenceWithDiscriminator(): void { - $factory = new EntityAwareFactory($this->createMock(EntityAwareFactoryInterface::class), self::$em); + $innerFactory = $this->createMock(EntityAwareFactoryInterface::class); + $innerFactory->expects(self::once()) + ->method('getClass') + ->willReturnArgument(0); + $factory = new EntityAwareFactory($innerFactory, self::$em); self::assertInstanceOf(Proxy::class, $ref = $factory->reference(Entities\TestParentEntity::class, ['id' => 'foo', 'discriminator' => 'child'])); self::assertInstanceOf(Entities\TestChildEntity::class, $ref); @@ -99,29 +113,11 @@ public function testIdentify(): void $innerFactory = $this->createMock(EntityAwareFactoryInterface::class); $innerFactory->expects(self::once()) ->method('identify') - ->with(Entities\TestEntity::class, 1) + ->with('foo', 1) ->willReturn($obj = $this->createMock(DomainIdInterface::class)); - $factory = new EntityAwareFactory($innerFactory, self::$em, ['alias' => Entities\TestEntity::class]); - - self::assertSame($obj, $factory->identify('alias', 1)); - } - - public function testIdentifyWithUnknownClass(): void - { - $factory = new EntityAwareFactory($this->createMock(EntityAwareFactoryInterface::class), self::$em); - - $this->expectException(InvalidClassException::class); - - $factory->identify('foo', 1); - } - - public function testIdentifyWithUnknownEntity(): void - { - $factory = new EntityAwareFactory($this->createMock(EntityAwareFactoryInterface::class), self::$em); - - $this->expectException(InvalidClassException::class); + $factory = new EntityAwareFactory($innerFactory, self::$em); - $factory->identify(\stdClass::class, 1); + self::assertSame($obj, $factory->identify('foo', 1)); } public function testNextIdentifier(): void @@ -129,28 +125,10 @@ public function testNextIdentifier(): void $innerFactory = $this->createMock(EntityAwareFactoryInterface::class); $innerFactory->expects(self::once()) ->method('nextIdentifier') - ->with(Entities\TestEntity::class) + ->with('foo') ->willReturn($obj = $this->createMock(DomainIdInterface::class)); - $factory = new EntityAwareFactory($innerFactory, self::$em, ['alias' => Entities\TestEntity::class]); - - self::assertSame($obj, $factory->nextIdentifier('alias')); - } - - public function testNextIdentifierWithUnknownClass(): void - { - $factory = new EntityAwareFactory($this->createMock(EntityAwareFactoryInterface::class), self::$em); - - $this->expectException(InvalidClassException::class); - - $factory->nextIdentifier('foo'); - } - - public function testNextIdentifierUnknownEntity(): void - { - $factory = new EntityAwareFactory($this->createMock(EntityAwareFactoryInterface::class), self::$em); - - $this->expectException(InvalidClassException::class); + $factory = new EntityAwareFactory($innerFactory, self::$em); - $factory->nextIdentifier(\stdClass::class); + self::assertSame($obj, $factory->nextIdentifier('foo')); } } diff --git a/src/Domain/composer.json b/src/Domain/composer.json index ab00bf8c..b8db7718 100644 --- a/src/Domain/composer.json +++ b/src/Domain/composer.json @@ -34,7 +34,8 @@ "symfony/http-kernel": "^3.4|^4.0", "symfony/messenger": "^4.2", "symfony/phpunit-bridge": "^3.4.9|^4.0.9", - "symfony/property-access": "^3.4|^4.0" + "symfony/property-access": "^3.4|^4.0", + "symfony/var-exporter": "^4.2" }, "conflict": { "symfony/messenger": "<4.2"