Sur Créa-code, nous souhaitons que chaque interaction soit humaine, chaleureuse et motivante. Echo, notre mascotte virtuelle, est là pour ça : elle encourage, guide, félicite ou console les utilisateurs à travers des petites phrases bien pensées.
Aujourd’hui, nous allons créer un système intelligent qui permet à Echo de parler, selon le contexte de la page ou de l’action de l’utilisateur. Pour cela, nous allons :
- Organiser les messages d’Echo
- Créer les fichiers JSON des phrases
- Créer la classe EchoService
- Création de la vue Echo
- Appel d’EchoService depuis un contrôleur
- Affichage d’Echo dans la page Dashboard
- Éviter les répétitions d’une même phrase
- Mise en place du contexte default (fallback)
- Utiliser Echo sur les pages souhaitées
- Maintenance facile
- Et maintenant ? Des idées pour faire évoluer Echo
- Echo, une mascotte vivante et intelligente
On va prendre le temps d’expliquer chaque étape. Ce tutoriel est fait pour les débutants comme pour les curieux plus avancés.
Organiser les messages d’Echo
Avant même de coder, nous devons réfléchir à l’organisation de notre contenu. Echo ne dira pas la même chose lorsqu’un utilisateur réussit un challenge que lorsqu’il consulte son profil.
Nous allons donc créer des catégories de messages. Chaque catégorie correspond à un contexte.
Par exemple :
welcome
pour l’accueil de l’utilisateur,success
pour une réussite,fail
pour un échec,profile
pour la consultation du profil,idle
si l’utilisateur ne fait rien pendant un moment,- Etc…
Pour garder les choses simples, alors nous allons stocker les phrases d’Echo dans des fichiers JSON classés par contexte.

Créer les fichiers JSON des phrases
Nous allons créer un dossier dans notre projet pour ranger les fichiers de phrases. Imaginons que notre structure ressemble à cela :
├── app/
├── public/
├── resources/
│ └── data/
│ └── echo/
│ ├── welcome.json
│ ├── success.json
│ └── fail.json
Commençons par créer notre premier fichier : resources/data/echo/success.json
Contenu de success.json
[
"Bravo ! Tu viens de réussir un challenge !",
"Excellent travail ! Tu progresses à vue d’œil.",
"Mission accomplie ! Continue comme ça.",
"Tu t'améliores chaque jour, impressionnant !",
"Et un de plus dans la poche ! Bien joué !"
]
C’est un tableau JSON simple. Chaque élément est une phrase qu’Echo pourra dire dans le contexte success
(Tout savoir sur le format JSON).
On fait la même chose pour fail.json
:
[
"Oups ! Ce n'est pas encore bon, mais tu vas y arriver.",
"Chaque erreur est une opportunité d’apprendre.",
"Pas grave, on réessaie ensemble ?",
"Courage ! L’échec est temporaire, la maîtrise arrive.",
"Repose-toi un instant, puis reviens plus fort."
]
Et pour welcome.json
:
[
"Bienvenue sur Créa-code ! Prêt(e) à progresser ?",
"Salut {user}, heureux de te revoir !",
"Echo est là pour t’accompagner dans ta mission apprentissage !",
"Nouveau jour, nouvelles lignes de code. Allons-y !",
"Bonjour {user}, tu es en forme ? On commence quand tu veux."
]
Tu remarques ici la présence de {user}
: nous allons voir un peu plus loin comment remplacer ce mot-clé dynamique par le pseudo de l’utilisateur.
Créer la classe EchoService
Nous allons maintenant créer une classe PHP pour gérer toute la logique d’Echo. On va l’appeler EchoService
, et elle sera responsable de :
- Lire les fichiers JSON selon le contexte,
- Choisir une phrase au hasard,
- Remplacer les variables
{user}
,{date}
, etc., - Fournir une phrase de secours si aucune n’est trouvée (fallback).
Créons un fichier dans app/Services/EchoService.php
Structure de base de la classe
<?php
namespace App\Services;
class EchoService
{
private static string $basePath = __DIR__ . '/../../resources/data/echo/';
public static function say(string $context, array $vars = []): string
{
$messages = self::loadMessages($context);
if (empty($messages)) {
$messages = self::loadMessages('default');
}
if (empty($messages)) {
return "Echo est muet... mais il te soutient !";
}
$phrase = $messages[array_rand($messages)];
return self::interpolate($phrase, $vars);
}
private static function loadMessages(string $context): array
{
$file = self::$basePath . $context . '.json';
if (!file_exists($file)) {
return [];
}
$json = file_get_contents($file);
return json_decode($json, true) ?? [];
}
private static function interpolate(string $phrase, array $vars): string
{
foreach ($vars as $key => $value) {
$phrase = str_replace("{" . $key . "}", $value, $phrase);
}
return $phrase;
}
}
Prenons maintenant le temps de décortiquer ce code morceau par morceau pour bien le comprendre.
Explication de la classe ligne par ligne
Tout d’abord, la ligne :
private static string $basePath = __DIR__ . '/../../resources/data/echo/';
Elle sert à indiquer le chemin de base où se trouvent les fichiers JSON des messages d’Echo. On utilise __DIR__
pour obtenir le chemin du dossier actuel, puis on remonte de deux niveaux (../../
) pour atteindre le dossier resources/data/echo/.
Ensuite, la méthode publique say()
est le point d’entrée : c’est cette méthode qu’on va appeler depuis les contrôleurs ou les vues pour faire parler Echo.
Elle prend deux paramètres :
$context
: le contexte du message (commesuccess
,fail
, etc.)$vars
: un tableau de variables à insérer dans la phrase (comme le pseudo de l’utilisateur)
Dans cette méthode, on commence par charger les messages pour le contexte demandé :
$messages = self::loadMessages($context);
Si aucun message n’est trouvé (par exemple si le fichier n’existe pas), on utilise un contexte de secours :
if (empty($messages)) {
$messages = self::loadMessages('default');
}
Et si toujours rien, on retourne une phrase neutre par défaut :
if (empty($messages)) {
return "Echo est muet... mais il te soutient !";
}
Une fois que nous avons des messages, on en choisit un au hasard :
$phrase = $messages[array_rand($messages)];
Puis on remplace les variables dynamiques (comme {user}
) grâce à la méthode interpolate()
.
Maintenant que nous avons notre service EchoService
capable de choisir une phrase selon un contexte, il est temps de l’utiliser concrètement dans notre application.
Maintenant, nous allons créer une vue Echo qui affiche la mascotte et sa bulle de dialogue. Elle sera appeler EchoService::say()
depuis un contrôleur (comme celui de la page Dashboard par exemple) et elle permettra de passer le message récupéré à la vue Echo pour affichage.
Création de la vue Echo
Commençons par créer une petite vue partielle pour Echo.
Dans notre structure de projet, allons dans :
views/
└── components/
└── echo.php
Code de echo.php
<div class="container-echo">
<div class="bubble"><?= htmlspecialchars($message) ?></div>
<img class="img-theme-switch" src="<?= BASE_URL ?>assets/img/echo/echo-<?= htmlspecialchars($expression) ?>.webp"
data-src-light="<?= BASE_URL ?>assets/img/echo/echo-<?= htmlspecialchars($expression) ?>.webp"
data-src-dark="<?= BASE_URL ?>assets/img/echo/echo-<?= htmlspecialchars($expression) ?>-dark.webp"
alt="Logo Créa-code" loading="lazy">
</div>
Cette vue est ultra simple. Elle contient deux éléments :
- L’image de la mascotte Echo
- Une bulle de dialogue avec le message généré
On utilise htmlspecialchars()
pour protéger le message et le chemin de l’image contre les injections HTML, au cas où.
Appel d’EchoService depuis un contrôleur
Imaginons que nous voulons qu’Echo parle sur la page d’accueil du Dashboard utilisateur. Ouvrons notre contrôleur app/Controllers/DashboardController.php :
<?php
namespace App\Controllers;
use App\Core\Controller;
use App\Core\View;
use App\Services\EchoService;
class DashboardController extends Controller
{
public function index()
{
// Vérifie l’authentification depuis la classe Controller
$this->checkAuth();
$echoMessage = EchoService::say('welcome', [
'user' => $_SESSION['user']['pseudo']
]);
$title = "Dashboard - Créa-code";
$desc = "Page d’accueil de votre espace personnel sur Créa-code.";
$meta_robots = 'noindex, follow';
View::render('dashboard/dashboard', compact('title', 'desc', 'meta_robots', 'echoMessage'));
}
}
Prenons le temps d’expliquer ce que nous faisons ici.
Nous avons ajouté cette ligne :
$echoMessage = EchoService::say('welcome', [
'user' => $_SESSION['user']['pseudo']
]);
Elle demande à Echo de dire un message du contexte welcome
(accueil), et lui passe une variable user
contenant le pseudo de l’utilisateur connecté.
Le résultat est stocké dans la variable $echoMessage
, que nous transmettons ensuite à la vue via View::render()
.
$this->checkAuth();
La ligne ci-dessus permet de vérifier que l’utilisateur est connecté et que son compte est vérifié. La méthode checkAuth()
est définit dans app/Core/Controller.php :
<?php
namespace App\Core;
class Controller
{
protected function checkAuth(): void
{
if (!isset($_SESSION['user'])) {
header('Location: ' . BASE_URL . 'login');
exit;
}
if ($_SESSION['user']['is_active'] == 0) {
$_SESSION['login_errors'] = ["Votre compte n'est pas encore activé. Veuillez vérifier votre email."];
header('Location: ' . BASE_URL . 'login');
exit;
}
}
}
Affichage d’Echo dans la page Dashboard
Dans la vue app/Views/dashboard/dashboard.php, nous allons maintenant inclure la vue Echo.
Si nous voulons afficher Echo sur la page du Dashboard, nous insérons ceci dans la vue :

Des formations informatique pour tous !
Débutant ou curieux ? Apprenez le développement web, le référencement, le webmarketing, la bureautique, à maîtriser vos appareils Apple et bien plus encore…
Formateur indépendant, professionnel du web depuis 2006, je vous accompagne pas à pas et en cours particulier, que vous soyez débutant ou que vous souhaitiez progresser. En visio, à votre rythme, et toujours avec pédagogie.
Découvrez mes formations Qui suis-je ?<?php View::component('echo', [
'expression' => 'serein',
'message' => $echoMessage
]); ?>
Cette ligne appelle notre fichier (vue) echo.php
dans le dossier components
, et lui transmet le message qu’Echo doit afficher et sélectionne l’humeur d’Echo. Mais pour cela, il nous faut ajouter la méthode statique component
au fichier app/Core/View.php :
public static function component(string $path, array $params = []): void
{
$file = APP_ROOT . '/creacode/app/Views/components/' . $path . '.php';
if (!file_exists($file)) {
echo "Composant introuvable : $file";
return;
}
extract($params);
require $file;
}
Nous utilisons dans la méthode component
une constante : APP_ROOT
.
Il nous faut maintenant la définir dans le fichier config.php qui est à la racine du projet :
define('APP_ROOT', dirname(__DIR__));
Et enfin, ne pas oublier d’appeler la classe en haut de chaque vue ou l’on souhaite afficher Echo :
<?php
use App\Core\View;
?>
Cela affichera le petit encart de notre mascotte avec sa phrase du moment.
Résultat attendu
Quand l’utilisateur ouvre son Dashboard, il voit par exemple :
Echo (avatar)
« Salut Alban, heureux de te revoir ! »
Et à chaque rechargement, Echo choisit une nouvelle phrase parmi celles disponibles dans le fichier welcome.json
.
À ce stade, nous avons un fichier JSON par contexte avec des phrases adaptées. Libre à nous d’ajouter au fil du développement d’autres contextes. Nous avons également un service Echo capable de charger et interpoler dynamiquement un message, une vue Echo pour afficher la mascotte et un premier appel concret d’EchoService dans un contrôleur.
Maintenant, nous allons maintenant enrichir notre système pour qu’il devienne plus intelligent. Echo va devoir éviter de répéter deux fois la même phrase, utiliser des fallbacks en cas de contexte manquant et être intégré sur d’autres pages facilement.
Nous avons une première version fonctionnelle de notre Echo. Il lit ses phrases depuis des fichiers JSON, choisit une phrase au hasard, et la rend dynamique avec les variables comme {user}
.
Mais nous allons améliorer l’expérience utilisateur. Imaginez un utilisateur qui recharge plusieurs fois une page et voit toujours la même phrase d’Echo… Cela casserait l’effet de surprise.
Éviter les répétitions d’une même phrase
Commençons par notre système d’anti-répétition. L’idée est de se souvenir de la dernière phrase affichée à l’utilisateur (pendant sa session) et de ne pas la répéter immédiatement.
Ajout dans EchoService
On modifie la méthode say()
dans EchoService
:
public static function say(string $context, array $vars = []): string
{
$messages = self::loadMessages($context);
if (empty($messages)) {
$messages = self::loadMessages('default');
}
if (empty($messages)) {
return "Echo est muet... mais il te soutient !";
}
// Éviter de répéter la dernière phrase
$last = $_SESSION['last_echo_phrase'] ?? null;
$filtered = array_filter($messages, fn($m) => $m !== $last);
$pool = !empty($filtered) ? $filtered : $messages;
$phrase = $pool[array_rand($pool)];
$_SESSION['last_echo_phrase'] = $phrase;
return self::interpolate($phrase, $vars);
}
Explication ligne par ligne
On commence par récupérer la dernière phrase affichée :
$last = $_SESSION['last_echo_phrase'] ?? null;
Puis on filtre le tableau $messages
pour retirer cette phrase :
$filtered = array_filter($messages, fn($m) => $m !== $last);
On utilise ce nouveau tableau filtré (si disponible), sinon on reprend la liste complète :
$pool = !empty($filtered) ? $filtered : $messages;
On choisit ensuite une phrase au hasard dans ce nouveau pool, et on la stocke pour la prochaine fois :
$phrase = $pool[array_rand($pool)];
$_SESSION['last_echo_phrase'] = $phrase;
Avec cette logique, Echo ne dira plus deux fois de suite la même chose, sauf s’il n’a qu’une seule phrase disponible.
Mise en place du contexte default
(fallback)
Si on venait à appeller un contexte qui n’existe pas encore, plutôt que de ne rien dire, Echo doit pouvoir afficher sur un message neutre, encourageant, ou générique.
Pour cela, nous allons créer un fichier default.json
dans resources/data/echo/
.
Contenu de default.json
[
"Echo est là, même quand il n’a rien à dire.",
"Continue, chaque ligne de code compte.",
"Tu avances, même si tu ne le vois pas encore.",
"Je suis toujours à tes côtés. Courage !"
]
Désormais, si un fichier JSON n’est pas trouvé, Echo piochera dans ce contexte par défaut.
Tout cela est déjà géré dans le bloc suivant de say()
:
if (empty($messages)) {
$messages = self::loadMessages('default');
}
Utiliser Echo sur les pages souhaitées
Maintenant que notre service est fiable, nous allons pouvoir l’intégrer facilement partout. Imaginons que sur la page des challenges, Echo doit nous encourager. Dans le contrôleur correspondant :
use App\Services\EchoService;
public function index(): void
{
$this->checkAuth();
$echoMessage = EchoService::say('challenges', [
'user' => $_SESSION['user']['pseudo']
]);
View::render('dashboard/challenges', compact('echoMessage'));
}
Il nous suffit de passer $echoMessage
à la vue, et d’y inclure le composant Echo :
<?php View::component('echo', [
'expression' => 'triste',
'message' => $echoMessage
]); ?>
Et voilà ! Echo parle automatiquement, selon le contexte donné. Si challenges.json
n’existe pas, il prendra un message de secours dans default.json
.
Maintenance facile
Grâce à notre système, il est très simple d’ajouter de nouvelles phrases ou de nouveaux contextes. Il suffit de créer un fichier NOM_CONTEXT.json
dans resources/data/echo/, et de l’alimenter avec quelques phrases.
Nous avons mis en place un système simple et puissant qui permet à Echo de parler aux utilisateurs dans différents contextes, avec des messages tirés de fichiers JSON. Le tout est géré par un EchoService qui sélectionne une phrase au hasard, évite les répétitions, et utilise un fallback en cas de besoin.
Et maintenant ? Des idées pour faire évoluer Echo
Maintenant que nous avons une base propre et stable, nous pourrons avec le temps le faire grandir en le rendant plus « intelligent ». Voici quelques idées :
1. Ajouter des « moods » (états d’esprit)
Tu pourrais créer des variantes de phrases selon l’humeur d’Echo :
- Sérieux,
- Motivant,
- Ironique,
- Blagueur…
Cela se ferait avec des fichiers comme success_motivant.json
, success_humour.json
, etc., ou en ajoutant un second paramètre mood
à EchoService::say()
.
2. Filtrer les phrases selon l’heure ou la date
Par exemple :
- S’il est 23h : « Tu codes encore ? Quelle passion ! »
- Le lundi matin : « Nouvelle semaine, nouveau défi. »
Il suffit d’ajouter une condition dans EchoService
pour personnaliser encore davantage l’expérience utilisateur.
Echo, une mascotte vivante et intelligente
Nous venons de construire un système simple, modulaire et évolutif pour donner une voix à Echo, la mascotte de Créa-code. Grâce à l’approche « EchoService + JSON + fallback », nous avons :
- Centralisé la logique des messages,
- Permis la personnalisation contextuelle (ex. :
success
,welcome
,fail
, etc.), - Évité les répétitions en mémoire de session,
- Rendu possible une extension sans casser l’existant.
C’est un exemple concret de conception modulaire : chaque pièce (service, fichier, vue) a son rôle, et tout est pensé pour être simple à maintenir, à tester et à faire évoluer.
La suite dès demain…