Programme du TRACKING défi

CatégorieCours
Déroulé de la séquence
  • Vous allez faire un défi chez vous : 30 minutes de logique par jour
  • Présentation rapide du projet de programme tracking défi
  • Description des étapes de création d’un programme
  • description du programme
  • définition de la base de données
  • algorithme du programme
  • les écrans du programme
  • les technologies utilisées
  • création de la base de données
  • le codage du programme
    • étape 1 : ajouter un utilisateur
    • étape 2 : ajouter un défi
    • étape 3 : ajouter une session de travail
    • étape 4 : ajouter un rapport

ÉTAPE DE CRÉATION D’UN PROGRAMME

  1. description du programme
  1. définition de la base de données
  1. algorithme du programme
  1. les écrans du programme
  1. les technologies utilisées
  1. création de la base de données
  1. le codage du programme
Description du programme “Suivi de défis” (Challenge Tracker)

Ce programme, développé en PHP, a pour objectif de permettre aux utilisateurs de suivre leurs défis personnels au quotidien. Il s’agit notamment de mesurer et d’analyser leur engagement sur des objectifs réguliers, comme par exemple : “faire 30 minutes d’exercice de logique par jour.”

Fonctionnalités principales :

  1. Création d’un défi personnalisé :
    • Nom du défi
    • Objectif du défi (ex. : durée quotidienne, fréquence, etc.)
    • Pseudo de l’utilisateur
    • Adresse e-mail de l’utilisateur (utilisée pour l’envoi de rapports hebdomadaires)
  1. Tracking des séances :
    • Pour chaque occurrence d’une activité liée au défi, l’utilisateur enregistre :
      • La date
      • L’heure
      • La durée de la session
  1. Base de données :

    La base stockera les informations suivantes :

    • Utilisateur (pseudo, email)
    • Défis (nom, objectif)
    • Sessions de suivi (date, heure, durée, lien avec un défi et un utilisateur)
  1. Rapport automatique hebdomadaire :
    • Envoyé chaque dimanche soir par e-mail
    • Contenu du rapport :
      • Nombre d’occurrences de l’activité durant la semaine et le mois
      • Durée totale réalisée
      • Pourcentage d’accomplissement par rapport à l’objectif défini
      • Comparaison avec les semaines/mois précédents (sous forme de tableau)
Structure de la base de données (MCD/MLD)

Tables :

  • Un utilisateur peut avoir plusieurs défis
  • Un défi appartient à un seul utilisateur
  • Un défi peut avoir plusieurs suivis
  • Chaque suivi est rattaché à un seul défi
  • utilisateurs (id_util, pseudo, email)
  • defis (id_defi, nom_defi, objectif, duree_session_defi, id__defi_util)
  • Suivis (id_suivi, id_suivi_defi, date_session, heure_session, duree_session_suivi)
CREATE TABLE utilisateurs (
    id_util INT AUTO_INCREMENT PRIMARY KEY,
    pseudo VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE
);

CREATE TABLE defis (
    id_defi INT AUTO_INCREMENT PRIMARY KEY,
    nom_defi VARCHAR(100) NOT NULL,
    objectif VARCHAR(255) NOT NULL,
    duree_session_defi INT NOT NULL,
    id__defi_util INT NOT NULL,
    FOREIGN KEY (id__defi_util) REFERENCES utilisateurs(id_util) ON DELETE CASCADE
);

CREATE TABLE suivis (
    id_suivi INT AUTO_INCREMENT PRIMARY KEY,
    id_suivi_defi INT NOT NULL,
    date_session DATE NOT NULL,
    heure_session TIME NOT NULL,
    duree_session_suivi INT NOT NULL,
    FOREIGN KEY (id_suivi_defi) REFERENCES defis(id_defi) ON DELETE CASCADE
);
Algorithme
DEBUT

Afficher le menu principal :
    1 - Créer un compte utilisateur
    2 - Créer un défi
    3 - Enregistrer une session d'activité
    4 - Générer un rapport hebdomadaire
    5 - Quitter

TANT QUE l'utilisateur ne choisit pas "Quitter" :
    Lire le choix utilisateur

    SELON le choix :
        CAS 1 : Créer un compte utilisateur
            Demander pseudo et email
            Enregistrer dans la table `utilisateurs`

        CAS 2 : Créer un défi
            Demander l’ID utilisateur, le nom du défi, l’objectif (texte), la durée quotidienne visée (en minutes)
            Enregistrer dans la table `defis`

        CAS 3 : Enregistrer une session d'activité
            Demander l’ID du défi, la date, l’heure et la durée en minutes
            Enregistrer dans la table `suivis`

        CAS 4 : Générer un rapport hebdomadaire
            POUR chaque utilisateur :
                Récupérer les défis de l'utilisateur
                POUR chaque défi :
                    Calculer le nombre de sessions cette semaine et ce mois
	                    	Aller dans la table suivis
												Sélectionner toutes les entrées (sessions d’activité) liées à ce défi (defi_id = ...)
												Filtrer par date, pour ne garder que celles de cette semaine (ou ce mois)
												Compter combien de lignes il y a
                    Calculer la durée totale effectuée par période
		                    Aller dans la table suivis
												Sélectionner toutes les entrées (sessions d’activité) liées à ce défi (defi_id = ...)
												Faire la somme de la colonne duree
                    Calculer le taux d’accomplissement :
		                    calculé l'objectif total à atteindre :
				                    (duree_session_defi * nombre de jours de la période)
                        (durée totale effectuée / objectif total à atteindre) * 100
                Générer un rapport texte
                Envoyer un e-mail avec ce rapport

        CAS 5 : Quitter
            Afficher "Au revoir"
            FIN

        CAS PAR DEFAUT :
            Afficher "Choix invalide"

Taux d’accomplissement : l’objectif à atteindre représente 100%, la durée totale effectuée multipliée par 100 et divisée par l’objectif à atteindre représente le taux.


Remarques

  • Pour calculer le nombre de jours concernés par un défi actif, on peut supposer que l’objectif est quotidien.
  • Le rapport doit être lancé automatiquement tous les dimanches à 23h via un script PHP exécuté par cron job (ou Scheduled Task).
  • On peut stocker l’historique des envois dans une table rapports_envoyes si besoin.
Les écrans


Accueil
Gestion des utilisateurs
Gestion des défis
Enregistrement des sessions
Rapports


Les technologies utilisées
  • affichage page web : HTML, CSS
  • fonctionnalités : php
  • stockage des données : base de données MySql
Code HTML et PHP pour créer, enregistrer, et suivre les défis
Création du projet
  • XAMPP
    • démarrer Apache depuis le panneau de contrôle XAMPP
    • le projet PHP doit être enregistré dans le dossier racine du serveur web Apache C:\xampp\htdocs\suivi-defis\
  • MySQL
    • XAMPP : démarré MySQL depuis le panneau de contrôle XAMPP
    • Créer une base de données “defis” interclassement utf8mb4_unicode_520_ci
    • Ajouter les tables avec les 3 requêtes SQL de création (DQL Data Query Language)
  • VSC
  • Pour voir les erreurs PHP
    • C:\xampp\php\php.ini
    • fichier php.ini
      display_errors = On
      display_startup_errors = On
      error_reporting = E_ALL
    • redémarrer Apache
    • Les erreurs seront dans ce fichier : C:\xampp\apache\logs\error.log

Ajouter un utilisateur
  • Outil PDO utilisé avec PHP afin que le programme PHP dialogue avec la base de données
  • utilisateur MySQL est "root" sans mot de passe (valeurs par défaut XAMPP)

Fichier index.php

<?php
require_once 'creer_utilisateur.php';
?>

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="UTF-8">
        <title>Suivi de Défis</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <h1>Suivi de Défis</h1>

        <!-- Formulaire : Créer un utilisateur -->
        <section>
            <h2>Créer un utilisateur</h2>
            <form method="post">
                <input type="hidden" name="action" value="creer_utilisateur">

                <div>
                    <label for="pseudo">Pseudo :</label>
                    <input type="text" id="pseudo" name="pseudo" required>
                </div>

                <div>
                    <label for="email">Email :</label>
                    <input type="email" id="email" name="email" required>
                </div>

                <button type="submit">Créer utilisateur</button>
            </form>
            <?php if ($message_util): ?>
                <p><?= $message_util ?></p>
            <?php endif; ?>
        </section>

        <hr>

    </body>
</html>

Fichier style.css

div {
    margin-bottom: 10px;
}

Fichier creer_utilisateur.php

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
    if ($_POST['action'] === 'creer_utilisateur') {
        // Récupérer les données du formulaire
        $pseudo = $_POST['pseudo'];
        $email = $_POST['email'];

        // Connexion à la base de données avec PDO

        try {
            $pdo = new PDO("mysql:host=localhost;dbname=defis;charset=utf8mb4", "root", "root");
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

            // Préparer la requête SQL d'insertion
            $sql = "INSERT INTO utilisateurs (pseudo, email) VALUES (:pseudo, :email)";
            $stmt = $pdo->prepare($sql);

            // Exécuter la requête avec les valeurs du formulaire
            $stmt->execute([
                ':pseudo' => $pseudo,
                ':email' => $email
            ]);

            $message_util =  "<p>✅ Utilisateur <strong>$pseudo</strong> créé avec succès.</p>";

        } catch (PDOException $e) {
            $message_util = "<p>‼️ Erreur lors de la connexion ou de l'insertion : " . $e->getMessage() . "</p>";
        }
    }
}
Ajouter un défi

Fichier index.php

  • ajouter require_once 'recup_info_menu_deroulant.php'; et require_once 'creer_defi.php';
  • ajouter la section <!-- Formulaire : Créer un défi -->
require_once 'recup_info_menu_deroulant.php';
require_once 'creer_defi.php';

<!-- Formulaire : Créer un défi -->
<section>
    <h2>Créer un défi</h2>
    <form method="post">
        <input type="hidden" name="action" value="creer_defi">

        <div>
            <label for="utilisateur_id">ID Utilisateur :</label>
            <select name="utilisateur_id" required>
                <option value="">-- Sélectionner --</option>
                <?php foreach ($utilisateurs as $u): ?>
                    <option value="<?= $u['id_util'] ?>"><?= $u['id_util'] ?>
                        - <?= htmlspecialchars($u['pseudo']) ?></option>
                <?php endforeach; ?>
            </select>
        </div>

        <div>
            <label for="nom_defi">Nom du défi :</label>
            <input type="text" id="nom_defi" name="nom_defi" required>
        </div>

        <div>
                <label for="objectif">Objectif (ex : 30 min de logique) :</label>
                <input type="text" id="objectif" name="objectif" required>
        </div>

        <div>
            <label for="duree_objectif">Durée quotidienne (en minutes) :</label>
            <input type="number" id="duree_objectif" name="duree_objectif" required>
        </div>

        <button type="submit">Créer défi</button>
    </form>
    <?php if ($message_defi): ?>
        <p><?= $message_defi ?></p>
    <?php endif; ?>
</section>

<hr>

Fichier creer_defi.php

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
    if ($_POST['action'] === 'creer_defi') {
        // Récupérer les données du formulaire
        $nom = $_POST['nom_defi'];
        $objectif = $_POST['objectif'];
        $duree_objectif = (int) $_POST['duree_objectif'];
        $utilisateur_id = (int) $_POST['utilisateur_id'];

        try {
            $pdo = new PDO("mysql:host=localhost;dbname=defis;charset=utf8mb4", "root", "root");
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

            $sql = "INSERT INTO defis (nom_defi, objectif, duree_session_defi, id_defi_util)
                    VALUES (:nom, :objectif, :duree, :uid)";
            $stmt = $pdo->prepare($sql);

            $stmt->execute([
                ':nom' => $nom,
                ':objectif' => $objectif,
                ':duree' => $duree_objectif,
                ':uid' => $utilisateur_id
            ]);

            $message_defi = "<p>✅ Défi <strong>$nom</strong> ajouté avec succès pour l'utilisateur #$utilisateur_id.</p>";

        } catch (PDOException $e) {
            $message_defi = "<p>‼️ Erreur lors de l'insertion du défi : " . $e->getMessage() . "</p>";
        }
    }
}

Fichier recup_info_menu_deroulant.php

<?php
// Connexion à la base
try {
    $pdo = new PDO("mysql:host=localhost;dbname=defis;charset=utf8mb4", "root", "root");
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Charger les utilisateurs
    $utilisateurs = $pdo->query("SELECT id_util, pseudo FROM utilisateurs ORDER BY pseudo")->fetchAll(PDO::FETCH_ASSOC);

    // Charger les défis
    $defis = $pdo->query("
        SELECT d.id_defi, d.nom_defi, u.pseudo
        FROM defis d
        JOIN utilisateurs u ON d.id_defi_util = u.id_util
        ORDER BY u.pseudo, d.nom_defi
    ")->fetchAll(PDO::FETCH_ASSOC);

} catch (PDOException $e) {
    echo "Erreur de connexion : " . $e->getMessage();
    $utilisateurs = [];
    $defis = [];
}
Ajouter une session de travail

Fichier index.php

  • ajouter require_once 'creer_session.php';
  • ajouter la section <!-- Formulaire : Créer un défi -->
require_once 'creer_session.php';

<!-- Formulaire : Enregistrer une session -->
<section>
    <h2>Enregistrer une session</h2>
    <form method="post">
        <input type="hidden" name="action" value="creer_session">

        <div>
            <label for="defi_id">ID du défi :</label>
            <select name="defi_id" required>
                <option value="">-- Sélectionner un défi --</option>
                <?php foreach ($defis as $defi): ?>
                    <option value="<?= $defi['id_defi'] ?>">
                        <?= $defi['id_defi'] ?> - <?= htmlspecialchars($defi['nom_defi']) ?>
                        (<?= htmlspecialchars($defi['pseudo']) ?>)
                    </option>
                <?php endforeach; ?>
            </select>
        </div>

        <div>
            <label for="date">Date :</label>
            <input type="date" id="date" name="date" required>
        </div>

        <div>
            <label for="heure">Heure :</label>
            <input type="time" id="heure" name="heure" required>
        </div>

        <div>
            <label for="duree">Durée (en minutes) :</label>
            <input type="number" id="duree" name="duree" required>
        </div>

        <button type="submit">Enregistrer session</button>
    </form>
    <?php if ($message_session): ?>
        <p><?= $message_session ?></p>
    <?php endif; ?>
    </section>

    <hr>

Fichier creer_session.php

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
    if ($_POST['action'] === 'creer_session') {
        // Récupérer les données du formulaire
        $defi_id = (int) $_POST['defi_id'];
        $date = $_POST['date'];
        $heure = $_POST['heure'];
        $duree = (int) $_POST['duree'];

        try {
            $pdo = new PDO("mysql:host=localhost;dbname=defis;charset=utf8mb4", "root", "root");
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


            $sql = "INSERT INTO suivis (id_suivi_defi, date_session, heure_session, duree_session_suivi)
                    VALUES (:defi_id, :date, :heure, :duree)";
            $stmt = $pdo->prepare($sql);

            $stmt->execute([
                ':defi_id' => $defi_id,
                ':date' => $date,
                ':heure' => $heure,
                ':duree' => $duree
            ]);

            $message_session = "✅ Suivi ajouté avec succès pour le défi #$defi_id.";

        } catch (PDOException $e) {
            $message_session = "‼️ Erreur lors de l'ajout du suivi : " . $e->getMessage();
        }

    }
}
Ajouter un rapport

Fichier index.php

  • ajouter require_once 'rapport.php';
  • ajouter la section <!-- Rapport -->
require_once 'rapport.php';

<!-- Rapport -->
<section>
    <h2>Afficher un rapport des suivis</h2>

    <form method="post">
        <input type="hidden" name="action" value="rapport">
        <button type="submit">Afficher rapport</button>
    </form>

    <?php if (isset($rapport)): ?>
        <br>
        <table border="3" cellpadding="6">
            <thead>
            <tr>
                <th>ID Défi</th>
                <th>Nom du défi</th>
                <th>Utilisateur</th>
                <th>Sessions effectuées cette semaine</th>
                <th>Sessions à faire</th>
                <th>Taux semaine (%)</th>
                <th>Sessions effectuées ce mois</th>
                <th>Sessions à faire</th>
                <th>Taux mois (%)</th>
            </tr>
            </thead>
            <tbody>
            <?php foreach ($rapport as $ligne): ?>
                <tr>
                    <td><?= $ligne['id'] ?></td>
                    <td><?= htmlspecialchars($ligne['nom']) ?></td>
                    <td><?= htmlspecialchars($ligne['pseudo']) ?></td>
                    <td><?= $ligne['sessions_semaine'] ?></td>
                    <td><?= $ligne['attendues_semaine'] ?></td>
                    <td><?= $ligne['taux_semaine'] ?>%</td>
                    <td><?= $ligne['sessions_mois'] ?></td>
                    <td><?= $ligne['attendues_mois'] ?></td>
                    <td><?= $ligne['taux_mois'] ?>%</td>
                </tr>
            <?php endforeach; ?>
            </tbody>
        </table>
    <?php endif; ?>

</section>

Fichier rapport.php

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
    if ($_POST['action'] === 'rapport') {
        try {
            $pdo = new PDO("mysql:host=localhost;dbname=defis;charset=utf8mb4", "root", "root");
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

            // Calcul des dates de début de semaine et de mois
            $today = date('Y-m-d');
            $debut_semaine = date('Y-m-d', strtotime('monday this week'));
            $debut_mois = date('Y-m-01');

            // Nombre de jours entre lundi et aujourd'hui
            $nb_jours_semaine = (new DateTime($debut_semaine))->diff(new DateTime($today))->days + 1;

            // Nombre de jours entre le début du mois et aujourd'hui
            $nb_jours_mois = (new DateTime($debut_mois))->diff(new DateTime($today))->days + 1;

            // Récupérer tous les défis et leur nombre de sessions cette semaine et ce mois
            $stmt = $pdo->query("
                SELECT d.id_defi, d.nom_defi, u.pseudo,
                    (SELECT COUNT(*) FROM suivis s WHERE s.id_suivi_defi = d.id_defi AND s.date_session >= '$debut_semaine') AS sessions_semaine,
                    (SELECT COUNT(*) FROM suivis s WHERE s.id_suivi_defi = d.id_defi AND s.date_session >= '$debut_mois') AS sessions_mois
                FROM defis d
                JOIN utilisateurs u ON d.id_defi_util = u.id_util
                ORDER BY u.pseudo, d.nom_defi
            ");

            $rapport = $stmt->fetchAll(PDO::FETCH_ASSOC);

            // Ajouter sessions attendues
            foreach ($rapport as &$ligne) {
                $ligne['attendues_semaine'] = $nb_jours_semaine;
                $ligne['attendues_mois'] = $nb_jours_mois;

                if ($ligne['attendues_semaine'] > 0) {
                    $ligne['taux_semaine'] = round(($ligne['sessions_semaine'] / $ligne['attendues_semaine']) * 100, 1);
                } else {
                    $ligne['taux_semaine'] = 0;
                }

                if ($ligne['attendues_mois'] > 0) {
                    $ligne['taux_mois'] = round(($ligne['sessions_mois'] / $ligne['attendues_mois']) * 100, 1);
                } else {
                    $ligne['taux_mois'] = 0;
                }
            }

        } catch (PDOException $e) {
            $rapport = [];
            $message_rapport = "Erreur lors de la récupération du rapport : " . $e->getMessage();
        }

    }
}