Skip to content

Commit

Permalink
update generate nested tags from operation id
Browse files Browse the repository at this point in the history
  • Loading branch information
chriskapp committed Sep 10, 2023
1 parent 401005e commit f209d5d
Show file tree
Hide file tree
Showing 26 changed files with 636 additions and 254 deletions.
2 changes: 1 addition & 1 deletion src/Generator/Client/Dto/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Client
public function __construct(
public string $className,
/** @var array<Operation> */ public array $operations,
public array $tags,
/** @var array<Tag> */ public array $tags,
/** @var array<Exception> */ public array $exceptions,
public ?array $security,
public ?string $baseUrl,
Expand Down
3 changes: 2 additions & 1 deletion src/Generator/Client/Dto/Tag.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class Tag
public function __construct(
public string $className,
public string $methodName,
/** @var Operation */ public array $operations,
/** @var array<Operation> */ public array $operations,
/** @var array<Tag> */ public array $tags = [],
)
{
}
Expand Down
10 changes: 10 additions & 0 deletions src/Generator/Client/Language/php-tag.php.twig
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,15 @@ use Sdkgen\Client\TagAbstract;

class {{ className }} extends TagAbstract
{
{% for tag in tags %}
public function {{ tag.methodName }}(): {{ tag.className }}
{
return new {{ tag.className }}(
$this->httpClient,
$this->parser
);
}

{% endfor %}
{{ operations|raw }}
}
10 changes: 10 additions & 0 deletions src/Generator/Client/Language/typescript-tag.ts.twig
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,15 @@ import {{ '{' }}{{ className }}{{ '}' }} from "./{{ className }}";
{% endfor %}

export class {{ className }} extends TagAbstract {
{% for tag in tags %}
public {{ tag.methodName }}(): {{ tag.className }}
{
return new {{ tag.className }}(
this.httpClient,
this.parser
);
}

{% endfor %}
{{ operations|raw }}
}
59 changes: 39 additions & 20 deletions src/Generator/Client/LanguageAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,26 +90,7 @@ public function generate(SpecificationInterface $specification): Generator\Code\
$tagImports = [];

foreach ($client->tags as $tag) {
$imports = [];
foreach ($tag->operations as $operation) {
$imports = array_merge($imports, $operation->imports);
}
sort($imports);

/** @var Tag $tag */
$operations = $this->engine->render($this->getOperationTemplate(), [
'className' => $tag->className,
'operations' => $tag->operations,
]);

$code = $this->engine->render($this->getTagTemplate(), [
'namespace' => $this->namespace,
'className' => $tag->className,
'operations' => $operations,
'imports' => $imports,
]);

$chunks->append($this->getFileName($tag->className), $this->getFileContent($code, $tag->className));
$this->buildTag($tag, $chunks);

$tagImports[] = $tag->className;
}
Expand Down Expand Up @@ -202,6 +183,44 @@ protected function getTemplateDir(): string
return __DIR__ . '/Language';
}

private function buildTag(Tag $tag, Generator\Code\Chunks $chunks): void
{
$imports = [];
if (!empty($tag->tags)) {
foreach ($tag->tags as $subTag) {
$this->buildTag($subTag, $chunks);

$imports[] = $subTag->className;
}
}

if (!empty($tag->operations)) {
foreach ($tag->operations as $operation) {
$imports = array_merge($imports, $operation->imports);
}

/** @var Tag $tag */
$operations = $this->engine->render($this->getOperationTemplate(), [
'className' => $tag->className,
'operations' => $tag->operations,
]);
} else {
$operations = '';
}

sort($imports);

$code = $this->engine->render($this->getTagTemplate(), [
'namespace' => $this->namespace,
'className' => $tag->className,
'tags' => $tag->tags,
'operations' => $operations,
'imports' => $imports,
]);

$chunks->append($this->getFileName($tag->className), $this->getFileContent($code, $tag->className));
}

private function newTemplateEngine(): Environment
{
$twig = new Environment(new FilesystemLoader([$this->getTemplateDir()]));
Expand Down
69 changes: 40 additions & 29 deletions src/Generator/Client/LanguageBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,29 +87,11 @@ public function getClient(SpecificationInterface $specification): Dto\Client
$security = $specification->getSecurity()->toArray();
}

$operations = [];
$tags = [];
$exceptions = [];

$grouped = $this->groupOperationsByTag($specification->getOperations());
if (count($grouped) > 1) {
foreach ($grouped as $tagName => $tagOperations) {
$operations = $this->getOperations($tagOperations, $specification->getDefinitions(), $exceptions);
$grouped = $this->groupOperations($specification->getOperations());

$tags[] = new Dto\Tag(
$this->naming->buildClassNameByTag($tagName),
$this->naming->buildMethodNameByTag($tagName),
$operations
);
}

$operations = [];
} else {
$tagOperations = reset($grouped);
if (!empty($tagOperations)) {
$operations = $this->getOperations($tagOperations, $specification->getDefinitions(), $exceptions);
}
}
[$tags, $operations] = $this->buildTags($grouped, $specification->getDefinitions(), $exceptions, []);

return new Dto\Client(
'Client',
Expand All @@ -121,6 +103,35 @@ public function getClient(SpecificationInterface $specification): Dto\Client
);
}

/**
* @throws InvalidTypeException
* @throws TypeNotFoundException
*/
private function buildTags(array $grouped, DefinitionsInterface $definitions, array &$exceptions, array $path): array
{
$tags = [];
$operations = [];
foreach ($grouped as $key => $value) {
if ($value instanceof OperationInterface) {
$operations[$key] = $value;
} elseif (is_array($value)) {
$subExceptions = [];
[$subTags, $subOperations] = $this->buildTags($value, $definitions, $subExceptions, array_merge($path, [$key]));

$tags[] = new Dto\Tag(
$this->naming->buildClassNameByTag(array_merge($path, [$key])),
$this->naming->buildMethodNameByTag($key),
$subOperations,
$subTags
);
}
}

$operations = $this->getOperations($operations, $definitions, $exceptions);

return [$tags, $operations];
}

/**
* @param array<string, OperationInterface> $operations
* @throws TypeNotFoundException
Expand Down Expand Up @@ -257,22 +268,22 @@ private function resolveImport(TypeInterface $type, array &$imports): void
}
}

private function groupOperationsByTag(OperationsInterface $operations): array
private function groupOperations(OperationsInterface $operations): array
{
$result = [];
foreach ($operations->getAll() as $operationId => $operation) {
$tags = $operation->getTags();
if (empty($tags)) {
$tags = ['default'];
}
$parts = explode('.', $operationId);

foreach ($tags as $tagName) {
if (!isset($result[$tagName])) {
$result[$tagName] = [];
$last = &$result;
foreach ($parts as $partName) {
if (!isset($last[$partName])) {
$last[$partName] = [];
}

$result[$tagName][$operationId] = $operation;
$last = &$last[$partName];
}

$last = $operation;
}

return $result;
Expand Down
4 changes: 2 additions & 2 deletions src/Generator/Client/Util/Naming.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public function __construct(NormalizerInterface $normalizer)
$this->normalizer = $normalizer;
}

public function buildClassNameByTag(string $tagName): string
public function buildClassNameByTag(array $parts): string
{
return $this->normalizer->class($tagName, 'Tag');
return $this->normalizer->class(...array_merge($parts, ['Tag']));
}

public function buildMethodNameByTag(string $tagName): string
Expand Down
20 changes: 16 additions & 4 deletions src/Generator/Markup/MarkupAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ public function generate(SpecificationInterface $specification): string
$lines = $this->startLines($client);

foreach ($client->tags as $tag) {
/** @var Dto\Tag $tag */
foreach ($tag->operations as $operation) {
$lines[] = $this->generateOperation($operation, $tag->methodName);
}
$lines = array_merge($lines, $this->buildTag($tag, [$tag->methodName]));
}

foreach ($client->operations as $operation) {
Expand Down Expand Up @@ -95,4 +92,19 @@ protected function generateSchema(DefinitionsInterface $definitions): string

return $return;
}

private function buildTag(Dto\Tag $tag, array $path): array
{
$lines = [];

foreach ($tag->tags as $subTag) {
$lines = array_merge($lines, $this->buildTag($subTag, array_merge($path, [$subTag->methodName])));
}

foreach ($tag->operations as $operation) {
$lines[] = $this->generateOperation($operation, implode('.', $path));
}

return $lines;
}
}
17 changes: 12 additions & 5 deletions src/Repository/SDKgen/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,22 @@
*/
class Config implements ConfigInterface
{
private string $accessToken;
private ?string $clientId;
private ?string $clientSecret;

public function __construct(?string $accessToken)
public function __construct(?string $clientId, ?string $clientSecret)
{
$this->accessToken = $accessToken;
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
}

public function getAccessToken(): ?string
public function getClientId(): ?string
{
return $this->accessToken;
return $this->clientId;
}

public function getClientSecret(): ?string
{
return $this->clientSecret;
}
}
3 changes: 2 additions & 1 deletion src/Repository/SDKgen/ConfigInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@
*/
interface ConfigInterface
{
public function getAccessToken(): ?string;
public function getClientId(): ?string;
public function getClientSecret(): ?string;
}
46 changes: 41 additions & 5 deletions src/Repository/SDKgenRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,16 @@ public function __construct(ConfigInterface $config, ?ClientInterface $httpClien

public function getAll(): array
{
$accessToken = $this->config->getAccessToken();
if (empty($accessToken)) {
$clientId = $this->config->getClientId();
$clientSecret = $this->config->getClientSecret();
if (empty($clientId) || empty($clientSecret)) {
return [];
}

$accessToken = $this->obtainAccessToken($clientId, $clientSecret);

$return = [];
$types = $this->getTypes();
$types = $this->getTypes($accessToken);
foreach ($types as $type) {
[$name, $fileExtension, $mime] = $type;

Expand All @@ -69,15 +72,15 @@ public function getAll(): array
return $return;
}

private function getTypes(): array
private function getTypes(string $accessToken): array
{
$item = $this->cache->getItem('psx-api-generator-types');
if ($item->isHit()) {
return $item->get();
}

$response = $this->httpClient->request(new GetRequest('https://api.sdkgen.app/generator/types', [
'Authorization' => $this->config->getAccessToken(),
'Authorization' => 'Bearer ' . $accessToken,
'Accept' => 'application/json',
]));

Expand Down Expand Up @@ -128,4 +131,37 @@ private function parse(mixed $data): array

return $data;
}

private function obtainAccessToken(string $clientId, string $clientSecret): ?string
{
$item = $this->cache->getItem('psx-api-generator-token');
if ($item->isHit()) {
return $item->get();
}

$response = $this->httpClient->request(new GetRequest('https://api.sdkgen.app/authorization/token', [
'Authorization' => 'Basic ' . base64_encode($clientId . ':' . $clientSecret),
'Accept' => 'application/json',
]));

if ($response->getStatusCode() !== 200) {
return null;
}

$data = json_decode((string) $response->getBody());
if (!$data instanceof \stdClass) {
return null;
}

$accessToken = $data->access_token ?? null;
if (empty($accessToken)) {
return null;
}

$item->set($accessToken);
$item->expiresAfter(new \DateInterval('P1D'));
$this->cache->save($item);

return $accessToken;
}
}
Loading

0 comments on commit f209d5d

Please sign in to comment.