# Conception

## Organisation

Notre projet est divisé en plusieurs parties:

-   `src/API`, qui définit les classes qui implémentent les actions de l’api
-   `src/App`, qui définit les contrôleurs et les vues de l’application web
-   `src/Core`, définit les modèles, les classes métiers, les librairies internes (validation, http), les gateways, en somme, les élements logiques de l’application et les actions que l’ont peut faire avec.
-   `sql`, définit la base de donnée utilisée, et éxécute les fichiers sql lorsque la base de donnée n’est pas initialisée.
-   `profiles`, définit les profiles d’execution, voir `Documentation/how-to-dev.md` pour plus d’info
-   `front` contient le code front-end react/typescript
-   `ci` contient les scripts de déploiement et la définition du workflow d’intégration continue et de déploiement constant vers notre staging server ([maxou.dev/<branch>/public/](https://maxou.dev/IQBall/master/public)).
-   `public` point d’entrée, avec :
    -   `public/index.php` point d’entrée pour la webapp
    -   `public/api/index.php` point d’entrée pour l’api.

## Backend

### Validation et résilience des erreurs

#### Motivation

Un controlleur a pour but de valider les données d'une requête avant de les manipuler.

Nous nous sommes rendu compte que la vérification des données d'une requête était redondante, même en factorisant les différents
types de validation, nous devions quand même explicitement vérifier la présence des champs utilisés dans la requête.

```php
public function doPostAction(array $form) {
    $failures = [];
    $req = new HttpRequest($form);
    $email = $req['email'] ?? null;
    if ($email == null) {
        $failures[] = "Vous n'avez pas entré d'adresse email.";
        return;
    }
    if (Validation::isEmail($email)) {
        $failures[] = "Format d'adresse email invalide.";
    }
    if (Validation::isLenBetween($email, 6, 64))) {
        $failures[] = "L'adresse email doit être d'une longueur comprise entre 6 et 64 charactères.";
    }

    if (!empty($failures)) {
        return ViewHttpResponse::twig('error.html.twig', ['failures' => $failures]);
    }

    // traitement ...
}
```

Nous sommes obligés de tester à la main la présence des champs dans la requête, et nous avons une paire condition/erreur par type de validation,
ce qui, pour des requêtes avec plusieurs champs, peut vite devenir illisible si nous voulons être précis sur les erreurs.

Ici, une validation est une règle, un prédicat qui permet de valider une donnée sur un critère bien précis (injection html, adresse mail, longueur, etc.).  
Bien souvent, lorsque le prédicat échoue, un message est ajouté à la liste des erreurs rencontrés, mais ce message est souvent le même, ce qui rajoute en plus
de la redondance sur les messages d'erreurs choisis lorsqu'une validation échoue.

#### Schéma

Toutes ces lignes de code pour définir que notre requête doit contenir un champ nommé `email`, dont la valeur est une adresse mail, d'une longueur comprise entre 6 et 64.  
Nous avons donc trouvé l'idée de définir un système nous permettant de déclarer le schéma d'une requête,
et de reporter le plus d'erreurs possibles lorsqu'une requête ne valide pas le schéma :

```php
public function doPostAction(array $form): HttpResponse {
    $failures = [];
    $req = HttpRequest::from($form, $failures, [
        'email' => [DefaultValidators::email(), DefaultValidators::isLenBetween(6, 64)]
    ]);

    if (!empty($failures)) { //ou $req == null
        return ViewHttpResponse::twig('error.html.twig', ['failures' => $failures])
    }

    // traitement ...
}
```

Ce système nous permet de faire de la programmation _déclarative_, nous disons à _quoi_ ressemble la forme de la requête que l'on souhaite,
plustot que de définir _comment_ réagir face à notre requête.  
Ce système permet d'être beaucoup plus clair sur la forme attendue d'une requête, et de garder une lisibilité satisfaisante peu importe le nombre de
champs que celle-ci contient.

Nous pouvons ensuite emballer les erreurs de validation dans des `ValidationFail` et `FieldValidationFail`, ce qui permet ensuite d'obtenir
plus de précision sur une erreur, comme le nom du champ qui est invalidé, et qui permet ensuite à nos vues de pouvoir manipuler plus facilement
les erreurs et facilement entourer les champs invalides en rouge, ainsi que d'afficher toutes les erreurs que l'utilisateur a fait, d'un coup.

### HttpRequest, HttpResponse

Nous avons choisi d'encapsuler les requêtes et les réponses afin de faciliter leur manipulation.  
Cela permet de mieux repérer les endroits du code qui manipulent une requête d'un simple tableau,
et de garder à un seul endroit la responsabilitée d'écrire le contenu de la requête vers client.

`src/App` définit une `ViewHttpResponse`, qui permet aux controlleurs de retourner la vue qu'ils ont choisit.
C'est ensuite à la classe `src/App/App` d'afficher la réponse.

### index.php

Il y a deux points d'entrés, celui de la WebApp (`public/index.php`), et celui de l'API (`public/api/index.php`).  
Ces fichiers ont pour but de définir ce qui va être utilisé dans l'application, comme les routes, la base de donnée, les classes métiers utilisés,
comment gérer l'authentification dans le cadre de l'API, et une session dans le cadre de la web app.

L'index définit aussi quoi faire lorsque l'application retourne une réponse. Dans les implémentations actuelles, elle délègue simplement
l'affichage dans une classe (`IQBall\App\App` et `IQBall\API\API`).

### API

Nous avons définit une petite API (`src/Api`) pour nous permettre de faire des actions en arrière plan depuis le front end.  
Par exemple, l'API permet de changer le nom d'une tactique, ou de sauvegarder son contenu.  
C'est plus pratique de faire des requêtes en arrière-plan plustot que faire une requête directement à la partie WebApp, ce qui
aurait eu pour conséquences de recharger la page

## Frontend

### Utilisation de React

Notre application est une application de création et de visualisation de stratégies pour des match de basket.  
L’éditeur devra comporter un terrain sur lequel il est possible de placer et bouger des pions, représentant les joueurs.  
Une stratégie est un arbre composé de plusieurs étapes, une étape étant constituée d’un ensemble de joueurs et d’adversaires sur le terrain,
aillant leur position de départ, et leur position cible, avec des flèches représentant le type de mouvement (dribble, écran, etc) effectué.  
les enfants d’une étape, sont d’autres étapes en fonction des cas de figures (si tel joueur fait tel mouvement, ou si tel joueur fait telle passe etc).  
Pour rendre le tout agréable à utiliser, il faut que l’interface soit réactive : si l’on bouge un joueur,
il faut que les flèches qui y sont liés bougent aussi, il faut que les joueurs puissent bouger le long des flèches en mode visualiseur etc…

Le front-end de l’éditeur et du visualiseur étant assez ambitieux, et occupant une place importante du projet, nous avons décidés de l’effectuer en utilisant
le framework React qui rend simple le développement d’interfaces dynamiques, et d’utiliser typescript parce qu’ici on code bien et qu’on impose une type safety a notre code.
