Skip to content

Commit

Permalink
Merge c3ce35b into ff3c92c
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar committed Aug 13, 2018
2 parents ff3c92c + c3ce35b commit 8217944
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .docs/README.md
Expand Up @@ -119,7 +119,7 @@ At the end, open your browser and locate to `localhost/<api-project>/hello/world
| `@Path` | Method | `path={a-zA-Z0-9}` | Set `path` to target method. A.k.a. URL path. |
| `@RequestParameters` | Method | `@RequestParameter` | Group annotation for `@RequestParameter`. |
| `@RequestParameter` | Method | `name={string}`, `type={int/string/float/bool}`, `description={string}`, `in={path/query}`, `required={true/false}`, `deprecated={true/false}`, `allowEmpty={true/false}` | Define dynamic typed parameter. |
| `@Tag` | Method | `name={string}`, `value={string}` | Add `tag` to target method. |
| `@Tag` | Method | `name={string}`, `value={mixed}` | Add `tag` to target method. |

## Plugins

Expand Down
2 changes: 1 addition & 1 deletion src/DI/Loader/DoctrineAnnotationLoader.php
Expand Up @@ -233,7 +233,7 @@ protected function parseControllerMethodsAnnotations(Controller $controller, Cla
// Parse @Tag ==============================
if (get_class($annotation) === Tag::class) {
/** @var Tag $annotation */
$schemaMethod->addTag($annotation->getName());
$schemaMethod->addTag($annotation->getName(), $annotation->getValue());
continue;
}

Expand Down
23 changes: 18 additions & 5 deletions src/Schema/Builder/Controller/Controller.php
Expand Up @@ -23,7 +23,7 @@ final class Controller
/** @var string[] */
private $groupPaths = [];

/** @var string[] */
/** @var mixed[] */
private $tags = [];

public function __construct(string $class)
Expand Down Expand Up @@ -106,17 +106,30 @@ public function addGroupPath(string $path): void
$this->groupPaths[] = $path;
}

public function addTag(string $name, ?string $value): void
/**
* @return mixed[]
*/
public function getTags(): array
{
return $this->tags;
}

/**
* @param mixed $value
*/
public function addTag(string $name, $value = null): void
{
$this->tags[$name] = $value;
}

/**
* @return string[]
* @param mixed[] $tags
*/
public function getTags(): array
public function addTags(array $tags): void
{
return $this->tags;
foreach ($tags as $name => $value) {
$this->addTag($name, $value);
}
}

}
17 changes: 10 additions & 7 deletions src/Schema/Builder/Controller/Method.php
Expand Up @@ -20,7 +20,7 @@ final class Method
/** @var string[] */
private $methods = [];

/** @var string[] */
/** @var mixed[] */
private $tags = [];

/** @var string[] */
Expand Down Expand Up @@ -110,25 +110,28 @@ public function addMethods(array $methods): void
}

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

public function addTag(string $tag): void
/**
* @param mixed $value
*/
public function addTag(string $name, $value = null): void
{
$this->tags[] = $tag;
$this->tags[$name] = $value;
}

/**
* @param string[] $tags
* @param mixed[] $tags
*/
public function addTags(array $tags): void
{
foreach ($tags as $tag) {
$this->addTag($tag);
foreach ($tags as $name => $value) {
$this->addTag($name, $value);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/Schema/Endpoint.php
Expand Up @@ -212,18 +212,18 @@ public function getTags(): array
*/
public function getTag(string $name)
{
return $this->hasTag($name) ? $this->tags[$name] : null;
return $this->tags[$name] ?? null;
}

public function hasTag(string $name): bool
{
return array_key_exists($name, $this->tags);
return isset($this->tags[$name]);
}

/**
* @param mixed $value
*/
public function addTag(string $name, $value): void
public function addTag(string $name, $value = null): void
{
$this->tags[$name] = $value;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Schema/Serialization/ArrayHydrator.php
Expand Up @@ -102,7 +102,7 @@ protected function hydrateEndpoint(array $data): Endpoint

if (isset($data['responseMapper'])) {
$responseMapper = new EndpointResponseMapper();
$responseMapper->setEntity($data['requestMapper']['entity']);
$responseMapper->setEntity($data['responseMapper']['entity']);
$endpoint->setResponseMapper($responseMapper);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Schema/Serialization/ArraySerializator.php
Expand Up @@ -129,7 +129,7 @@ protected function serializePattern(array &$endpoint, Controller $controller, Me

// Duplication check
if (isset($maskParameters[$variableName])) {
throw new InvalidStateException(sprintf(sprintf('Duplicate mask parameter "%s" in path "%s"', $variableName, $endpoint['mask'])));
throw new InvalidStateException(sprintf('Duplicate mask parameter "%s" in path "%s"', $variableName, $endpoint['mask']));
}

// Build parameter pattern
Expand Down
150 changes: 149 additions & 1 deletion tests/cases/Schema/Serialization/ArrayHydrator.phpt
Expand Up @@ -6,12 +6,160 @@

require_once __DIR__ . '/../../../bootstrap.php';

use Apitte\Core\Schema\Endpoint;
use Apitte\Core\Schema\EndpointParameter;
use Apitte\Core\Schema\Serialization\ArrayHydrator;
use Contributte\Psr7\Psr7Response;
use Tester\Assert;

// AddMethod: success
test(function (): void {
$hydrator = new ArrayHydrator();

Assert::same(true, true);
$data = [
[
'handler' => ['class' => 'c1-class', 'method' => 'm2', 'arguments' => []],
'id' => null,
'tags' => ['c1-t1' => 'c1-t1-value'],
'methods' => ['GET', 'POST', 'PUT'],
'mask' => '/group1-path/group2-path/c1-path/m2-path',
'description' => null,
'parameters' => [],
'negotiations' => [],
'attributes' => ['pattern' => '/group1-path/group2-path/c1-path/m2-path'],
'requestMapper' => [
'entity' => 'An\\Class\\Which\\Implements\\Apitte\\Core\\Mapping\\Request\\IRequestEntity',
'validation' => true,
],
'responseMapper' => [
'entity' => 'An\\Class\\Which\\Implements\\Apitte\\Core\\Mapping\\Response\\IResponseEntity',
],
],
[
'handler' => [
'class' => 'c1-class',
'method' => 'm3',
'arguments' => ['m3-a1' => 'Contributte\\Psr7\\Psr7Response'],
],
'id' => 'c1-group-id.c1-id.m3-id',
'tags' => ['c1-t1' => 'c1-t1-value', 'm3-t1' => null, 'm3-t2' => 'm3-t2-value'],
'methods' => ['GET', 'POST'],
'mask' => '/group1-path/group2-path/c1-path/m3-path/{m3-p1}',
'description' => 'm3-description',
'parameters' => [
'm3-p1' => [
'name' => 'm3-p1',
'type' => 'int',
'description' => 'm3-p1-desc',
'in' => 'path',
'required' => 1,
'allowEmpty' => 1,
'deprecated' => 1,
],
'm3-p2' => [
'name' => 'm3-p2',
'type' => 'string',
'description' => null,
'in' => 'query',
'required' => 1,
'allowEmpty' => 0,
'deprecated' => 0,
],
],
'negotiations' => [
[
'suffix' => 'json',
'default' => true,
'renderer' => 'A\\Middleware\\Implementing\\Class',
],
['suffix' => 'xml', 'default' => true, 'renderer' => null],
],
'attributes' => [
'pattern' => '/group1-path/group2-path/c1-path/m3-path/(?P<m3-p1>[^/]+)',
],
],
];

$schema = $hydrator->hydrate($data);

$endpoints = $schema->getEndpoints();
Assert::count(2, $endpoints);

// Endpoint 1
$endpoint1 = $endpoints[0];
Assert::same([Endpoint::METHOD_GET, Endpoint::METHOD_POST, Endpoint::METHOD_PUT], $endpoint1->getMethods());
Assert::same('/group1-path/group2-path/c1-path/m2-path', $endpoint1->getMask());
Assert::same('/group1-path/group2-path/c1-path/m2-path', $endpoint1->getAttribute('pattern'));
Assert::same(null, $endpoint1->getAttribute('missing'));
Assert::same('#/group1-path/group2-path/c1-path/m2-path$/?\z#A', $endpoint1->getPattern());
Assert::same(null, $endpoint1->getDescription());
Assert::same([], $endpoint1->getParameters());
Assert::same([], $endpoint1->getNegotiations());

$requestMapper1 = $endpoint1->getRequestMapper();
Assert::same('An\Class\Which\Implements\Apitte\Core\Mapping\Request\IRequestEntity', $requestMapper1->getEntity());
Assert::same(true, $requestMapper1->isValidation());

$responseMapper1 = $endpoint1->getResponseMapper();
Assert::same('An\\Class\\Which\\Implements\\Apitte\\Core\\Mapping\\Response\\IResponseEntity', $responseMapper1->getEntity());

Assert::same(['c1-t1' => 'c1-t1-value'], $endpoint1->getTags());
Assert::same('c1-t1-value', $endpoint1->getTag('c1-t1'));

$handler1 = $endpoint1->getHandler();
Assert::same('c1-class', $handler1->getClass());
Assert::same('m2', $handler1->getMethod());
Assert::same([], $handler1->getArguments());

// Endpoint 2
$endpoint2 = $endpoints[1];
Assert::same([Endpoint::METHOD_GET, Endpoint::METHOD_POST], $endpoint2->getMethods());
Assert::same('/group1-path/group2-path/c1-path/m3-path/{m3-p1}', $endpoint2->getMask());
Assert::same('/group1-path/group2-path/c1-path/m3-path/(?P<m3-p1>[^/]+)', $endpoint2->getAttribute('pattern'));
Assert::same(null, $endpoint2->getAttribute('missing'));
Assert::same('#/group1-path/group2-path/c1-path/m3-path/(?P<m3-p1>[^/]+)(?:json|xml)?$/?\z#A', $endpoint2->getPattern());
Assert::same('m3-description', $endpoint2->getDescription());

Assert::same(null, $endpoint2->getRequestMapper());
Assert::same(null, $endpoint2->getResponseMapper());

Assert::same(['c1-t1' => 'c1-t1-value', 'm3-t1' => null, 'm3-t2' => 'm3-t2-value', 'id' => 'c1-group-id.c1-id.m3-id'], $endpoint2->getTags());
Assert::same('c1-t1-value', $endpoint2->getTag('c1-t1'));

$handler2 = $endpoint2->getHandler();
Assert::same('c1-class', $handler2->getClass());
Assert::same('m3', $handler2->getMethod());
Assert::same(['m3-a1' => Psr7Response::class], $handler2->getArguments());

$parameters2 = $endpoint2->getParameters();
Assert::count(2, $parameters2);
Assert::same(EndpointParameter::IN_PATH, $parameters2['m3-p1']->getIn());
Assert::same(EndpointParameter::TYPE_INTEGER, $parameters2['m3-p1']->getType());
Assert::same('m3-p1', $parameters2['m3-p1']->getName());
Assert::same('m3-p1-desc', $parameters2['m3-p1']->getDescription());
Assert::same(true, $parameters2['m3-p1']->isAllowEmpty());
Assert::same(true, $parameters2['m3-p1']->isDeprecated());
Assert::same(true, $parameters2['m3-p1']->isRequired());

Assert::same(EndpointParameter::IN_QUERY, $parameters2['m3-p2']->getIn());
Assert::same(EndpointParameter::TYPE_STRING, $parameters2['m3-p2']->getType());
Assert::same('m3-p2', $parameters2['m3-p2']->getName());
Assert::same(null, $parameters2['m3-p2']->getDescription());
Assert::same(false, $parameters2['m3-p2']->isAllowEmpty());
Assert::same(false, $parameters2['m3-p2']->isDeprecated());
Assert::same(true, $parameters2['m3-p2']->isRequired());

$parameters2inPath = $endpoint2->getParametersByIn(EndpointParameter::IN_PATH);
Assert::count(1, $parameters2inPath);
Assert::same('m3-p1', $parameters2inPath['m3-p1']->getName());

$negotiations2 = $endpoint2->getNegotiations();
Assert::count(2, $negotiations2);
Assert::same('A\Middleware\Implementing\Class', $negotiations2[0]->getRenderer());
Assert::same('json', $negotiations2[0]->getSuffix());
Assert::same(true, $negotiations2[0]->isDefault());

Assert::same(null, $negotiations2[1]->getRenderer());
Assert::same('xml', $negotiations2[1]->getSuffix());
Assert::same(true, $negotiations2[1]->isDefault());
});

0 comments on commit 8217944

Please sign in to comment.