Skip to content

Commit

Permalink
Validators: PathValidator validates @path with @method(s)
Browse files Browse the repository at this point in the history
  • Loading branch information
f3l1x committed Mar 14, 2017
1 parent 4c071d6 commit 896b501
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 17 deletions.
12 changes: 9 additions & 3 deletions src/Schema/Endpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@
final class Endpoint
{

/** @var array */
private static $allowed = [
// Methods
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
const METHOD_PUT = 'PUT';
const METHOD_DELETE = 'DELETE';
const METHOD_OPTION = 'OPTION';

const METHODS = [
'GET',
'POST',
'PUT',
Expand Down Expand Up @@ -58,7 +64,7 @@ public function addMethod($method)
{
$method = strtoupper($method);

if (!in_array($method, self::$allowed)) {
if (!in_array($method, self::METHODS)) {
throw new InvalidArgumentException(sprintf('Method %s is not allowed', $method));
}

Expand Down
37 changes: 23 additions & 14 deletions src/Schema/Validator/Impl/PathValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Contributte\Api\Exception\Logical\Validation\InvalidSchemaException;
use Contributte\Api\Schema\Builder\SchemaBuilder;
use Contributte\Api\Schema\Endpoint;
use Contributte\Api\Schema\Validator\IValidator;
use Contributte\Api\Utils\Regex;

Expand All @@ -25,7 +26,7 @@ public function validate(SchemaBuilder $builder)
* @param SchemaBuilder $builder
* @return void
*/
public function validateDuplicities(SchemaBuilder $builder)
protected function validateDuplicities(SchemaBuilder $builder)
{
$controllers = $builder->getControllers();
$paths = [];
Expand All @@ -34,23 +35,31 @@ public function validateDuplicities(SchemaBuilder $builder)
foreach ($controller->getMethods() as $method) {
// Init controller paths
if (!isset($paths[$controller->getClass()])) {
$paths[$controller->getClass()] = [];
$paths[$controller->getClass()] = [
Endpoint::METHOD_GET => [],
Endpoint::METHOD_POST => [],
Endpoint::METHOD_PUT => [],
Endpoint::METHOD_DELETE => [],
Endpoint::METHOD_OPTION => [],
];
}

// If this RootPath exists, throw an exception
if (array_key_exists($method->getPath(), $paths[$controller->getClass()])) {
throw new InvalidSchemaException(
sprintf(
'Duplicate @Path "%s" in %s at methods "%s()" and "%s()"',
$method->getPath(),
$controller->getClass(),
$method->getName(),
$paths[$controller->getClass()][$method->getPath()]
)
);
foreach ($method->getMethods() as $httpMethod) {
if (array_key_exists($method->getPath(), $paths[$controller->getClass()][$httpMethod])) {
throw new InvalidSchemaException(
sprintf(
'Duplicate @Path "%s" in %s at methods "%s()" and "%s()"',
$method->getPath(),
$controller->getClass(),
$method->getName(),
$paths[$controller->getClass()][$httpMethod][$method->getPath()]
)
);
}

$paths[$controller->getClass()][$httpMethod][$method->getPath()] = $method->getName();
}

$paths[$controller->getClass()][$method->getPath()] = $method->getName();
}
}
}
Expand Down
99 changes: 99 additions & 0 deletions tests/cases/unit/Schema/Validator/Impl/PathValidator.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

/**
* Test: Schema\Validator\Impl\PathValidator
*/

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

use Contributte\Api\Exception\Logical\ValidationException;
use Contributte\Api\Schema\Builder\SchemaBuilder;
use Contributte\Api\Schema\Validator\Impl\PathValidator;
use Tester\Assert;

// Validate: start slash
test(function () {
$builder = new SchemaBuilder();

$c1 = $builder->addController('c1');
$c1m1 = $c1->addMethod('foo');
$c1m1->setPath('foobar');

Assert::exception(function () use ($builder) {
$validator = new PathValidator();
$validator->validate($builder);
}, ValidationException::class, '@Path "foobar" in "c1::foo()" must starts with "/" (slash).');
});

// Validate: end slash
test(function () {
$builder = new SchemaBuilder();

$c1 = $builder->addController('c1');
$c1m1 = $c1->addMethod('foo');
$c1m1->setPath('/foobar/');

Assert::exception(function () use ($builder) {
$validator = new PathValidator();
$validator->validate($builder);
}, ValidationException::class, '@Path "/foobar/" in "c1::foo()" must not ends with "/" (slash).');
});

// Validate: duplicities
test(function () {
$builder = new SchemaBuilder();

$c1 = $builder->addController('c1');
$c1m1 = $c1->addMethod('foo1');
$c1m1->setPath('/foobar');
$c1m1->addMethod('GET');

$c1m2 = $c1->addMethod('foo2');
$c1m2->setPath('/foobar');
$c1m2->addMethod('GET');

Assert::exception(function () use ($builder) {
$validator = new PathValidator();
$validator->validate($builder);
}, ValidationException::class, 'Duplicate @Path "/foobar" in c1 at methods "foo2()" and "foo1()"');
});

// Validate: duplicities
test(function () {
$builder = new SchemaBuilder();

$c1 = $builder->addController('c1');
$c1m1 = $c1->addMethod('foo1');
$c1m1->setPath('/foobar');
$c1m1->setMethods(['GET', 'POST']);

$c1m2 = $c1->addMethod('foo2');
$c1m2->setPath('/foobar');
$c1m2->setMethods(['POST', 'PUT']);

Assert::exception(function () use ($builder) {
$validator = new PathValidator();
$validator->validate($builder);
}, ValidationException::class, 'Duplicate @Path "/foobar" in c1 at methods "foo2()" and "foo1()"');
});

// Validate: [NOT] duplicities
test(function () {
$builder = new SchemaBuilder();

$c1 = $builder->addController('c1');
$c1m1 = $c1->addMethod('foo1');
$c1m1->setPath('/foobar');
$c1m1->addMethod('GET');

$c1m2 = $c1->addMethod('foo2');
$c1m2->setPath('/foobar');
$c1m2->setMethods(['POST']);

try {
$validator = new PathValidator();
$validator->validate($builder);
} catch (Exception $e) {
Assert::fail('This is fail. Paths+Method are different.');
}
});

0 comments on commit 896b501

Please sign in to comment.