add diagrams, fix documentation
continuous-integration/drone/push Build is passing Details

pull/8/head
Override-6 1 year ago
parent a1910d1167
commit b08e761abb
Signed by untrusted user who does not match committer: maxime.batista
GPG Key ID: 8002CC4B4DD9ECA5

@ -0,0 +1,47 @@
@startuml
class HttpRequest implements ArrayAccess {
- data: array
+ __construct(data: array)
+ offsetExists(offset: mixed): bool
+ offsetGet(offset: mixed): mixed
+ offsetSet(offset: mixed, value: mixed)
+ offsetUnset(offset: mixed)
+ <u>from(request: array, fails: &array, schema: array): HttpRequest
+ <u>fromPayload(fails: &array, schema: array): HttpRequest
}
class HttpResponse {
- code: int
+ __construct(code: int)
+ getCode(): int
<u>fromCode(code: int): HttpResponse
}
class JsonHttpResponse extends HttpResponse {
- payload: mixed
+ __construct(payload: mixed, code: int = HttpCodes::OK)
+ getJson(): string
}
class ViewHttpResponse extends HttpResponse {
+ <u>TWIG_VIEW: int {frozen}
+ <u>REACT_VIEW: int {frozen}
- file: string
- arguments: array
- kind: int
+ __construct(kind: int, file: string, arguments: array, code: int = HttpCodes::OK)
+ getViewKind(): int
+ getFile(): string
+ getArguments(): array
+ <u>twig(file: string, arguments: array, code: int = HttpCodes::OK): ViewHttpResponse
+ <u>react(file: string, arguments: array, code: int = HttpCodes::OK): ViewHttpResponse
}
@enduml

@ -0,0 +1,59 @@
@startuml
abstract class Validator {
+ validate(name: string, val: mixed): array
+ then(other: Validator): Validator
}
class ComposedValidator extends Validator {
- first: Validator
- then: Validator
+ __construct(first: Validator, then: Validator)
validate(name: string, val: mixed): array
}
class SimpleFunctionValidator extends Validator {
- predicate: callable
- error_factory: callable
+ __construct(predicate: callable, errorsFactory: callable)
+ validate(name: string, val: mixed): array
}
class ValidationFail implements JsonSerialize {
- kind: string
- message: string
+ __construct(kind: string, message: string)
+ getMessage(): string
+ getKind(): string
+ jsonSerialize()
+ <u>notFound(message: string): ValidationFail
}
class FieldValidationFail extends ValidationFail {
- fieldName: string
+ __construct(fieldName: string, message: string)
+ getFieldName(): string
+ jsonSerialize()
+ <u>invalidChars(fieldName: string): FieldValidationFail
+ <u>empty(fieldName: string): FieldValidationFail
+ <u>missing(fieldName: string): FieldValidationFail
}
class Validation {
<u> + validate(val: mixed, valName: string, failures: &array, validators: Validator...): bool
}
class Validators {
+ <u>nonEmpty(): Validator
+ <u>shorterThan(limit: int): Validator
+ <u>userString(maxLen: int): Validator
}
@enduml

@ -3,10 +3,10 @@
namespace App\Controller\Api; namespace App\Controller\Api;
use App\Controller\Control; use App\Controller\Control;
use App\Http\HttpCodes;
use App\Http\HttpRequest; use App\Http\HttpRequest;
use App\Http\HttpResponse; use App\Http\HttpResponse;
use App\Http\JsonHttpResponse; use App\Http\JsonHttpResponse;
use App\HttpCodes;
use App\Model\TacticModel; use App\Model\TacticModel;
use App\Validation\Validators; use App\Validation\Validators;

@ -2,13 +2,20 @@
namespace App\Controller; namespace App\Controller;
use App\Http\HttpCodes;
use App\Http\HttpRequest; use App\Http\HttpRequest;
use App\Http\HttpResponse; use App\Http\HttpResponse;
use App\Http\JsonHttpResponse; use App\Http\JsonHttpResponse;
use App\HttpCodes;
class Control { class Control {
/**
* Runs given callback, if the request's json validates the given schema.
* @param array $schema an array of `fieldName => Validators` which represents the request object schema
* @param callable $run the callback to run if the request is valid according to the given schema.
* THe callback must accept an HttpRequest, and return an HttpResponse object.
* @return HttpResponse
*/
public static function runChecked(array $schema, callable $run): HttpResponse { public static function runChecked(array $schema, callable $run): HttpResponse {
$request_body = file_get_contents('php://input'); $request_body = file_get_contents('php://input');
$payload = get_object_vars(json_decode($request_body)); $payload = get_object_vars(json_decode($request_body));
@ -16,6 +23,14 @@ class Control {
return self::runCheckedFrom($payload, $schema, $run); return self::runCheckedFrom($payload, $schema, $run);
} }
/**
* Runs given callback, if the given request data array validates the given schema.
* @param array $data the request's data array.
* @param array $schema an array of `fieldName => Validators` which represents the request object schema
* @param callable $run the callback to run if the request is valid according to the given schema.
* THe callback must accept an HttpRequest, and return an HttpResponse object.
* @return HttpResponse
*/
public static function runCheckedFrom(array $data, array $schema, callable $run): HttpResponse { public static function runCheckedFrom(array $data, array $schema, callable $run): HttpResponse {
$fails = []; $fails = [];
$request = HttpRequest::from($data, $fails, $schema); $request = HttpRequest::from($data, $fails, $schema);

@ -3,10 +3,10 @@
namespace App\Controller; namespace App\Controller;
use App\Data\TacticInfo; use App\Data\TacticInfo;
use App\Http\HttpCodes;
use App\Http\HttpResponse; use App\Http\HttpResponse;
use App\Http\JsonHttpResponse; use App\Http\JsonHttpResponse;
use App\Http\ViewHttpResponse; use App\Http\ViewHttpResponse;
use App\HttpCodes;
use App\Model\TacticModel; use App\Model\TacticModel;
class EditorController { class EditorController {

@ -1,6 +1,6 @@
<?php <?php
namespace App; namespace App\Http;
/** /**
* Utility class to define constants of used http codes * Utility class to define constants of used http codes
@ -9,6 +9,5 @@ class HttpCodes {
public const OK = 200; public const OK = 200;
public const BAD_REQUEST = 400; public const BAD_REQUEST = 400;
public const NOT_FOUND = 404; public const NOT_FOUND = 404;
public const PRECONDITION_FAILED = 412;
} }

@ -39,12 +39,6 @@ class HttpRequest implements ArrayAccess {
return new HttpRequest($request); return new HttpRequest($request);
} }
public static function fromPayload(array &$fails, array $schema): ?HttpRequest {
$request_body = file_get_contents('php://input');
$data = json_decode($request_body);
return self::from($data, $fails, $schema);
}
public function offsetExists($offset): bool { public function offsetExists($offset): bool {
return isset($this->data[$offset]); return isset($this->data[$offset]);
} }

@ -2,10 +2,11 @@
namespace App\Http; namespace App\Http;
use App\HttpCodes;
class JsonHttpResponse extends HttpResponse { class JsonHttpResponse extends HttpResponse {
/**
* @var mixed Any JSON serializable value
*/
private $payload; private $payload;
/** /**
@ -16,8 +17,13 @@ class JsonHttpResponse extends HttpResponse {
$this->payload = $payload; $this->payload = $payload;
} }
public function getJson() { public function getJson(): string {
return json_encode($this->payload); $result = json_encode($this->payload);
if (!$result) {
throw new \RuntimeException("Given payload is not json encodable");
}
return $result;
} }
} }

@ -2,15 +2,22 @@
namespace App\Http; namespace App\Http;
use App\HttpCodes;
class ViewHttpResponse extends HttpResponse { class ViewHttpResponse extends HttpResponse {
public const TWIG_VIEW = 0; public const TWIG_VIEW = 0;
public const REACT_VIEW = 1; public const REACT_VIEW = 1;
/**
* @var string File path of the responded view
*/
private string $file; private string $file;
/**
* @var array View arguments
*/
private array $arguments; private array $arguments;
/**
* @var int Kind of view, see {@link self::TWIG_VIEW} and {@link self::REACT_VIEW}
*/
private int $kind; private int $kind;
/** /**
@ -38,10 +45,24 @@ class ViewHttpResponse extends HttpResponse {
return $this->arguments; return $this->arguments;
} }
/**
* Create a twig view response
* @param string $file
* @param array $arguments
* @param int $code
* @return ViewHttpResponse
*/
public static function twig(string $file, array $arguments, int $code = HttpCodes::OK): ViewHttpResponse { public static function twig(string $file, array $arguments, int $code = HttpCodes::OK): ViewHttpResponse {
return new ViewHttpResponse(self::TWIG_VIEW, $file, $arguments, $code); return new ViewHttpResponse(self::TWIG_VIEW, $file, $arguments, $code);
} }
/**
* Create a react view response
* @param string $file
* @param array $arguments
* @param int $code
* @return ViewHttpResponse
*/
public static function react(string $file, array $arguments, int $code = HttpCodes::OK): ViewHttpResponse { public static function react(string $file, array $arguments, int $code = HttpCodes::OK): ViewHttpResponse {
return new ViewHttpResponse(self::REACT_VIEW, $file, $arguments, $code); return new ViewHttpResponse(self::REACT_VIEW, $file, $arguments, $code);
} }

@ -8,20 +8,20 @@ namespace App\Validation;
class SimpleFunctionValidator extends Validator { class SimpleFunctionValidator extends Validator {
private $predicate; private $predicate;
private $error_factory; private $errorFactory;
/** /**
* @param callable $predicate a function predicate with signature: `(string) => bool`, to validate the given string * @param callable $predicate a function predicate with signature: `(string) => bool`, to validate the given string
* @param callable $errors_factory a factory function with signature `(string) => array` to emit failures when the predicate fails * @param callable $errorsFactory a factory function with signature `(string) => array` to emit failures when the predicate fails
*/ */
public function __construct(callable $predicate, callable $errors_factory) { public function __construct(callable $predicate, callable $errorsFactory) {
$this->predicate = $predicate; $this->predicate = $predicate;
$this->error_factory = $errors_factory; $this->errorFactory = $errorsFactory;
} }
public function validate(string $name, $val): array { public function validate(string $name, $val): array {
if (!call_user_func_array($this->predicate, [$val])) { if (!call_user_func_array($this->predicate, [$val])) {
return call_user_func_array($this->error_factory, [$name]); return call_user_func_array($this->errorFactory, [$name]);
} }
return []; return [];
} }

@ -10,15 +10,15 @@ class Validation {
/** /**
* Validate a value from validators, appending failures in the given errors array. * Validate a value from validators, appending failures in the given errors array.
* @param mixed $val the value to validate * @param mixed $val the value to validate
* @param string $val_name the name of the value * @param string $valName the name of the value
* @param array $failures array to push when a validator fails * @param array $failures array to push when a validator fails
* @param Validator ...$validators given validators * @param Validator ...$validators given validators
* @return bool true if any of the given validators did fail * @return bool true if any of the given validators did fail
*/ */
public static function validate($val, string $val_name, array &$failures, Validator...$validators): bool { public static function validate($val, string $valName, array &$failures, Validator...$validators): bool {
$had_errors = false; $had_errors = false;
foreach ($validators as $validator) { foreach ($validators as $validator) {
$error = $validator->validate($val_name, $val); $error = $validator->validate($valName, $val);
if ($error != null) { if ($error != null) {
$failures[] = $error; $failures[] = $error;
$had_errors = true; $had_errors = true;

@ -28,6 +28,4 @@ class Validators {
return self::nonEmpty()->then(self::shorterThan($maxLen)); return self::nonEmpty()->then(self::shorterThan($maxLen));
} }
} }
Loading…
Cancel
Save