From 4aa2bde233017142da9910e12c8a7d992ace4739 Mon Sep 17 00:00:00 2001 From: Vivien DUFOUR Date: Tue, 14 Nov 2023 15:37:42 +0100 Subject: [PATCH] error-view (#10) Add an error view Co-authored-by: vivien.dufour Co-authored-by: vidufour1 Reviewed-on: https://codefirst.iut.uca.fr/git/IQBall/Application-Web/pulls/10 --- public/index.php | 6 ++- src/Controller/Control.php | 21 ++++++--- src/Controller/ErrorController.php | 20 +++++++++ src/Controller/SampleFormController.php | 4 +- src/Validation/FieldValidationFail.php | 2 +- src/Validation/Validation.php | 2 +- src/Validation/Validators.php | 8 ++-- src/Views/error.html.twig | 57 +++++++++++++++++++++++++ 8 files changed, 105 insertions(+), 15 deletions(-) create mode 100644 src/Controller/ErrorController.php create mode 100644 src/Views/error.html.twig diff --git a/public/index.php b/public/index.php index caa8a2e..ba9d7c0 100644 --- a/public/index.php +++ b/public/index.php @@ -14,6 +14,8 @@ use App\Http\JsonHttpResponse; use App\Http\ViewHttpResponse; use App\Model\TacticModel; use Twig\Loader\FilesystemLoader; +use App\Validation\ValidationFail; +use App\Controller\ErrorController; $loader = new FilesystemLoader('../src/Views/'); @@ -29,6 +31,7 @@ $router->setBasePath($basePath); $sampleFormController = new SampleFormController(new FormResultGateway($con), $twig); $editorController = new EditorController(new TacticModel(new TacticInfoGateway($con))); + $router->map("GET", "/", fn() => $sampleFormController->displayFormReact()); $router->map("POST", "/submit", fn() => $sampleFormController->submitFormReact($_POST)); $router->map("GET", "/twig", fn() => $sampleFormController->displayFormTwig()); @@ -39,9 +42,8 @@ $router->map("GET", "/tactic/[i:id]/edit", fn(int $id) => $editorController->ope $match = $router->match(); if ($match == null) { - // TODO redirect to a 404 not found page instead (issue #1) http_response_code(404); - echo "Page non trouvée"; + ErrorController::displayFailures([ValidationFail::notFound("Cette page n'existe pas")], $twig); return; } diff --git a/src/Controller/Control.php b/src/Controller/Control.php index 2aacb19..8c00d2e 100644 --- a/src/Controller/Control.php +++ b/src/Controller/Control.php @@ -6,6 +6,7 @@ use App\Http\HttpCodes; use App\Http\HttpRequest; use App\Http\HttpResponse; use App\Http\JsonHttpResponse; +use App\Http\ViewHttpResponse; use App\Validation\ValidationFail; class Control { @@ -17,14 +18,18 @@ class Control { * 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, bool $errorInJson): HttpResponse { $request_body = file_get_contents('php://input'); $payload_obj = json_decode($request_body); if (!$payload_obj instanceof \stdClass) { - return new JsonHttpResponse([new ValidationFail("bad-payload", "request body is not a valid json object"), HttpCodes::BAD_REQUEST]); + $fail = new ValidationFail("bad-payload", "request body is not a valid json object"); + if($errorInJson) { + return new JsonHttpResponse([$fail, HttpCodes::BAD_REQUEST]); + } + return ViewHttpResponse::twig("error.html.twig", ["failures" => [$fail]], HttpCodes::BAD_REQUEST); } $payload = get_object_vars($payload_obj); - return self::runCheckedFrom($payload, $schema, $run); + return self::runCheckedFrom($payload, $schema, $run, $errorInJson); } /** @@ -35,16 +40,22 @@ class Control { * 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, bool $errorInJson): HttpResponse { $fails = []; $request = HttpRequest::from($data, $fails, $schema); if (!empty($fails)) { - return new JsonHttpResponse($fails, HttpCodes::BAD_REQUEST); + if($errorInJson) { + return new JsonHttpResponse($fails, HttpCodes::BAD_REQUEST); + } + return ViewHttpResponse::twig("error.html.twig", ['failures' => $fails], HttpCodes::BAD_REQUEST); } return call_user_func_array($run, [$request]); } + + + } \ No newline at end of file diff --git a/src/Controller/ErrorController.php b/src/Controller/ErrorController.php new file mode 100644 index 0000000..e91d05f --- /dev/null +++ b/src/Controller/ErrorController.php @@ -0,0 +1,20 @@ +display("error.html.twig", ['failures' => $failures]); + } catch (LoaderError | RuntimeError | SyntaxError $e) { + echo "Twig error: $e"; + } + } +} diff --git a/src/Controller/SampleFormController.php b/src/Controller/SampleFormController.php index bbf1f59..4241ad4 100644 --- a/src/Controller/SampleFormController.php +++ b/src/Controller/SampleFormController.php @@ -32,14 +32,14 @@ class SampleFormController { private function submitForm(array $form, callable $response): HttpResponse { return Control::runCheckedFrom($form, [ - "name" => [Validators::lenBetween(0, 32), Validators::name()], + "name" => [Validators::lenBetween(0, 32), Validators::name("Le nom ne peut contenir que des lettres, des chiffres et des accents")], "description" => [Validators::lenBetween(0, 512)] ], function (HttpRequest $req) use ($response) { $description = htmlspecialchars($req["description"]); $this->gateway->insert($req["name"], $description); $results = ["results" => $this->gateway->listResults()]; return call_user_func_array($response, [$results]); - }); + }, false); } public function submitFormTwig(array $form): HttpResponse { diff --git a/src/Validation/FieldValidationFail.php b/src/Validation/FieldValidationFail.php index 404a497..5b535f7 100644 --- a/src/Validation/FieldValidationFail.php +++ b/src/Validation/FieldValidationFail.php @@ -14,7 +14,7 @@ class FieldValidationFail extends ValidationFail { * @param string $message */ public function __construct(string $fieldName, string $message) { - parent::__construct("field", $message); + parent::__construct("Champ invalide", $message); $this->fieldName = $fieldName; } diff --git a/src/Validation/Validation.php b/src/Validation/Validation.php index b797edc..4372380 100644 --- a/src/Validation/Validation.php +++ b/src/Validation/Validation.php @@ -20,7 +20,7 @@ class Validation { foreach ($validators as $validator) { $error = $validator->validate($valName, $val); if ($error != null) { - $failures[] = $error; + $failures = array_merge($failures, $error); $had_errors = true; } } diff --git a/src/Validation/Validators.php b/src/Validation/Validators.php index c9172b1..ea9da46 100644 --- a/src/Validation/Validators.php +++ b/src/Validation/Validators.php @@ -10,18 +10,18 @@ class Validators { /** * @return Validator a validator that validates a given regex */ - public static function regex(string $regex): Validator { + public static function regex(string $regex, string $msg = null): Validator { return new SimpleFunctionValidator( fn(string $str) => preg_match($regex, $str), - fn(string $name) => [new FieldValidationFail($name, "field does not validates pattern $regex")] + fn(string $name) => [new FieldValidationFail($name, $msg == null ? "field does not validates pattern $regex" : $msg)] ); } /** * @return Validator a validator that validates strings that only contains numbers, letters, accents letters, `-` and `_`. */ - public static function name(): Validator { - return self::regex("/^[0-9a-zA-Zà-üÀ-Ü_-]*$/"); + public static function name($msg = null): Validator { + return self::regex("/^[0-9a-zA-Zà-üÀ-Ü_-]*$/", $msg); } /** diff --git a/src/Views/error.html.twig b/src/Views/error.html.twig new file mode 100644 index 0000000..1d1db7d --- /dev/null +++ b/src/Views/error.html.twig @@ -0,0 +1,57 @@ + + + + + Error + + + + +

IQBall

+ + {% for fail in failures %} +

{{ fail.getKind() }} : {{ fail.getMessage() }}

+ {% endfor %} + + + + + + \ No newline at end of file