Skip to content

Commit

Permalink
Create a IsMapped expression
Browse files Browse the repository at this point in the history
This will allow us to ensure that certain classes are always in a map.
This is useful, for example, to ensure that DTOs like commands and
events are always set in a map, so that a serializer knows how
to serialize/deserialize them.
  • Loading branch information
Herberto Graca authored and hgraca committed Sep 5, 2023
1 parent 976c200 commit 56a0749
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,23 @@ For example: `phparkitect debug:expression ResideInOneOfTheseNamespaces App`

Currently, you can check if a class:

### Is referenced in a given map

This is useful, for example, to ensure that DTOs like commands and
events are always set in a map, so that we are sure a serializer knows how
to serialize/deserialize them.

```php
$map = [
'a' => 'App\Core\Component\MyComponent\Command\MyCommand',
'b' => 'App\Core\Component\MyComponent\Event\MyEvent',
];
$rules = Rule::allClasses()
->that(new ResideInOneOfTheseNamespaces('App\Core\Component\**\Command', 'App\Core\Component\**\Event'))
->should(new IsMapped($map))
->because('we want to ensure our serializer can serialize/deserialize all commands and events');
```

### Depends on a namespace

```php
Expand Down
44 changes: 44 additions & 0 deletions src/Expression/ForClasses/IsMapped.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Arkitect\Expression\ForClasses;

use Arkitect\Analyzer\ClassDescription;
use Arkitect\Expression\Description;
use Arkitect\Expression\Expression;
use Arkitect\Rules\Violation;
use Arkitect\Rules\ViolationMessage;
use Arkitect\Rules\Violations;

final class IsMapped implements Expression
{
public const POSITIVE_DESCRIPTION = 'should exist in the list';

/** @var array */
private $list;

public function __construct(array $list)
{
$this->list = array_flip($list);
}

public function describe(ClassDescription $theClass, string $because): Description
{
return new Description(self::POSITIVE_DESCRIPTION, $because);
}

public function evaluate(ClassDescription $theClass, Violations $violations, string $because): void
{
if (isset($this->list[$theClass->getFQCN()])) {
return;
}

$violation = Violation::create(
$theClass->getFQCN(),
ViolationMessage::selfExplanatory($this->describe($theClass, $because))
);

$violations->add($violation);
}
}
46 changes: 46 additions & 0 deletions tests/Unit/Expressions/ForClasses/IsMappedTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Arkitect\Tests\Unit\Expressions\ForClasses;

use Arkitect\Analyzer\ClassDescriptionBuilder;
use Arkitect\Expression\ForClasses\IsMapped;
use Arkitect\Rules\Violations;
use PHPUnit\Framework\TestCase;

final class IsMappedTest extends TestCase
{
public function test_it_should_not_add_violation_if_fqcn_is_in_list(): void
{
$listedFqcn = 'App\SharedKernel\Component\MyClass';
$list = [
'a' => $listedFqcn,
'b' => 'App\SharedKernel\Component\MyOtherClass',
];
$expression = new IsMapped($list);
$classDescription = (new ClassDescriptionBuilder())->setClassName($listedFqcn)->build();

$violations = new Violations();
$expression->evaluate($classDescription, $violations, '');

self::assertEquals(0, $violations->count());
}

public function test_it_should_add_violation_if_fqcn_is_not_in_list(): void
{
$nonListedFqcn = 'App\SharedKernel\Component\MyClass';
$list = [
'a' => 'App\SharedKernel\Component\SomeClass',
'b' => 'App\SharedKernel\Component\MyOtherClass',
];
$expression = new IsMapped($list);
$classDescription = (new ClassDescriptionBuilder())->setClassName($nonListedFqcn)->build();

$violations = new Violations();
$expression->evaluate($classDescription, $violations, '');

self::assertEquals(1, $violations->count());
self::assertEquals(IsMapped::POSITIVE_DESCRIPTION, $expression->describe($classDescription, '')->toString());
}
}

0 comments on commit 56a0749

Please sign in to comment.