front-controller (#17)
continuous-integration/drone/push Build is passing Details

I did the FRONT CONTROLLERRRRR. (Salva version lol)

# When you create a new controller
When you create a new controller, define the path to call it here (image 1).
Don't forget to associate a controller with a role.

# The action's main method
The main method have to return a `ViewHttpResponse`.

If you create a new action, please make sure that the action's main method have the same name than the action (image 2 and 3) and to make the main method public.

Co-authored-by: DahmaneYanis <dahmane.yanis.2004@gmail.com>
Co-authored-by: d_yanis <dahmane.yanis.2004@gmail.com>
Co-authored-by: Override-6 <maximebatista18@gmail.com>
Reviewed-on: #17
Co-authored-by: Yanis DAHMANE-BOUNOUA <yanis.dahmane-bounoua@etu.uca.fr>
Co-committed-by: Yanis DAHMANE-BOUNOUA <yanis.dahmane-bounoua@etu.uca.fr>
pull/20/head
Yanis DAHMANE-BOUNOUA 1 year ago committed by Maxime BATISTA
parent 9333288705
commit 5d4bb84368

@ -35,7 +35,7 @@ class ViewHttpResponse extends HttpResponse {
- arguments: array
- kind: int
+ __construct(kind: int, file: string, arguments: array, code: int = HttpCodes::OK)
- __construct(kind: int, file: string, arguments: array, code: int = HttpCodes::OK)
+ getViewKind(): int
+ getFile(): string
+ getArguments(): array

@ -0,0 +1,8 @@
@startuml
class FrontController {
- router : AltoRouter
}
@enduml

@ -4,83 +4,10 @@ require "../vendor/autoload.php";
require "../config.php";
require "../sql/database.php";
require "utils.php";
require "../src/react-display.php";
use App\Connexion;
use App\Controller\EditorController;
use App\Controller\SampleFormController;
use App\Gateway\FormResultGateway;
use App\Gateway\TacticInfoGateway;
use App\Http\JsonHttpResponse;
use App\Http\ViewHttpResponse;
use App\Model\TacticModel;
use Twig\Loader\FilesystemLoader;
use App\Gateway\AuthGateway;
use App\Controller\AuthController;
use App\Validation\ValidationFail;
use App\Controller\ErrorController;
use App\Controller\VisualizerController;
$loader = new FilesystemLoader('../src/Views/');
$twig = new \Twig\Environment($loader);
use App\Controller\FrontController;
$basePath = get_public_path();
$con = new Connexion(get_database());
// routes initialization
$router = new AltoRouter();
$router->setBasePath($basePath);
$sampleFormController = new SampleFormController(new FormResultGateway($con));
$authGateway = new AuthGateway($con);
$authController = new \App\Controller\AuthController(new \App\Model\AuthModel($authGateway));
$editorController = new EditorController(new TacticModel(new TacticInfoGateway($con)));
$visualizerController = new VisualizerController(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());
$router->map("POST", "/submit-twig", fn() => $sampleFormController->submitFormTwig($_POST));
$router->map("GET", "/register", fn() => $authController->displayRegister());
$router->map("POST", "/register", fn() => $authController->confirmRegister($_POST));
$router->map("GET", "/login", fn() => $authController->displayLogin());
$router->map("POST", "/login", fn() => $authController->confirmLogin($_POST));
$router->map("GET", "/tactic/new", fn() => $editorController->makeNew());
$router->map("GET", "/tactic/[i:id]/edit", fn(int $id) => $editorController->openEditorFor($id));
$router->map("GET", "/tactic/[i:id]", fn(int $id) => $visualizerController->openVisualizer($id));
$match = $router->match();
if ($match == null) {
http_response_code(404);
ErrorController::displayFailures([ValidationFail::notFound("Cette page n'existe pas")], $twig);
return;
}
$response = call_user_func_array($match['target'], $match['params']);
http_response_code($response->getCode());
if ($response instanceof ViewHttpResponse) {
$file = $response->getFile();
$args = $response->getArguments();
switch ($response->getViewKind()) {
case ViewHttpResponse::REACT_VIEW:
send_react_front($file, $args);
break;
case ViewHttpResponse::TWIG_VIEW:
try {
$twig->display($file, $args);
} catch (\Twig\Error\RuntimeError|\Twig\Error\SyntaxError $e) {
http_response_code(500);
echo "There was an error rendering your view, please refer to an administrator.\nlogs date: " . date("YYYD, d M Y H:i:s");
throw $e;
}
break;
}
} elseif ($response instanceof JsonHttpResponse) {
header('Content-type: application/json');
echo $response->getJson();
}
$frontController = new FrontController($basePath);
$frontController->run();

@ -2,9 +2,10 @@
namespace App\Controller;
use App\Connexion;
use App\Data\TacticInfo;
use App\Gateway\TacticInfoGateway;
use App\Http\HttpCodes;
use App\Http\HttpRequest;
use App\Http\HttpResponse;
use App\Http\JsonHttpResponse;
use App\Http\ViewHttpResponse;
@ -13,18 +14,15 @@ use App\Model\TacticModel;
class EditorController {
private TacticModel $model;
/**
* @param TacticModel $model
*/
public function __construct(TacticModel $model) {
$this->model = $model;
public function __construct() {
$this->model = new TacticModel(new TacticInfoGateway(new Connexion(get_database())));
}
private function openEditor(TacticInfo $tactic): HttpResponse {
return ViewHttpResponse::react("views/Editor.tsx", ["name" => $tactic->getName(), "id" => $tactic->getId()]);
}
public function makeNew(): HttpResponse {
public function create(): HttpResponse {
$tactic = $this->model->makeNewDefault();
return $this->openEditor($tactic);
}
@ -34,7 +32,7 @@ class EditorController {
* @param int $id the targeted tactic identifier
* @return HttpResponse
*/
public function openEditorFor(int $id): HttpResponse {
public function edit(int $id): HttpResponse {
$tactic = $this->model->get($id);
if ($tactic == null) {

@ -0,0 +1,162 @@
<?php
namespace App\Controller;
use AltoRouter;
use App\Http\HttpCodes;
use App\Http\HttpResponse;
use App\Http\JsonHttpResponse;
use App\Http\ViewHttpResponse;
use Exception;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Loader\FilesystemLoader;
class FrontController {
private AltoRouter $router;
public function __construct(string $basePath) {
$this->router = $this->createRouter($basePath);
$this->initializeRouterMap();
}
/**
* Main behavior of the FrontController
*
* @return void
*/
public function run(): void {
$match = $this->router->match();
if ($match != null) {
$this->handleMatch($match);
} else {
$this->displayViewByKind(ViewHttpResponse::twig("error.html.twig", [], HttpCodes::NOT_FOUND));
}
}
/**
* Create a new instance of an AltoRouter
*
* @param string $basePath
* @return AltoRouter
*/
public function createRouter(string $basePath): AltoRouter {
$router = new AltoRouter();
$router->setBasePath($basePath);
return $router;
}
/**
* Initialize project's routes
*
* @return void
*/
private function initializeRouterMap(): void {
$this->router->map("GET", "/", "UserController");
$this->router->map("GET", "/[a:action]?", "UserController");
$this->router->map("GET", "/tactic/[a:action]/[i:idTactic]?", "EditorController");
}
/**
* @param array<string, mixed> $match
* @return void
*/
private function handleMatch(array $match): void {
$tag = $match['target'];
$action = $this->getAction($match);
$params = $match["params"];
unset($params['action']);
$this->handleResponseByType($this->tryToCall($tag, $action, array_values($params)));
}
/**
* @param string $controller
* @param string $action
* @param array<int, mixed> $params
* @return HttpResponse
*/
private function tryToCall(string $controller, string $action, array $params): HttpResponse {
$controller = $this->getController($controller);
try {
if (is_callable([$controller, $action])) {
return call_user_func_array([$controller, $action], $params);
} else {
return ViewHttpResponse::twig("error.html.twig", [], HttpCodes::NOT_FOUND);
}
} catch (Exception $e) {
return ViewHttpResponse::twig("error.html.twig", [], HttpCodes::NOT_FOUND);
}
}
/**
* Get the right method to call to do an action
*
* @param array<string, mixed> $match
* @return string
*/
private function getAction(array $match): string {
if (isset($match["params"]["action"])) {
return $match["params"]["action"];
}
return "default";
}
/**
* Initialize the right controller by the user's role
*
* @param string $controller
* @return mixed
*/
private function getController(string $controller) {
$namespace = "\\App\\Controller\\";
$controller = $namespace . $controller;
return new $controller();
}
/**
* Redirect the return by the response's type
*
* @param HttpResponse $response
* @return void
*/
private function handleResponseByType(HttpResponse $response): void {
http_response_code($response->getCode());
if ($response instanceof ViewHttpResponse) {
$this->displayViewByKind($response);
} elseif ($response instanceof JsonHttpResponse) {
header('Content-type: application/json');
echo $response->getJson();
}
}
/**
* Use the right method to display the response
*
* @param ViewHttpResponse $response
* @return void
*/
private function displayViewByKind(ViewHttpResponse $response): void {
$file = $response->getFile();
$args = $response->getArguments();
switch ($response->getViewKind()) {
case ViewHttpResponse::REACT_VIEW:
send_react_front($file, $args);
break;
case ViewHttpResponse::TWIG_VIEW:
try {
$loader = new FilesystemLoader('../src/Views/');
$twig = new Environment($loader);
$twig->display($file, $args);
} catch (RuntimeError|SyntaxError|LoaderError $e) {
http_response_code(500);
echo "There was an error rendering your view, please refer to an administrator.\nlogs date: " . date("YYYD, d M Y H:i:s");
throw $e;
}
break;
}
}
}

@ -0,0 +1,16 @@
<?php
namespace App\Controller;
use App\Http\HttpResponse;
use App\Http\ViewHttpResponse;
class UserController {
public function home(): HttpResponse {
return ViewHttpResponse::twig("home.twig", []);
}
public function default(): HttpResponse {
return self::home();
}
}

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Page Home à faire</h1>
</body>
</html>
Loading…
Cancel
Save