diff --git a/Documentation/http.puml b/Documentation/http.puml new file mode 100644 index 0000000..b41135d --- /dev/null +++ b/Documentation/http.puml @@ -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) + + + from(request: array, fails: &array, schema: array): HttpRequest + + fromPayload(fails: &array, schema: array): HttpRequest +} + +class HttpResponse { + - code: int + + __construct(code: int) + + getCode(): int + + fromCode(code: int): HttpResponse +} + +class JsonHttpResponse extends HttpResponse { + - payload: mixed + + __construct(payload: mixed, code: int = HttpCodes::OK) + + getJson(): string +} + +class ViewHttpResponse extends HttpResponse { + + TWIG_VIEW: int {frozen} + + 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 + + + twig(file: string, arguments: array, code: int = HttpCodes::OK): ViewHttpResponse + + react(file: string, arguments: array, code: int = HttpCodes::OK): ViewHttpResponse +} + +@enduml \ No newline at end of file diff --git a/Documentation/validation.puml b/Documentation/validation.puml new file mode 100644 index 0000000..dd0cafe --- /dev/null +++ b/Documentation/validation.puml @@ -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() + + + notFound(message: string): ValidationFail +} + +class FieldValidationFail extends ValidationFail { + - fieldName: string + + __construct(fieldName: string, message: string) + + getFieldName(): string + + jsonSerialize() + + + invalidChars(fieldName: string): FieldValidationFail + + empty(fieldName: string): FieldValidationFail + + missing(fieldName: string): FieldValidationFail +} + + +class Validation { + + validate(val: mixed, valName: string, failures: &array, validators: Validator...): bool +} + +class Validators { + + nonEmpty(): Validator + + shorterThan(limit: int): Validator + + userString(maxLen: int): Validator +} + + +@enduml \ No newline at end of file diff --git a/src/Controller/Api/APITacticController.php b/src/Controller/Api/APITacticController.php index a1f7767..031c88e 100644 --- a/src/Controller/Api/APITacticController.php +++ b/src/Controller/Api/APITacticController.php @@ -3,10 +3,10 @@ namespace App\Controller\Api; use App\Controller\Control; +use App\Http\HttpCodes; use App\Http\HttpRequest; use App\Http\HttpResponse; use App\Http\JsonHttpResponse; -use App\HttpCodes; use App\Model\TacticModel; use App\Validation\Validators; diff --git a/src/Controller/Control.php b/src/Controller/Control.php index af1a38b..327a475 100644 --- a/src/Controller/Control.php +++ b/src/Controller/Control.php @@ -2,13 +2,20 @@ namespace App\Controller; +use App\Http\HttpCodes; use App\Http\HttpRequest; use App\Http\HttpResponse; use App\Http\JsonHttpResponse; -use App\HttpCodes; 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 { $request_body = file_get_contents('php://input'); $payload = get_object_vars(json_decode($request_body)); @@ -16,6 +23,14 @@ class Control { 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 { $fails = []; $request = HttpRequest::from($data, $fails, $schema); diff --git a/src/Controller/EditorController.php b/src/Controller/EditorController.php index cf71d9d..96b8125 100644 --- a/src/Controller/EditorController.php +++ b/src/Controller/EditorController.php @@ -3,10 +3,10 @@ namespace App\Controller; use App\Data\TacticInfo; +use App\Http\HttpCodes; use App\Http\HttpResponse; use App\Http\JsonHttpResponse; use App\Http\ViewHttpResponse; -use App\HttpCodes; use App\Model\TacticModel; class EditorController { diff --git a/src/HttpCodes.php b/src/Http/HttpCodes.php similarity index 75% rename from src/HttpCodes.php rename to src/Http/HttpCodes.php index 6bcfa5f..b41af8a 100644 --- a/src/HttpCodes.php +++ b/src/Http/HttpCodes.php @@ -1,6 +1,6 @@ data[$offset]); } diff --git a/src/Http/JsonHttpResponse.php b/src/Http/JsonHttpResponse.php index 1c30017..9d7423f 100644 --- a/src/Http/JsonHttpResponse.php +++ b/src/Http/JsonHttpResponse.php @@ -2,10 +2,11 @@ namespace App\Http; -use App\HttpCodes; - class JsonHttpResponse extends HttpResponse { + /** + * @var mixed Any JSON serializable value + */ private $payload; /** @@ -16,8 +17,13 @@ class JsonHttpResponse extends HttpResponse { $this->payload = $payload; } - public function getJson() { - return json_encode($this->payload); + public function getJson(): string { + $result = json_encode($this->payload); + if (!$result) { + throw new \RuntimeException("Given payload is not json encodable"); + } + + return $result; } } \ No newline at end of file diff --git a/src/Http/ViewHttpResponse.php b/src/Http/ViewHttpResponse.php index 6950559..0e92054 100644 --- a/src/Http/ViewHttpResponse.php +++ b/src/Http/ViewHttpResponse.php @@ -2,15 +2,22 @@ namespace App\Http; -use App\HttpCodes; - class ViewHttpResponse extends HttpResponse { public const TWIG_VIEW = 0; public const REACT_VIEW = 1; + /** + * @var string File path of the responded view + */ private string $file; + /** + * @var array View arguments + */ private array $arguments; + /** + * @var int Kind of view, see {@link self::TWIG_VIEW} and {@link self::REACT_VIEW} + */ private int $kind; /** @@ -38,10 +45,24 @@ class ViewHttpResponse extends HttpResponse { 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 { 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 { return new ViewHttpResponse(self::REACT_VIEW, $file, $arguments, $code); } diff --git a/src/Validation/SimpleFunctionValidator.php b/src/Validation/SimpleFunctionValidator.php index 101dfe6..079452d 100644 --- a/src/Validation/SimpleFunctionValidator.php +++ b/src/Validation/SimpleFunctionValidator.php @@ -8,20 +8,20 @@ namespace App\Validation; class SimpleFunctionValidator extends Validator { private $predicate; - private $error_factory; + private $errorFactory; /** * @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->error_factory = $errors_factory; + $this->errorFactory = $errorsFactory; } public function validate(string $name, $val): array { 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 []; } diff --git a/src/Validation/Validation.php b/src/Validation/Validation.php index 659c8b0..b797edc 100644 --- a/src/Validation/Validation.php +++ b/src/Validation/Validation.php @@ -10,15 +10,15 @@ class Validation { /** * Validate a value from validators, appending failures in the given errors array. * @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 Validator ...$validators given validators * @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; foreach ($validators as $validator) { - $error = $validator->validate($val_name, $val); + $error = $validator->validate($valName, $val); if ($error != null) { $failures[] = $error; $had_errors = true; diff --git a/src/Validation/Validators.php b/src/Validation/Validators.php index ebf0f80..11d8fbd 100644 --- a/src/Validation/Validators.php +++ b/src/Validation/Validators.php @@ -28,6 +28,4 @@ class Validators { return self::nonEmpty()->then(self::shorterThan($maxLen)); } -} - - +} \ No newline at end of file