diff --git a/README.md b/README.md index 79709c9..08f022d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Why developers love CRUD? Because it's easy to automate work around it. Why developers hate DDD/CQRS? Boilerplates. -Using this small app `proophgen` and single 15th lines `yaml` file you can generate a project that contains more than 20 files (with phpspec tests!) and start coding. No more boilerplates. +Using this small app `proophgen` and single 15th lines `yaml` file you can generate a project that contains **40 files** (with phpspec tests!) and start coding. No more boilerplates. You can also use singe command to create your ValueObject, Command. @@ -72,14 +72,25 @@ And there is your result (in v0.1.2): ./src/Model/ValueObject/Mail.php ./src/Model/ValueObject/Name.php ./src/Model/ValueObject/Password.php +./spec/Infrastructure/Identity/EventSourcedSpec.php +./spec/Infrastructure/Identity/InMemorySpec.php +./spec/Infrastructure/User/EventSourcedSpec.php +./spec/Infrastructure/User/InMemorySpec.php ./spec/Model/Command/LoginUserSpec.php ./spec/Model/Command/RegisterUserSpec.php ./spec/Model/CommandHandler/LoginUserHandlerSpec.php ./spec/Model/CommandHandler/RegisterUserHandlerSpec.php +./spec/Model/Identity/Event/EmailIdentityCreatedSpec.php +./spec/Model/Identity/Event/UserLoggedSpec.php +./spec/Model/Identity/Event/UserToIdentityAssignedSpec.php +./spec/Model/Identity/Exception/IdentityNotFoundSpec.php +./spec/Model/IdentitySpec.php +./spec/Model/User/Event/UserRegisteredSpec.php +./spec/Model/User/Exception/UserNotFoundSpec.php +./spec/Model/UserSpec.php ./spec/Model/ValueObject/MailSpec.php ./spec/Model/ValueObject/NameSpec.php ./spec/Model/ValueObject/PasswordSpec.php - ``` ## Create single ValueObject diff --git a/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/AggregateRootCodeGeneratorSpec.php b/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/AggregateRootCodeGeneratorSpec.php index c2b5994..5b771aa 100644 --- a/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/AggregateRootCodeGeneratorSpec.php +++ b/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/AggregateRootCodeGeneratorSpec.php @@ -76,6 +76,7 @@ class User extends AggregateRoot { \t} \tprivate function whenUserRegistered(UserRegistered \$event): void { +\t\t\$this->id = \$event->aggregateId(); \t} } "; diff --git a/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecAggregateCodeSpec.php b/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecAggregateCodeSpec.php index f64fae9..071f6d3 100644 --- a/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecAggregateCodeSpec.php +++ b/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecAggregateCodeSpec.php @@ -5,6 +5,8 @@ use gossi\codegen\generator\CodeFileGenerator; use Pilsniak\GossiCodeGenerator\AggregateRootGenerator\PhpSpecGenerator\PhpSpecAggregateCode; use PhpSpec\ObjectBehavior; +use Pilsniak\ProophGen\Model\AggregateRoot; +use Pilsniak\ProophGen\Model\Event; use Prophecy\Argument; class PhpSpecAggregateCodeSpec extends ObjectBehavior @@ -21,8 +23,58 @@ function let() $this->beConstructedWith($generator); } - function it_is_initializable() + function it_generates_code_with_event_non_creator() { - $this->shouldHaveType(PhpSpecAggregateCode::class); + $content = "registerUser(); +\t} + +\tpublic function it_returns_id() { +\t\t\$this->id()->shouldBe('id'); +\t} +} +"; + $aggregateRoot = new AggregateRoot('Model\User', [new Event('UserRegistered')]); + $this->execute($aggregateRoot)->filename()->shouldBe('./spec/Model/UserSpec.php'); + $this->execute($aggregateRoot)->fileContent()->shouldBe($content); + } + + function it_generates_code_with_event_creator() + { + $content = "id()->shouldBe('id'); +\t} + +\tpublic function let() { +\t\t\$this->beConstructedThrough('registerUser', ['id']); +\t} +} +"; + $aggregateRoot = new AggregateRoot('Model\User', [new Event('UserRegistered', true)]); + $this->execute($aggregateRoot)->filename()->shouldBe('./spec/Model/UserSpec.php'); + $this->execute($aggregateRoot)->fileContent()->shouldBe($content); } + } diff --git a/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecEventSpec.php b/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecEventSpec.php index 5622254..2286b93 100644 --- a/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecEventSpec.php +++ b/spec/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecEventSpec.php @@ -5,6 +5,8 @@ use gossi\codegen\generator\CodeFileGenerator; use Pilsniak\GossiCodeGenerator\AggregateRootGenerator\PhpSpecGenerator\PhpSpecEvent; use PhpSpec\ObjectBehavior; +use Pilsniak\ProophGen\Model\AggregateRoot; +use Pilsniak\ProophGen\Model\Event; use Prophecy\Argument; class PhpSpecEventSpec extends ObjectBehavior @@ -20,8 +22,29 @@ function let() $this->beConstructedWith($generator); } - function it_is_initializable() + function it_generates_code() { - $this->shouldHaveType(PhpSpecEvent::class); + $content = "beConstructedThrough('create', ['id']); +\t\t\$this->aggregateId()->shouldBe('id'); +\t} +} +"; + + $event = new Event('UserRegistered'); + $aggregateRoot = new AggregateRoot('Model\User', [$event]); + $this->execute($aggregateRoot, $event)->filename()->shouldBe('./spec/Model/User/Event/UserRegisteredSpec.php'); + $this->execute($aggregateRoot, $event)->fileContent()->shouldBe($content); } } diff --git a/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/AggregateRootCodeGenerator.php b/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/AggregateRootCodeGenerator.php index 6026478..2a575d5 100644 --- a/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/AggregateRootCodeGenerator.php +++ b/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/AggregateRootCodeGenerator.php @@ -92,6 +92,7 @@ private function getContentAggregateRoot(AggregateRoot $aggregateRoot): string ->addParameter(PhpParameter::create('event')->setType($event->name())) ->setType('void') ->setVisibility('private') + ->setBody($this->generateBodyForWhenMethod($event)) ); } @@ -126,4 +127,12 @@ private function defaultEventMethod(PhpClass $class, Event $event) ->setType('void') ); } + + private function generateBodyForWhenMethod(Event $event): string + { + if (!$event->isCreator()) { + return ''; + } + return '$this->id = $event->aggregateId();'; + } } diff --git a/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecAggregateCode.php b/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecAggregateCode.php index 980a4ea..353c5b1 100644 --- a/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecAggregateCode.php +++ b/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecAggregateCode.php @@ -3,7 +3,10 @@ namespace Pilsniak\GossiCodeGenerator\AggregateRootGenerator\PhpSpecGenerator; use gossi\codegen\generator\CodeFileGenerator; +use gossi\codegen\model\PhpClass; +use gossi\codegen\model\PhpMethod; use Pilsniak\ProophGen\Model\AggregateRoot; +use Pilsniak\ProophGen\Model\Event; use Pilsniak\ProophGen\Model\FileToSave; class PhpSpecAggregateCode @@ -25,11 +28,51 @@ public function execute(AggregateRoot $aggregateRoot): FileToSave private function generateFileContent(AggregateRoot $aggregateRoot): string { - return ''; + $phpClass = new PhpClass(); + $phpClass->setQualifiedName('spec\\'.$aggregateRoot->qualifiedName().'Spec'); + $phpClass->setParentClassName('ObjectBehavior'); + $phpClass->addUseStatement('PhpSpec\ObjectBehavior'); + $phpClass->addUseStatement('Prophecy\Argument'); + $phpClass->addUseStatement($aggregateRoot->qualifiedName()); + + $phpClass->setMethod( + PhpMethod::create('it_returns_id') + ->setBody('$this->id()->shouldBe(\'id\');') + ); + + foreach ($aggregateRoot->events() as $event) { + if ($event->isCreator()) { + $phpClass->setMethod( + PhpMethod::create('let') + ->setBody('$this->beConstructedThrough(\''.$event->aggregateMethodName().'\', [\'id\']);') + ); + } else { + $phpClass->setMethod( + PhpMethod::create('it_can_' . $event->aggregateMethodName()) + ->setBody($this->generateBodyForEvent($aggregateRoot, $event)) + ); + } + + } + + return $this->codeFileGenerator->generate($phpClass); } private function generateFileName(AggregateRoot $aggregateRoot): string { - return ''; + return str_replace(['./src/', '.php'], ['./spec/', 'Spec.php'], $aggregateRoot->path()); + } + + private function generateBodyForEvent(AggregateRoot $aggregateRoot, Event $event): string + { + if ($event->isCreator()) { + $body = '$this->beConstructedThrough(\''.$event->aggregateMethodName().'\', [\'id\']);' . "\n"; + $body .= '$this->id()->shouldBe(\'id\');'; + + return $body; + } + $body = '$this->'.$event->aggregateMethodName().'();'; + + return $body; } } diff --git a/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecEvent.php b/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecEvent.php index efcc698..d524638 100644 --- a/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecEvent.php +++ b/src/Pilsniak/GossiCodeGenerator/AggregateRootGenerator/PhpSpecGenerator/PhpSpecEvent.php @@ -3,6 +3,8 @@ namespace Pilsniak\GossiCodeGenerator\AggregateRootGenerator\PhpSpecGenerator; use gossi\codegen\generator\CodeFileGenerator; +use gossi\codegen\model\PhpClass; +use gossi\codegen\model\PhpMethod; use Pilsniak\ProophGen\Model\AggregateRoot; use Pilsniak\ProophGen\Model\Event; use Pilsniak\ProophGen\Model\FileToSave; @@ -21,16 +23,36 @@ public function __construct(CodeFileGenerator $codeFileGenerator) public function execute(AggregateRoot $aggregateRoot, Event $event): FileToSave { - return new FileToSave($this->generateFileName($aggregateRoot), $this->generateFileContent($aggregateRoot)); + return new FileToSave($this->generateFileName($aggregateRoot, $event), $this->generateFileContent($aggregateRoot, $event)); } - private function generateFileContent(AggregateRoot $aggregateRoot): string + private function generateFileContent(AggregateRoot $aggregateRoot, Event $event): string { - return ''; + $phpClass = new PhpClass(); + $phpClass->setQualifiedName('spec\\'. $aggregateRoot->eventNamespace($event).'Spec'); + $phpClass->setParentClassName('ObjectBehavior'); + $phpClass->addUseStatement('PhpSpec\ObjectBehavior'); + $phpClass->addUseStatement('Prophecy\Argument'); + $phpClass->addUseStatement($aggregateRoot->eventNamespace($event)); + + $phpClass->setMethod( + PhpMethod::create('it_is_created_with_id') + ->setBody($this->generateBodyForCreateWithIdMethod($aggregateRoot, $event)) + ); + + return $this->codeFileGenerator->generate($phpClass); + } + + private function generateFileName(AggregateRoot $aggregateRoot, Event $event): string + { + return str_replace(['./src/', '.php'], ['./spec/', 'Spec.php'], $aggregateRoot->eventPath($event)); } - private function generateFileName(AggregateRoot $aggregateRoot): string + private function generateBodyForCreateWithIdMethod(AggregateRoot $aggregateRoot, Event $event): string { - return ''; + $body = '$this->beConstructedThrough(\'create\', [\'id\']);' . "\n"; + $body .= '$this->aggregateId()->shouldBe(\'id\');'; + + return $body; } }