Skip to content

Commit

Permalink
add phpspec support to aggregate roots
Browse files Browse the repository at this point in the history
  • Loading branch information
mmp4k committed Oct 28, 2017
1 parent 95c4dc7 commit 154d9ce
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 13 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class User extends AggregateRoot {
\t}
\tprivate function whenUserRegistered(UserRegistered \$event): void {
\t\t\$this->id = \$event->aggregateId();
\t}
}
";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 = "<?php
declare(strict_types=1);
namespace spec\Model;
use Model\User;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class UserSpec extends ObjectBehavior {
\tpublic function it_can_registerUser() {
\t\t\$this->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 = "<?php
declare(strict_types=1);
namespace spec\Model;
use Model\User;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class UserSpec extends ObjectBehavior {
\tpublic function it_returns_id() {
\t\t\$this->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);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -20,8 +22,29 @@ function let()

$this->beConstructedWith($generator);
}
function it_is_initializable()
function it_generates_code()
{
$this->shouldHaveType(PhpSpecEvent::class);
$content = "<?php
declare(strict_types=1);
namespace spec\Model\User\Event;
use Model\User\Event\UserRegistered;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class UserRegisteredSpec extends ObjectBehavior {
\tpublic function it_is_created_with_id() {
\t\t\$this->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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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))
);
}

Expand Down Expand Up @@ -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();';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
}

0 comments on commit 154d9ce

Please sign in to comment.