From 37679a34c70e03359df41eeea1aa9d3d34e2004d Mon Sep 17 00:00:00 2001 From: Sandro Keil Date: Fri, 20 Nov 2020 14:38:16 +0100 Subject: [PATCH] Add factory for string uuid value object - Close #8 --- src/ValueObject/UuidFactory.php | 200 ++++++++++++++++++++++++++ src/ValueObjectFactory.php | 7 + tests/ValueObject/UuidFactoryTest.php | 116 +++++++++++++++ 3 files changed, 323 insertions(+) create mode 100644 src/ValueObject/UuidFactory.php create mode 100644 tests/ValueObject/UuidFactoryTest.php diff --git a/src/ValueObject/UuidFactory.php b/src/ValueObject/UuidFactory.php new file mode 100644 index 0000000..fa7b352 --- /dev/null +++ b/src/ValueObject/UuidFactory.php @@ -0,0 +1,200 @@ +uuid = $uuid; + * } + * + * public function toString(): string + * { + * return $this->uuid; + * } + * + * public function equals($other): bool + * { + * if(!$other instanceof self) { + * return false; + * } + * + * return $this->uuid === $other->uuid; + * } + * + * public function __toString(): string + * { + * return $this->uuid; + * } + */ +final class UuidFactory +{ + private Parser $parser; + private PropertyFactory $propertyFactory; + private bool $typed; + + public function __construct(Parser $parser, bool $typed) + { + $this->parser = $parser; + $this->typed = $typed; + $this->propertyFactory = new PropertyFactory($typed); + } + + /** + * @param StringType $typeDefinition + * @return array + */ + public function nodeVisitors(StringType $typeDefinition): array + { + $name = $typeDefinition->name() ?: 'uuid'; + + return $this->nodeVisitorsFromNative($name); + } + + public function classBuilder(StringType $typeDefinition): ClassBuilder + { + $name = $typeDefinition->name() ?: 'uuid'; + + return $this->classBuilderFromNative($name); + } + + /** + * @param string $name + * @return array + */ + public function nodeVisitorsFromNative(string $name): array + { + $nodeVisitors = $this->propertyFactory->nodeVisitorFromNative($name, 'UuidInterface'); + $nodeVisitors[] = new ClassMethod($this->methodFromString($name)); + $nodeVisitors[] = new ClassMethod($this->methodMagicConstruct($name)); + $nodeVisitors[] = new ClassMethod($this->methodToString($name)); + $nodeVisitors[] = new ClassMethod($this->methodEquals($name)); + $nodeVisitors[] = new ClassMethod($this->methodMagicToString($name)); + + return $nodeVisitors; + } + + public function classBuilderFromNative(string $name): ClassBuilder + { + return ClassBuilder::fromNodes( + $this->propertyFactory->propertyGenerator($name, 'UuidInterface')->generate(), + $this->methodFromString($name)->generate(), + $this->methodMagicConstruct($name)->generate(), + $this->methodToString($name)->generate(), + $this->methodEquals($name)->generate(), + $this->methodMagicToString($name)->generate(), + )->setTyped($this->typed); + } + + public function methodFromString(string $argumentName): MethodGenerator + { + $method = new MethodGenerator( + 'fromString', + [ + new ParameterGenerator($argumentName, 'string'), + ], + MethodGenerator::FLAG_STATIC | MethodGenerator::FLAG_PUBLIC, + new BodyGenerator($this->parser, 'return new self(Uuid::fromString($' . $argumentName . '));') + ); + $method->setTyped($this->typed); + $method->setReturnType('self'); + + return $method; + } + + public function methodMagicConstruct(string $argumentName): MethodGenerator + { + $method = new MethodGenerator( + '__construct', + [ + new ParameterGenerator($argumentName, 'UuidInterface'), + ], + MethodGenerator::FLAG_PRIVATE, + new BodyGenerator($this->parser, \sprintf('$this->%s = $%s;', $argumentName, $argumentName)) + ); + $method->setTyped($this->typed); + + return $method; + } + + public function methodToString(string $argumentName): MethodGenerator + { + $method = new MethodGenerator( + 'toString', + [], + MethodGenerator::FLAG_PUBLIC, + new BodyGenerator($this->parser, 'return $this->' . $argumentName . ';') + ); + $method->setTyped($this->typed); + $method->setReturnType('string'); + + return $method; + } + + public function methodEquals(string $propertyName, string $argumentName = 'other'): MethodGenerator + { + $body = <<$propertyName === \$$argumentName->$propertyName; +PHP; + + $method = new MethodGenerator( + 'equals', + [ + new ParameterGenerator($argumentName), + ], + MethodGenerator::FLAG_PUBLIC, + new BodyGenerator($this->parser, $body) + ); + $method->setTyped($this->typed); + $method->setReturnType('bool'); + + return $method; + } + + public function methodMagicToString(string $argumentName): MethodGenerator + { + $method = new MethodGenerator( + '__toString', + [], + MethodGenerator::FLAG_PUBLIC, + new BodyGenerator($this->parser, 'return $this->' . $argumentName . ';') + ); + $method->setTyped($this->typed); + $method->setReturnType('string'); + + return $method; + } +} diff --git a/src/ValueObjectFactory.php b/src/ValueObjectFactory.php index e6dcf23..dded174 100644 --- a/src/ValueObjectFactory.php +++ b/src/ValueObjectFactory.php @@ -22,6 +22,7 @@ use OpenCodeModeling\JsonSchemaToPhpAst\ValueObject\IntegerFactory; use OpenCodeModeling\JsonSchemaToPhpAst\ValueObject\NumberFactory; use OpenCodeModeling\JsonSchemaToPhpAst\ValueObject\StringFactory; +use OpenCodeModeling\JsonSchemaToPhpAst\ValueObject\UuidFactory; use PhpParser\NodeVisitor; use PhpParser\Parser; @@ -33,6 +34,7 @@ final class ValueObjectFactory private NumberFactory $numberFactory; private DateTimeFactory $dateTimeFactory; private EnumFactory $enumFactory; + private UuidFactory $uuidFactory; /** * @param Parser $parser @@ -52,6 +54,7 @@ public function __construct( $this->numberFactory = new NumberFactory($parser, $typed); $this->dateTimeFactory = new DateTimeFactory($parser, $typed); $this->enumFactory = new EnumFactory($parser, $typed, $constNameFilter, $constValueFilter); + $this->uuidFactory = new UuidFactory($parser, $typed); } /** @@ -68,6 +71,8 @@ public function nodeVisitors(TypeDefinition $typeDefinition): array switch ($typeDefinition->format()) { case TypeDefinition::FORMAT_DATETIME: return $this->dateTimeFactory->nodeVisitors($typeDefinition); + case 'uuid': + return $this->uuidFactory->nodeVisitors($typeDefinition); default: return $this->stringFactory->nodeVisitors($typeDefinition); } @@ -94,6 +99,8 @@ public function classBuilder(TypeDefinition $typeDefinition): ClassBuilder switch ($typeDefinition->format()) { case TypeDefinition::FORMAT_DATETIME: return $this->dateTimeFactory->classBuilder($typeDefinition); + case 'uuid': + return $this->uuidFactory->classBuilder($typeDefinition); default: return $this->stringFactory->classBuilder($typeDefinition); } diff --git a/tests/ValueObject/UuidFactoryTest.php b/tests/ValueObject/UuidFactoryTest.php new file mode 100644 index 0000000..acf6696 --- /dev/null +++ b/tests/ValueObject/UuidFactoryTest.php @@ -0,0 +1,116 @@ +uuidFactory = new UuidFactory($this->parser, true); + } + + /** + * @test + */ + public function it_generates_code_from_native(): void + { + $this->assertCode($this->uuidFactory->nodeVisitorsFromNative('uuid')); + } + + /** + * @test + */ + public function it_generates_code_via_value_object_factory(): void + { + $this->assertCode( + $this->voFactory->nodeVisitors( + StringType::fromDefinition( + [ + 'type' => 'string', + 'name' => 'uuid', + 'format' => 'uuid', + ] + ) + ) + ); + } + + /** + * @test + */ + public function it_generates_code_via_value_object_factory_with_class_builder(): void + { + $classBuilder = $this->voFactory->classBuilder( + StringType::fromDefinition( + [ + 'type' => 'string', + 'name' => 'uuid', + 'format' => 'uuid', + ] + ) + ); + $classBuilder->setName('UuidVO'); + + $this->assertCode( + $classBuilder->generate($this->parser) + ); + } + + /** + * @param array $nodeVisitors + */ + private function assertCode(array $nodeVisitors): void + { + $ast = $this->parser->parse('addVisitor($nodeVisitor); + } + + $expected = <<<'EOF' +uuid = $uuid; + } + public function toString() : string + { + return $this->uuid; + } + public function equals($other) : bool + { + if (!$other instanceof self) { + return false; + } + return $this->uuid === $other->uuid; + } + public function __toString() : string + { + return $this->uuid; + } +} +EOF; + + $this->assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($ast))); + } +}