Mini-projet PHP

L’objectif de cet atelier est de compléter le code source d’un site web :

  • codé en PHP objet

  • …​.et possédant une architecture MVC

Qu’est que l’architecture MVC ?[1]

L’utilisation de classes PHP permet délà d’aboutir à un code modulaire. L’utilisation d’une architecture MVC va, de surcroît, clairement séparer les différents composants d’une application web classique :

  • Les Modèles (→ le ‘M’ de MVC)

    Les modèles sont les éléments qui se chargent des échanges avec la base de données. On ne met pas de traitement dans ces fichiers, uniquement des requêtes (SQL).

  • Les Vues (→ le ‘V’ de MVC)

    Les vues contiennent uniquement le code HTML destiné à structurer les pages.

  • Les Contrôleurs (→ le ‘C’ de MVC)

    Les contrôleurs, pour leur part, contiennent toute l’intelligence de l’application, le traitement des données en vue de leur affichage, par exemple.

En plus, des ces élements, on va souvent en trouver un autre qu’on nomme parfois “Routeur” ou “Front Controller” qui est le point d’entrée de l’application, quelle que soit la page affichée. Il est systématiquement appelé, et envoie la demande au bon contrôleur. Il est chargé de trouver le bon chemin pour que l’utilisateur récupère la bonne page, d’où le nom de routeur.

On parvient alors au schéma récapitulatif suivant :

design pattern mvc

Mise en situation

On désire compléter le code d’une application — nommée "`Shareboard`" — permettant de partager au sein d’une communauté des liens vers des sites web (→ shares) que l’on juge intéressants.

Le code existant permet déjà :

  • d’ajouter, lister, mettre à jour, supprimer des entrées

  • d’enregistrer des utilisateurs

  • d’authentifier les utilisateurs enregistrés

Il utilise une architecture MVC à travers toute une série de classes PHP et s’appuie sur le framework CSS Bootstrap 4 link pour le rendu de ses pages web.

Les fonctionnalités supplémentaires que vous allez devoir coder sont celles consistant à :

  • permettre à l’utilisateur de préciser une catégorie pour le partage qu’il veut créer

  • ajouter — sous forme de graphiques — des métriques sur le nombre de partages publiés sur certaines périodes (ex. : sur 1 semaine, 1 mois, 1 année) de façon à évaluer la popularité du site web.

💻 Travail n° 1 Installation du code de base

  1. Se rendre, avec le navigateur web, sur le dépôt Github du projet oop-php-mvc link

  2. Télécharger l’archive du code que vous allez devoir étudier et compléter et la décompresser dans le répertoire racine de votre site web personnel (→ C:\Users\ <compte> \Documents\public_html)

  3. Depuis le panneau de contrôle XAMPP, lancer Apache et MySQL

  4. Depuis PHPMyAdmin (→ http://localhost/phpmyadmin/) , créer une base de données dbShareboard à laquelle vous assignerez un nouvel utilisateur db-admin (mot de passe : yesUcan) ayant tous les droits “Données” et “Structure” sur celle-ci.

  5. Suivre les instructions du fichier README.md de l’archive téléchargée pour configurer l’application via le fichier config.php et créer les tables nécessaires dans la base de données (→ tables “shares” et “users”)

  6. Accéder au site (→ http://localhost/~<compte>) pour vérifier son bon fonctionnement.

    Vous exécuterez notamment les actions suivantes :

    • création d’un compte sur le site

    • connexion/déconnexion du site

    • ajout d’un ou plusieurs “partages”

💻 Travail n° 2 Étude du code

L’analyse du code permet de déterminer le diagramme de classes UML de l’application :

shareboard class diagram

On peut également tirer du code les diagrammes de séquence UML pour :

  • l’affichage de la page d’accueil :

    shareboard seq diagram home
  • l’affichage de la page des partages puis l’ajout d’un nouveau partage :

    shareboard seq diagram shares

🎯 Travail à faire :

  1. Quel est le rôle du fichier .htaccess situé à la racine du site ?

    Donner les URLs “réelles” fournies à l’application web suite au traitement des requêtes émises par le navigateur pour chaque action du site par le fichier .htaccess : schéma, domaine, chemin, chaine de requête/paramètres (→ query string/parameters).

  2. Quel type de requête HTTP est utilisée pour transmettre à l’application les données d’authentification d’un utilisateur lors de sa connexion ?

    L’implémentation actuelle de la connexion d’un utilisateur vous semble-t-elle satisfaisante en terme de sécurité ?

  3. À partir des diagrammes de séquence donnés plus haut, reproduire dans MagicDraw le diagramme de séquence correspondant au “Login”

    Les diagrammes de séquences donnés plus haut ont été réalisés en ligne avec PlantUML link.

    Ce n’est pas un logiciel de modélisation comme l’outil “institutionnel” MagicDraw mais plutôt un logiciel de dessin.

    En utilisant une description textuelle des diagrammes UML (mais malheureusement pas SysML), il est, à mon goût, plus simple à utiliser que MagicDraw, surtout pour les diagrammes de séquence.

    Du fait de cette même description textuelle, le format PlantUML est, de plus, tout à fait adapté aux outils de gestion de version.

    Cependant, contrairement à MagicDraw, il ne permet pas le lien entre les différents diagrammes. Il faut parfois savoir rendre à César ce qui est à César ! 😉

    Pour vous faire une idée de la syntaxe PlantUML, on vous fournit :

💻 Travail n° 3 Modification du formulaire d’ajout de partage

On désire modifier le formulaire de saisie des informations pour un nouveau partage.

🎯 Travail à faire :

Modifier le code du site pour permettre à l’utilisateur d’attribuer une catégorie au partage qu’il est en train de créer à l’aide de boutons radio comme dans cet exemple issu de la documentation de Bootstrap 4 link.

bs4 radio example

Vous pourrez par exemple proposer les domaines correspondants aux pôles d’activités définis dans le référentiel du BTS CIEL :

  • Étude et Conception de réseaux

  • Exploitation et Maintenance des réseaux

  • Valorisation de la donnée / Cybersécurité

  • Autre

La liste des partages devra alors faire apparaître le domaine de chacun (sous forme de “badge” Bootstrap link par exemple).

Veiller à modifier aussi le code qui permet de modifier un partage de façon à pouvoir changer son domaine.

  • Cet ajout nécessite de modifier la structure de la tables shares dans la base de données pour y ajouter le domaine (sous la forme de texte ou, préférablement, sous forme d’une clé étrangère vers une entrée d’une table domains contenant l’ensemble des domaines possibles)

    dbshareboard schema
  • Lors de vos essais, sous serez sûrement amenés à réinitialiser les tables de la base de données. Or, du fait de l’auto-incrémentation de la clé primaire, celle-ci n’est pas affectée par la remise à 0.
    Pour la réinitialiser à 0 vous pouvez exécuter le code SQL suivant :

    Réinitialisation de la clé primaire de la table shares
    SET @num := 0;
    UPDATE shares SET id = @num := (@num+1);
    ALTER TABLE shares AUTO_INCREMENT =1;

💻 Travail n° 4 Métriques de popularité

On désire enfin ajouter une nouvelle page au site permettant de suivre l’évolution de la popularité du site à l’aide de graphes, un peu à la manière de ce qu’on peut voir sur un site comme Sourceforge

sourceforge insights
Statistiques de téléchargement de XAMPP sur Sourceforge

Vous devrez proposer à l’utilisateur des graphes montrant le nombre de partages publiés par jour, semaine et mois.

🎯 Travail à faire :

  1. Se renseigner sur l’utilisation de la librairie Charts.js link

  2. Ajouter un nouvel item “Insights” dans la barre de navigation

  3. Créer un nouveau Contrôleur, un nouveau Modèle et une nouvelle Vue pour afficher le nombre de partages créés sur 7 jours

  4. Améliorer le site pour permettre à l’utilisateur — comme dans la démo donnée ci-dessus — de sélectionner la période sur laquelle il désire visualiser les métriques (hebdomadaire, mensuelle, annuelle)

  • Si vous chargez la librairie Chart.jS via une balise <script>…​</script> vous devez utiliser la version UMD (Universal Module Definition) sous peine d’obtenir le message d’erreur “Uncaught ReferenceError: Chart is not defined”…​

    Cette version de Chart.js contient du code supplémentaire au début pour détecter la façon dont il est chargé et pour s’exécuter de manière appropriée.

  • La requête SQL permettant de récupérer le nombre de partages crées sur 1 heure est :

    SELECT COUNT(*) FROM shares WHERE DAY(create_date) = DAY(NOW()) AND HOUR(create_date)=:h; (1)
    1 :h étant une variable dont la valeur va de 0(heure) à 24(heures)
  • Pour obtenir une vue contenant un graphique Chart.js, on pourra utiliser le code suivant :

    views/Insights/show.php
    <div class="col col-lg-8 mt-5 mx-3 mx-lg-auto text-center">
    <a class="btn btn-outline-primary" href="<?php echo ROOT_PATH; ?>insights/show/d" role="button">Daily</a>
    <a class="btn btn-outline-primary" href="<?php echo ROOT_PATH; ?>insights/show/w" role="button">Weekly</a>
    <a class="btn btn-outline-primary" href="<?php echo ROOT_PATH; ?>insights/show/m" role="button">Monthly</a>
       <div id="chart-wrapper">
          <canvas id="insights"></canvas>
       </div>
    </div>
    
    <script>
    let ctx = document.querySelector("#insights");
    
    let graph = new Chart(ctx, {
    type : 'line',
    data : <?php echo $viewmodel ?>, (1)
    options: {
       responsive: true
    }
    });
    </script>
    1 $viewmodel : valeur retournée par une action/fonction du Modèle associé aux statistiques du site

    Les données affichées sur le graphes étant un un objet encodé au format JSON avec un code similaire au suivant :

    models/insights.php
    class Data {
       public array $labels;
       public array $datasets;
    }
    
    class DataSet {
       public string $label;
       public array $data;
    }
    
    public function show(){
       // [...]
       $dataset = new DataSet();
       $dataset->data = [5, 4, 3, 2, 1, 6, 7];
       $data = new Data();
       $data->labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
    
       $jsonData = json_encode($data);
    
       return $jsonData;
    }
  • En PHP, on peut obtenir le :

    • nom abrégé d’un jour avec jddayofweek($d,2) avec $d le numéro du jour de la semaine (0..6)

    • nom abrégé du mois avec jdmonthname(gregoriantojd($m, 1, 1), CAL_MONTH_JULIAN_SHORT) avec $m le numéro du mois (1…​12)

🞄  🞄  🞄