Skip to content

Commit

Permalink
Merge pull request #37 from codeliner/force_datetime
Browse files Browse the repository at this point in the history
Force \DateTimeInterface
  • Loading branch information
prolic committed Aug 25, 2015
2 parents ffb3a5d + 64674fe commit c3093fd
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 36 deletions.
26 changes: 2 additions & 24 deletions src/Messaging/DomainMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@ abstract class DomainMessage implements Message
*/
protected $metadata = [];

/**
* Override this in your message if you want to use another format
*
* @var string
*/
protected $dateTimeFormat = \DateTime::ISO8601;

/**
* Return message payload as array
*
Expand Down Expand Up @@ -82,17 +75,7 @@ abstract protected function setPayload(array $payload);
*/
public static function fromArray(array $messageData)
{
Assertion::keyExists($messageData, 'uuid');
Assertion::keyExists($messageData, 'message_name');
Assertion::string($messageData['message_name'], 'message name needs to be string');
Assertion::notEmpty($messageData['message_name'], 'message name must not be empty');
Assertion::keyExists($messageData, 'version');
Assertion::integer($messageData['version'], 'version needs to be an integer');
Assertion::keyExists($messageData, 'payload');
Assertion::isArray($messageData['payload'], 'payload needs to be an array');
Assertion::keyExists($messageData, 'metadata');
Assertion::keyExists($messageData, 'created_at');
Assertion::isArray($messageData['metadata'], 'metadata needs to be an array');
MessageDataAssertion::assert($messageData);

$messageRef = new \ReflectionClass(get_called_class());

Expand All @@ -104,11 +87,6 @@ public static function fromArray(array $messageData)
$message->version = $messageData['version'];
$message->setPayload($messageData['payload']);
$message->metadata = $messageData['metadata'];

if (! $messageData['created_at'] instanceof \DateTimeInterface) {
$messageData['created_at'] = \DateTimeImmutable::createFromFormat($message->dateTimeFormat, $messageData['created_at'], new \DateTimeZone('UTC'));
}

$message->createdAt = $messageData['created_at'];

return $message;
Expand Down Expand Up @@ -177,7 +155,7 @@ public function toArray()
'version' => $this->version,
'payload' => $this->payload(),
'metadata' => $this->metadata,
'created_at' => $this->createdAt()->format($this->dateTimeFormat)
'created_at' => $this->createdAt(),
];
}

Expand Down
4 changes: 2 additions & 2 deletions src/Messaging/FQCNMessageFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ public function createMessageFromArray($messageName, array $messageData)
}

if (! isset($messageData['version'])) {
$messageData['version'] = 1;
$messageData['version'] = 0;
}

if (! isset($messageData['created_at'])) {
$messageData['created_at'] = new \DateTimeImmutable();
$messageData['created_at'] = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
}

if (! isset($messageData['metadata'])) {
Expand Down
5 changes: 4 additions & 1 deletion src/Messaging/MessageConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ interface MessageConverter
* 'version' => int,
* 'payload' => array, //MUST only contain sub arrays and/or scalar types, objects, etc. are not allowed!
* 'metadata' => array, //MUST only contain key/value pairs with values being only scalar types!
* 'created_at' => string, //formatted \DateTime
* 'created_at' => \DateTimeInterface,
* ]
*
* The correct structure and types are asserted by MessageDataAssertion::assert()
* so make sure that the returned array of your custom conversion logic passes the assertion.
*
* @param Message $domainMessage
* @return array
*/
Expand Down
116 changes: 116 additions & 0 deletions src/Messaging/MessageDataAssertion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php
/*
* This file is part of the prooph/common.
* (c) 2014-2015 prooph software GmbH <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Date: 8/25/15 - 3:27 PM
*/
namespace Prooph\Common\Messaging;

use Assert\Assertion;

/**
* Class MessageDataAssertion
*
* @package Prooph\Common\Messaging
* @author Alexander Miertsch <[email protected]>
*/
final class MessageDataAssertion
{
/**
* @param mixed $messageData
*/
public static function assert($messageData)
{
Assertion::isArray($messageData, 'MessageData must be an array');
Assertion::keyExists($messageData, 'message_name', 'MessageData must contain a key message_name');
Assertion::keyExists($messageData, 'uuid', 'MessageData must contain a key uuid');
Assertion::keyExists($messageData, 'version', 'MessageData must contain a key version');
Assertion::keyExists($messageData, 'payload', 'MessageData must contain a key payload');
Assertion::keyExists($messageData, 'metadata', 'MessageData must contain a key metadata');
Assertion::keyExists($messageData, 'created_at', 'MessageData must contain a key created_at');

self::assertMessageName($messageData['message_name']);
self::assertUuid($messageData['uuid']);
self::assertVersion($messageData['version']);
self::assertPayload($messageData['payload']);
self::assertMetadata($messageData['metadata']);
self::assertCreatedAt($messageData['created_at']);
}

/**
* @param string $uuid
*/
public static function assertUuid($uuid)
{
Assertion::uuid($uuid, 'uuid must be a valid UUID string');
}

/**
* @param string $messageName
*/
public static function assertMessageName($messageName)
{
Assertion::minLength($messageName, 3, 'message_name must be string with at least 3 chars length');
}

/**
* @param $version
*/
public static function assertVersion($version)
{
Assertion::min($version, 0, 'version must be an unsigned integer');
}

/**
* @param array $payload
*/
public static function assertPayload($payload)
{
Assertion::isArray($payload, 'payload must be an array');
self::assertSubPayload($payload);
}

/**
* @param mixed $payload
*/
private static function assertSubPayload($payload)
{
if (is_array($payload)) {
foreach ($payload as $subPayload) {
self::assertSubPayload($subPayload);
return;
}
}

Assertion::scalar($payload, 'payload must only contain arrays and scalar values');
}

/**
* @param array $metadata
*/
public static function assertMetadata($metadata)
{
Assertion::isArray($metadata, 'metadata must be an array');

foreach ($metadata as $key => $value) {
Assertion::minLength($key, 1, 'A metadata key must be non empty string');
Assertion::scalar($value, 'A metadata value must have a scalar type. Got ' . gettype($value) . ' for ' . $key);
}
}

/**
* @param \DateTimeInterface $createdAt
*/
public static function assertCreatedAt($createdAt)
{
Assertion::isInstanceOf($createdAt, \DateTimeInterface::class, sprintf(
'created_at must be of type %s. Got %s',
\DateTimeInterface::class,
is_object($createdAt)? get_class($createdAt) : gettype($createdAt)
));
}
}
8 changes: 7 additions & 1 deletion src/Messaging/MessageFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@ interface MessageFactory
* Message data MUST contain at least a "payload" key
* but may also contain "uuid", "message_name", "version", "metadata", and "created_at".
*
* In general the message factory MUST support creating event objects from an array returned by
* the corresponding Prooph\Common\Messaging\MessageConverter
*
* You can use the assertion helper Prooph\Common\Messaging\MessageDataAssertion to assert message data
* before processing it.
*
* If one of the optional keys is not part of the message data the factory should use a default instead:
* For example:
* uuid = Uuid::uuid4()
* message_name = $messageName //First parameter passed to the method
* version = 1
* metadata = []
* created_at = new \DateTimeImmutable('now', new \DateTimeZone('UTC')) //We recommend using UTC
* created_at = new \DateTimeImmutable('now', new \DateTimeZone('UTC')) //We treat all dates as UTC
*
* @param string $messageName
* @param array $messageData
Expand Down
4 changes: 2 additions & 2 deletions tests/Messaging/CommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ final class CommandTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
$this->uuid = Uuid::uuid4();
$this->createdAt = new \DateTimeImmutable();
$this->createdAt = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));

$this->command = DoSomething::fromArray([
'message_name' => 'TestCommand',
'uuid' => $this->uuid->toString(),
'version' => 1,
'created_at' => $this->createdAt->format(\DateTime::ISO8601),
'created_at' => $this->createdAt,
'payload' => ['command' => 'payload'],
'metadata' => ['command' => 'metadata']
]);
Expand Down
4 changes: 2 additions & 2 deletions tests/Messaging/DomainEventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ final class DomainEventTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
$this->uuid = Uuid::uuid4();
$this->createdAt = new \DateTimeImmutable();
$this->createdAt = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));

$this->domainEvent = SomethingWasDone::fromArray([
'message_name' => 'TestDomainEvent',
'uuid' => $this->uuid->toString(),
'version' => 1,
'created_at' => $this->createdAt->format(\DateTime::ISO8601),
'created_at' => $this->createdAt,
'payload' => ['event' => 'payload'],
'metadata' => ['event' => 'metadata']
]);
Expand Down
6 changes: 3 additions & 3 deletions tests/Messaging/FQCNMessageFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ public function it_creates_a_new_message_from_array_and_fqcn()
'version' => 2,
'payload' => ['command' => 'payload'],
'metadata' => ['command' => 'metadata'],
'created_at' => $createdAt->format(\DateTime::ISO8601),
'created_at' => $createdAt,
]);

$this->assertEquals(DoSomething::class, $command->messageName());
$this->assertEquals($uuid->toString(), $command->uuid()->toString());
$this->assertEquals($createdAt->format(\DateTime::ISO8601), $command->createdAt()->format(\DateTime::ISO8601));
$this->assertEquals($createdAt, $command->createdAt());
$this->assertEquals(2, $command->version());
$this->assertEquals(['command' => 'payload'], $command->payload());
$this->assertEquals(['command' => 'metadata'], $command->metadata());
Expand All @@ -68,7 +68,7 @@ public function it_creates_a_new_message_with_defaults_from_array_and_fqcn()
]);

$this->assertEquals(DoSomething::class, $command->messageName());
$this->assertEquals(1, $command->version());
$this->assertEquals(0, $command->version());
$this->assertEquals(['command' => 'payload'], $command->payload());
$this->assertEquals([], $command->metadata());
}
Expand Down
Loading

0 comments on commit c3093fd

Please sign in to comment.