Skip to content

Commit

Permalink
New annotations - response, request, openApi
Browse files Browse the repository at this point in the history
  • Loading branch information
josefbenjac authored and Milan Felix Šulc committed Jan 28, 2019
1 parent 4c4f5db commit 31d7008
Show file tree
Hide file tree
Showing 15 changed files with 645 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/Annotation/Controller/OpenApi.php
@@ -0,0 +1,33 @@
<?php declare(strict_types = 1);

namespace Apitte\Core\Annotation\Controller;

use Doctrine\Common\Annotations\Annotation\Target;

/**
* @Annotation
* @Target({"CLASS","METHOD"})
*/
final class OpenApi
{

/** @var mixed[] */
private $data;

/**
* @param mixed[] $data
*/
public function __construct(array $data)
{
$this->data = $data;
}

/**
* @return mixed[]
*/
public function getData(): array
{
return $this->data;
}

}
50 changes: 50 additions & 0 deletions src/Annotation/Controller/Request.php
@@ -0,0 +1,50 @@
<?php declare(strict_types = 1);

namespace Apitte\Core\Annotation\Controller;

use Doctrine\Common\Annotations\Annotation\Target;

/**
* @Annotation
* @Target("METHOD")
*/
final class Request
{

/** @var string|null */
private $description;

/** @var string|null */
private $entity;

/** @var bool */
private $required = false;

/**
* @param mixed[] $values
*/
public function __construct(array $values)
{
$this->description = $values['description'] ?? null;
$this->description = $values['entity'] ?? null;

This comment has been minimized.

Copy link
@miranovy

miranovy Jan 30, 2019

Contributor
  $this->entity = $values['entity'] ?? null;
if (isset($values['required']) && $values['required'] === true) {
$this->required = true;
}
}

public function getEntity(): ?string
{
return $this->entity;
}

public function getDescription(): ?string
{
return $this->description;
}

public function isRequired(): bool
{
return $this->required;
}

}
52 changes: 52 additions & 0 deletions src/Annotation/Controller/Response.php
@@ -0,0 +1,52 @@
<?php declare(strict_types = 1);

namespace Apitte\Core\Annotation\Controller;

use Doctrine\Common\Annotations\Annotation\Target;
use Doctrine\Common\Annotations\AnnotationException;

/**
* @Annotation
* @Target("ANNOTATION")
*/
final class Response
{

/** @var string */
private $code = 'default';

/** @var string */
private $description;

/** @var string|null */
private $entity;

/**
* @param mixed[] $values
*/
public function __construct(array $values)
{
if (!isset($values['description']) || empty($values['description'])) {
throw new AnnotationException('Empty @Response description given');
}
$this->code = $values['code'] ?? 'default';
$this->entity = $values['entity'] ?? null;
$this->description = $values['description'];
}

public function getDescription(): string
{
return $this->description;
}

public function getCode(): string
{
return $this->code;
}

public function getEntity(): ?string
{
return $this->entity;
}

}
54 changes: 54 additions & 0 deletions src/Annotation/Controller/Responses.php
@@ -0,0 +1,54 @@
<?php declare(strict_types = 1);

namespace Apitte\Core\Annotation\Controller;

use Doctrine\Common\Annotations\Annotation\Target;
use Doctrine\Common\Annotations\AnnotationException;

/**
* @Annotation
* @Target("METHOD")
*/
final class Responses
{

/** @var Response[] */
private $responses = [];

/**
* @param mixed[] $values
*/
public function __construct(array $values)
{
if (isset($values['value'])) {
if (empty($values['value'])) {
throw new AnnotationException('Empty @Responses given');
}
$this->responses = is_array($values['value']) ? $values['value'] : [$values['value']];
} else {
throw new AnnotationException('No @Response given in @Responses');
}

$takenCodes = [];
/** @var Response $value */
foreach ($values['value'] as $value) {
if (!isset($takenCodes[$value->getCode()])) {
$takenCodes[$value->getCode()] = $value;
} else {
throw new AnnotationException(sprintf(
'Multiple @Response annotations with "code=%s" given. Each response must have unique code.',
$value->getCode()
));
}
}
}

/**
* @return Response[]
*/
public function getResponses(): array
{
return $this->responses;
}

}
38 changes: 38 additions & 0 deletions src/DI/Loader/DoctrineAnnotationLoader.php
Expand Up @@ -10,13 +10,17 @@
use Apitte\Core\Annotation\Controller\Id;
use Apitte\Core\Annotation\Controller\Method;
use Apitte\Core\Annotation\Controller\Negotiations;
use Apitte\Core\Annotation\Controller\OpenApi;
use Apitte\Core\Annotation\Controller\Path;
use Apitte\Core\Annotation\Controller\Request;
use Apitte\Core\Annotation\Controller\RequestMapper;
use Apitte\Core\Annotation\Controller\RequestParameters;
use Apitte\Core\Annotation\Controller\ResponseMapper;
use Apitte\Core\Annotation\Controller\Responses;
use Apitte\Core\Annotation\Controller\Tag;
use Apitte\Core\Exception\Logical\InvalidStateException;
use Apitte\Core\Schema\Builder\Controller\Controller;
use Apitte\Core\Schema\Builder\Controller\MethodRequest;
use Apitte\Core\Schema\Builder\SchemaBuilder;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
Expand Down Expand Up @@ -155,6 +159,13 @@ protected function parseControllerClassAnnotations(Controller $controller, Class
$controller->addTag($annotation->getName(), $annotation->getValue());
}

// Parse @OpenApi ============================
if (get_class($annotation) === OpenApi::class) {
/** @var OpenApi $annotation */
$controller->setOpenApi($annotation->getData());
continue;
}

// Parse @GroupId ==============================
if (get_class($annotation) === GroupId::class) {
throw new InvalidStateException(sprintf('Annotation @GroupId cannot be on non-abstract "%s"', $class->getName()));
Expand Down Expand Up @@ -258,6 +269,33 @@ protected function parseControllerMethodsAnnotations(Controller $controller, Cla
continue;
}

// Parse @Response ================
if (get_class($annotation) === Responses::class) {
/** @var Responses $annotation */
foreach ($annotation->getResponses() as $r) {
$response = $schemaMethod->addResponse($r->getCode(), $r->getDescription());
$response->setEntity($r->getEntity());
}
continue;
}

// Parse @Request ================
if (get_class($annotation) === Request::class) {
/** @var Request $annotation */
$request = $schemaMethod->setRequest(new MethodRequest());
$request->setDescription($annotation->getDescription());
$request->setEntity($annotation->getEntity());
$request->setRequired($annotation->isRequired());
continue;
}

// Parse @OpenApi ================
if (get_class($annotation) === OpenApi::class) {
/** @var OpenApi $annotation */
$schemaMethod->setOpenApi($annotation->getData());
continue;
}

// Parse @Negotiations =====================
if (get_class($annotation) === Negotiations::class) {
/** @var Negotiations $annotation */
Expand Down
19 changes: 19 additions & 0 deletions src/Schema/Builder/Controller/Controller.php
Expand Up @@ -26,6 +26,9 @@ final class Controller
/** @var mixed[] */
private $tags = [];

/** @var mixed[] */
private $openApi = [];

public function __construct(string $class)
{
$this->class = $class;
Expand Down Expand Up @@ -132,4 +135,20 @@ public function addTags(array $tags): void
}
}

/**
* @param mixed[] $openApi
*/
public function setOpenApi(array $openApi): void
{
$this->openApi = $openApi;
}

/**
* @return mixed[]
*/
public function getOpenApi(): array
{
return $this->openApi;
}

}
56 changes: 56 additions & 0 deletions src/Schema/Builder/Controller/Method.php
Expand Up @@ -28,9 +28,15 @@ final class Method
/** @var string[] */
private $arguments = [];

/** @var MethodRequest|null */
private $request;

/** @var MethodParameter[] */
private $parameters = [];

/** @var MethodResponse[] */
private $responses = [];

/** @var MethodNegotiation[] */
private $negotiations = [];

Expand All @@ -40,6 +46,9 @@ final class Method
/** @var ResponseMapper|null */
private $responseMapper;

/** @var mixed[] */
private $openApi = [];

public function __construct(string $name)
{
$this->name = $name;
Expand Down Expand Up @@ -171,11 +180,34 @@ public function addParameter(string $name, string $type = EndpointParameter::TYP
return $parameter;
}

public function getRequest(): ?MethodRequest
{
return $this->request;
}

public function setRequest(?MethodRequest $request): ?MethodRequest
{
$this->request = $request;
return $request;
}

public function addResponse(string $code, string $description): MethodResponse
{
$response = new MethodResponse($code, $description);
$this->responses[$code] = $response;
return $response;
}

public function hasParameter(string $name): bool
{
return isset($this->parameters[$name]);
}

public function hasResponse(string $code): bool
{
return isset($this->responses[$code]);
}

/**
* @return MethodParameter[]
*/
Expand All @@ -184,6 +216,30 @@ public function getParameters(): array
return $this->parameters;
}

/**
* @return MethodResponse[]
*/
public function getResponses(): array
{
return $this->responses;
}

/**
* @param mixed[] $openApi
*/
public function setOpenApi(array $openApi): void
{
$this->openApi = $openApi;
}

/**
* @return mixed[]
*/
public function getOpenApi(): array
{
return $this->openApi;
}

public function addNegotiation(string $suffix): MethodNegotiation
{
$negotiation = new MethodNegotiation($suffix);
Expand Down

0 comments on commit 31d7008

Please sign in to comment.