En migrant la plateforme maison vers une version 3, Tiria a souhaiter permettre de fonctionner avec des plugins, ces derniers offrant une solution plus souple pour le développement.
Le plugin TODD est ensoi un cas particulier. À la différence des autres plugins qui fonctionnent dans l'écosystème de la plateforme, TODD doit pouvoir avoir un rendu autonome, la plateforme devant assurer la constitution des éléments HTML à afficher à l'extérieur de son écosystème.
L'objectif du jour est donc de donner cette indépendance au plugin TODD et pouvoir afficher une vue correspondant à un contenu TODD. Un contenu TODD est associé à une URL publique, cette URL permettant au dispositif de diffusion de récupérer le contenu à afficher. Ce contenu correspond à du HTML, qui est généré par le serveur hébergeant l'application. Pour le moment, l'URL du contenu n'est pas interprétée correctement par le navigateur : la mécanique interne (notamment la production dynamique des liens internes) est cassée.
Interprétation d'une URL
Problématique
Je me fais expliquer par Frédéric le mécanisme d'interprétation d'une URL par l'application.
Prenons un exemple pour une URL qui ne se charge pas actuellement (produite par l'ancienne version de TODD): http://127.0.0.1:8081/project_todd/?page=todd_view&id=1
Dans un premier temps, cette URL est traduite par un fichier .htaccess :
Options FollowSymLinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^scripts/(.*)$ scripts/router.php?route=$1 [QSA,L]
RewriteRule ^api/([a-zA-Z0-9_\-]+)?(/([a-zA-Z0-9_\-]+))?(/([a-zA-Z0-9_\-]+))?(/([a-zA-Z0-9_\-]+))?/?.*$ api/index.php?route=$1&route_id=$3&subroute=$5&subroute_id=$7 [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
RewriteRule ^([a-z_\-]+)/([a-z0-9_\-]+)/([a-z0-9_\-]+)/?$ index.php?page=$1¶m=$2&option=$3 [L]
RewriteRule ^([a-z_\-]+)/([a-z0-9_\-]+)/?$ index.php?page=$1¶m=$2 [L]
RewriteRule ^([a-z_\-]+)/?$ index.php?page=$1 [L]
<FilesMatch "\.(md|sample)$">
Require all denied
</FilesMatch>La ligne qui nous intéresse est RewriteRule ^([a-z_\-]+)/?$ index.php?page=$1 [L]. C'est elle qui a réécris l'URL que nous avons maintenant à traiter. Elle intercepte une URL propre demandée par le client et la réécrit en interne vers un contrôleur frontal (index.php). Elle convertit le segment de l'URL en paramètre dynamique GET, sans modifier l'URL affichée dans le navigateur de l'utilisateur.
Tout est donc maintenant régi par la page index.php à la racine du site. Un fichier très court qui redirige en fonction de cette URL vers les bonnes fonctions :
<?php
if (isset($_COOKIE['connected']) && $_COOKIE['connected'] == 1) {
session_set_cookie_params(3600 * 24 * 7);
}
require_once('includes/base.inc.php');
if(file_exists(CONTROLLER_PATH.'pages/'.$page.'.inc.php')) {
include(CONTROLLER_PATH.'pages/'.$page.'.inc.php');
}
elseif (isset($page_plugin)
&& file_exists(PLUGIN_PATH.$page_plugin.'/controllers/pages/'.$page.'.inc.php')){
include(PLUGIN_PATH.$page_plugin.'/controllers/pages/'.$page.'.inc.php');
}
elseif(file_exists(CONTROLLER_PATH.'core/pages/'.$page.'.inc.php')) {
include(CONTROLLER_PATH.'core/pages/'.$page.'.inc.php');
}
if(isset($componentsLoaded) && is_array($componentsLoaded)){
foreach($componentsLoaded as $name => $value){
if($value) include($value);
}
}
include('templates/constructor.php');Explications :
- le premier
ifn'a rien à voir et permet juste de définir la durée des cookies de l'utilisateur lorsqu'il est connecté à une semaine. - le
require_oncecharge toutes les paramètres nécessaires au fonctionnement de la base : libraires, variables d'accès, etc. - la cascade de
ifetelseifpermet d'aller chercher la vue dans un répertoire particulier de l'arborescence. Dans notre cas :- Il ne trouve pas de fichier
pages/todd_view.inc.phpà la racine du site. - Il contrôle s'il existe bien des plugins (c'est le cas, il y a
todd) mais ne trouve pas non plus de fichiertodd/controlles/pages/todd_view.inc.php(qui correspond au chemin vers les plugins). - Il cherche alors dans
core/pages/todd_viw.inc.phpet ne trouve rien carcorecontient seulement les pages de base nécessaire à l'interface. - Comme il n'y a pas de
else, aucune action n'est finalement exécutée et on reste dans le dashboard classique.
- Il ne trouve pas de fichier
- le
include('templates/constructor.php')permet de charger les scripts qui vont construire une page.
Le processus est normal : la vue d'un composant ne doit pas se fabriquer dans le dashboard mais doit être autome et proposée à part.
Solution
La solution retenue par Frédéric que je vais tenter de mettre en place est la suite : lors de l'installation du plugin dans l'interface, il sera créé un dossier <nom_du_plugin>_view dans lequel on retrouvera deux fichiers :
.htaccessqui transformera comme l'autre fichier à la racine l'URL pour ajouter des paramètresGET;index.phpqui sera responsable de la vue à afficher.
En réalité, le dossier sera préparé à un endroit dans l'arborescence du plugin et sera recopié récursivement à la racine.
Implémentation
Dans le fichier d'installation du plugin, on ajoute le code suivant afin de copier le contenu du répertoire todd_view :
$src = __DIR__ . '/todd_view';
$dst = BASE_PATH . 'todd_view';
if (is_dir($src)) {
if (!is_dir($dst)) {
mkdir($dst, 0755, true);
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($src, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $item) {
$target = $dst . DIRECTORY_SEPARATOR . $iterator->getInnerIterator()->getSubPathName();
if ($item->isDir()) {
if (!is_dir($target)) {
mkdir($target, 0755, true);
}
}
else {
copy($item->getRealPath(), $target);
}
}
}Dans le répertoire todd_view, on a un fichier .htaccess qui va intercepter l'URL et lui attribuer un paramètre id en lui affectant comme valeur le nombre récupéré en fin d'URL :
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([0-9]+)/?$ index.php?id=$1 [L,QSA]
</IfModule>Le fichier index.php sera sollicité pour la création du HTML à afficher :
<?php
require_once dirname(__DIR__) . "/includes/base.inc.php";
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
if (!$id) {
die("ID manquant.");
}
global $db;
if (!$db) {
require_once(LIBRARY_PATH . "class.new_dbAccess.php");
$db = new dbAccess();
}
$content = $db->getRow("SELECT module_code, payload_json FROM " . DBPFX . "todd_contents WHERE id = :id", [':id' => $id]);
if (!$content) {
die("Contenu introuvable.");
}
$module_code = $content['module_code'];
$payload = json_decode($content['payload_json'], true);
if (!is_array($payload)) {
$payload = [];
}
$viewFile = BASE_PATH . "plugins/todd/modules/" . $module_code . "/view.php";
if (file_exists($viewFile)) {
include $viewFile;
}
else {
die("Vue manquante pour le module " . htmlspecialchars($module_code) . ".");
}L'ID passée en paramètre correspond au numéro d'entrée du contenu dans la table todd_content : on retrouvera ainsi tous les paramètre nécéssaires à la création de la vue de ce module.
Conclusion
Le but de la mission du jour est atteint. Le plugin TODD aura à présent une autonomie dans l'installation : il pourra être intégré dans toutes les implèmentation de cPanel, la plateforme maison. ET cette dernière délivrera le bon contenu, c'est-à-dire du code HTML indépendant.