Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: schema V3 #11

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<testsuite name="unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="integration">
<directory>tests/Integration</directory>
</testsuite>
</testsuites>

<php>
Expand Down
7 changes: 7 additions & 0 deletions src/Attribute/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public function __construct(
public readonly string $name,
public array $properties = [],
public array $channels = [],
public array $operations = [],
) {
}

Expand All @@ -26,6 +27,7 @@ public function toArray(): array
'name' => $this->name,
'properties' => array_map(static fn(PropertyInterface $property) => $property->toArray(), $this->properties),
'channels' => array_map(static fn(Channel $channel) => $channel->toArray(), $this->channels),
'operations' => array_map(static fn(Operation $operation) => $operation->toArray(), $this->operations),
];
}

Expand All @@ -39,6 +41,11 @@ public function addChannel(Channel $channel): void
$this->channels[] = $channel;
}

public function addOperation(Operation $operation): void
{
$this->operations[] = $operation;
}

public function enrich(self $self): self
{
// UPDATE EXISTING
Expand Down
36 changes: 36 additions & 0 deletions src/Attribute/Operation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Ferror\AsyncapiDocBundle\Attribute;

use Attribute;
use Ferror\AsyncapiDocBundle\Schema\V3\OperationType;

#[Attribute(Attribute::TARGET_CLASS)]
class Operation
{
public function __construct(
public string $name,
public OperationType $type = OperationType::SEND,
public array $channels = [],
) {
}

public function toArray(): array
{
return [
'name' => $this->name,
'type' => $this->type->value,
'channels' => array_map(
static fn (Channel $channel) => $channel->toArray(),
$this->channels
),
];
}

public function addChannel(Channel $channel): void
{
$this->channels[] = $channel;
}
}
9 changes: 9 additions & 0 deletions src/DocumentationStrategy/AttributeDocumentationStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Ferror\AsyncapiDocBundle\Attribute\Channel;
use Ferror\AsyncapiDocBundle\Attribute\Message;
use Ferror\AsyncapiDocBundle\Attribute\Operation;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionException;
Expand Down Expand Up @@ -50,6 +51,14 @@ public function document(string $class): Message
$message->addChannel($channelAttribute->newInstance());
}

// Channels are optional as it's possible to document just Messages.
/** @var ReflectionAttribute<Operation>[] $operationAttributes */
$operationAttributes = $reflection->getAttributes(Operation::class);

foreach ($operationAttributes as $operationAttribute) {
$message->addOperation($operationAttribute->newInstance());
}

return $message;
}
}
26 changes: 26 additions & 0 deletions src/Schema/V3/OperationRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Ferror\AsyncapiDocBundle\Schema\V3;

final readonly class OperationRenderer
{
public function render(array $document): array
{
$operations = [];

foreach ($document['operations'] as $operation) {
foreach ($operation['channels'] as $channel) {
$operations[$operation['name']] = [
'action' => $operation['type'],
'channel' => [
'$ref' => '#/channels/' . $channel['name'],
],
];
}
}

return $operations;
}
}
12 changes: 12 additions & 0 deletions src/Schema/V3/OperationType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Ferror\AsyncapiDocBundle\Schema\V3;

enum OperationType: string
{
case SEND = 'send';
case RECEIVE = 'receive';
}

141 changes: 140 additions & 1 deletion tests/Integration/DumpSpecificationConsoleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,12 @@ public function testExecuteClass(): void
$this->assertEquals($expectedDisplay, $display);
}

public function testExecuteYaml(): void
public function testExecuteYamlV2(): void
{
if ($this->isV3()) {
$this->markTestSkipped('Skipping schema V2 test on V3 variable');
}

$kernel = self::bootKernel();
$application = new Application($kernel);

Expand Down Expand Up @@ -195,6 +199,141 @@ public function testExecuteYaml(): void
}
}

public function testExecuteYamlV3(): void
{
if (false === $this->isV3()) {
$this->markTestSkipped('Skipping schema V3 test on V2 variable');
}

$kernel = self::bootKernel();
$application = new Application($kernel);

$command = $application->find('ferror:asyncapi:dump');
$commandTester = new CommandTester($command);
$commandTester->execute(['format' => 'yaml']);

$commandTester->assertCommandIsSuccessful();

$display = $commandTester->getDisplay();

$expectedDisplay = <<<YAML
asyncapi: 3.0.0
info:
title: 'Service Example API'
version: 1.2.3
description: 'This service is in charge of processing user signups'
channels:
user_signed_up:
messages:
UserSignedUp:
\$ref: '#/components/messages/UserSignedUp'
payment_executed:
messages:
PaymentExecuted:
\$ref: '#/components/messages/PaymentExecuted'
product.created:
messages:
ProductCreated:
\$ref: '#/components/messages/ProductCreated'
components:
messages:
UserSignedUp:
payload:
type: object
properties:
name:
type: string
description: 'Name of the user'
format: string
example: John
email:
type: string
description: 'Email of the user'
format: email
example: [email protected]
age:
type: integer
description: 'Age of the user'
format: int32
example: '18'
isCitizen:
type: boolean
description: 'Is user a citizen'
format: boolean
example: 'true'
required:
- name
- email
- age
- isCitizen
PaymentExecuted:
payload:
type: object
properties:
amount:
type: number
createdAt:
type: string
required:
- amount
- createdAt
ProductCreated:
payload:
type: object
properties:
id:
type: integer
amount:
type: number
currency:
type: string
isPaid:
type: boolean
createdAt:
type: string
format: date-time
week:
type: integer
payment:
type: string
products:
type: string
tags:
type: string
required:
- id
- amount
- currency
- isPaid
- createdAt
- week
- payment
- products
- tags
servers:
production:
protocol: amqp
description: 'This is production broker.'
host: broker.mycompany.com
staging:
protocol: amqp
description: 'This is staging broker.'
host: broker.mycompany.com


YAML;

$this->assertEquals($expectedDisplay, $display);

mkdir(dirname(__DIR__) . '/../var/' . $this->getSchemaVersion());

$content = file_put_contents(dirname(__DIR__) . '/../var/' . $this->getSchemaVersion() . '/asyncapi.yaml', $display);

if (false === $content) {
throw new RuntimeException('Schema file was not save');
}
}

public function testExecuteJson(): void
{
$kernel = self::bootKernel();
Expand Down
1 change: 1 addition & 0 deletions tests/Unit/DocumentationEditorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public function testDocument(): void
],
],
'channels' => [],
'operations' => [],
];

$this->assertEquals($expected, $actual);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public function testUserSignedUp(): void
'type' => 'subscribe',
],
],
'operations' => [],
];

$this->assertEquals($expected, $actual);
Expand Down Expand Up @@ -154,6 +155,7 @@ public function testProductCreated(): void
'type' => 'subscribe',
],
],
'operations' => [],
];

$this->assertEquals($expected, $actual);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function test(): void
],
],
'channels' => [],
'operations' => [],
];

$this->assertEquals($expected, $documentation->document(UserSignedUp::class)->toArray());
Expand Down Expand Up @@ -98,9 +99,9 @@ public function testEnum(): void
],
],
'channels' => [],
'operations' => [],
];


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

$this->assertEquals($expected, $actual);
Expand Down
Loading
Loading