Fonctionnement de MindFlow¶
Le pipeline de rendu¶
Le pipeline de rendu de MindFlow s’exécute en 4 étapes :

Etape 1 : Initialisation du framework¶
L’appel du script par défaut (/index.php
en frontend, /mf/index.php
en backend) crée une instance de MindFlow avec notamment un objet $mf
qui est le pivot de l’application. Mindflow détermine alors s’il est exécuté en mode frontend ou en mode backend selon l’un ou l’autre de ces 2 scripts qui a été appellé. Cette information est stockée dans la variable $mf->mode
.
Si l’utilisateur courant est connecté au backend sans être encore identifié, la variable $mf->mode
pourra prendre une troisième valeur : “authentification”.
Une fois instancié, l’objet $mf
crée lui-même les principales variables suivantes :
info
: un tableau qui permet de stocker un grand nombre de données et qui sert de mémoire du framework et de canal de communication d’informations entre les objets durant l’exécution. C’est par exemple dans le tableau info que seront stockées la liste des pages web du site courant, qui pourront ainsi être facilement consultées par les plugins qui voudraient interagir avec.l10n
: une instance de l10nManager, le gestionnaire de textes localisés qui sert à traduire et afficher tous les textes / labels.db
: une instance de dbManager, le gestionnaire de base de données. Celui-ci ouvre le canal de communication avec la BDD et la rend disponible aux requêtes.pluginManager
: une instance du gestionnaire de plugins. Celui-ci charge tous les plugins en mémoire.
Etape 2 : Préparation des données¶
Une fois toutes les initialisations réalisées et tous les plugins chargés, il est temps de passer au traitement de données proprement dit.
Dans MindFlow, nous avons souhaité que le maximum de traitements soit réalisé sous forme de plugins de manière à avoir la conception la plus modulaire possible.
Ainsi la gestion et l’affichage des pages web est réalisé via le plugin Pages
, la gestion de la réécriture d’URLs via le plugin URLRewriter
, etc.
Le pluginManager de MindFlow va donc appeler la fonction prepareData()
de chaque plugin, l’un après l’autre, et provoquer ainsi le traitement de toutes les données requises, par exemple la récupération des valeurs d’un formulaire et l’envoi d’un email, ou alors la lecture d’informations dans la base de données en vue de leur affichage.
Etape 3 : Rendu, restitution des données traitées¶
Normalement, cette fonction ne devrait traiter que les opérations d’affichage. Par “opérations d’affichage”, on entend généralement la production de code HTML, XML, JSON, SVG, créer un fichier texte etc...
Durant l’étape de préparation de rendu, le pluginManager de MindFlow va donc appeler la fonction render() de chaque plugin, l’un après l’autre, et va agréger le rendu produit par chaque plugin au gabarit de la page qui sera finalement envoyé au navigateur. Cette opération est généralement réalisée en substituant les informations produites aux marqueurs de type {nom_du_marqueur}
présents dans les gabarits HTML du frontend ou du backend.
Etape 4 : Affichage des données¶
Il ne reste plus à MindFlow qu’a présenter le contenu produit. Dans le cas de figure le plus commun, le framework va tout simplement afficher le code HTML produit dans le navigateur de l’internaute avec une commande ultra-sophistiquée :
echo $html;
Mais on pourrait aussi bien lui faire écrire un fichier sur le disque du serveur ou alors lui faire contacter un autre serveur et y transférer les informations produites.
Instanciation du framework¶
Tout logiciel ayant une tendance naturelle à tourner rapidement à l’usine à gaz, nous avons voulu rendre MindFlow aussi simple que possible, et cela reste, à chaque étape de son développement, une préoccupation constante.
2 éléments essentiels permettent d’atteindre cet objectif :
- L’encapsulation : tous les éléments complexes doivent être encapsulés dans un élément plus simple qui gère leur complexité et y donne accès via des fonctions simplifiées, sans toutefois jamais interdire l’accès aux données complexes au cas ou il y aurait un besoin impératif d’y accéder directement.
- La conception Orientée Objet, qui est dérivée du principe d’encapsulation et qui vise à découper l’application sous forme de groupes logiques ayant une fonction bien précise, que l’on appellera Objet, ou Classe en langage PHP. Dans MindFlow par exemple, le Frontend est un objet.
Imaginons que vous vouliez créer un script très simple et autonome qui voudrait accéder au Frontend de MindFlow pour extraire de la base de données et afficher la liste des régions de France.
Il vous suffira de quelques lignes :
//On lit les fichiers de configuration de MindFlow
require_once 'mf_config/config.php';
//On inclus la classe Frontend pour y avoir accès
require_once DOC_ROOT.SUB_DIR.'/mf/frontend/frontend.php';
//On crée un objet Frontend
$mindFlowFrontend = new frontend();
//On prépare les données de manière à ce qu'elles soient prêtes à être utilisées pour l'affichage
$mindFlowFrontend->prepareData();
//On charge et on affiche notre liste de régions
$regions = mfFrance::listRegions();
$html = '<html><body>';
foreach($regions as $regionID => $regionName){
$html .= '<p>'.$regionName.'</p>';
}
$html .= '</html></body>';
echo $html;
Et voilà ! Pour faire la même chose en Backend, il vous suffirait de créer un objet backend au lien d’un objet frontend.
Comme vous avez pu le constater, hormis l’inclusion de la configuration et de la classe frontend, il ne faut réellement que 2 lignes pour exécuter MindFlow et avoir toutes vos données prêtes à utiliser pour l’affichage :
$mindFlowFrontend = new frontend();
$mindFlowFrontend->prepareData();
La première ligne crée un objet Frontend, et ce faisant, celui-ci crée en cascade tous les objets que MindFlow utilisera pour son travail, par exemple le pluginManager
qui va charger et initialiser tous les plugins, ou le dbManager
qui va établir la connexion à la base de données et la rendre disponible en tous point de l’application.
La seconde ligne prépare toutes les données : MindFlow appelle tous les plugins et leur demande de préparer leurs données. Par exemple le Plugin “pages” va consulter et tenir à disposition la liste des pages du site que l’on pourrait vouloir afficher.
Notez que dans l’exemple ci-dessus, on n’est pas passé par le Plugin “pages” pour l’affichage, mais on a géré la génération et l’affichage du HTML de manière autonome avec un simple echo $html;
pour la simplicité et la facilité de l’exemple.
En fait, si l’on voulait que ce soit MindFlow plutôt que nous qui génère le HTML et l’affiche, il suffirait d’ajouter une troisième ligne pour assurer le rendu de la page web courante :
$mindFlowFrontend->renderPage();
C’est d’ailleurs ce que fait le script index.php
situé à la racine de MindFlow qui est en mesure d’afficher toutes les pages d’un site Internet :
//lecture de la configuration du CMS
require_once 'mf_config/config.php';
require_once DOC_ROOT.SUB_DIR.'/mf/frontend/frontend.php';
//création et exécution du rendu Frontend
$mindFlowFrontend = new frontend();
$mindFlowFrontend->prepareData();
$mindFlowFrontend->renderPage();
$mindFlowFrontend->freeRessources();
Ce code affiche un site Internet ! Comme vous le constatez, l’emploi des principes d’encapsulation / Orienté Objet permet des gains importants de simplicité et de convivialité dans le cadre de la programmation.
L’appel de la fonction mfFrance::listRegions()
est aussi un exemple d’encapsulation, la fonction listRegions()
réalisant une requête SQL pour retourner à l’utilisateur la liste des régions sous forme d’un tableau (Array) de données PHP.
Regardons de plus près son code, de manière à vous montrer qu’il est également simple de consulter la base de données avec MindFlow :
//récupération de la liste des régions française depuis la base de données
static function listRegions(){
global $mf,$pdo;
$sql = "SELECT DISTINCT code_reg, nom_region FROM mf_france WHERE 1";
$stmt = $pdo->query($sql);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach($rows as $row){
$items[$row['code_reg']] = $row['nom_region'];
}
return $items;
}
D’abord on récupère les objets $mf
depuis la variable globale. On fait de même pour l’objet $pdo
qui est l’interface pour accéder à la base de données depuis PHP. A partir de là, vous n’avez plus qu’a utiliser l’API PDO standard de PHP et effectuer votre requête SQL comme vous le feriez depuis n’importe quel script PHP fait maison.
Important
Depuis MindFlow 1.9, il n’est plus nécessaire de récupérer la variable $mf
avec un appel $mf = $GLOBALS['mf'];
en début de fonction.
Nous avons trouvé le moyen de la passer une variable globale (ce qui n’était pas si trivial qu’on pourrait le penser de prime abord). Ceci allège significativement la syntaxe et réduit l’utilisation mémoire en évitant la recopie des informations de $GLOBALS[‘mf’] dans une variable locale à la fonction.
Il en est de même pour les variables suivantes, que vous pouvez désormais utiliser directement en déclarant celles dont vous aurez l’utilité avec le mot clé global
en début de fonction :
global $mf,$db,$pdo,$l10n,$config,$pluginManager,$formsManager;
Le seul prérequis pour pouvoir accéder à ces variables est que vous ayez préalablement créé un objet frontend ou un objet backend, qui eux-même créent une instance de la classe mf
, celle-ci se chargeant de déclarer ces variables superglobales.
Les anciennes méthodes d’accès à ces variables demeurent fonctionnelles, et la compatibilité avec les développements existants est maintenue :
$mf = $GLOBALS['mf'];
$db = $mf->db;
$pdo = $mf->db->pdo;
$l10n = $mf->l10n;
$config = $GLOBALS['config'];
$pluginManager = $mf->pluginManager;
$formsManager = $mf->formsManager;
La classe MF¶
L’objet MF est l’objet le plus important de MindFlow. Il est stocké dans la variable globale $mf
dès lors que vous créez un objet Backend ou un objet Frontend.
Cette variable étant globale, elle est accessible en tous point de l’application, donc dans n’importe lequel de vos scripts ou fonctions. Ceci en fait le pivot idéal pour accéder aux différents objets du framework et passer des données entre classes ou scripts. Dans une application MindFlow, on le retrouve d’ailleurs quasiment en tête de toutes les fonctions, tant il est utilisé partout :
static function maFonction(){
// récupération de la variable globale $mf
global $mf;
//affichage du code ISO2 de la langue courante :
echo $mf->getLocale();
//affiche "fr"
//affichage d'un texte localisé
echo $mf->l10n->getLabel('backend','object-save-success');
//affiche "Enregistrement réussi" dans la langue 'fr'
//affichage des informations de l'utilisateur couramment identifié en backend
var_dump($mf->currentUser);
//ou
echo $mf->currentUser->toHTML();
//affiche le contenu de l'instance de la classe mfUser contenant les données
//de l'utilisateur, élément trop grand pour être cité en exemple ici.
}
L’objet MF contient en son sein des instances d’autres objets :
$mf->db :
instance de dbManager, le gestionnaire de base de données. Comme son nom l’indique, il donne accès aux bases de données. Pour accéder à pdo, utilisez $mf->db->pdo
.
$mf->l10n :
instance de l10nManager, le gestionnaire de ‘localisation’ (mot abrégé en l10n = contraction de ‘localization’, comme c’est souvent l’usage en programmation). Donne accès aux données de localisation / traduction.
$mf->pluginManager :
instance de pluginManager, le gestionnaire de plugins. Donne accès aux instances de plugins en cours d’exécution.
$mf->formsManager :
instance de formsManager, le gestionnaire de formulaires. Permet de générer des formulaires et de collecter les données remplies par l’utilisateur
Ces 4 objets suffisent à fournir l’ensemble des fonctionnalités généralistes de MindFlow. Les fonctionnalités plus spécifiques sont ensuite fournies par les plugins.
A cela s’ajoutent les variables de données :
$mf->mode :
permet de savoir quel est le mode courant d’exécution de MindFlow. Sa valeur peut être ‘frontend’, ‘backend’ ou ‘authentification’. Ce dernier mode n’est valable que durant le court laps de temps de la procédure d’authentification de l’utilisateur en backend.
$mf->backend :
permet de récupérer l’instance du backend en cours, si MindFlow est exécuté en mode backend.
$mf->frontend :
permet de récupérer l’instance du Frontend en cours, si MindFlow est exécuté en mode Frontend.
$mf->currentUser :
renvoie l’instance de l’utilisateur actuellement identifié en backend
$mf->templates :
stocke, sous la forme d’un tableau PHP, la liste des définitions de gabarits destinés à l’affichage du HTML qui ont été chargés au démarrage
$mf->microtemplates :
stocke, sous la forme d’un tableau PHP, la liste des définitions de micro-gabarits destinés à l’affichage du HTML qui ont été chargés au démarrage. Un microtemplate ou micro-gabarit est une portion de code HTML, qui n’inclus pas une page entière, mais seulement une fraction de cette page, par exemple le microtemplate permettant l’affichage d’une actualité, que l’on pourra répéter et afficher autant de fois qu’il y aura d’actualités à montrer au sein d’une même page.
$mf->info
: la variable info est un tableau PHP dans lequel on peut ajouter et lire toutes les données que l’on souhaite rendre disponibles à l’ensemble de l’application. Si vous ajoutez des données à ce tableau, il vous faudra juste faire attention à ne pas prendre le nom d’un index déjà utilisé.
Par défaut, MindFlow stocke les données suivantes dans le tableau info :
$mf->info['pageTree'] :
la liste des pages du site, stockées sous la forme d’une arborescence d’objets de type ‘Page’, avec toutes leurs informations est préchargée par le plugin urlRewriter et stockée ici. Lorsque vous consultez un objet Page depuis ce tableau, sa variable $children
est initialisée et peut être consultée pour accéder aux pages enfants. Ce n’est en revanche pas le cas lorsque vous chargez directement une page au moyen de la fonction load(). Cette variable est assignée par le plugin URLRewriter et ce plugin est donc requis pour que celle-ci puisse être consultée.
$mf->info['pagesByUid'] :
la même liste des pages du site, stockée cette fois-ci sous forme d’une liste d’objets de type ‘Page’ indexées cette fois-ci en fonction de leur UID, un identifiant unique de type int alloué à toutes les pages MindFlow. Si par exemple vous voulez accéder à la page ayant l’UID 193, vous appellerez $mf->info['pagesByUid'][193]
. Cette variable est assignée par le plugin URLRewriter et ce plugin est donc requis pour que celle-ci puisse être consultée.
$mf->info['currentPageUid'] :
retourne l’uid de la page courante, qui sera affichée en frontend. Il est possible d’altérer le contenu de cette variable dans une fonction prepareData() de manière à afficher une autre page que celle pré-seclectionnée par MindFlow en fonction de l’URL. Ceci revient donc à faire une redirection silencieuse. Cette variable est assignée par le plugin URLRewriter et ce plugin est donc requis pour que celle-ci puisse être consultée.
$mf->info['parsed_url'] :
contient l’URL d’appel de la page courante décomposé sous forme d’un tableau. Cette variable est assignée par le plugin URLRewriter et ce plugin est donc requis pour que celle-ci puisse être consultée.
$mf->info['http_status'] :
retourne le code de statut HTTP présélectionné par MindFlow. Il est possible d’altérer le contenu de cette variable dans une fonction prepareData() pour retourner un code http différent. Par exemple : $mf->info['http_status'] = 404;
MindFlow tentera alors de charger le gabarit défini dans le tableau $mf->templates[$httpStatus.'-page']
(donc ici $mf->templates['404-page']
), et s’il ne le trouve pas, il recherchera à la racine du dossier du site un gabarit HTML nommé $httpStatus.’.html’, (donc ici ‘404.html’). Si aucun des deux n’est trouvé, alors MindFlow continuera d’afficher la page courante normalement.
$mf->info['frontend_locale'] :
le code ISO à 2 lettres de la langue couramment affichée en Frontend. Pour le français : ‘fr’, l’anglais : ‘en’, l’allemand : ‘de’ etc...
$mf->info['backend_locale'] :
le code ISO à 2 lettres de la langue couramment affichée en backend.
$mf->info['data_editing_locale'] :
le code ISO à 2 lettres de la langue des données couramment éditées en backend. En effet il est possible d’éditer des données en langue anglaise à partir d’une interface utilisateur affichée en langue française. Dans ce cas de figure, on aurait $mf->info['backend_locale'] == 'fr'
et $mf->info['data_editing_locale'] == 'en'
Afin de ne pas être totalement indigeste, nous n’avons listé ici que les variables essentielles. D’autres existent. Vous les trouverez dans le code source de la classe.
La classe MF propose également des méthodes utiles. Voici les plus importantes :
getFrontendLanguage() :
retourne le code ISO2 de la langue affichée en frontend. Par exemple ‘fr’
getBackendLanguage() :
retourne le code ISO2 de la langue affichée en backend. Par exemple ‘fr’
getLocale() :
retourne le code ISO2 de la langue des données affichées ou éditées en cours, qu’on soit en frontend ou en backend
getSiteRootPages() :
retourne un tableau contenant les pages racines de site Internet présentes dans la base de données. MindFlow étant multisites, il est possible d’avoir plusieurs pages racines, mais le plus souvent il n’y en aura qu’une.
getRootline($leafUid, &$rootLine=array()) :
rempli le tableau $rootline fourni en argument avec la liste de toutes les pages situées au-dessus de la page courante, sous forme d’objets page. Cette fonction est très pratique pour récupérer les infos nécessaires pour créer un fil d’Ariane (breadcrumb). N’est valable que pour le Frontend.
addWarningMessage($messageText) :
ajoute un message d’avertissement à afficher dans le backend de MindFlow. Ce message peut également être affiché en Frontend en ajoutant le marqueur {warning-messages}
dans vos gabarits HTML
addErrorMessage($messageText) :
ajoute un message d’erreur à afficher dans le backend de MindFlow. Ce message peut également être affiché en Frontend en ajoutant le marqueur {error-messages}
dans vos gabarits HTML
addSuccessMessage($messageText) :
ajoute un message de succès à afficher dans le backend de MindFlow. Ce message peut également être affiché en Frontend en ajoutant le marqueur {success-messages}
dans vos gabarits HTML
addInfoMessage($messageText) :
ajoute un message d’information à afficher dans le backend de MindFlow. Ce message peut également être affiché en Frontend en ajoutant le marqueur {info-messages}
dans vos gabarits HTML
Là encore, afin de ne pas être indigeste, nous n’avons listé ici que les fonctions les plus importantes. D’autres existent. Vous les trouverez dans le code source de la classe mf.
Log d’erreurs & debogage¶
Depuis la version 1.9, MindFlow propose l’outil de log Monolog, qui a largement été popularisé par son utilisation dans Symfony. Monolog permet d’écrire des informations dans le log avec différents niveaux de gravité (emergency, alert, critical, error, warning, notice, info, debug). Le log peut-être dirigé vers différents types de sorties traitées par des “handlers” : fichier log, email, base de données, console firePHP etc...
MindFlow recourrant massivement à l’usage de l’AJAX, le debogage des requêtes client-serveur peut se révéler complexe, surtout lorsque vous faite un echo
de variable lors d’un réponse à une requête AJAX, ce qui va corrompre la réponse et son traitement.
Monolog permet de diriger vos messages de log vers la sortie désirée, par exemple un fichier log que vous pourrez afficher en temps réel via une console SSH connectée au serveur et la commande tail -f nom-du-fichier.log
La console firePHP permet également d’afficher un log temps réel dans l’outil de debogage de Firefox.
Utilisation du log¶
Pour utiliser le log dans MindFlow, il vous suffit d’avoir recours à la variable globale $logger
:
//gagner l'accès à la variable
global $logger;
//déclarer ensuite vos entrés de log
$logger->emergency('An emergency');
$logger->alert('An alert');
$logger->critical('A critical message');
$logger->error('An error');
$logger->warning('A warning');
$logger->notice('A notice');
$logger->info('An info');
$logger->debug('A debug');
Ceci produira les entrées de log suivantes
[2018-01-24 11:44:16] Mindflow_161236683.INFO: An info [] []
[2018-01-24 11:44:16] Mindflow_161236683.EMERGENCY: An emergency [] []
[2018-01-24 11:44:16] Mindflow_161236683.ALERT: An alert [] []
[2018-01-24 11:44:16] Mindflow_161236683.CRITICAL: A critical message [] []
[2018-01-24 11:44:16] Mindflow_161236683.ERROR: An error [] []
[2018-01-24 11:44:16] Mindflow_161236683.WARNING: A warning [] []
[2018-01-24 11:44:16] Mindflow_161236683.NOTICE: A notice [] []
[2018-01-24 11:44:16] Mindflow_161236683.DEBUG: A debug [] []
Une fois passé la délicate étape de la configuration du log, nécéssaire uniquement si vous voulez ajuster finement son comportement à vos besoins, l’exploitation du log est donc relativement simple.
Comme vous le constatez dans l’exemple ci-dessus, chaque entrée est préfixée de :
- La date et l’heure enregistrés automatiquement avec votre entrée de log
- Le nom du “chanel” de log, intitulé Mindflow_ et concaténé avec un nombre aléatoire définissant un id unique pour l’execution en cours. En effet, si vous avez plusieurs utilisateurs qui surfent votre site et votre application simultanément, les entrées de log sont susceptibles de se mélanger dans votre fichier. L’identifiant unique associé à chaque execution vous permettra de discriminer les entrées de log entre 2 exécutions simultanées par 2 utilisateurs différents.
Configuration du log¶
Un fichier de configuration par défaut et d’exemple est défini dans le fichier ``mf_config/monolog-config.php``.
Celui-ci écrit par défaut le log dans un fichier mindflow-AAAA-MM-DD.log
journalisé sur 10 jours à la racine de votre hébergement. Il devrait répondre à la plupart des usages de base.**
Vous pouvez spécifier votre propre configuration en définissant la variable de configuration suivante :
$GLOBALS['config]['monolog'] = 'mf_websites/my-website/monolog-config.php';
Dans la configuration par défaut, seul le log vers le fichier .log est actif. Mais vous pouvez décommenter la configuration de log d’erreur critique par email ou le log firePHP.
Il vous sera ainsi possible de définir une configuration de log pour votre site de développement et une configuration différente pour votre site de production en fonction définie dans le fichier de configuration relatif à chaque site.
Contrairement à Symfony qui emploie des fichiers de configuration Yaml, certes conviviaux, Mindflow repose sur une configuration PHP de Monolog. Ceci présente à notre sens 2 avantages :
- On offre ainsi l’accès à 100% des fonctionnalités de l’API Monolog sans être pénalisé par des problèmes potentiels d’interprétation ou de fonctions non cablées d’une couche middleware
- A quoi bon lire et interpréter un fichier Yaml, en invoquant des fonction de l’API Reflection très couteuses en temps d’exécution, et ceci à chaque execution de MindFlow, alors qu’en définitive ce type de fichier de configuration sera rarement modifié ?
Comme souvent, MindFlow privilégie la performance.
Vous pourrez retrouver toutes les informations de configuration de Monolog à l’adresse suivante : https://github.com/Seldaek/monolog
Note
Notez qu’il vous est possible de définir un second chanel dirigé vers un second fichier log, si vous souhaitez par exemple séparer vos entrées de log de celles de MindFlow :
//Ajout de votre logger comme variable globale
global $loggerMyApp;
//define the channel with a unique render ID for each Mindflow execution
$loggerMyApp = new \Monolog\Logger('MyApp_'.$renderID);
$loggerMyApp->pushHandler(new \Monolog\Handler\RotatingFileHandler(DOC_ROOT.SUB_DIR.'/my_app.log', 10,\Monolog\Logger::DEBUG));
$loggerMyApp->info('*** My App logger is ready ***');
Utilisation de firePHP¶
FirePHP requiert l’utilisation du navigateur Firefox Developper Edition : https://www.mozilla.org/fr/firefox/developer/
Vous pouvez ensuite télécharger l’extension firePHP ici : https://github.com/firephp/firephp-for-firefox-devtools/raw/master/dist/firephp.xpi
Faites glisser le fichier .xpi sur la fenêtre de votre navigateur pour l’activer.
Ensuite combinez Ctrl+Shift+i pour afficher les outils développeur. Un nouvel onglet intitulé “FirePHP” devrait s’afficher.
Entrez dedans, et dans les options de gestion firePHP, cochez Enable User Agent Header
et FirePHP Header
.
Cliquez également le bouton ‘Enable’ dans le panneau de droite.
N’oubliez pas de décommenter la ligne suivante dans votre fichier de configuration Monolog de MindFlow :
// Sample firePHP handler
$logger->pushHandler(new \Monolog\Handler\FirePHPHandler());
Maintenant rechargez la page affichant votre site web / application : le log MindFlow devrait s’afficher dans l’onglet FirePHP.

Vous trouverez plus d’informations sur l’extension firePHP à l’adresse suivante : https://github.com/firephp/firephp-for-firefox-devtools
Notez que Monolog propose également un handler pour Chrome ou pour la console javascript des navigateurs. A cette heure, nous ne les avons pas encore expérimentés.