Skip to content

Commit

Permalink
Add factory for string uuid value object - Close #8
Browse files Browse the repository at this point in the history
  • Loading branch information
sandrokeil committed Nov 20, 2020
1 parent 952bd0c commit 37679a3
Show file tree
Hide file tree
Showing 3 changed files with 323 additions and 0 deletions.
200 changes: 200 additions & 0 deletions src/ValueObject/UuidFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<?php

/**
* @see https://github.com/open-code-modeling/json-schema-to-php-ast for the canonical source repository
* @copyright https://github.com/open-code-modeling/json-schema-to-php-ast/blob/master/COPYRIGHT.md
* @license https://github.com/open-code-modeling/json-schema-to-php-ast/blob/master/LICENSE.md MIT License
*/

declare(strict_types=1);

namespace OpenCodeModeling\JsonSchemaToPhpAst\ValueObject;

use OpenCodeModeling\CodeAst\Builder\ClassBuilder;
use OpenCodeModeling\CodeAst\Code\BodyGenerator;
use OpenCodeModeling\CodeAst\Code\MethodGenerator;
use OpenCodeModeling\CodeAst\Code\ParameterGenerator;
use OpenCodeModeling\CodeAst\NodeVisitor\ClassMethod;
use OpenCodeModeling\JsonSchemaToPhp\Type\StringType;
use OpenCodeModeling\JsonSchemaToPhpAst\PropertyFactory;
use PhpParser\NodeVisitor;
use PhpParser\Parser;

/**
* This file creates node visitors for a value object of type string.
*
* The following code will be generated:
*
* private UuidInterface $uuid;
*
* public static function fromString(string $uuid): self
* {
* return new self(Uuid::fromString($uuid));
* }
*
* private function __construct(UuidInterface $uuid)
* {
* $this->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<NodeVisitor>
*/
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<NodeVisitor>
*/
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 = <<<PHP
if(!\$$argumentName instanceof self) {
return false;
}
return \$this->$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;
}
}
7 changes: 7 additions & 0 deletions src/ValueObjectFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -33,6 +34,7 @@ final class ValueObjectFactory
private NumberFactory $numberFactory;
private DateTimeFactory $dateTimeFactory;
private EnumFactory $enumFactory;
private UuidFactory $uuidFactory;

/**
* @param Parser $parser
Expand All @@ -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);
}

/**
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down
116 changes: 116 additions & 0 deletions tests/ValueObject/UuidFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

declare(strict_types=1);

namespace OpenCodeModelingTest\JsonSchemaToPhpAst\ValueObject;

use OpenCodeModeling\JsonSchemaToPhp\Type\StringType;
use OpenCodeModeling\JsonSchemaToPhpAst\ValueObject\UuidFactory;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor;

final class UuidFactoryTest extends BaseTestCase
{
private UuidFactory $uuidFactory;

public function setUp(): void
{
parent::setUp();
$this->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<NodeVisitor> $nodeVisitors
*/
private function assertCode(array $nodeVisitors): void
{
$ast = $this->parser->parse('<?php final class UuidVO {}');

$nodeTraverser = new NodeTraverser();

foreach ($nodeVisitors as $nodeVisitor) {
$nodeTraverser->addVisitor($nodeVisitor);
}

$expected = <<<'EOF'
<?php
final class UuidVO
{
private UuidInterface $uuid;
public static function fromString(string $uuid) : self
{
return new self(Uuid::fromString($uuid));
}
private function __construct(UuidInterface $uuid)
{
$this->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)));
}
}

0 comments on commit 37679a3

Please sign in to comment.