Skip to content

Commit

Permalink
feat: Updates PHP version, refactor models, add event emission and ot…
Browse files Browse the repository at this point in the history
…her adjustments.
  • Loading branch information
gustavofreze committed Mar 3, 2024
1 parent 9d3f63f commit 8b65e00
Show file tree
Hide file tree
Showing 33 changed files with 258 additions and 128 deletions.
5 changes: 1 addition & 4 deletions infection.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@
"BCMath": false,
"CastInt": false,
"CastFloat": false,
"ArrayItem": false,
"CastArray": false,
"CastString": false,
"InstanceOf_": false,
"MatchArmRemoval": false,
"ArrayItemRemoval": false,
"PublicVisibility": false,
"MethodCallRemoval": false,
"NullSafePropertyCall": false
Expand Down
7 changes: 3 additions & 4 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ parameters:
- src
level: 9
tmpDir: report/phpstan
excludePaths:
- src/Application/Domain/Models/Commons/Utc.php
ignoreErrors:
- '#No value type specified in iterable type#'
- '#expects string\|null, mixed given#'
- '#with no value type specified in iterable type array#'
- '#expects array, mixed given#'
- '#expects class-string<T of object>\|T of object, string given#'
- '#return type has no value type specified in iterable type array#'
reportUnmatchedIgnoredErrors: false
2 changes: 2 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
</source>

<php>
<env name="CHEAP_DELIVERY_HOST" value="cheap-delivery.localhost"/>

<env name="MYSQL_DATABASE_HOST" value="cheap-delivery-adm"/>
<env name="MYSQL_DATABASE_PORT" value="3306"/>
<env name="MYSQL_DATABASE_NAME" value="cheap_delivery_adm_test"/>
Expand Down
15 changes: 1 addition & 14 deletions src/Application/Domain/Models/Commons/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Closure;
use Generator;
use Traversable;

/**
* @implements Collectible<mixed, mixed>
Expand All @@ -21,7 +20,7 @@ class Collection implements Collectible
*/
public function __construct(iterable $elements = [])
{
$this->elements = $this->normalize(elements: $elements);
$this->elements = iterator_to_array($elements);
}

public function add(mixed $element): Collectible
Expand Down Expand Up @@ -81,16 +80,4 @@ public function getIterator(): Generator
yield $element;
}
}

/**
* @param mixed[] $elements
* @return mixed[]
*/
private function normalize(iterable $elements): array
{
return match (true) {
$elements instanceof Traversable => iterator_to_array($elements),
default => $elements
};
}
}
1 change: 1 addition & 0 deletions src/Application/Domain/Models/Commons/Utc.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public static function now(): Utc
$dateTime = new DateTimeImmutable(datetime: 'now', timezone: $timezone);
$formattedDate = $dateTime->format(format: self::FORMAT_RFC3339);

/** @var DateTimeImmutable $utc */
$utc = DateTimeImmutable::createFromFormat(
format: self::FORMAT_RFC3339,
datetime: $formattedDate,
Expand Down
16 changes: 15 additions & 1 deletion src/Application/Domain/Models/Commons/Uuid.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@

namespace CheapDelivery\Application\Domain\Models\Commons;

use InvalidArgumentException;

final readonly class Uuid
{
private const UUID_PATTERN = '/^[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}$/i';
private const RANDOM_BYTES_SIZE = 16;

public function __construct(private string $value)
{
if (!self::isUuid($value)) {
$template = 'Invalid UUID <%s>.';
throw new InvalidArgumentException(message: sprintf($template, $this->value));
}
}

public static function generateV4(): Uuid
{
$randomBytes = random_bytes(16);
$randomBytes = random_bytes(self::RANDOM_BYTES_SIZE);

$randomBytes[6] = chr(ord($randomBytes[6]) & 0x0f | 0x40);
$randomBytes[8] = chr(ord($randomBytes[8]) & 0x3f | 0x80);
Expand All @@ -24,4 +33,9 @@ public function toString(): string
{
return $this->value;
}

public static function isUuid(string $value): bool
{
return preg_match(self::UUID_PATTERN, $value) === 1;
}
}
14 changes: 7 additions & 7 deletions src/Application/Handlers/DispatchWithLowestCostHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ public function __construct(private Carriers $carriers, private Dispatches $disp
{
}

/**
* @param DispatchWithLowestCost $command
* @return void
*/
public function handle(Command $command): void
public function handle(Command|DispatchWithLowestCost $command): void
{
$carriers = $this->carriers->findAll();

/** @var DispatchWithLowestCost $command */
$person = $command->person;
$product = $command->product;

$dispatch = Dispatch::create();
$dispatch->dispatchWithLowestCost(
weight: $command->product->weight,
distance: $command->person->distance,
weight: $product->weight,
distance: $person->distance,
carriers: $carriers
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ public function __construct(private array $costModality)

public function build(): CostModality
{
return new FixedCost(fixedCost: new Cost(value: floatval($this->costModality['cost'])));
return new FixedCost(fixedCost: new Cost(value: (float)$this->costModality['cost']));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ public function __construct(private array $costModality)

public function build(): CostModality
{
return new LinearCost(variableCost: new Cost(value: floatval($this->costModality['cost'])));
return new LinearCost(variableCost: new Cost(value: (float)$this->costModality['cost']));
}
}
2 changes: 1 addition & 1 deletion src/Driven/Carrier/Repository/Record.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static function from(array $value): Record

public function toCarrier(): Carrier
{
$costModality = json_decode($this->value['costModality'], true);
$costModality = (array)json_decode($this->value['costModality'], true);

return new Carrier(
name: new Name(value: $this->value['name']),
Expand Down
10 changes: 5 additions & 5 deletions src/Driven/Dispatch/OutboxEvent/EventRecordFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
{
public static function from(Event $event): EventRecord
{
$record = match (get_class($event)) {
DispatchedWithLowestCost::class => new DispatchedWithLowestCostV1(event: $event),
default => throw new LogicException(message: 'Unsupported event type. Cannot convert event to EventRecord.')
};
if ($event::class === DispatchedWithLowestCost::class) {
return (new DispatchedWithLowestCostV1(event: $event))->build();
}

return $record->build();
$template = 'Event <%s> is not supported. Unable to create an EventRecord.';
throw new LogicException(message: sprintf($template, $event::class));
}
}
6 changes: 0 additions & 6 deletions src/Driven/Shared/OutboxEvent/Commons/AggregateType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,13 @@
namespace CheapDelivery\Driven\Shared\OutboxEvent\Commons;

use ReflectionClass;
use ReflectionException;

final class AggregateType
{
private function __construct(public string $value)
{
}

/**
* @param class-string $class
* @return AggregateType
* @throws ReflectionException
*/
public static function from(string $class): AggregateType
{
return new AggregateType(value: (new ReflectionClass(objectOrClass: $class))->getShortName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function __construct(private DispatchWithLowestCostHandler|CommandHandler

public function handle(ServerRequestInterface $request): ResponseInterface
{
$payload = json_decode($request->getBody()->__toString(), true);
$payload = (array)json_decode($request->getBody()->__toString(), true);
$request = new Request(payload: $payload);
$command = $request->toCommand();

Expand Down
4 changes: 0 additions & 4 deletions src/Query/Dispatch/Database/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@

final class Builder
{
/**
* @param array $dispatches
* @return mixed[]
*/
public static function from(array $dispatches): array
{
$mapper = fn(array $dispatch) => [
Expand Down
5 changes: 0 additions & 5 deletions src/Query/Dispatch/Database/Facade.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ public function __construct(private QueryBuilder $queryBuilder)
{
}

/**
* @param DispatchFilters|Filters $filters
* @return mixed[]
* @throws QueryFailure
*/
public function findAll(DispatchFilters|Filters $filters): array
{
try {
Expand Down
2 changes: 1 addition & 1 deletion src/Query/Filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface Filters
/**
* Creates a Filters instance from an array of data.
*
* @param array $data The data to create the Filters instance from.
* @param mixed[] $data The data to create the Filters instance from.
* @return Filters The created Filters instance.
*/
public static function from(array $data): Filters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public function testDispatchWithLowestCost(): void
/** @Then the dispatch should be persisted */
$actual = $this->query->findLastDispatch();

self::assertEquals(96.4, $actual->shipment->cost->value);
self::assertEquals('DHL', $actual->shipment->carrierName->value);
self::assertEquals(96.4, $actual->shipment?->cost->value);
self::assertEquals('DHL', $actual->shipment?->carrierName->value);

/** @And a new event will be inserted into the outbox table */
$event = $this->query->findEventBy(aggregateId: $actual->id, eventType: 'DispatchedWithLowestCost');
Expand Down
19 changes: 13 additions & 6 deletions tests/Integration/Query/Dispatch/Factories/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Test\Integration\Query\Dispatch\Factories;

use CheapDelivery\Environment;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Psr7\Headers;
use Slim\Psr7\Request as SlimRequest;
Expand All @@ -12,12 +13,18 @@ final class Request
{
public static function getFrom(array $parameters): ServerRequestInterface
{
$stream = fopen('php://memory', 'r+');
$uri = new Uri(
scheme: 'https',
host: Environment::get(variable: 'CHEAP_DELIVERY_HOST')->toString(),
port: null,
path: '/',
query: http_build_query($parameters)
);
/** @var resource $stream */
$stream = fopen(filename: 'php://memory', mode: 'r+');
$body = new Stream(stream: $stream);
$headers = new Headers(headers: ['Content-Type' => 'application/json']);

$uri = new Uri('https', 'cheap-delivery.localhost', null, '/', http_build_query($parameters));
$body = new Stream($stream);
$headers = new Headers(['Content-Type' => 'application/json']);

return new SlimRequest('GET', $uri, $headers, [], [], $body);
return new SlimRequest(method: 'GET', uri: $uri, headers: $headers, cookies: [], serverParams: [], body: $body);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class CollectionTest extends TestCase
{
/**
* @param iterable $elements
* @param mixed[] $elements
* @param array $expected
* @return void
* @dataProvider itemsProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

namespace CheapDelivery\Application\Domain\Models\Commons\Factories;

use CheapDelivery\Application\Domain\Models\Commons\Collectible;
use CheapDelivery\Application\Domain\Models\Commons\Collection;

final class SomeThings extends Collection implements Collectible
final class SomeThings extends Collection
{
}
42 changes: 42 additions & 0 deletions tests/Unit/Application/Domain/Models/Commons/UuidTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace CheapDelivery\Application\Domain\Models\Commons;

use InvalidArgumentException;
use PHPUnit\Framework\TestCase;

class UuidTest extends TestCase
{
public function testInvalidUuid(): void
{
/** @Given a value that is not a valid UUID */
$value = 'not-a-valid-uuid';

/** @Then an exception indicating invalid UUID should be thrown */
$template = 'Invalid UUID <%s>.';
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(sprintf($template, $value));

/** @When I try to construct a UUID with this value */
new Uuid(value: $value);
}

/**
* @param string $value
* @return void
* @dataProvider uuidProvider
*/
public function testIsUuidValid(string $value): void
{
self::assertTrue(Uuid::isUuid(value: $value));
}

public static function uuidProvider(): array
{
return [
[Uuid::generateV4()->toString()],
['550e8400-e29b-41d4-a716-446655440000'],
['00000000-1111-2222-3333-444444444444']
];
}
}
4 changes: 2 additions & 2 deletions tests/Unit/Application/Domain/Models/DispatchTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public function testCalculateTheDispatchWithLowestCost(Weight $weight, Distance
$actual = $dispatch->dispatchWithLowestCost(weight: $weight, distance: $distance, carriers: $carriers);

/** @Then the value should be the same as expected */
self::assertEquals($expected->cost, $actual->shipment->cost);
self::assertEquals($expected->carrierName, $actual->shipment->carrierName);
self::assertEquals($expected->cost, $actual->shipment?->cost);
self::assertEquals($expected->carrierName, $actual->shipment?->carrierName);
self::assertNotEmpty($actual->id->getValue());
}

Expand Down
24 changes: 24 additions & 0 deletions tests/Unit/Driven/Dispatch/OutboxEvent/EventRecordFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace CheapDelivery\Driven\Dispatch\OutboxEvent;

use CheapDelivery\Driven\Dispatch\OutboxEvent\Mocks\RejectedDispatch;
use LogicException;
use PHPUnit\Framework\TestCase;

class EventRecordFactoryTest extends TestCase
{
public function testExceptionWhenUnsupportedEventType(): void
{
/** @Given I have an unmapped event */
$event = new RejectedDispatch();

/** @Then an exception indicating unsupported event type should be thrown */
$template = 'Event <%s> is not supported. Unable to create an EventRecord.';
$this->expectException(LogicException::class);
$this->expectExceptionMessage(sprintf($template, $event::class));

/** @When I try to build an event record with this event */
EventRecordFactory::from(event: $event);
}
}
Loading

0 comments on commit 8b65e00

Please sign in to comment.