Skip to content

Commit

Permalink
chore: enable contract between documentation strategy (#16)
Browse files Browse the repository at this point in the history
Quite a smart-ish improvement when instead of an array as contract (a
bad one, but flexible), we can reuse the Message and Property
attributes, so now instead of array-ing properties, we just add extra
property either via Reflection or via an attribute.
  • Loading branch information
Ferror authored Jan 28, 2024
1 parent 51dfdd0 commit 2d0ab10
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 29 deletions.
7 changes: 6 additions & 1 deletion src/Attribute/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Message implements PropertyInterface
public function __construct(
public readonly string $name,
public readonly string $channel,
public readonly array $properties = [],
public array $properties = [],
public readonly ChannelType $channelType = ChannelType::SUBSCRIBE,
) {
}
Expand All @@ -30,4 +30,9 @@ public function toArray(): array
'channelType' => $this->channelType->value,
];
}

public function addProperty(PropertyInterface $property): void
{
$this->properties[] = $property;
}
}
2 changes: 1 addition & 1 deletion src/DocumentationEditor.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function document(string $class): array
}

foreach ($strategies as $documentationStrategy) {
$result = array_merge($result, $documentationStrategy->document($class));
$result = array_merge($result, $documentationStrategy->document($class)->toArray());
}

return $result;
Expand Down
6 changes: 3 additions & 3 deletions src/DocumentationStrategy/AttributeDocumentationStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function __construct(
) {
}

public function document(string $class): array
public function document(string $class): Message
{
$reflection = new ReflectionClass($class);
/** @var ReflectionAttribute<Message>[] $messageAttributes */
Expand All @@ -25,10 +25,10 @@ public function document(string $class): array
throw new DocumentationStrategyException('Error: class ' . $class . ' must have at least ' . Message::class . ' attribute.');
}

$message = $messageAttributes[0]->newInstance()->toArray();
$message = $messageAttributes[0]->newInstance();

foreach ($this->propertyExtractor->extract($class) as $property) {
$message['properties'][] = $property->toArray();
$message->addProperty($property);
}

return $message;
Expand Down
4 changes: 3 additions & 1 deletion src/DocumentationStrategy/DocumentationStrategyInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

namespace Ferror\AsyncapiDocBundle\DocumentationStrategy;

use Ferror\AsyncapiDocBundle\Attribute\Message;

interface DocumentationStrategyInterface
{
/**
* @param class-string $class
*/
public function document(string $class): array;
public function document(string $class): Message;
}
32 changes: 21 additions & 11 deletions src/DocumentationStrategy/ReflectionDocumentationStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

namespace Ferror\AsyncapiDocBundle\DocumentationStrategy;

use Ferror\AsyncapiDocBundle\Attribute\Message;
use Ferror\AsyncapiDocBundle\Attribute\Property;
use Ferror\AsyncapiDocBundle\Schema\PropertyType;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionException;
use ReflectionNamedType;
Expand All @@ -14,27 +18,33 @@
* @param class-string $class
*
* @throws ReflectionException
* @throws DocumentationStrategyException
*/
public function document(string $class): array
public function document(string $class): Message
{
$reflection = new ReflectionClass($class);
$properties = $reflection->getProperties();
/** @var ReflectionAttribute<Message>[] $messageAttributes */
$messageAttributes = $reflection->getAttributes(Message::class);

if (empty($messageAttributes)) {
throw new DocumentationStrategyException('Error: class ' . $class . ' must have at least ' . Message::class . ' attribute.');
}

$message['name'] = $reflection->getShortName();
$message = $messageAttributes[0]->newInstance();

$properties = $reflection->getProperties();
foreach ($properties as $property) {
/** @var ReflectionNamedType|null $type */
$type = $property->getType();
$name = $property->getName();

if ($type && !$type->allowsNull()) {
$message['required'][] = $name;
}

$message['properties'][] = [
'name' => $name,
'type' => $type?->getName(),
];
$message->addProperty(
new Property(
name: $name,
type: PropertyType::fromNative($type?->getName()),
required: $type && !$type->allowsNull(),
)
);
}

return $message;
Expand Down
10 changes: 10 additions & 0 deletions src/Schema/PropertyType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,14 @@ enum PropertyType: string
case BOOLEAN = 'boolean';
case INTEGER = 'integer';
case FLOAT = 'number';

public static function fromNative(string $type): self
{
return match ($type) {
'bool', 'boolean' => self::BOOLEAN,
'int', 'integer' => self::INTEGER,
'float', 'number' => self::FLOAT,
default => self::STRING,
};
}
}
1 change: 1 addition & 0 deletions src/Schema/V2/SchemaRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public function generate(): array

foreach ($classes as $class) {
$document = $this->documentationStrategy->document($class);
$document = $document->toArray();
$channel = $this->channelRenderer->render($document);
$message = $this->messageRenderer->render($document);

Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Console/DumpSpecificationConsole.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
if ($input->getArgument('class')) {
$document = $this->documentationStrategy->document($input->getArgument('class'));

$schema = $this->messageRenderer->render($document);
$schema = $this->messageRenderer->render($document->toArray());

$io->writeln(Yaml::dump($schema, 10, 2));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public function testUserSignedUp(): void
{
$documentation = new AttributeDocumentationStrategy(new PropertyExtractor());

$actual = $documentation->document(UserSignedUp::class)->toArray();

$expected = [
'name' => 'UserSignedUp',
'channel' => 'user_signed_up',
Expand Down Expand Up @@ -56,13 +58,15 @@ public function testUserSignedUp(): void
],
];

$this->assertEquals($expected, $documentation->document(UserSignedUp::class));
$this->assertEquals($expected, $actual);
}

public function testProductCreated(): void
{
$documentation = new AttributeDocumentationStrategy(new PropertyExtractor());

$actual = $documentation->document(ProductCreated::class)->toArray();

$expected = [
'name' => 'ProductCreated',
'channel' => 'product.created',
Expand Down Expand Up @@ -144,6 +148,6 @@ public function testProductCreated(): void
],
];

$this->assertEquals($expected, $documentation->document(ProductCreated::class));
$this->assertEquals($expected, $actual);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,44 @@ public function test(): void

$expected = [
'name' => 'UserSignedUp',
'channel' => 'user_signed_up',
'channelType' => 'subscribe',
'properties' => [
[
'name' => 'name',
'type' => 'string',
'required' => true,
'description' => '',
'format' => null,
'example' => null,
],
[
'name' => 'email',
'type' => 'string',
'required' => true,
'description' => '',
'format' => null,
'example' => null,
],
[
'name' => 'age',
'type' => 'int',
'type' => 'integer',
'required' => true,
'description' => '',
'format' => null,
'example' => null,
],
[
'name' => 'isCitizen',
'type' => 'bool',
'type' => 'boolean',
'required' => true,
'description' => '',
'format' => null,
'example' => null,
],
],
'required' => [
'name',
'email',
'age',
'isCitizen',
]
];

$this->assertEquals($expected, $documentation->document(UserSignedUp::class));
$this->assertEquals($expected, $documentation->document(UserSignedUp::class)->toArray());
}
}

0 comments on commit 2d0ab10

Please sign in to comment.