Skip to content

Commit

Permalink
Strict schema and schema validations
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar authored and Milan Felix Šulc committed Aug 23, 2018
1 parent 373c780 commit 7eb28cd
Show file tree
Hide file tree
Showing 33 changed files with 840 additions and 250 deletions.
8 changes: 3 additions & 5 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ includes:

parameters:
ignoreErrors:
# phpstan bug
- '#^Parameter \#1 \$function of function call_user_func_array expects callable, array\<int, object\|string\> given.$#'

# Missing strict comparison
- '#^Construct empty\(\) is not allowed. Use more strict comparison.$#'
- '#^Only booleans are allowed in#'
- '#string|null given.$#'

# Magic access
- '#^Access to private property \$previous of parent class Exception.$#'

# Shoudl not happen - $method and $class are just missing in __construct
- '#^Cannot call method getMethod\(\) on Apitte\\Core\\Schema\\EndpointHandler\|null.$#'
- '#^Cannot call method getClass\(\) on Apitte\\Core\\Schema\\EndpointHandler\|null.$#'

# There is no apitte/negotiation dependency
- '#^Return typehint of method Apitte\\Core\\Http\\ApiResponse::getEntity\(\) has invalid type Apitte\\Negotiation\\Http\\AbstractEntity.$#'
- '#^Parameter \$entity of method Apitte\\Core\\Http\\ApiResponse::withEntity\(\) has invalid typehint type Apitte\\Negotiation\\Http\\AbstractEntity.$#'
Expand Down
15 changes: 4 additions & 11 deletions src/DI/Loader/DoctrineAnnotationLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,7 @@ protected function parseControllerMethodsAnnotations(Controller $controller, Cla
if (get_class($annotation) === RequestParameters::class) {
/** @var RequestParameters $annotation */
foreach ($annotation->getParameters() as $p) {
$parameter = $schemaMethod->addParameter($p->getName());
$parameter->setType($p->getType());
$parameter = $schemaMethod->addParameter($p->getName(), $p->getType());
$parameter->setDescription($p->getDescription());
$parameter->setIn($p->getIn());
$parameter->setRequired($p->isRequired());
Expand All @@ -263,8 +262,7 @@ protected function parseControllerMethodsAnnotations(Controller $controller, Cla
if (get_class($annotation) === Negotiations::class) {
/** @var Negotiations $annotation */
foreach ($annotation->getNegotiations() as $n) {
$negotiation = $schemaMethod->addNegotiation();
$negotiation->setSuffix($n->getSuffix());
$negotiation = $schemaMethod->addNegotiation($n->getSuffix());
$negotiation->setDefault($n->isDefault());
$negotiation->setRenderer($n->getRenderer());
}
Expand All @@ -274,19 +272,14 @@ protected function parseControllerMethodsAnnotations(Controller $controller, Cla
// Parse @RequestMapper ====================
if (get_class($annotation) === RequestMapper::class) {
/** @var RequestMapper $annotation */
$schemaMethod->setRequestMapper([
'entity' => $annotation->getEntity(),
'validation' => $annotation->isValidation(),
]);
$schemaMethod->setRequestMapper($annotation->getEntity(), $annotation->isValidation());
continue;
}

// Parse @ResponseMapper ===================
if (get_class($annotation) === ResponseMapper::class) {
/** @var ResponseMapper $annotation */
$schemaMethod->setResponseMapper([
'entity' => $annotation->getEntity(),
]);
$schemaMethod->setResponseMapper($annotation->getEntity());
continue;
}
}
Expand Down
26 changes: 17 additions & 9 deletions src/DI/Plugin/CoreSchemaPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
use Apitte\Core\Schema\Validation\FullpathValidation;
use Apitte\Core\Schema\Validation\GroupPathValidation;
use Apitte\Core\Schema\Validation\IdValidation;
use Apitte\Core\Schema\Validation\NegotiationValidation;
use Apitte\Core\Schema\Validation\PathValidation;
use Apitte\Core\Schema\Validation\RequestMapperValidation;
use Apitte\Core\Schema\Validation\RequestParameterValidation;
use Apitte\Core\Schema\Validation\ResponseMapperValidation;
use Apitte\Core\Schema\Validator\SchemaBuilderValidator;

class CoreSchemaPlugin extends AbstractPlugin
Expand All @@ -27,11 +30,14 @@ class CoreSchemaPlugin extends AbstractPlugin
/** @var string[] */
public static $validations = [
'controllerPath' => ControllerPathValidation::class,
'groupPath' => GroupPathValidation::class,
'path' => PathValidation::class,
'fullPath' => FullpathValidation::class,
'groupPath' => GroupPathValidation::class,
'id' => IdValidation::class,
'negotiation' => NegotiationValidation::class,
'path' => PathValidation::class,
'requestMapper' => RequestMapperValidation::class,
'requestParameter' => RequestParameterValidation::class,
'responseMapper' => ResponseMapperValidation::class,
];

/** @var IDecorator[] */
Expand Down Expand Up @@ -85,9 +91,7 @@ protected function compileSchema(): array

// Convert schema to array (for DI)
$generator = new ArraySerializator();
$schema = $generator->serialize($builder);

return $schema;
return $generator->serialize($builder);
}

protected function loadSchema(SchemaBuilder $builder): SchemaBuilder
Expand All @@ -97,13 +101,17 @@ protected function loadSchema(SchemaBuilder $builder): SchemaBuilder
$loader = new DoctrineAnnotationLoader($this->getContainerBuilder());

return $loader->load($builder);
} elseif ($this->config['loader'] === 'neon') {
}

if ($this->config['loader'] === 'neon') {
throw new InvalidStateException('Not implemented');
} elseif ($this->config['loader'] === 'php') {
}

if ($this->config['loader'] === 'php') {
throw new InvalidStateException('Not implemented');
} else {
throw new InvalidStateException('Unknown loader type');
}

throw new InvalidStateException('Unknown loader type');
}

protected function validateSchema(SchemaBuilder $builder): SchemaBuilder
Expand Down
42 changes: 16 additions & 26 deletions src/Schema/Builder/Controller/Method.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Apitte\Core\Schema\Builder\Controller;

use Apitte\Core\Schema\EndpointParameter;

final class Method
{

Expand Down Expand Up @@ -32,11 +34,11 @@ final class Method
/** @var MethodNegotiation[] */
private $negotiations = [];

/** @var mixed[] */
private $requestMapper = [];
/** @var RequestMapper|null */
private $requestMapper;

/** @var mixed[] */
private $responseMapper = [];
/** @var ResponseMapper|null */
private $responseMapper;

public function __construct(string $name)
{
Expand Down Expand Up @@ -161,9 +163,9 @@ public function getArguments(): array
/**
* @internal
*/
public function addParameter(string $name): MethodParameter
public function addParameter(string $name, string $type = EndpointParameter::TYPE_SCALAR): MethodParameter
{
$parameter = new MethodParameter($name);
$parameter = new MethodParameter($name, $type);
$this->parameters[$name] = $parameter;

return $parameter;
Expand All @@ -182,9 +184,9 @@ public function getParameters(): array
return $this->parameters;
}

public function addNegotiation(): MethodNegotiation
public function addNegotiation(string $suffix): MethodNegotiation
{
$negotiation = new MethodNegotiation();
$negotiation = new MethodNegotiation($suffix);
$this->negotiations[] = $negotiation;

return $negotiation;
Expand All @@ -198,36 +200,24 @@ public function getNegotiations(): array
return $this->negotiations;
}

/**
* @return mixed[]
*/
public function getRequestMapper(): array
public function getRequestMapper(): ?RequestMapper
{
return $this->requestMapper;
}

/**
* @param mixed[] $requestMapper
*/
public function setRequestMapper(array $requestMapper): void
public function setRequestMapper(string $entity, bool $validation = true): void
{
$this->requestMapper = $requestMapper;
$this->requestMapper = new RequestMapper($entity, $validation);
}

/**
* @return mixed[]
*/
public function getResponseMapper(): array
public function getResponseMapper(): ?ResponseMapper
{
return $this->responseMapper;
}

/**
* @param mixed[] $responseMapper
*/
public function setResponseMapper(array $responseMapper): void
public function setResponseMapper(string $entity): void
{
$this->responseMapper = $responseMapper;
$this->responseMapper = new ResponseMapper($entity);
}

}
10 changes: 5 additions & 5 deletions src/Schema/Builder/Controller/MethodNegotiation.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
final class MethodNegotiation
{

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

/** @var bool */
Expand All @@ -14,14 +14,14 @@ final class MethodNegotiation
/** @var string|null */
private $renderer;

public function getSuffix(): ?string
public function __construct(string $suffix)
{
return $this->suffix;
$this->suffix = $suffix;
}

public function setSuffix(?string $suffix): void
public function getSuffix(): string
{
$this->suffix = $suffix;
return $this->suffix;
}

public function isDefault(): bool
Expand Down
13 changes: 4 additions & 9 deletions src/Schema/Builder/Controller/MethodParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ final class MethodParameter
/** @var string */
private $name;

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

/** @var string|null */
Expand All @@ -28,26 +28,22 @@ final class MethodParameter
/** @var bool */
private $allowEmpty = false;

public function __construct(string $name)
public function __construct(string $name, string $type = EndpointParameter::TYPE_SCALAR)
{
$this->name = $name;
$this->type = $type;
}

public function getName(): string
{
return $this->name;
}

public function getType(): ?string
public function getType(): string
{
return $this->type;
}

public function setType(?string $type): void
{
$this->type = $type;
}

public function getDescription(): ?string
{
return $this->description;
Expand All @@ -65,7 +61,6 @@ public function getIn(): string

public function setIn(string $in): void
{
// @todo validation
$this->in = $in;
}

Expand Down
30 changes: 30 additions & 0 deletions src/Schema/Builder/Controller/RequestMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php declare(strict_types = 1);

namespace Apitte\Core\Schema\Builder\Controller;

class RequestMapper
{

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

/** @var bool */
private $validation;

public function __construct(string $entity, bool $validation = true)
{
$this->entity = $entity;
$this->validation = $validation;
}

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

public function isValidation(): bool
{
return $this->validation;
}

}
21 changes: 21 additions & 0 deletions src/Schema/Builder/Controller/ResponseMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php declare(strict_types = 1);

namespace Apitte\Core\Schema\Builder\Controller;

class ResponseMapper
{

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

public function __construct(string $entity)
{
$this->entity = $entity;
}

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

}
14 changes: 7 additions & 7 deletions src/Schema/Endpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ final class Endpoint
/** @var string|null */
private $pattern;

/** @var EndpointHandler|null */
/** @var EndpointHandler */
private $handler;

/** @var string|null */
Expand All @@ -62,6 +62,11 @@ final class Endpoint
/** @var mixed[] */
private $metadata = [];

public function __construct(EndpointHandler $handler)
{
$this->handler = $handler;
}

/**
* @return string[]
*/
Expand Down Expand Up @@ -120,16 +125,11 @@ public function setPattern(?string $pattern): void
$this->pattern = $pattern;
}

public function getHandler(): ?EndpointHandler
public function getHandler(): EndpointHandler
{
return $this->handler;
}

public function setHandler(?EndpointHandler $handler): void
{
$this->handler = $handler;
}

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

0 comments on commit 7eb28cd

Please sign in to comment.