Implemented Validation for controllers
This commit is contained in:
parent
508695efb2
commit
7414f9b23d
|
@ -25,6 +25,7 @@ return [
|
||||||
\Engelsystem\Middleware\RouteDispatcherServiceProvider::class,
|
\Engelsystem\Middleware\RouteDispatcherServiceProvider::class,
|
||||||
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
||||||
\Engelsystem\Middleware\SessionHandlerServiceProvider::class,
|
\Engelsystem\Middleware\SessionHandlerServiceProvider::class,
|
||||||
|
\Engelsystem\Http\Validation\ValidationServiceProvider::class,
|
||||||
|
|
||||||
// Additional services
|
// Additional services
|
||||||
\Engelsystem\Mail\MailerServiceProvider::class,
|
\Engelsystem\Mail\MailerServiceProvider::class,
|
||||||
|
|
|
@ -2,8 +2,12 @@
|
||||||
|
|
||||||
namespace Engelsystem\Controllers;
|
namespace Engelsystem\Controllers;
|
||||||
|
|
||||||
|
use Engelsystem\Http\Validation\ValidatesRequest;
|
||||||
|
|
||||||
abstract class BaseController
|
abstract class BaseController
|
||||||
{
|
{
|
||||||
|
use ValidatesRequest;
|
||||||
|
|
||||||
/** @var string[]|string[][] A list of Permissions required to access the controller or certain pages */
|
/** @var string[]|string[][] A list of Permissions required to access the controller or certain pages */
|
||||||
protected $permissions = [];
|
protected $permissions = [];
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Http\Exceptions;
|
||||||
|
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use RuntimeException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ValidationException extends RuntimeException
|
||||||
|
{
|
||||||
|
/** @var Validator */
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Validator $validator
|
||||||
|
* @param string $message
|
||||||
|
* @param int $code
|
||||||
|
* @param Throwable|null $previous
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Validator $validator,
|
||||||
|
string $message = '',
|
||||||
|
int $code = 0,
|
||||||
|
Throwable $previous = null
|
||||||
|
) {
|
||||||
|
$this->validator = $validator;
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Validator
|
||||||
|
*/
|
||||||
|
public function getValidator(): Validator
|
||||||
|
{
|
||||||
|
return $this->validator;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Http\Validation;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
class Validates
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function accepted($value): bool
|
||||||
|
{
|
||||||
|
return in_array($value, ['true', '1', 'y', 'yes', 'on', 1, true], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
* @param array $parameters ['min', 'max']
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function between($value, $parameters): bool
|
||||||
|
{
|
||||||
|
$this->validateParameterCount(2, $parameters, __FUNCTION__);
|
||||||
|
$size = $this->getSize($value);
|
||||||
|
|
||||||
|
return $size >= $parameters[0] && $size <= $parameters[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function bool($value): bool
|
||||||
|
{
|
||||||
|
return in_array($value, ['1', 1, true, '0', 0, false], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters ['1,2,3,56,7']
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function in($value, $parameters): bool
|
||||||
|
{
|
||||||
|
$this->validateParameterCount(1, $parameters, __FUNCTION__);
|
||||||
|
|
||||||
|
return in_array($value, explode(',', $parameters[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function int($value): bool
|
||||||
|
{
|
||||||
|
return filter_var($value, FILTER_VALIDATE_INT) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
* @param array $parameters ['max']
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function max($value, $parameters): bool
|
||||||
|
{
|
||||||
|
$this->validateParameterCount(1, $parameters, __FUNCTION__);
|
||||||
|
$size = $this->getSize($value);
|
||||||
|
|
||||||
|
return $size <= $parameters[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
* @param array $parameters ['min']
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function min($value, $parameters)
|
||||||
|
{
|
||||||
|
$this->validateParameterCount(1, $parameters, __FUNCTION__);
|
||||||
|
$size = $this->getSize($value);
|
||||||
|
|
||||||
|
return $size >= $parameters[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters ['1,2,3,56,7']
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function notIn($value, $parameters): bool
|
||||||
|
{
|
||||||
|
$this->validateParameterCount(1, $parameters, __FUNCTION__);
|
||||||
|
|
||||||
|
return !$this->in($value, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function numeric($value): bool
|
||||||
|
{
|
||||||
|
return is_numeric($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function required($value): bool
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
is_null($value)
|
||||||
|
|| (is_string($value) && trim($value) === '')
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
* @return int|float
|
||||||
|
*/
|
||||||
|
protected function getSize($value)
|
||||||
|
{
|
||||||
|
if (is_numeric($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mb_strlen($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $count
|
||||||
|
* @param array $parameters
|
||||||
|
* @param string $rule
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected function validateParameterCount(int $count, array $parameters, string $rule)
|
||||||
|
{
|
||||||
|
if (count($parameters) < $count) {
|
||||||
|
throw new InvalidArgumentException(sprintf(
|
||||||
|
'The rule "%s" requires at least %d parameters',
|
||||||
|
$rule,
|
||||||
|
$count
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Http\Validation;
|
||||||
|
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
|
||||||
|
trait ValidatesRequest
|
||||||
|
{
|
||||||
|
/** @var Validator */
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param array $rules
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function validate(Request $request, array $rules)
|
||||||
|
{
|
||||||
|
if (!$this->validator->validate(
|
||||||
|
(array)$request->getParsedBody(),
|
||||||
|
$rules
|
||||||
|
)) {
|
||||||
|
throw new ValidationException($this->validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->validator->getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function setValidator(Validator $validator)
|
||||||
|
{
|
||||||
|
$this->validator = $validator;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Http\Validation;
|
||||||
|
|
||||||
|
use Engelsystem\Application;
|
||||||
|
use Engelsystem\Container\ServiceProvider;
|
||||||
|
use Engelsystem\Controllers\BaseController;
|
||||||
|
|
||||||
|
class ValidationServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
$validates = $this->app->make(Validates::class);
|
||||||
|
$this->app->instance(Validates::class, $validates);
|
||||||
|
|
||||||
|
$validator = $this->app->make(Validator::class);
|
||||||
|
$this->app->instance(Validator::class, $validator);
|
||||||
|
$this->app->instance('validator', $validator);
|
||||||
|
|
||||||
|
$this->app->afterResolving(function ($object, Application $app) {
|
||||||
|
if (!$object instanceof BaseController) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$object->setValidator($app->get(Validator::class));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Http\Validation;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
class Validator
|
||||||
|
{
|
||||||
|
/** @var Validates */
|
||||||
|
protected $validate;
|
||||||
|
|
||||||
|
/** @var string[] */
|
||||||
|
protected $errors = [];
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Validates $validate
|
||||||
|
*/
|
||||||
|
public function __construct(Validates $validate)
|
||||||
|
{
|
||||||
|
$this->validate = $validate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @param array $rules
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function validate($data, $rules)
|
||||||
|
{
|
||||||
|
$this->errors = [];
|
||||||
|
$this->data = [];
|
||||||
|
|
||||||
|
foreach ($rules as $key => $values) {
|
||||||
|
foreach (explode('|', $values) as $parameters) {
|
||||||
|
$parameters = explode(':', $parameters);
|
||||||
|
$rule = array_shift($parameters);
|
||||||
|
$rule = Str::camel($rule);
|
||||||
|
|
||||||
|
if (!method_exists($this->validate, $rule)) {
|
||||||
|
throw new InvalidArgumentException('Unknown validation rule: ' . $rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = isset($data[$key]) ? $data[$key] : null;
|
||||||
|
if (!$this->validate->{$rule}($value, $parameters, $data)) {
|
||||||
|
$this->errors[$key][] = implode('.', ['validation', $key, $rule]);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->data[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return empty($this->errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getData(): array
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getErrors(): array
|
||||||
|
{
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,8 @@
|
||||||
namespace Engelsystem\Middleware;
|
namespace Engelsystem\Middleware;
|
||||||
|
|
||||||
use Engelsystem\Http\Exceptions\HttpException;
|
use Engelsystem\Http\Exceptions\HttpException;
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
use Engelsystem\Http\Response;
|
use Engelsystem\Http\Response;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
@ -43,6 +45,21 @@ class ErrorHandler implements MiddlewareInterface
|
||||||
$response = $handler->handle($request);
|
$response = $handler->handle($request);
|
||||||
} catch (HttpException $e) {
|
} catch (HttpException $e) {
|
||||||
$response = $this->createResponse($e->getMessage(), $e->getStatusCode(), $e->getHeaders());
|
$response = $this->createResponse($e->getMessage(), $e->getStatusCode(), $e->getHeaders());
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$response = $this->createResponse('', 302, ['Location' => $this->getPreviousUrl($request)]);
|
||||||
|
|
||||||
|
if ($request instanceof Request) {
|
||||||
|
$session = $request->getSession();
|
||||||
|
$session->set(
|
||||||
|
'errors',
|
||||||
|
array_merge_recursive(
|
||||||
|
$session->get('errors', []),
|
||||||
|
['validation' => $e->getValidator()->getErrors()]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$session->set('form-data', $request->request->all());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$statusCode = $response->getStatusCode();
|
$statusCode = $response->getStatusCode();
|
||||||
|
@ -106,4 +123,17 @@ class ErrorHandler implements MiddlewareInterface
|
||||||
{
|
{
|
||||||
return response($content, $status, $headers);
|
return response($content, $status, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ServerRequestInterface $request
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getPreviousUrl(ServerRequestInterface $request)
|
||||||
|
{
|
||||||
|
if ($header = $request->getHeader('referer')) {
|
||||||
|
return array_pop($header);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '/';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,5 +21,7 @@ class BaseControllerTest extends TestCase
|
||||||
'dolor',
|
'dolor',
|
||||||
],
|
],
|
||||||
], $controller->getPermissions());
|
], $controller->getPermissions());
|
||||||
|
|
||||||
|
$this->assertTrue(method_exists($controller, 'setValidator'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Http\Exceptions;
|
||||||
|
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ValidationExceptionTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Exceptions\ValidationException::__construct
|
||||||
|
* @covers \Engelsystem\Http\Exceptions\ValidationException::getValidator
|
||||||
|
*/
|
||||||
|
public function testConstruct()
|
||||||
|
{
|
||||||
|
/** @var Validator|MockObject $validator */
|
||||||
|
$validator = $this->createMock(Validator::class);
|
||||||
|
|
||||||
|
$exception = new ValidationException($validator);
|
||||||
|
|
||||||
|
$this->assertEquals($validator, $exception->getValidator());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Http\Validation\Stub;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\BaseController;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
|
||||||
|
class ValidatesRequestImplementation extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param array $rules
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function validateData(Request $request, array $rules)
|
||||||
|
{
|
||||||
|
return $this->validate($request, $rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasValidator()
|
||||||
|
{
|
||||||
|
return !is_null($this->validator);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Http\Validation;
|
||||||
|
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use Engelsystem\Test\Unit\Http\Validation\Stub\ValidatesRequestImplementation;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ValidatesRequestTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\ValidatesRequest::validate
|
||||||
|
* @covers \Engelsystem\Http\Validation\ValidatesRequest::setValidator
|
||||||
|
*/
|
||||||
|
public function testValidate()
|
||||||
|
{
|
||||||
|
/** @var Validator|MockObject $validator */
|
||||||
|
$validator = $this->createMock(Validator::class);
|
||||||
|
$validator->expects($this->exactly(2))
|
||||||
|
->method('validate')
|
||||||
|
->withConsecutive(
|
||||||
|
[['foo' => 'bar'], ['foo' => 'required']],
|
||||||
|
[[], ['foo' => 'required']]
|
||||||
|
)
|
||||||
|
->willReturnOnConsecutiveCalls(
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$validator->expects($this->once())
|
||||||
|
->method('getData')
|
||||||
|
->willReturn(['foo' => 'bar']);
|
||||||
|
|
||||||
|
$implementation = new ValidatesRequestImplementation();
|
||||||
|
$implementation->setValidator($validator);
|
||||||
|
|
||||||
|
$return = $implementation->validateData(new Request([], ['foo' => 'bar']), ['foo' => 'required']);
|
||||||
|
|
||||||
|
$this->assertEquals(['foo' => 'bar'], $return);
|
||||||
|
|
||||||
|
$this->expectException(ValidationException::class);
|
||||||
|
$implementation->validateData(new Request([], []), ['foo' => 'required']);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,308 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Http\Validation;
|
||||||
|
|
||||||
|
use Engelsystem\Http\Validation\Validates;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ValidatesTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideAccepted()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['true'],
|
||||||
|
['1'],
|
||||||
|
['y'],
|
||||||
|
['yes'],
|
||||||
|
['on'],
|
||||||
|
['1test', false],
|
||||||
|
['false', false],
|
||||||
|
['no', false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::accepted
|
||||||
|
* @param mixed $value
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideAccepted
|
||||||
|
*/
|
||||||
|
public function testAccepted($value, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->accepted($value) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideBetween()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['42', [10, 100]],
|
||||||
|
[42.5, [42, 43]],
|
||||||
|
[42, [42, 1000]],
|
||||||
|
[1337, [0, 99], false],
|
||||||
|
[-17, [32, 45], false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::between
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideBetween
|
||||||
|
*/
|
||||||
|
public function testBetween($value, array $parameters, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->between($value, $parameters) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideBool()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['1'],
|
||||||
|
[1],
|
||||||
|
[true],
|
||||||
|
['0'],
|
||||||
|
[0],
|
||||||
|
[false],
|
||||||
|
['true', false],
|
||||||
|
['false', false],
|
||||||
|
['yes', false],
|
||||||
|
['no', false],
|
||||||
|
['bool', false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::bool
|
||||||
|
* @param mixed $value
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideBool
|
||||||
|
*/
|
||||||
|
public function testBool($value, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->bool($value) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideIn()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['lorem', ['lorem,ipsum,dolor']],
|
||||||
|
[99, ['66,77,88,99,111']],
|
||||||
|
[4, ['1,3,5,7'], false],
|
||||||
|
['toggle', ['on,off'], false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::in
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideIn
|
||||||
|
*/
|
||||||
|
public function testIn($value, array $parameters, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->in($value, $parameters) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideInt()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['1337'],
|
||||||
|
[42],
|
||||||
|
['0'],
|
||||||
|
[false, false],
|
||||||
|
['12asd1', false],
|
||||||
|
['one', false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::int
|
||||||
|
* @param mixed $value
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideInt
|
||||||
|
*/
|
||||||
|
public function testInt($value, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->int($value) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideMax()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['99', [100]],
|
||||||
|
[-42, [1024]],
|
||||||
|
[99, [99]],
|
||||||
|
[100, [10], false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::max
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideMax
|
||||||
|
*/
|
||||||
|
public function testMax($value, array $parameters, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->max($value, $parameters) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideMin()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[32, [0]],
|
||||||
|
[7, [7]],
|
||||||
|
['99', [10]],
|
||||||
|
[3, [42], false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::min
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideMin
|
||||||
|
*/
|
||||||
|
public function testMin($value, array $parameters, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->min($value, $parameters) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideNotIn()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[77, ['50,60,70']],
|
||||||
|
['test', ['coding,deployment']],
|
||||||
|
['PHP', ['Java,PHP,bash'], false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::notIn
|
||||||
|
* @param mixed $value
|
||||||
|
* @param array $parameters
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideNotIn
|
||||||
|
*/
|
||||||
|
public function testNotIn($value, array $parameters, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->notIn($value, $parameters) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideNumeric()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[77],
|
||||||
|
['42'],
|
||||||
|
['1337e0'],
|
||||||
|
['123f00', false],
|
||||||
|
[null, false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::numeric
|
||||||
|
* @param mixed $value
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideNumeric
|
||||||
|
*/
|
||||||
|
public function testNumeric($value, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->numeric($value) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideRequired()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Lorem ipsum'],
|
||||||
|
['1234'],
|
||||||
|
[1234],
|
||||||
|
['0'],
|
||||||
|
[0],
|
||||||
|
['', false],
|
||||||
|
[' ', false],
|
||||||
|
[null, false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::required
|
||||||
|
* @param mixed $value
|
||||||
|
* @param bool $result
|
||||||
|
* @dataProvider provideRequired
|
||||||
|
*/
|
||||||
|
public function testRequired($value, bool $result = true)
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->required($value) === $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::getSize
|
||||||
|
*/
|
||||||
|
public function testGetSize()
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->max(42, [999]));
|
||||||
|
$this->assertTrue($val->max('99', [100]));
|
||||||
|
$this->assertFalse($val->max('101', [100]));
|
||||||
|
$this->assertTrue($val->max('lorem', [5]));
|
||||||
|
$this->assertFalse($val->max('Lorem Ipsum', [5]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validates::validateParameterCount
|
||||||
|
*/
|
||||||
|
public function testValidateParameterCount()
|
||||||
|
{
|
||||||
|
$val = new Validates;
|
||||||
|
$this->assertTrue($val->between(42, [1, 100]));
|
||||||
|
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$val->between(42, [1]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Http\Validation;
|
||||||
|
|
||||||
|
use Engelsystem\Application;
|
||||||
|
use Engelsystem\Http\Validation\ValidationServiceProvider;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use Engelsystem\Test\Unit\Http\Validation\Stub\ValidatesRequestImplementation;
|
||||||
|
use Engelsystem\Test\Unit\ServiceProviderTest;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class ValidationServiceProviderTest extends ServiceProviderTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\ValidationServiceProvider::register
|
||||||
|
*/
|
||||||
|
public function testRegister()
|
||||||
|
{
|
||||||
|
$app = new Application();
|
||||||
|
|
||||||
|
$serviceProvider = new ValidationServiceProvider($app);
|
||||||
|
$serviceProvider->register();
|
||||||
|
|
||||||
|
$this->assertTrue($app->has(Validator::class));
|
||||||
|
$this->assertTrue($app->has('validator'));
|
||||||
|
|
||||||
|
/** @var ValidatesRequestImplementation $validatesRequest */
|
||||||
|
$validatesRequest = $app->make(ValidatesRequestImplementation::class);
|
||||||
|
$this->assertTrue($validatesRequest->hasValidator());
|
||||||
|
|
||||||
|
// Test afterResolving early return
|
||||||
|
$app->make(stdClass::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Http\Validation;
|
||||||
|
|
||||||
|
use Engelsystem\Http\Validation\Validates;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ValidatorTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validator::__construct
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validator::validate
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validator::getData
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validator::getErrors
|
||||||
|
*/
|
||||||
|
public function testValidate()
|
||||||
|
{
|
||||||
|
$val = new Validator(new Validates);
|
||||||
|
$this->assertTrue($val->validate(
|
||||||
|
['foo' => 'bar', 'lorem' => 'on'],
|
||||||
|
['foo' => 'required|not_in:lorem,ipsum,dolor', 'lorem' => 'accepted']
|
||||||
|
));
|
||||||
|
$this->assertEquals(['foo' => 'bar', 'lorem' => 'on'], $val->getData());
|
||||||
|
|
||||||
|
$this->assertFalse($val->validate(
|
||||||
|
[],
|
||||||
|
['lorem' => 'required|min:3']
|
||||||
|
));
|
||||||
|
$this->assertEquals(
|
||||||
|
['lorem' => ['validation.lorem.required', 'validation.lorem.min']],
|
||||||
|
$val->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Http\Validation\Validator::validate
|
||||||
|
*/
|
||||||
|
public function testValidateNotImplemented()
|
||||||
|
{
|
||||||
|
$val = new Validator(new Validates);
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
|
||||||
|
$val->validate(
|
||||||
|
['lorem' => 'bar'],
|
||||||
|
['foo' => 'never_implemented']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,14 +2,23 @@
|
||||||
|
|
||||||
namespace Engelsystem\Test\Unit\Middleware;
|
namespace Engelsystem\Test\Unit\Middleware;
|
||||||
|
|
||||||
|
use Engelsystem\Application;
|
||||||
use Engelsystem\Http\Exceptions\HttpException;
|
use Engelsystem\Http\Exceptions\HttpException;
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Psr7ServiceProvider;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
use Engelsystem\Http\Response;
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Http\ResponseServiceProvider;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
use Engelsystem\Middleware\ErrorHandler;
|
use Engelsystem\Middleware\ErrorHandler;
|
||||||
use Engelsystem\Test\Unit\Middleware\Stub\ReturnResponseMiddlewareHandler;
|
use Engelsystem\Test\Unit\Middleware\Stub\ReturnResponseMiddlewareHandler;
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Session;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||||
use Twig_LoaderInterface as TwigLoader;
|
use Twig_LoaderInterface as TwigLoader;
|
||||||
|
|
||||||
class ErrorHandlerTest extends TestCase
|
class ErrorHandlerTest extends TestCase
|
||||||
|
@ -104,7 +113,7 @@ class ErrorHandlerTest extends TestCase
|
||||||
/**
|
/**
|
||||||
* @covers \Engelsystem\Middleware\ErrorHandler::process
|
* @covers \Engelsystem\Middleware\ErrorHandler::process
|
||||||
*/
|
*/
|
||||||
public function testProcessException()
|
public function testProcessHttpException()
|
||||||
{
|
{
|
||||||
/** @var ServerRequestInterface|MockObject $request */
|
/** @var ServerRequestInterface|MockObject $request */
|
||||||
$request = $this->createMock(ServerRequestInterface::class);
|
$request = $this->createMock(ServerRequestInterface::class);
|
||||||
|
@ -144,6 +153,63 @@ class ErrorHandlerTest extends TestCase
|
||||||
$this->assertEquals($psrResponse, $return);
|
$this->assertEquals($psrResponse, $return);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Middleware\ErrorHandler::process
|
||||||
|
* @covers \Engelsystem\Middleware\ErrorHandler::getPreviousUrl
|
||||||
|
*/
|
||||||
|
public function testProcessValidationException()
|
||||||
|
{
|
||||||
|
/** @var TwigLoader|MockObject $twigLoader */
|
||||||
|
$twigLoader = $this->createMock(TwigLoader::class);
|
||||||
|
$handler = $this->getMockForAbstractClass(RequestHandlerInterface::class);
|
||||||
|
$validator = $this->createMock(Validator::class);
|
||||||
|
|
||||||
|
$handler->expects($this->exactly(2))
|
||||||
|
->method('handle')
|
||||||
|
->willReturnCallback(function () use ($validator) {
|
||||||
|
throw new ValidationException($validator);
|
||||||
|
});
|
||||||
|
|
||||||
|
$validator->expects($this->exactly(2))
|
||||||
|
->method('getErrors')
|
||||||
|
->willReturn(['foo' => ['validation.foo.numeric']]);
|
||||||
|
|
||||||
|
$session = new Session(new MockArraySessionStorage());
|
||||||
|
$session->set('errors', ['validation' => ['foo' => ['validation.foo.required']]]);
|
||||||
|
$request = Request::create('/foo/bar', 'POST', ['foo' => 'bar']);
|
||||||
|
$request->setSession($session);
|
||||||
|
|
||||||
|
/** @var Application $app */
|
||||||
|
$app = app();
|
||||||
|
(new ResponseServiceProvider($app))->register();
|
||||||
|
(new Psr7ServiceProvider($app))->register();
|
||||||
|
|
||||||
|
$errorHandler = new ErrorHandler($twigLoader);
|
||||||
|
|
||||||
|
$return = $errorHandler->process($request, $handler);
|
||||||
|
|
||||||
|
$this->assertEquals(302, $return->getStatusCode());
|
||||||
|
$this->assertEquals('/', $return->getHeaderLine('location'));
|
||||||
|
$this->assertEquals([
|
||||||
|
'errors' => [
|
||||||
|
'validation' => [
|
||||||
|
'foo' => [
|
||||||
|
'validation.foo.required',
|
||||||
|
'validation.foo.numeric',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'form-data' => [
|
||||||
|
'foo' => 'bar',
|
||||||
|
],
|
||||||
|
], $session->all());
|
||||||
|
|
||||||
|
$request = $request->withAddedHeader('referer', '/foo/batz');
|
||||||
|
$return = $errorHandler->process($request, $handler);
|
||||||
|
|
||||||
|
$this->assertEquals('/foo/batz', $return->getHeaderLine('location'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers \Engelsystem\Middleware\ErrorHandler::process
|
* @covers \Engelsystem\Middleware\ErrorHandler::process
|
||||||
*/
|
*/
|
||||||
|
@ -153,7 +219,7 @@ class ErrorHandlerTest extends TestCase
|
||||||
$request = $this->createMock(ServerRequestInterface::class);
|
$request = $this->createMock(ServerRequestInterface::class);
|
||||||
/** @var TwigLoader|MockObject $twigLoader */
|
/** @var TwigLoader|MockObject $twigLoader */
|
||||||
$twigLoader = $this->createMock(TwigLoader::class);
|
$twigLoader = $this->createMock(TwigLoader::class);
|
||||||
$response = new Response('<!DOCTYPE html><html><body><h1>Hi!</h1></body></html>', 500);
|
$response = new Response('<!DOCTYPE html><html lang="en"><body><h1>Hi!</h1></body></html>', 500);
|
||||||
$returnResponseHandler = new ReturnResponseMiddlewareHandler($response);
|
$returnResponseHandler = new ReturnResponseMiddlewareHandler($response);
|
||||||
|
|
||||||
/** @var ErrorHandler|MockObject $errorHandler */
|
/** @var ErrorHandler|MockObject $errorHandler */
|
||||||
|
|
Loading…
Reference in New Issue