<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="https://dotclear.watch/feed/rss2/xslt" ?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>DotclearWatch / Blog - Mot-clé - 2.36</title>
    <link>https://dotclear.watch/</link>
    <atom:link href="https://dotclear.watch/feed/tag/2.36/rss2" rel="self" type="application/rss+xml" />
    <description>Suivez l'évolution du moteur de blogs Dotclear.</description>
    <language>fr</language>
    <pubDate>Mon, 25 May 2026 06:49:11 +0200</pubDate>
    <copyright>Tous droits réservés © Jean-Christian Denis</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>Dotclear</generator>
          <item>
        <title>[2.36] Modification des Utility et Process</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-Utility-et-Process</link>
        <guid isPermaLink="false">urn:md5:dd15ff21d3bb2a4b4b58828f6f461ff4</guid>
        <pubDate>Sat, 18 Oct 2025 11:47:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>abstract</category>
                  <category>process</category>
                  <category>trait</category>
                  <category>utility</category>
                <description>&lt;p&gt;Depuis Dotclear 2.36 les classes de context sont accessibles directement en tant que méthodes de ces context, cela implique des changements dans leur fontionnement qui se répercutent jusque sur les thèmes et plugins.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;L'arborescence de Dotclear contient un nouvel espace de nom &lt;strong&gt;Dotclear\Helper\Process&lt;/strong&gt; qui embarque differentes classes utiles au fonctionnement des Utility et Process :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Dotclear\Helper\Process\AbstractProcess&lt;/li&gt;
	&lt;li&gt;Dotclear\Helper\Process\AbstractSingleton&lt;/li&gt;
	&lt;li&gt;Dotclear\Helper\Process\AbstractUtility&lt;/li&gt;
	&lt;li&gt;Dotclear\Helper\Process\TraitProcess&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Utility&lt;/h3&gt;

&lt;p&gt;Normalement nul besoin de se préoccuper de cette partie, elle appartient au core de Dotclear, mais c'est toujours bon de savoir comment cela fonctionne.&lt;/p&gt;

&lt;p&gt;Les Utility (Backend, Frontend, Upragde, Install) sont désormais des Container, leurs Process sont des services, leurs classes de second niveau sont des services et tous sont accessibles depuis des méthodes ( voir &lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-conteneurs#process&quot;&gt;Modification des containeurs&lt;/a&gt; ) Les Utility étendent la classe abstraite AbstractUtility qui embarque tout ce qu'il faut pour charger leurs services. Enfin les Utility utilisent le trait TraitProcess qui embarque ce qu'il faut pour le bon déroulement du processus requis par le core.&lt;/p&gt;

&lt;p&gt;Exemple de l'Utility Backend et de la classe de second niveau Favorites :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

declare(strict_types=1);

namespace Dotclear\Core\Backend;


class Utility extends AbstractUtility
{
    // ...

    public function getDefaultServices(): array
    {
        return [
            Favorites::class   =&amp;gt; Favorites::class,
            // ...
        ];
    }

    public function favorites(): Favorites
    {
        return $this-&amp;gt;get(Favorites::class);
    }

    // ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Accessible désormais avec :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;App::backend()-&amp;gt;favorites();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;Process&lt;/h3&gt;

&lt;p&gt;Jusqu'à Dotclear 2.36 toutes les classes de second niveaux du core (les servcies des Utility) et toutes les classes des plugins et thèmes lièes à la gestion de modules devaient étendre la classe Process du core. Depuis Dotclear 2.36 les services des Utility peuvent avoir besoin d'étendre d'autres classes ce qui serait impossible tel quel. La classes abstraite Process s'est donc transformée en trait, afin de pouvoir être utilisé en plus d'autres classes.&lt;/p&gt;

&lt;p&gt;Exemple du plugin blogroll de la distribution :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

declare(strict_types=1);

namespace Dotclear\Plugin\blogroll;

use Dotclear\Helper\Process\TraitProcess;

class Backend
{
    use TraitProcess;

    public static function init(): bool
    {
        //...
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Les plugins dcProxy s'occupent de faire le lien entre les plugins / thèmes qui ne sont pas à jour et l'utilisation du trait.&lt;/p&gt;

&lt;p&gt;Ce qu'il faut retenir et que là ou on utilisait :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

declare(strict_types=1);

namespace Dotclear\Plugin\MonPlugin;

Use Dotclear\Core\Process;

class Backend extends Process
{
    //...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Il faut utiliser :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

declare(strict_types=1);

namespace Dotclear\Plugin\MonPlugin;

use Dotclear\Helper\Process\TraitProcess;

class Backend
{
    use TraitProcess;

    //...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-Utility-et-Process#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-Utility-et-Process#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/509</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Installation en mode CLI</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Installation-en-mode-CLI</link>
        <guid isPermaLink="false">urn:md5:3f2b8e580a6fa402fc011c172e6a0504</guid>
        <pubDate>Sat, 18 Oct 2025 11:16:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>CLI</category>
                  <category>installation</category>
                <description>&lt;p&gt;A partir de Dotclear 2.36, il est possible d'installer un multiblogs en ligne de commande.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Par exemple, après s'être connecté en SSH au serveur, on télécharge et on décompresse l'archive de la version 2.36 de Dotclear, puis on se place à la racine de ce répertoire. On suppose que php peut-être appelé directement. (Sinon il faudra utiliser quelque chose comme bin/php)&lt;/p&gt;

&lt;p&gt;Dans la console SSH on peut lister les paramètres de l'installation en ligne de commande avec l'option -h, ce qui devrait donner ça :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-bash&quot;&gt;me@srv:/var/www/html$ php admin/install/index.php -h
Command line options are:
-h =&amp;gt; This help
-n =&amp;gt; Disable interactive mode
--dbdriver =&amp;gt; The database driver
--dbhost =&amp;gt; The database host
--dbname =&amp;gt; The database name
--dbuser =&amp;gt; The database user
--dbpassword =&amp;gt; The database password
--dbprefix =&amp;gt; The database table prefix, can be empty for deault to _dc
--adminemail =&amp;gt; The administration mail from
--ufirstname =&amp;gt; The super administrator first name, can be empty
--ulastname =&amp;gt; The super administrator last name, can be empty
--uemail =&amp;gt; The super administrator email
--ulogin =&amp;gt; The super administrator login
--upassword =&amp;gt; The super administrator password
--adminurl =&amp;gt; The admoin dashboard URL
--blogurl =&amp;gt; The default blog URL&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Comme on peut le voir, soit on lance l'installation en mode intercatif, c'est à dire sans option, dans quel cas une succession de questions nous seront posées, soit on utilise les options.&amp;nbsp;Si une option est manquante ou ne correspond pas à une valeur attendue, le script repassera en mode interactif et posera la question correspondante à l'option.&lt;/p&gt;

&lt;p&gt;Un début d'exemple du mode intercatif :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-bash&quot;&gt;me@srv:/var/www/html$ php admin/install/index.php
Starting first step of Dotclear installation process.
[IN] Configure the database driver (mysqli,mysqlimb4,pgsql,pdomysql,pdomysqlmb4,pdosqlite,pdopgsql): pdosqlite
[OK] Database driver is set to &quot;pdosqlite&quot;.
[IN] Configure the database path:
[OK] Database path is set to &quot;/var/www/html/db/202510180930.sqlite&quot;.
[IN] Configure the database table prefix:
[OK] Database table prefix is set to &quot;dc_&quot;.
[IN] Configure the administration mail from: plop
[KO] Invalid administration mail from.
[IN] Configure the administration mail from:
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Il est possible de ne pas utiliser le mode intractif avec l'option -n, dès lors, il faut renseigner toutes les options et le script retournera 1 si tout s'est bien passer pendant le processus d'installation. Ce mode de fonctionnement peut être pratique lors d'installations automatiques depuis des scripts bash.&lt;/p&gt;

&lt;p&gt;.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Installation-en-mode-CLI#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Installation-en-mode-CLI#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/508</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Modification du service de base de données</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-base-de-donn%C3%A9es</link>
        <guid isPermaLink="false">urn:md5:6d4246c76f73c25281905c82eb71ba4c</guid>
        <pubDate>Tue, 02 Sep 2025 14:17:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>connexion</category>
                  <category>database</category>
                  <category>service</category>
                <description>&lt;p&gt;Dans Dotclear 2.36 le Container principal est encore plus soyeux avec uniquement de vraies classes comme services, cela entraîne certaines modifications.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Avant la version 2.36 de Dotclear, l'accès à la base de données se faisait par l'appel &lt;strong&gt;App::con()&lt;/strong&gt;; mais d'un point de vu technique cet appel passait par une fonction intermediaire directement dans la pile de services du Container principal, fonctionnel mais pas vraiment joli et surtout trop strict et rigide. C'est pourquoi la version 2.36 de Dotclear introduit un nouveau service du core nommé &lt;strong&gt;db()&lt;/strong&gt; qui fait le lien entre Dotclear et les drivers de base de données. De ce fait, l'appel qui se faisait par &lt;strong&gt;App::con()&lt;/strong&gt; devient &lt;strong&gt;App::db()-&amp;gt;con()&lt;/strong&gt;, plus long et donc moins sexy, mais cela va permettre de travailler et d'améliorer les drivers de base de données beaucoup plus facilement.&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;//App::con()-&amp;gt;openCursor('xyz');
App::db()-&amp;gt;con()-&amp;gt;openCursor('xyz);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Bien entendu l'écriture &lt;strong&gt;App::con()&lt;/strong&gt;&amp;nbsp;est dépréciée mais reste fonctionnelle encore pour quelques siècles.&lt;/p&gt;

&lt;p&gt;Ce changement a permis dès la version 2.36 de proposer d'autres drivers de base de données et d'améliorer le processus d'installation.&lt;/p&gt;

&lt;h3&gt;Le nouveau service App::db()&lt;/h3&gt;

&lt;p&gt;Le coeur de l'application Dotclear embarque donc un nouveau service qui va permettre de faire le lien entre les drivers de base de données et le reste de Dotclear.&lt;/p&gt;

&lt;p&gt;Il est identifié comme suit dans le container :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Identifiant du service : Dotclear\Core\DatabaseInterface&lt;/li&gt;
	&lt;li&gt;Classe par défaut : Dotclear\Core\Database&lt;/li&gt;
	&lt;li&gt;Methode du service : App::db()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Son interface montre ses méthodes :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;App::db()-&amp;gt;con() : l'accès à la base de données&lt;/li&gt;
	&lt;li&gt;App::db()-&amp;gt;newCon() : Une instance isolé de l'accès à une&amp;nbsp;base de données&lt;/li&gt;
	&lt;li&gt;App::db()-&amp;gt;structure() : l'accès à la gestion de structure de base de données&lt;/li&gt;
	&lt;li&gt;App::db()-&amp;gt;combo() : liste des drivers utilisables (sert dans le process d'installation Dotclear)&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;interface DatabaseInterface
{
    /**
     * Get dabatase connection handler instance.
     *
     * This connection instance uses parameters from config service.
     */
    public function con(): ConnectionInterface;

    /**
     * Get new dabatase connection handler instance.
     *
     * @param   string  $driver         Driver name
     * @param   string  $host           Database hostname
     * @param   string  $database       Database name
     * @param   string  $user           User ID
     * @param   string  $password       Password
     * @param   bool    $persistent     Persistent connection
     * @param   string  $prefix         Database tables prefix
     */
    public function newCon(
        string $driver, 
        string $host, 
        string $database, 
        string $user = '', 
        string $password = '', 
        bool $persistent = false, 
        string $prefix = ''
    ): ConnectionInterface;

    /**
     * Get database structure handler.
     *
     * The handler uses current connexion.
     * Each call to this method MUST return a new instance.
     *
     * @return  Structure   The database structure handler
     */
    public function structure(): Structure;

    /**
     * Get combo of available database drivers.
     *
     * @return  array&amp;lt;string, string&amp;gt;   The drivers name/driver pairs
     */
    public function combo(): array;
}
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;Cette classe est récente et va surement évoluer dans les versions à venir.&lt;/p&gt;

&lt;h3&gt;Le gestionnaire de connexion App::db()-&amp;gt;con()&lt;/h3&gt;

&lt;p&gt;Une fois le driver choisi et inscrit dans le fichier de configuration de Dotclear, ses méthodes sont accessibles depuis l'application dans App::db()-&amp;gt;con().&amp;nbsp;&lt;br /&gt;
Un driver est généralement constitué d'une classe principale qui étend une classe d'abstraction qui étend elle même une interface. Le driver fournit également une classe de gestion de Schema. Toutes ces classes sont disponibles à divers endroits de Dotclear :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Les classes d'abstraction sont dans&amp;nbsp;Dotclear\Database,&lt;/li&gt;
	&lt;li&gt;Les interfaces dans Dotclear\Interface\Database&lt;/li&gt;
	&lt;li&gt;Les drivers dans Dotclear\Schema\Database&lt;/li&gt;
	&lt;li&gt;Les drivers sont ajoutés à un container dédié&lt;/li&gt;
	&lt;li&gt;Les drivers vérifient&amp;nbsp;l'installation&amp;nbsp;avant d'être proposés&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Une nouvelle méthode fait sont appartition dans le gestionnaire de connexion (driver), afin de tester que les conditions requises à son utilisation sont présentes. Sa définition est visible dans l'interface :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;/**
 * Check driver requirements.
 *
 * This method MUST throw a DatabaseException if driver can not be used.
 * This method does NOT say a SGBD is installed but only PHP supports it.
 *
 * @since   2.36
 *
 * @throws  \Dotclear\Exception\DatabaseException   if condition does not meet driver requirements
 */
public static function precondition(): void;&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Les drivers PDO&lt;/h3&gt;

&lt;p&gt;PDO est une extension de PHP signifiant PHP Data Objects, c'est une interface d'abstraction de l'accès à des bases de données, en d'autre termes cela doit simplifier l'accès à differents types de base de données depuis une application comme Dotclear. Jusqu'à la version 2.36 Dotclear n'utilisait PDO que pour la connexion à des bases de donnée Sqlite, depuis la version 2.36 il est possible de se connecter à des bases Mysql et PostgreSql à travers les drivers PDO. Les drivers de Dotclear utilisant PDO ne sont pour l'instant que des passerelles de connexion, toutes les fonctionnalités de PDO ne sont pas exploitées, Dotclear ayant déjà son propre système de préparation de requêtes.&lt;/p&gt;

&lt;p&gt;Par défaut sur les sytèmes Linux, PHP embarque l'extension PDO avec le pilote pour Sqlite, si ce n'est pas le cas,&amp;nbsp;&lt;a href=&quot;https://www.php.net/manual/fr/pdo.installation.php&quot; hreflang=&quot;fr&quot; title=&quot;Installer PDO&quot;&gt;le site de PHP&lt;/a&gt; fournira un peu d'aide à l'installation plus complète de PDO.&lt;/p&gt;

&lt;h3&gt;Le cas Sqlite&lt;/h3&gt;

&lt;p&gt;Le driver Sqlite de Dotclear était déjà basé sur PDO, il a simplement été renommé pour correspondre aux autres drivers. Il n'y a rien besoin de modifier, Dotclear se charge de comprendre que si vous avez définie le driver à &quot;&lt;strong&gt;sqlite&lt;/strong&gt;&quot; cela veut dire qu'il faut utiliser &quot;&lt;strong&gt;pdosqlite&lt;/strong&gt;&quot;.&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;Les drivers livrés avec Dotclear&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;mysqli : Mysql avec les fonctions mysqli_*&amp;nbsp;de PHP&lt;/li&gt;
	&lt;li&gt;mysqlimb4 : Idem avec le support utf8-mb4&lt;/li&gt;
	&lt;li&gt;pgsql : PostgreSql avec les classes&amp;nbsp;PgSql&amp;nbsp;de PHP&lt;/li&gt;
	&lt;li&gt;pdosqlite : Sqlite sous PDO&lt;/li&gt;
	&lt;li&gt;pdomysql : Mysql sous PDO&lt;/li&gt;
	&lt;li&gt;pdomysqlmb4 : Mysql sous PDO avec support utf8-mb4&lt;/li&gt;
	&lt;li&gt;pdopgsql : PostgreSql sous PDO&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lors de l'installation de Dotclear tous les drivers ayant un support dans la version installée de PHP seront proposés pour définir la connexion à la base de données.&lt;/p&gt;

&lt;h3&gt;Utiliser un driver PDO sur une installation existante&lt;/h3&gt;

&lt;p&gt;Si votre système embarque les composants PDO pour votre base de données, il est possible de passer sur les drivers PDO simplement en mettant à jour le fichier config.php, il faut remplacer la définiton de&amp;nbsp;DC_DBDRIVER par le nouveau driver. Et l'inverse est également vrai. Voici les equivalents :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;mysqli &amp;lt;=&amp;gt; pdomysql&lt;/li&gt;
	&lt;li&gt;mysqlimb4 &amp;lt;=&amp;gt; pdomysqlmb4&lt;/li&gt;
	&lt;li&gt;sqlite &amp;lt;=&amp;gt; pdosqlite&lt;/li&gt;
	&lt;li&gt;pgsql &amp;lt;=&amp;gt; pdopgsql&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;// define('DC_DBDRIVER', 'mysqli');
define('DC_DBDRIVER', 'pdomysql');&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Auncune recommandation ici, rien ne vous oblige aujourd'hui à changer, ce ne sont que des drivers qui permettent le lien entre Dotclear et votre base de données et ils sont tous maintenus pour le moment.&lt;/p&gt;

&lt;h3&gt;Créer un driver&lt;/h3&gt;

&lt;p&gt;Pour l'exemple on va prendre un driver utilisant PDO. L'extension PDO de PHP n'est pas magique, chaque type de base de données à ses propres lois et chaque type est diffèrent. Néanmoins Dotclear propose un classe d'abstraction pour simplifier la création d'un driver de base de données utilisant PDO. Par exemple, si vous souhaiter commencer un driver pour MsSql voici ce à quoi ça pourrait ressembler.&lt;/p&gt;

&lt;p&gt;On ajoute notre service au container des drivers de base de données et on crée notre classe de service :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;&amp;lt;php

namespace /MySpace/PdoMsSql;

use Dotclear\Database\AbstractPdoHandler;
use Dotclear\Helper\Container\Container;
use Dotclear\Helper\Conttainer\Factories;

Factories::addService('database', 'pdomssql', PdoMsSql::class);

class PdoMsSql extends AbstractPdoHandler
{
    public const HANDLER_NAME   = 'MsSql (PDO)';
    public const HANDLER_DRIVER = 'pdomssql';
    public const HANDLER_SYNTAX = 'mssql';
    public const HANDLER_PDO    = 'sqlsrv';

    // ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Il faut ensuite modifier toutes les methodes qui demandent un ajustement par rapport au language MsSql et lui adjoindre un classe de Schema. Bon courage.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Il y aurait beaucoup à dire sur cette partie mais ce serait bien trop long. Les très rares personnes qui souhaiteraient créer leur propre driver de base de données sont sans aucun doute assez callées pour comprendre le code de Dotclear.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-base-de-donn%C3%A9es#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-base-de-donn%C3%A9es#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/447</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Modification des conteneurs</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-conteneurs</link>
        <guid isPermaLink="false">urn:md5:56ec421497f9dea239c3da9d9a8876cf</guid>
        <pubDate>Tue, 02 Sep 2025 09:33:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>container</category>
                  <category>factory</category>
                <description>&lt;p&gt;Avec les corrections des divers bugs du coeur de Dotclear 2.36, la classe de Container a été améliorée.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Le gestionnaire de service (Container) embarqué dans Dotclear ne permettait pas de passer à ses services le container lui-même, c'est désormais possible depuis Dotclear 2.36. Une autre limite du container était qu'on ne pouvait pas récupèrer d'instance d'une service pour un usage isolé sans propager les intercations à tout le container. Pour faire simple si on modifiait les paramètres d'un service, cela modifiait ce service pour tout le script. Il est désomrais possible de créer des instances de service à usage ponctuel.&lt;/p&gt;

&lt;p&gt;L'appel d'un service avec le paramètre NULL permet d'avoir une instance isolée de ce service. Les valeurs TRUE et FALSE de ce paramètre ont toujours les mêmes fonction qu'avant.&lt;/p&gt;

&lt;p&gt;Voici un exemple complet montrant le passage du container au service et l'utilisation du paramétre NULL à la récupération du service :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php 

use Dotclear\Helper\Container\Container;
use Dotclear\Helper\Conttainer\Factories;

// Class du service
class MonService
{
    protected int $nb = 0;

    // On passe le container directement au service
    public function __construct(
        protected MonContainer $container
    ) {

    }

    // On met en mémoire du service un nombre
    public function nombre(int $nb): void
    {
        $this-&amp;gt;nb = $nb;
    }

    // On lance un calcul en utilisant une methode du container
    public function calcul(): string
    {
        $somme = $this-&amp;gt;container-&amp;gt;ajoute($this-&amp;gt;nb);

        return 'resultat : ' . $somme . &quot;\n&quot;;
    }
}

// Class du container
class MonContainer extends Container
{
    public const CONTAINER_ID = 'moncontainer';

    public function __construct()
    {
        parent::__construct(Factories::getFactory(static::CONTAINER_ID));
    }

    // Methode qui fait une addition
    public function ajoute(int $nb): int
    {
        return $nb + $nb;
    }
}

// On ajoute le service au container
Factories::addService('moncontainer', 'monservice', MonService::class);

// On crée l'instance du container
$container = new MonContainer();

// On récupère une instance du service depuis le container
$a = $container-&amp;gt;get('monservice');

// On lui donne un nombre
$a-&amp;gt;nombre(2);

// On fait une première fois le calcul
echo $a-&amp;gt;calcul(); // resultat : 4

// On donne un autre nombre à notre instance du sevice
$a-&amp;gt;nombre(3);

// On calcul, le résultat prend en compte le dernier nombre soumis
echo $a-&amp;gt;calcul(); // resultat : 6

// On recupère une instance du service depuis le container
$b = $container-&amp;gt;get('monservice');

// Même sans soumettre de nombre, 
// on voit que le calcul se fait sur la même instance de service que précédement.
echo $b-&amp;gt;calcul(); // resultat : 6

// On vérifie, et effectivement les deux instances a et b sont en réalité la même
echo $a-&amp;gt;calcul(); // resultat : 6

// On récupère une nouvelle instance avec le parametre null
$c = $container-&amp;gt;get('monservice', null);

// On donne à cette instance un nombre
$c-&amp;gt;nombre(4);

// Le calcul prend bien en compte ce nombre
echo $c-&amp;gt;calcul(); // resultat : 8

// On refait le calcul sur l'instance précédente, elle a bien gardé en mémoire le nombre précèdent
echo $b-&amp;gt;calcul(); // resultat : 6

// Ce sont bien cette fois deux instances distinctes

// On récupère une instance du service depuis le container
$d = $container-&amp;gt;get('monsevrice');

// On fait un calcul sans donner de nombre
echo $d-&amp;gt;calcul(); // resultat: 6

// on voit que $c avec le paremetre null n'a pas d'influence sur les autres instances&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Attention aux effets de bords&lt;/u&gt;, les objets partagés dans ces instances peuvent être modifiés dans une instance et renvoyer un résultat inattendu dans une autre instance !&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A noter que tous les constructeurs des classes de premier niveau de Dotclear, celles qui sont disponibles dans le container principal, utilisables depuis App::xxx() ont désormais le container comme paramètre.&lt;br /&gt;
Par exemple classe Auth est passée de ça :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;class Auth
{
    // ...
    /**
     * Constructs a new instance.
     *
     *@param   BlogInterface               $blog           The blog instance
     * @param   BlogsInterface              $blogs          The blogs handler
     * @param   ConfigInterface             $config         The configuration instance
     * @param   DatabaseInterface           $db             The database handler instance
     * @param   SessionInterface            $session        The session handler
     * @param   UserPreferencesInterface    $user_prefs     The user preferences instance
     * @param   UsersInterface              $users          The users handler
     */
    public function __construct(
        protected BlogInterface $blog,
        protected BlogsInterface $blogs,
        protected ConfigInterface $config,
        protected DatabaseInterface $db,
        protected SessionInterface $session,
        public UserpreferencesInterface $user_prefs,
        protected UsersInterface $users
    ) {
        // ...
    }
    // ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;à ça :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;class Auth
{
    // ...
    /**
     * Constructs a new instance.
     *
     * @param   Core    $core   The core container
     */
    public function __construct(
        protected Core $core
    ) {
        // ...
    }
    // ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Certains y veront le grand retour de $core, mais il n'en est rien, car cela n'est effectif que dans les classes de premier niveau, associées au container.&lt;br /&gt;
 &lt;/p&gt;

&lt;h3 id=&quot;process&quot;&gt;Appel aux classes de context&lt;/h3&gt;

&lt;p&gt;Les instances de classes appartenant aux contextes (Utility) telles que Frontend, Backend, Upgrade et Install sont désormais disponibles comme méthodes du contexte. Il n'est plus nécessaire de déclarer l'utilisation des classes comme &lt;strong&gt;\Dotclear\Core\Backend\Favorites::class&lt;/strong&gt; pour les utiliser, car elles sont maintenant directement disponibles dans l'objet du contexte, ce qui donnera pour l'exemple &lt;strong&gt;App::backend()-&amp;gt;favorites()&lt;/strong&gt;;&lt;/p&gt;

&lt;p&gt;Voici une liste des classes de second niveau pour le Backend :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Dotclear\Core\Backend\Action::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;action(), (nouvelle classe, voir plus bas)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Auth::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;auth(), (nouvelle classe, voir plus bas)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Combos::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;combos(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Favorites::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;favorites(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Filter::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;filter(), (nouvelle classe, voir plus bas)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Helper::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;helper(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Listing::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;listing(), (nouvelle classe, voir plus bas)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\MediaPage::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;mediaPage(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Menus::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;menus(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\ModulesList::class =&amp;gt; App::backend()-&amp;gt;modulesList(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Notices::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;notices-),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Page::class =&amp;gt; App::backend()-&amp;gt;page(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Resources::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;resources(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\ThemeConfig::class =&amp;gt; App::backend()-&amp;gt;themeConfig(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\ThemesList::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;themesList(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Url::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;url(),&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\UserPref::class&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;userPref(),&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Les nouvelles classes de Backend utiles aux listes que sont Action, Filter et Listing fournissent les instances des objets suivant :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Dotclear\Core\Backend\Action\ActionsBlogs =&amp;gt; App::backend()-&amp;gt;action()-&amp;gt;blogs(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Action\ActionsComments&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;action()-&amp;gt;comments(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Action\ActionsPosts =&amp;gt; App::backend()-&amp;gt;action()-&amp;gt;posts(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Filter\FilterBlogs =&amp;gt; App::backend()-&amp;gt;filter()-&amp;gt;blogs(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Filter\FilterComments&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;filter()-&amp;gt;comments(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Filter\FilterMedia&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;filter()-&amp;gt;media(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Filter\FilterPosts&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;filter()-&amp;gt;posts(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Filter\FilterUsers =&amp;gt; App::backend()-&amp;gt;filter()-&amp;gt;users(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Listing\ListingBlogs =&amp;gt; App::backend()-&amp;gt;listing()-&amp;gt;blogs(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Listing\ListingCommnets&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;listing()-&amp;gt;comments(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Listing\ListingMedia&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;listing()-&amp;gt;media(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Listing\ListingPosts =&amp;gt; App::backend()-&amp;gt;listing()-&amp;gt;posts(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Listing\ListingPostsMini&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;listing()-&amp;gt;postsMini(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Listing\ListingUsers&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;listing()-&amp;gt;users(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Listing\Pager&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;listing()-&amp;gt;pager(...)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Une autre nouvelle classe fournit les instances des objets nécessaires aux connections tierces :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Dotclear\Core\Backend\Auth\Otp&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;auth()-&amp;gt;otp(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Auth\WebAuthn&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;auth()-&amp;gt;webauthn(...)&lt;/li&gt;
	&lt;li&gt;Dotclear\Core\Backend\Auth\OAuth2Client&amp;nbsp;=&amp;gt; App::backend()-&amp;gt;auth()-&amp;gt;oauth2(...)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Voici une liste des classes de second niveau pour le Frontend :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Doclear\Core\Frontend\Ctx::class&amp;nbsp;=&amp;gt; App::frontend()-&amp;gt;context(),&lt;/li&gt;
	&lt;li&gt;Doclear\Core\Frontend\Tpl::class&amp;nbsp;=&amp;gt; App::frontend()-&amp;gt;template(),&lt;/li&gt;
	&lt;li&gt;Doclear\Core\Frontend\XmlRpc::class&amp;nbsp;=&amp;gt; App::frontend()-&amp;gt;xmlrpc(),&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Les plugins et thèmes, en pouvant accèder directement depuis le contexte à ces objets, ne devraient plus avoir à déclarer des classes appartenant aux Backend ou Frontend hormis lors de la création de liste pour étendre une classe.&lt;br /&gt;
.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-conteneurs#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-conteneurs#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/446</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Modification du service de session</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-session</link>
        <guid isPermaLink="false">urn:md5:8284d4a2603513d4245cdb2539439939</guid>
        <pubDate>Tue, 02 Sep 2025 09:29:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>session</category>
                  <category>sevrice</category>
                <description>&lt;p&gt;Avec l'arrivé de la gestion des sessions coté publique, Dotclear 2.36 modifie le fonctionnement des sessions.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Le mécanisme de session de Dotclear dans ces versions inférieures à 2.36 était très stricte et écrit en dur là ou il y en avait besoin. La version 2.36 introduit des outils de connexions variés et la possibilité d'utilser des sessions coté publique, ce qui a obligé la team à revoir le fonctionnement des sessions. Pas de révoluton, les classes de sessions n'ont quasi pas été modifié, mais des changements qui peuvent porter à consequence.&lt;/p&gt;

&lt;h3&gt;Backend&lt;/h3&gt;

&lt;p&gt;Précedement, les sessions coté admin (backend) n'existait que lorsqu'on en avait besoin, c'est à dire lorsque l'utilisateur était connu. On pouvait donc faire simplement un test d'existence de session pour diverses routines. Mais depuis la version 2.36, les sessions sont toujours démarrées et existantes. Elle peuvent donc être vide et sans valeur de test.&lt;/p&gt;

&lt;h3&gt;Frontend&lt;/h3&gt;

&lt;p&gt;Coté publique, les sessions fournies par Dotclear n'existaient tout simplement pas avant la version 2.36. Depuis si un plugin veut utiliser des sessions coté publique, une simple ligne de code suffira à la démarrer.&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;App::session()-&amp;gt;start();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Et si plusieurs plugins utilisent des sessions coté publique, chacun ajoutera cette ligne de code. Pas de soucis à l'appeler plusieurs fois, elle teste qu'elle a déjà été appelé.&amp;nbsp;Ce nouveau système de session commune coté publique risque de poser problème avec de vieux plugins pas à jour utilisant leurs propres sessions, ce qui provoquera des erreurs assez fatales ! Un bien pour un mal, car avec la 2.36 on met tout le monde d'accord.&lt;/p&gt;

&lt;p&gt;A noter que si un plugin utilise &lt;strong&gt;App::session()-&amp;gt;destroy();&lt;/strong&gt; il détruira la session pour tous les autres plugins en même temps, ce n'est peut-être pas le comportement souhaité par les autres plugins !&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;Sans me faire de pub (qui risque plutôt de m'apporter des problèmes) un plugin &lt;strong&gt;FrontendSession &lt;/strong&gt;propose de gérer les sessions coté publique avec tous les points d'entrée nécessaire à d'autres plugins. Widget, formulaire de login, menu utilisateur, page de gestion des options publique de l'utilisateur, etc...&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Accès aux valeurs&lt;/h3&gt;

&lt;p&gt;Dans les versions précédentes de Dotclear, l'accès aux valeurs de session se faisait classiquement par $_SESSION, mais cela change. Le service de session contient trois nouvelles méthodes pour lire, écrire et effacer ces valeurs.&lt;/p&gt;

&lt;p&gt;Leurs définition est très simple :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;interface SessionInterface
{
    // ...

    /**
     * Set a value to session.
     *
     * @param   string  $key    The key
     * @param   mixed   $value  The value
     */
    public function set(string $key, mixed $value): void;

    /**
     * Get a value from session.
     *
     * @param   string  $key    The key
     *
     * @return  mixed   The value or null if not set
     */
    public function get(string $key): mixed;

    /**
     * Unset values from session.
     *
     * @param   string  $keys   The keys
     */
    public function unset(...$keys): void;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Le plugin n'a plus qu'à lire et écrire des valeurs de session avec par exemple :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;if (App::session()-&amp;gt;get('ma_valeur') == '' &amp;amp;&amp;amp; !empty($__POST['mon_formulaire'])) {
    App::session()-&amp;gt;set('ma_valeur', '1');
}
if (!empty($_POST['reset'])) {
    App::sesssion()-&amp;gt;unset('ma_valeur');
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;La valeur sera automatiquement enregistrée en session à la fin du script, le plugin n'a pas à gérer cette partie non plus. Et l'ancienne écriture avec &lt;strong&gt;$_SESSION&lt;/strong&gt; est encore valable mais pas récommander.&lt;/p&gt;

&lt;h3&gt;Configuration&lt;/h3&gt;

&lt;p&gt;Précédement la configuration du gestionnaire de session se faisait à sa construction. Une méthode désormais présente pour configurer le service avant de démarrer une session. Cela permet d'avoir un seul service App::session() qui peut être configurer suivant si on est en frontend ou backend.&lt;/p&gt;

&lt;p&gt;Elle est définie dans son interface comme suit :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;Interface SessionInterface
{
    //...

    /**
     * Configure session cookie.
     *
     * This MUST be done before session starts.
     *
     * @param   string          $cookie_name    Cookie name
     * @param   null|string     $cookie_path    Cookie path
     * @param   null|string     $cookie_domain  Cookie domain
     * @param   bool            $cookie_secure  Cookie secure
     * @param   null|string     $ttl            The ttl
     *
     * @throws  Dotclear\Exception\SessionException     if session is already configured
     */
    public function configure(
        string $cookie_name, 
        ?string $cookie_path = null, 
        ?string $cookie_domain = null, 
        bool $cookie_secure = false, 
        ?string $ttl = null
    ): void;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Mais pas besoin de retenir cette mécanique, les &lt;strong&gt;&quot;Utility&lt;/strong&gt;&quot; (backend, frontend, upgrade) gère cette méthode et prépare le service avant l'appel aux plugins et thèmes.&lt;/p&gt;

&lt;p&gt;.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-session#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-session#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/445</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Modification du service de configuration</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-configuration</link>
        <guid isPermaLink="false">urn:md5:fe76d1f14369d7c8562bafb2d1d0cab2</guid>
        <pubDate>Tue, 02 Sep 2025 09:26:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>configuration</category>
                  <category>service</category>
                <description>&lt;p&gt;Avec l'arrivé des authentifications exotiques, de nouvelles directives sont disponibles dans la configuration de Dotclear 2.36&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dotclear 2.36 propose une librairie oAuth2 client qui permet l'authentification depuis des applications tierces, cette librairie a besoin d'un fichier de configuration commun à toute la plateforme multiblogs. Ce fichier suit des régles strictes, il doit se nommer oauth2.php et être présent dans le même répertoire que le config.php.&lt;/p&gt;

&lt;p&gt;Dans diffèrentes parties de Dotclear ou même de plugins, il y aura besoin de connaitre le chemin de ce fichier, on peut alors simplement récupérer son chemin complet comme suit :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;$path = App::config()-&amp;gt;oauth2Path();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Dans diffèrentes parties de Dotclear ou même de plugins, il y aura besoin de savoir si ce fichier existe, on peut alors tester simplement comme suit :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;$exists = App::config()-&amp;gt;hasOauth2();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;oAuth2 n'est pas la seule nouvelle librairie d'authentification tiers, il y a également Webauthn (clé de sécurité) et OTP (Mot de passe à usage unique). Il est possible de désactiver toutes ces authentifiactions exotiques depuis le fichier de configuration de Dotclear, il suffit d'ajouter la définition suivante :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;define('DC_AUTH_PASSWORD_ONLY', true);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pour les plugins, li est possible de connaitre l'état de cette directive afin de désactiver certaines de leurs fonctions avec :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;$limited = App:config()-&amp;gt;authPasswordOnly();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-configuration#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-configuration#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/444</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Modification des composants HTML</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-composants-HTML</link>
        <guid isPermaLink="false">urn:md5:7430454cc8783c14ae27a0cd05a587fc</guid>
        <pubDate>Wed, 20 Aug 2025 00:33:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>download</category>
                  <category>HTML</category>
                  <category>link</category>
                <description>&lt;p&gt;Un nouvel attribut &lt;strong&gt;download&lt;/strong&gt; fait son apparition dans les composants HTML.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Le composant &lt;strong&gt;Link &lt;/strong&gt;se dote d'un nouvel attribut qui va permettre d'indiquer au navigateur que la cible peut être téléchargée.&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;echo (new Link)
    -&amp;gt;href('/public/DotclearWatch_logo.png')
    -&amp;gt;text('Télécharger le logo')
    -&amp;gt;download(true)
    -&amp;gt;render();

echo (new Link)
    -&amp;gt;href('/public/DotclearWatch_logo.png')
    -&amp;gt;text('Télécharger le logo')
    -&amp;gt;download('logo.svg')
    -&amp;gt;render();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;La valeur de l'attribue peut être :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Un booleen pour que la balise ait ou non&amp;nbsp;l'attribue download&lt;/li&gt;
	&lt;li&gt;Un nom de fichier qui sera proposé lors du téléchargement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La plupart des navigateurs supporte cette attribut. Mais attention il risque d'être sans effet si le lien pointe vers une origine distante car il suit la régle de &lt;strong&gt;Same-Origin Policy&lt;/strong&gt;.&amp;nbsp;&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-composants-HTML#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-composants-HTML#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/440</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Gestion de jeton utilisateur</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Gestion-de-jeton-utilisateur</link>
        <guid isPermaLink="false">urn:md5:08327aeb0c59c36b57dea9f5dc2d2322</guid>
        <pubDate>Tue, 19 Aug 2025 15:26:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>credential</category>
                  <category>databale</category>
                  <category>jeton</category>
                  <category>table</category>
                <description>&lt;p&gt;Avec l'arrivée des connexions exotiques sur la version 2.36, Dotclear embarque une nouvelle table dans la base de données accompagnée de sa classe de gestion.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Les jetons d'accés des utilisateurs à des services tiers doivent pouvoir être gérés par utilisateur mais également par service, les tables existantes de Dotclear ne proposaient pas de solution adéquate. Une nouvelle table &lt;strong&gt;credential&lt;/strong&gt; et sa classe &lt;strong&gt;App::credential()&lt;/strong&gt; sont donc disponibles depuis Dotclear 2.36.&lt;/p&gt;

&lt;p&gt;Préambule&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;La classe de gestion de jeton est très classique de ce qui se fait dans Dotclear.&lt;/li&gt;
	&lt;li&gt;La classe est toujours disponible directement dans Dotclear.&lt;/li&gt;
	&lt;li&gt;Si un utilisateur est supprimé, ses jetons seront également supprimés (cascade)&lt;/li&gt;
	&lt;li&gt;Si un blog est supprimé les jetons qui lui sont liés seront également&amp;nbsp;supprimés (cascade)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Attention &lt;/u&gt;: Les données sont cryptées avant d'être enregistrées dans la base de données, si vous perdez la&amp;nbsp;&quot;Master Key&quot; de votre installation, toutes ces données seront illisibles et donc perdues.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;Schéma de la table&lt;/h3&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;
$structure-&amp;gt;credential
            -&amp;gt;field('user_id', 'varchar', 32, false)
            -&amp;gt;field('blog_id', 'varchar', 32, true, null)
            -&amp;gt;field('credential_dt', 'timestamp', 0, false, 'now()')
            -&amp;gt;field('credential_type', 'varchar', 32, false)
            -&amp;gt;field('credential_value', 'varchar', 255, false, &quot;''&quot;)
            -&amp;gt;field('credential_data', 'text', 0, true, null)

            -&amp;gt;unique('uk_credential', 'credential_type', 'user_id', 'blog_id', 'credential_value')


$structure-&amp;gt;credential
            -&amp;gt;index('idx_credential_user_id', 'btree', 'user_id');
$structure-&amp;gt;credential
            -&amp;gt;index('idx_credential_blog_id', 'btree', 'blog_id');
$structure-&amp;gt;credential
            -&amp;gt;reference('fk_credential_user', 'user_id', 'user', 'user_id', 'cascade', 'cascade')
$structure-&amp;gt;credential
            -&amp;gt;reference('fk_credential_blog', 'blog_id', 'blog', 'blog_id', 'cascade', 'cascade');
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Définition de son interface&lt;/h3&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;
namespace Dotclear\Interface\Core;

use ArrayObject;
use Dotclear\Database\Cursor;
use Dotclear\Database\MetaRecord;

/**
 * @brief   User credentials handler interface.
 *
 * Use this class to store user credential
 * for third party applications.
 *
 * @author  Jean-Christian Paul Denis
 * @since   2.36
 */
interface CredentialInterface
{
    /**
     * Credential table name.
     *
     * @var    string  CREDENTIAL_TABLE_NAME
     */
    public const CREDENTIAL_TABLE_NAME = 'credential';

    /**
     * Open a credential database table cursor.
     *
     * @return  Cursor  The credential database table cursor
     */
    public function openCredentialCursor(): Cursor;

    /**
     * Get credentials.
     *
     * @param      array&amp;lt;string, mixed&amp;gt;|ArrayObject&amp;lt;string, mixed&amp;gt;  $params      The parameters
     *
     * @return     MetaRecord  The users.
     */
    public function getCredentials(array|ArrayObject $params = []): MetaRecord;

    /**
     * Set user credential.
     *
     * @param     string     $user_id     The user ID
     * @param     Cursor     $cur         The credential Cursor
     */
    public function setCredential(string $user_id, Cursor $cur): void;

    /**
     * Delete credentials.
     *
     * If &amp;lt;var&amp;gt;$global&amp;lt;/var&amp;gt; is set to False, current blog is selected.
     *
     * @param   string          $credential_type    The credential type
     * @param   string          $credential_value   The credential value
     * @param   null|string     $user_id            The user_id (or null for all users)
     * @param   bool            $global             True for global or false for current blog
     */
    public function delCredentials(string $credential_type, string $credential_value = '', ?string $user_id = null, bool $global = true): void;

    /**
     * Encrypt data.
     *
     * This is used to protect sensible data in database.
     * Data encryption is linked to Dotclear's master key.
     *
     * @param   ArrayObject&amp;lt;string, mixed&amp;gt;|array&amp;lt;string, mixed&amp;gt;     $data   The credential data to encode
     *
     * @return  string  The encoded credential data
     */
    public function encryptData(array|ArrayObject $data): string;

    /**
     * Decrypt data.
     *
     * Decode data encoded with self::encreyptData()
     *
     * @param   string  $data   The encoded credential data
     *
     * @return  array&amp;lt;string, mixed&amp;gt; The decoded credential data
     */
    public function decryptData(string $data): array;
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Recherche de jetons&lt;/h3&gt;

&lt;p&gt;Les paramètres de recherche de la méthode getCredentials() sont :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;user_id : optionnel : l'utilisateur du jeton&lt;/li&gt;
	&lt;li&gt;blog_id : optionnel : la blog courant (si ommit ce sera global)&lt;/li&gt;
	&lt;li&gt;credential_type : optionnel : généralement le nom du service associé au jeton (si ommit ce sera &quot;webauthn&quot;)&lt;/li&gt;
	&lt;li&gt;credential_value&amp;nbsp;: optionnel : une valeur mise en avant du jeton&lt;/li&gt;
	&lt;li&gt;order : optionnel : parametre de trie&lt;/li&gt;
	&lt;li&gt;limit : optionnel : limite de nombre de résultats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Les données du champs credential_data sont cryptées lors de l'enregistrement d'un champs, pour les décrypter il faut utiliser la méthode $rs-&amp;gt;getAllData(); de l'enregistrement retourné.&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;$rs = App::credential()-&amp;gt;getCredentials([
    'credential_type' =&amp;gt; 'plop',
    'user_id' =&amp;gt; App::auth()-&amp;gt;userID(),
]);
if (!$rs-&amp;gt;isEmpty()) {
    // tableau complet du jeton
    $data = $rs-&amp;gt;getAllData();
    // ou
    $un_morceau_de_jeton = $rs-&amp;gt;getData('un_morceau_de_jeton');
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Ajout de jeton&lt;/h3&gt;

&lt;p&gt;L'ajout du jeton se fait à la manière de Dotclear, en ouvrant un curseur et en y incluant les informations qu'on désire.&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;$cur = App::credential()-&amp;gt;openCredentialCursor();
$cur-&amp;gt;setField('blog_id', App::blog()-&amp;gt;id());
$cur-&amp;gt;setField('credential_type', 'mon_service');
$cur-&amp;gt;setField('credential_value', 'XYZEFFRE1234');
$cur-&amp;gt;setField('credential_data', new ArrayObject($mon_tableau_du_jeton));
App::credential()-&amp;gt;setCredential((string) App::auth()-&amp;gt;userID(), $cur);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On remarque que pour le champs &lt;strong&gt;credential_data&lt;/strong&gt; on crée un objet, cela permet de le manipuler dans la classe &lt;strong&gt;credential &lt;/strong&gt;et de pouvoir le crypter lors de l'enregistrement dans la base de données.&lt;/p&gt;

&lt;h3&gt;Supression de jeton&lt;/h3&gt;

&lt;p&gt;Le suppression de jetons se fait en empilant les critères suivant :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;credential_type : obligatoire.&lt;/li&gt;
	&lt;li&gt;credential_value : obligatoire, si ommit on cherche une valuer vide&lt;/li&gt;
	&lt;li&gt;user_id : optionnel&lt;/li&gt;
	&lt;li&gt;global : si vrai on recherche une valeur null de blog, si faux on recherche le blog courant&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;App::credential()-&amp;gt;delCredentials(
    'mon_service',
    'une_clé',
    null,
    false
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Dans cet exemple on supprimer le jeton de valeur 'une_clé' de type 'mon_service' sur le blog courant et peu importe l'utilisateur.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Rien d'extraordinaire sur cette classe, il suffit juste de réspecter les quelques recommandations présenteés ici.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Gestion-de-jeton-utilisateur#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Gestion-de-jeton-utilisateur#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/438</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Authentification à deux facteurs</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Authentification-%C3%A0-deux-facteurs</link>
        <guid isPermaLink="false">urn:md5:b50b2ae660538bfdae54e036c3f9edee</guid>
        <pubDate>Tue, 19 Aug 2025 14:46:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>2fa</category>
                  <category>authentification</category>
                  <category>otp</category>
                <description>&lt;p&gt;La version 2.36 de Dotclear possède une librairie OTP (One Time Password) qui sera utiliser pour l'authentification à deux facteurs (2fa) à l'aide d'outils tels que Google Authenticator.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Il n'y a aucune configuration pour l'authentification à deux facteurs et le protocole TOTP sera le seul proposé.&amp;nbsp;Une classe unique compose la librairie de gestion OTP (One Time Password) proposant les deux facettes de ce protocole qui sont par temps TOTP ou par compteur HOTP. Une seconde classe vient surcharger celle-ci pour coller à la partie backend de Dotclear qui utilise TOTP.&lt;/p&gt;

&lt;p&gt;Dans le premier onglet des préférences utilisateur une partie est dédiée à l'Authentification à deux facteurs. Si l'utilisateur n'a pas encore vérifié un code alors l'authentification pour cette utilisateur est désactivé.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;media-link media-center&quot; href=&quot;https://dotclear.watch/public/2.36/sshot_prefs_otp_logout.png&quot; title=&quot;Ouvrir le média&quot;&gt;&lt;img alt=&quot;Préférences utilisateur pour l'authentification à deux facteurs&quot; class=&quot;media&quot; src=&quot;https://dotclear.watch/public/2.36/.sshot_prefs_otp_logout_m.png&quot; /&gt;&lt;/a&gt;Il faut scanner avec son téléphone mobile (par exemple) le QR code, cela va ouvrir l'application d'authentification et propser un code qu'il faudra renseigner dans le formulaire pour activer le 2FA (Authentification à deux facteurs). Si aucune application d'authentification n'est présente sur le téléphone il faut en installer une, Microsoft Authenticator, Google Authenticator, etc...&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;media-link media-center&quot; href=&quot;https://dotclear.watch/public/2.36/sshot_prefs_otp_login.png&quot; title=&quot;Ouvrir le média&quot;&gt;&lt;img alt=&quot;Préférences utilisateur pour l'authentification à deux facteurs&quot; class=&quot;media&quot; src=&quot;https://dotclear.watch/public/2.36/.sshot_prefs_otp_login_m.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Si un code est vérifié, l'authentification à deux facteurs lui sera demander uniquement lors de la phase d'authentification par login et mot de passe (pas pour les éventuelles autres méhodes).&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;media-link media-center&quot; href=&quot;https://dotclear.watch/public/2.36/sshot_prefs_otp_setp1.png&quot; title=&quot;Ouvrir le média&quot;&gt;&lt;img alt=&quot;Page de login pour l'authentification à deux facteurs&quot; class=&quot;media&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_otp_setp1.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;media-link media-center&quot; href=&quot;https://dotclear.watch/public/2.36/sshot_prefs_otp_setp2.png&quot; title=&quot;Ouvrir le média&quot;&gt;&lt;img alt=&quot;Page de login pour l'authentification à deux facteurs&quot; class=&quot;media&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_otp_setp2.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si l'utilisateur à perdu le générateur de code sur sont téléphone mobile, il est alors obligé de suivre la procédure de perte de mot de passe de Dotclear qui désactivera l'authentification à deux facteurs. Il peut également desactiver cette authentification dans les préferences utilisateur. Il peut également y générer une nouveau secret qu'il faudra alors à nouveau scanner dans son application.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Authentification-%C3%A0-deux-facteurs#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Authentification-%C3%A0-deux-facteurs#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/435</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Gestion de session</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Gestion-de-session</link>
        <guid isPermaLink="false">urn:md5:ff518553435a1e4dbe965b61487ce6d4</guid>
        <pubDate>Tue, 19 Aug 2025 14:38:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>session</category>
                <description>&lt;p&gt;La version 2.36 de Dotclear modifie le fonctionnement des sessions.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Le mécanisme de session de Dotclear dans ces versions inférieures à 2.36 était très stricte et écrit en dur là ou il y en avait besoin. La version 2.36 introduit des outils de connexions variés et la possibilité d'utilser des sessions coté publique, ce qui a obligé la team à revoir le fonctionnement des sessions. Pas de révoluton, les classes de sessions n'ont quasi pas été modifié, mais des changements qui peuvent porter à consequence.&lt;/p&gt;

&lt;h3&gt;Backend&lt;/h3&gt;

&lt;p&gt;Précedement, les sessions coté admin (backend) n'existait que lorsqu'on en avait besoin, c'est à dire lorsque l'utilisateur était connu. On pouvait donc faire simplement un test d'existence de session pour diveses routines. Mais depuis la version 2.36, les sessions sont toujours démarrées et existantes. Et peuvent donc être vide et sans valeur de test.&lt;/p&gt;

&lt;h3&gt;Frontend&lt;/h3&gt;

&lt;p&gt;Coté publique, les sessions fournies par Dotclear n'existait tout simplement pas avant la version 2.36. Depuis si un plugin veut utiliser des sessions coté publique, une simple ligne de code suffira à la démarrer.&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;App::session()-&amp;gt;start();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Et si plusieurs plugins utilisent de session coté publique, chacun ajoutera cette ligne de code. Pas de soucis à l'appeler plusiseurs fois, elle teste qu'elle a déjà été appelé.&amp;nbsp;Ce nouveau systeme de session commune coté publique risque de poser problème avec de vieux plugins pas à jour utilisant leurs propres sessions, ce qui provoquera des erreurs assez fatales ! Un bien pour un mal, car avec la 2.36 on met tout le monde d'accord.&lt;br /&gt;
&lt;br /&gt;
Sans me faire de pub (qui risque plutôt de m'apporter des problèmes) un plugin &lt;strong&gt;FrontendSession &lt;/strong&gt;propose de gérer les sessions coté publique avec tous les points d'entrée nécessaire à d'autres plugins. Widget, formulaire de login, menu utilisateur, page de gestion des options publique de l'utilisateur, etc...&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Gestion-de-session#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Gestion-de-session#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/433</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Mode dévelopement pour l'éditeur de thème</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Mode-d%C3%A9velopement-pour-l-%C3%A9diteur-de-th%C3%A8me</link>
        <guid isPermaLink="false">urn:md5:2c74075a43fed6497e4a5ed6a7e86d56</guid>
        <pubDate>Tue, 19 Aug 2025 11:34:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>behavior</category>
                  <category>thème</category>
                <description>&lt;p&gt;Dotclear 2.35 introduisait une nouvelle gestion de &lt;a href=&quot;https://open-time.net/post/2025/06/29/Adapter-un-theme-pour-Dotclear-235&quot; hreflang=&quot;fr&quot; title=&quot;Adapter un thème pour Dotclear 2.35 - sur Open-Time&quot;&gt;surcharge de thèmes&lt;/a&gt;, et dans le version 2.36 une option de &lt;a href=&quot;https://open-time.net/post/2025/08/19/La-nouvelle-gestion-des-themes - sur Open-Time&quot; hreflang=&quot;fr&quot; title=&quot;La nouvelle gestion des thèmes&quot;&gt;mode de dévelopement&lt;/a&gt; fait son appartition dans l'éditeur de thème.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Le nouveau behavior&amp;nbsp;&lt;strong&gt;themeEditorDevMode&lt;/strong&gt;, si il retourne vrai, permet de modifier sur place les fichiers d'un thème dans l'éditeur de thème.&lt;/p&gt;

&lt;p&gt;Il suffit de l'activer en appelant le beharvior comme suit :&lt;/p&gt;

&lt;pre&gt;
&lt;code class=&quot;language-php&quot;&gt;App::behavior()-&amp;gt;addBehavior('themeEditorDevMode', fn(): bool =&amp;gt; true);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Un message apparaitra lors de la modification d'un thème.&lt;br /&gt;
&lt;br /&gt;
&lt;a class=&quot;media-link media-center&quot; href=&quot;https://dotclear.watch/public/2.36/dc_2.36_themeeditordevmode.png&quot; title=&quot;Ouvrir le média&quot;&gt;&lt;img alt=&quot;2.36 Theme editor dev mode&quot; class=&quot;media&quot; src=&quot;https://dotclear.watch/public/2.36/.dc_2.36_themeeditordevmode_m.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
Le plugin &lt;strong&gt;tidyAdmin &lt;/strong&gt;dans sa version pour Dotclear 2.36 propose une option pour faire cela depuis l'interface utilisateur.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Mode-d%C3%A9velopement-pour-l-%C3%A9diteur-de-th%C3%A8me#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Mode-d%C3%A9velopement-pour-l-%C3%A9diteur-de-th%C3%A8me#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/432</wfw:commentRss>
              </item>
          <item>
        <title>[2.36] Connexion par clé de sécurité</title>
        <link>https://dotclear.watch/Billet/%5B2.36%5D-Connexion-par-cl%C3%A9-de-s%C3%A9curit%C3%A9</link>
        <guid isPermaLink="false">urn:md5:6f06631eb824326769415c642daee2fc</guid>
        <pubDate>Tue, 19 Aug 2025 11:24:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.36</category>
                          <category>2.36</category>
                  <category>authentification</category>
                  <category>webauthn</category>
                <description>&lt;p&gt;La version 2.36 de Dotclear introduit une librairie webauthn permettant d'utiliser des clés de sécurité pour s'authentifier à la partie administration.&lt;/p&gt; &lt;p&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/2.36&quot; title=&quot;Article rédigé pour Dotclear 2.36&quot;&gt;&lt;img alt=&quot;badge Dotclear 2.36&quot; src=&quot;https://img.shields.io/badge/Dotclear-2.36-blue?style=for-the-badge&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Le protocole &lt;strong&gt;webauthn&lt;/strong&gt; fait partie de l'API &lt;strong&gt;Credential Management&lt;/strong&gt; des navigateurs web., il est donc lié à ce que va embarquer le navigateur de l'utilisateur, mais la plupart d'entre eux supportent très bien ce protocole. Le principe consiste à enregistrer dans les préférences utilisateur de Dotclear un mateirel physique comme une clé USB (passkey) ou une application comme 1Password, puis utiliser ce materiel par la suite pour s'identifier sur Dotclear sans rentrer de login ni mot de passe. A noter que cette fonction nécessite l'activation de javascript et du service Rest de Dotclear.&lt;/p&gt;

&lt;h3&gt;Exemple avec une clé de sécurité physique.&lt;/h3&gt;

&lt;p&gt;On commence par enregistrer notre clé, pour cela dans le premier onglet des préférences utilisateur du tableau de bord de Dotclear, vous trouverez un encart nommé &lt;strong&gt;Clés d'authentification&lt;/strong&gt;, l'appuie sur le bouton &lt;strong&gt;Enregistrer une nouvelle clé&lt;/strong&gt; lancera la procédure.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/.sshot_prefs_webauthn_step1_m.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Suivant le navigateur, ses extensions et votre matriel, il va vous proposer divers choix, pour l'exemple on choisie &lt;strong&gt;Clé de sécurité&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_webauthn_step2.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Comme on va se servir de la clé pour nous authentifier il va nous avertir de tout cela.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_webauthn_step3.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_webauthn_step4.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Puis, toujours parce qu'on utilise la clé pour s'authentifier, il demande de valider avec le code PIN de la clé.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_webauthn_step5.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ensuite c'est une clé physique avec validation de présence, il faut donc appyuer sur la clé pour montrer qu'on est présent vers la clé.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_webauthn_step6.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Enfin dernière étape qu'il ne faut surtout pas manquer, c'est la validation finale qui confirme qu'on a bien suivi la procédure et qui ensuite va enregistrer la clé dans Dotclear.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_webauthn_step7.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Tout cela peut paraitre long, mais si tout se passe bien on ne devrait avoir à la faire qu'une fois pour toute.&lt;br /&gt;
Voila notre clé est enregistré, on peut tester de s'authentifier à la page de login de Dotclear.&lt;/p&gt;

&lt;p&gt;Un appuie sur le bouton &lt;strong&gt;Se connecter avec une clé d'accès&lt;/strong&gt; lancera la procédure.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_auth_webauthn_step1.png&quot; /&gt;&lt;br /&gt;
On choisi le type de clé, dans notre exemple nous avons enregistré une &lt;strong&gt;Clé de sécurité&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/.sshot_auth_webauthn_step2_m.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Comme il s'agit d'authentification, il nous est demandé le code PIN de la clé.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_auth_webauthn_step3.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Et comme il s'agit du clé avec validation de présence, il faut alors toucher la clé.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_auth_webauthn_step4.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Une fois fait, on devrait voir apparaitre automatiquement le tableau de bord de Dotclear !&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;Exemple avec l'extension de navigateur 1password&lt;/h3&gt;

&lt;p&gt;L'exetnsion &lt;strong&gt;1password&lt;/strong&gt; s'intègre dans le navigateur et agit comme une clé de sécurité, à ceci prêt que la procédure est encore plus rapide.&lt;/p&gt;

&lt;p&gt;On recommence la procedure depuis le premier onlget des préférences utilisateur, et on appuie sur &lt;strong&gt;Enregistrer une nouvelle clé&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/.sshot_prefs_webauthn_step1_m.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Un encart dans le coin du navigateur nous invite à enregistrer 1password comme clé. (On peut également choisir d'utiliser une autre clé de sécurite en clqiuant sur la petite clé en haut à droite.)&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_prefs_webauthn_step8.png&quot; /&gt;On enregistre, et c'est tout ! L'extension sera notre clé d'authentification.&lt;/p&gt;

&lt;p&gt;Maintenant on teste de s'authentifier à la partie administration, un appui sur le bouton &lt;strong&gt;Se connecter avec un clé d'accès&lt;/strong&gt; lancera la procédure.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_auth_webauthn_step1.png&quot; /&gt;Et l'extension va automatiquement nous proposer de nous authentifier.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; class=&quot;media media-center&quot; src=&quot;https://dotclear.watch/public/2.36/sshot_auth_webauthn_step5.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On appuie sur connexion et on devrait voir apparaitre le tableau de bord de Dotclear ! Rapide.&lt;/p&gt;

&lt;h3&gt;Autres&lt;/h3&gt;

&lt;p&gt;Il existe d'autres materiels et d'autres logiciels, par exemple utiliser son téléphone en bluetooth comme clé d'accès. Le choix est vaste, chacun prendre la solution qui lui convient.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/%5B2.36%5D-Connexion-par-cl%C3%A9-de-s%C3%A9curit%C3%A9#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/%5B2.36%5D-Connexion-par-cl%C3%A9-de-s%C3%A9curit%C3%A9#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/427</wfw:commentRss>
              </item>
          <item>
        <title>2.36</title>
        <link>https://dotclear.watch/Billet/2.36</link>
        <guid isPermaLink="false">urn:md5:df07b531242af85e3617f49dcc89baf2</guid>
        <pubDate>Tue, 19 Aug 2025 11:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>Versions</category>
                          <category>2.36</category>
                  <category>preview</category>
                <description>&lt;p&gt;La prochaine version de Dotclear apportera une touche de modernité dés la page d'authentification.&lt;/p&gt; &lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Nouveau format de billet de présentation pour cette version 2.36 qui va détailler chaque changements techniques.&lt;br /&gt;
Ce billet évoluera jusqu'a la sortie de la 2.36.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img alt=&quot;badge version 2.36&quot; src=&quot;https://img.shields.io/badge/Version-2.36-blue?style=for-the-badge&quot; /&gt; &lt;img alt=&quot;badge date 13 nov 2025&quot; src=&quot;https://img.shields.io/badge/Date-13%20nov%202025-green?style=for-the-badge&quot; /&gt;&lt;/p&gt;

&lt;h3&gt;Résumé&lt;/h3&gt;

&lt;p&gt;Cette version modifie le fonctionnement des sessions coté admin (backend) et coté public (frontend) ce qui lui permet de proposer de nouveaux outils comme l'authentification par des applications et materiels tiers et la gestion d'utilisteur coté public. A noter l'arrivé de nouveaux supports de drivers de base de données basé sur PDO. Et bien plus encore, avec la correction de bugs et le renforcement des Tests Unitaires.&lt;/p&gt;

&lt;h3&gt;Nouveautés&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Mode-d%C3%A9velopement-pour-l-%C3%A9diteur-de-th%C3%A8me&quot;&gt;Nouveau mode dévelopement pour l'éditeur de thème&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-composants-HTML&quot;&gt;Nouvel attribue download du composant Link&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Gestion-de-jeton-utilisateur&quot;&gt;Nouvelle gestion de jeton utilisateur&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Authentification-%C3%A0-deux-facteurs&quot;&gt;Nouvelle authentification à deux facteurs OTP&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Connexion-par-cl%C3%A9-de-s%C3%A9curit%C3%A9&quot;&gt;Nouvelle connexion par clé de sécurité Webauhtn&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Nouvelle connexion par application tierce&amp;nbsp;oAuth2&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-configuration&quot;&gt;Nouvelles directives de configuration&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-base-de-donn%C3%A9es&quot;&gt;Nouveau service&amp;nbsp;d'accès à la base de données&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-base-de-donn%C3%A9es&quot;&gt;Nouveaux drivers de base de données basés sur PDO&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Installation-en-mode-CLI&quot;&gt;Nouveau mode d'installation en CLI&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Nouvelle&amp;nbsp;classe de description de média MediaFile&lt;/li&gt;
	&lt;li&gt;Nouveau behavior&amp;nbsp;adminPageHTMLBody&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Changements&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-session&quot;&gt;Modification de la gestion de session&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-du-service-de-base-de-donn%C3%A9es&quot;&gt;Modification de l'appel à la connexion à la base de donnée&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-Utility-et-Process&quot;&gt;Modification des Utility et Process&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-conteneurs&quot;&gt;Modification des contructeurs de classes de premier niveau&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;ref-post&quot; href=&quot;https://dotclear.watch/Billet/%5B2.36%5D-Modification-des-conteneurs&quot;&gt;Modification de l'appel aux services d'un container&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Passage des tests unitaires existants de &lt;strong&gt;Atoum &lt;/strong&gt;ver &lt;strong&gt;PHPUnit&lt;/strong&gt;&lt;/li&gt;
	&lt;li&gt;La classe File ne supporte plus les propriétés dynamiques&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Dépréciés&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;Voir le détail des changements ci-dessus&lt;/li&gt;
	&lt;li&gt;Pas de nouveaux dépréciés dans cette version&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Retirés&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;La méthode &lt;strong&gt;App::media()::flvplayer()&lt;/strong&gt; dépréciée depuis Dotclear 2.15 est définitivement retirée en 2.36.&lt;/li&gt;
	&lt;li&gt;La méthode &lt;strong&gt;App::media()::getFSDir()&lt;/strong&gt; est retirée en 2.36&lt;/li&gt;
	&lt;li&gt;La méthode &lt;strong&gt;ThemeConfig::cleanCss()&lt;/strong&gt;&amp;nbsp;est retiré en 2.36&lt;/li&gt;
	&lt;li&gt;Suppression de l'utilisation de &lt;strong&gt;iconv()&lt;/strong&gt; remplacé par &lt;strong&gt;mb_convert_encoding()&lt;/strong&gt;.&amp;nbsp;(Voir &lt;strong&gt;Text::toUTF8()&lt;/strong&gt; )&lt;/li&gt;
	&lt;li&gt;Supression de l'ancienne méthode &lt;strong&gt;dcCore::app()-&amp;gt;spamFilters&lt;/strong&gt; (Voir le behavior&amp;nbsp;&lt;strong&gt;AntispamInitFilters&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/2.36#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/2.36#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/424</wfw:commentRss>
              </item>
      </channel>
</rss>
