<?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.28</title>
    <link>https://dotclear.watch/</link>
    <atom:link href="https://dotclear.watch/feed/tag/2.28/rss2" rel="self" type="application/rss+xml" />
    <description>Suivez l'évolution du moteur de blogs Dotclear.</description>
    <language>fr</language>
    <pubDate>Wed, 24 Jun 2026 06:26:51 +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>Sortie de Dotclear 2.28</title>
        <link>https://dotclear.watch/Billet/Sortie-de-Dotclear-2.28</link>
        <guid isPermaLink="false">urn:md5:c54d3e2c3c66b821061874f6c5fd09b1</guid>
        <pubDate>Wed, 15 Nov 2023 18:25:00 +0100</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>Actualités</category>
                          <category>2.28</category>
                  <category>release</category>
                <description>&lt;p&gt;Ce mercredi 15 Novembre 2023 sort la version 2.28 du moteur de blogs Dotclear.&lt;/p&gt; &lt;p&gt;Comme dit dans &lt;a href=&quot;https://fr.dotclear.org/blog/post/2023/11/15/Dotclear-2.28&quot; hreflang=&quot;fr&quot; title=&quot;Annonce officielle de Dotclear 2.28&quot;&gt;le billet d'annonce officielle&lt;/a&gt; et dans &lt;a href=&quot;https://dotclear.watch/Billet/Release-2.28&quot; hreflang=&quot;fr&quot; title=&quot;Description de Dotclear 2.28&quot;&gt;la description de version sur ce blog&lt;/a&gt;, cette version finit la transition du moteur vers les espaces de noms PHP et passe les prérequis vers PHP 8.1 minimum. A noter que d'après les premiers essais, elle supporte très bien PHP 8.2 et 8.3.&lt;br&gt;
Cette mise à jour chamboule encore beaucoup le code et il est fortement conseillé de la faire en mode sans échec.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/Sortie-de-Dotclear-2.28#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/Sortie-de-Dotclear-2.28#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/51</wfw:commentRss>
              </item>
          <item>
        <title>Prévisions de la 2.28</title>
        <link>https://dotclear.watch/Billet/Pr%C3%A9visions-de-la-2.28</link>
        <guid isPermaLink="false">urn:md5:da205304ea19c2f72ff462114be88608</guid>
        <pubDate>Fri, 13 Oct 2023 08:01:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>Actualités</category>
                          <category>2.28</category>
                  <category>preview</category>
                <description>&lt;p&gt;Un mois avant la sortie de Dotclear 2.28 prévue autour du 13 novembre 2023.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://dotclear.watch/Billet/Release-2.28&quot;&gt;une série de billets&lt;/a&gt; pour se familiariser avec les nombreuses avancées apportées par cette version est disponible sur dotclear.watch.&lt;br&gt;
Il reste un mois (ou plus) avant la sortie de la version stable, certaines informations distillées dans ces billets peuvent encore évoluer d'ici là, ils seront donc mis à jour en temps réel si besoin.&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/Pr%C3%A9visions-de-la-2.28#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/Pr%C3%A9visions-de-la-2.28#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/35</wfw:commentRss>
              </item>
          <item>
        <title>Les exceptions de premier niveau</title>
        <link>https://dotclear.watch/Billet/Les-exceptions-de-premier-niveau-en-2.28</link>
        <guid isPermaLink="false">urn:md5:3ab7d5caaed81f3c359cbef84439b582</guid>
        <pubDate>Fri, 13 Oct 2023 08:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.28</category>
                          <category>2.28</category>
                  <category>error</category>
                  <category>exception</category>
                  <category>fault</category>
                <description>&lt;p&gt;La &lt;a href=&quot;https://dotclear.watch/Billet/Release-2.28&quot;&gt;version 2.28&lt;/a&gt; apporte une nouvelle gestion des exceptions et erreurs de premier niveau,&lt;/p&gt; &lt;p&gt;Après quelques balbutiements en version 2.27, une première avancée dans la gestion et la reconnaissance plus fine des erreurs bloquantes de l'application est introduite en version 2.28. Avec l'ajout d'une classe spéciale au gestionnaire d'erreur PHP, la majorité des erreurs générées par la racine de l'application ou de son cœur est désormais interceptée par des classes d'exception renvoyant un code et un message unique. Tous ces codes et messages sont regroupés dans un énumérateur. Les exceptions sont si possible traitées suivant différents paramètres (mode debug, mode CLI...) puis renvoyées à l'utilisateur.&lt;br /&gt;&lt;/p&gt;&lt;a href=&quot;https://dotclear.watch/public/2.28/exception.png&quot; title=&quot;exception.png, oct. 2023&quot;&gt;&lt;figure class=&quot;media-center&quot;&gt;&lt;img src=&quot;https://dotclear.watch/public/2.28/.exception_m.png&quot; alt=&quot;exception.png, oct. 2023&quot; title=&quot;exception.png, oct. 2023&quot; /&gt;&lt;figcaption&gt;Fault class in debug mode&lt;/figcaption&gt;&lt;/figure&gt;&lt;/a&gt;

&lt;h5&gt;Liste d'erreurs :&lt;/h5&gt;

&lt;p&gt;&lt;em&gt;susceptible de changer dans les versions à venir&lt;/em&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;503 : AppException : Site temporarily unavailable&lt;/li&gt;
&lt;li&gt;400 : BadRequestException : Bad Request&lt;/li&gt;
&lt;li&gt;570 : BlogException : Blog handling error&lt;/li&gt;
&lt;li&gt;551 : ConfigException : Application configuration error&lt;/li&gt;
&lt;li&gt;409 : ConflictException : Conflict&lt;/li&gt;
&lt;li&gt;553 : ContextException : Application context error&lt;/li&gt;
&lt;li&gt;560 : DatabaseException : Database connection error&lt;/li&gt;
&lt;li&gt;404 : NotFoundException : Not Found&lt;/li&gt;
&lt;li&gt;412 : PreconditionException : Precondition Failed&lt;/li&gt;
&lt;li&gt;552 : ProcessException : Application process error&lt;/li&gt;
&lt;li&gt;561 : SessionException : Session handling error&lt;/li&gt;
&lt;li&gt;571 : TemplateException : Template handling error&lt;/li&gt;
&lt;li&gt;401 : UnauthorizedException : Unauthorized&lt;/li&gt;
&lt;li&gt;500 : InternalServerException : Internal Server Error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deux grandes catégories sont présentes avec :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;4xx : Erreur client&lt;/li&gt;
&lt;li&gt;5xx : Erreur serveur&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Traitement&lt;/h5&gt;

&lt;p&gt;Les exceptions et erreurs interceptées par l'application sont alors envoyées à la classe Fault pour traitement et affichage à l'utilisateur. Il est possible d'intervenir avant l'affichage en définissant dans la constante DC_ERRORFILE un fichier à appeler, ce fichier php aura accès à toute la classe Fault.&lt;br /&gt;
Si la plateforme à déjà déclaré un gestionnaire d'exception à PHP, il sera alors utilisé.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Incompatibilité&lt;/h5&gt;

&lt;p&gt;Les méthodes de la classe Fault introduites en version 2.27 sont déjà obsolètes et tout simplement supprimées.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;&lt;q&gt;Le contenu de ce document a été écrit suivant le code de la version 2.28 de Dotclear.&lt;/q&gt;&lt;/em&gt;&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Les dépréciés</title>
        <link>https://dotclear.watch/Billet/Les-d%C3%A9pr%C3%A9ci%C3%A9s-en-2.28</link>
        <guid isPermaLink="false">urn:md5:8c3535a2f207a5b8343b876193e3974b</guid>
        <pubDate>Fri, 13 Oct 2023 08:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.28</category>
                          <category>2.28</category>
                  <category>déprécié</category>
                <description>&lt;p&gt;La &lt;a href=&quot;https://dotclear.watch/Billet/Release-2.28&quot;&gt;version 2.28&lt;/a&gt; de Dotclear apporte son lot de dépréciés.&lt;/p&gt; &lt;h5&gt;Core&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes de la classe principale du cœur de Dotclear (dcCore) passent en dépréciées, une &lt;a href=&quot;https://dotclear.watch/Billet/Les-d%C3%A9pr%C3%A9ci%C3%A9s-du-core-en-2.28&quot;&gt;page spéciale est dédiée à ces dépréciés&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Constantes&lt;/h5&gt;

&lt;p&gt;Les constantes suivantes sont dépréciées, il faut utiliser &lt;a href=&quot;https://dotclear.watch/Billet/Remplacer-une-classe-de-premier-niveau-en-2.28&quot;&gt;le système de service du Core&lt;/a&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DC_AUTH_CLASS =&amp;gt; doit remplacer le service AuthInterface::class&lt;/li&gt;
&lt;li&gt;DC_DBHANDLER_CLASS =&amp;gt; doit remplacer le service ConnectionInterface::class&lt;/li&gt;
&lt;li&gt;DC_DBSCHEMA_CLASS =&amp;gt; doit faire partie de la classe de Connection, et être fourni par App::con()-&amp;gt;schema()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour les autres constantes, il faut utiliser la nouvelle &lt;a href=&quot;https://dotclear.watch/Billet/Configuration-de-l-application-en-2.28&quot;&gt;classe de configuration&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Blog&lt;/h5&gt;

&lt;p&gt;Toues les propriétés public de la classe dcBlog (devenu Blog et accessible par App:blog() ) sont désormais dépréciées et ont une nouvelle méthode associée. (voir la partie Blog de l'article sur le &lt;a href=&quot;https://dotclear.watch/Billet/Le-conteneur-principal-en-2.28&quot;&gt;conteneur principale&lt;/a&gt;.)&lt;/p&gt;

&lt;h5&gt;Utils&lt;/h5&gt;

&lt;p&gt;Toute la classe dcUtils et ses méthodes passent en dépréciées. La version 2.28 ajoute ces derniers dépréciés :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::ADMIN_LOCALE&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::lexical()::ADMIN_LOCALE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::PUBLIC_LOCALE&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::lexical()::PUBLIC_LOCALE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::CUSTOM_LOCALE&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::lexical()::CUSTOM_LOCALE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::path()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;Path::reduce()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::getUserCN()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::users()-&amp;gt;getUserCN()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::cleanIds()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::blogs()-&amp;gt;cleanIds()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::versionsCompare()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::plugins()-&amp;gt;versionsCompare()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::cssLoad()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::plugins()-&amp;gt;cssLoad()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::jsLoad()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::plugins()-&amp;gt;jsLoad()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::jsJson()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;Html::jsJson()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::lexicalSort()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::lexical()-&amp;gt;lexicalSort()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::lexicalArraySort()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::lexical()-&amp;gt;lexicalArraySort()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::lexicalKeySort()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::lexical()-&amp;gt;lexicalKeySort()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::setLexicalLang()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;App::lexical()-&amp;gt;setLexicalLang()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcUtils::removeDiacritics()&lt;/strong&gt;  =&amp;gt; &lt;code&gt;Text::removeDiacritics()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Autres&lt;/h5&gt;

&lt;p&gt;Quelques changements de noms de méthodes et passages de propriétés à méthodes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;App::release(xxx)&lt;/strong&gt; =&amp;gt; &lt;code&gt;App:config()-&amp;gt;release(xxx) ou App:config()-&amp;gt;yyy()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;blog()-&amp;gt;settings-&amp;gt;addNamespace()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blog()-&amp;gt;settings()-&amp;gt;addWorspace()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;blog()-&amp;gt;settings-&amp;gt;renNamespace()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blog()-&amp;gt;settings()-&amp;gt;renWorkspace()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;blog()-&amp;gt;settings-&amp;gt;delNamespace()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blog()-&amp;gt;settings()-&amp;gt;delWorkspace()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;blog()-&amp;gt;settings-&amp;gt;dumpNamespaces()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blog()-&amp;gt;settings()-&amp;gt;dumpWorkspaces()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;blog()-&amp;gt;settings-&amp;gt;xxx-&amp;gt;dumpNamespace()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blog()-&amp;gt;settings()-&amp;gt;get('xxx')-&amp;gt;dumpWorkspace()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;error-&amp;gt;toHTML()&lt;/strong&gt; =&amp;gt; utiliser son propre parser&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;notices-&amp;gt;delNotices()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::notice()-&amp;gt;delNotice()&lt;/code&gt; ou &lt;code&gt;App::notice()-&amp;gt;delSessionNotices()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;media-&amp;gt;root&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::media()-&amp;gt;getRoot()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;media-&amp;gt;root_url&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::media()-&amp;gt;getRootUrl()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;media-&amp;gt;dir&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::media()-&amp;gt;getDirs()&lt;/code&gt; ou &lt;code&gt;App::media()-&amp;gt;getFiles()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;media-&amp;gt;thumb_tp&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::media()-&amp;gt;getThumbnailFilePattern()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;media-&amp;gt;thumb_tp_alpha&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::media()-&amp;gt;getThumbnailFilePattern('alpha')&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;media-&amp;gt;thumb_tp_webp&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::media()-&amp;gt;getThumbnailFilePattern('webp')&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;media-&amp;gt;thumb_sizes&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::media()-&amp;gt;getThumbnailCombo()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;log-&amp;gt;getTable()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::log()::LOG_TABLE_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;widgets&lt;/strong&gt; =&amp;gt; &lt;code&gt;Widgets::$widgets&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;ctx&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::frontend()-&amp;gt;context()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;tpl&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::frontend()-&amp;gt;template()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;adminurl&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;url()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;favs&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;favorites()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;menu&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;menus()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;resources&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;resources()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Déplacement&lt;/h5&gt;

&lt;p&gt;Voir les nombreuses &lt;a href=&quot;https://dotclear.watch/Billet/D%C3%A9placement-de-classes-en-2.28&quot;&gt;classes déplacées&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;&lt;q&gt;Le contenu de ce document a été écrit suivant le code de la version 2.28 de Dotclear.&lt;/q&gt;&lt;/em&gt;&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Permissions de modules</title>
        <link>https://dotclear.watch/Billet/Permissions-de-modules-en-2.28</link>
        <guid isPermaLink="false">urn:md5:15d7c95c8020af2f4684b0d553449ac4</guid>
        <pubDate>Fri, 13 Oct 2023 08:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.28</category>
                          <category>2.28</category>
                  <category>My</category>
                  <category>permission</category>
                <description>&lt;p&gt;Dans la &lt;a href=&quot;https://dotclear.watch/Billet/Release-2.28&quot;&gt;version 2.28&lt;/a&gt; de Dotclear, la classe &lt;strong&gt;My&lt;/strong&gt; d'aide aux modules peut gérer complètement leurs permissions.&lt;/p&gt; &lt;p&gt;Depuis quelques versions de Dotclear une aide au développement des modules (plugins et thèmes) est disponible, elle est depuis bien utilisée par les modules de la distribution et par nombre de modules tiers. La version 2.28, complète la classe My en lui ajoutant une nouvelle constante de contexte appelée MODULE. Celle-ci va permettre de supprimer la difficulté d'utiliser des classes dans le fichier _define.php en déplaçant la partie permissions de ce fichier.&lt;br /&gt;
Pour déplacer ces permissions et s'affranchir d'appels de classe hasardeux, il suffit d'indiquer dans le fichier _define.php du module qu'on déporte la gestion de permissions, puis dans le fichier My de vérifier ces permissions.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Premier exemple&lt;/h5&gt;

&lt;p&gt;Exemple du fichier &lt;strong&gt;\_define.php&lt;/strong&gt; du plugin attachments de la distribution :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
use Dotclear\App;

$this-&amp;gt;registerModule(
    // ...
    [
        // On indiquait la nécessité des droits usage, content admin ou pages pour utiliser ce plugin
        &amp;#039;permissions&amp;#039; =&amp;gt; App::auth()-&amp;gt;makePermissions([
            App::auth()::PERMISSION_USAGE,
            App::auth()::PERMISSION_CONTENT_ADMIN,
            initPages::PERMISSION_PAGES,
        ]),
        // ...
    ]
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Qui deviendra simplement :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
$this-&amp;gt;registerModule(
    // ...
    [
        &amp;#039;requires&amp;#039;    =&amp;gt; [[&amp;#039;pages&amp;#039;]],
        // On indique qu&amp;#039;on délègue à la class My la gestion des droits
        &amp;#039;permissions&amp;#039; =&amp;gt; &amp;#039;My&amp;#039;,
        // ...
    ]
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Plus de problème d'appel de classe potentiellement inexistante ici, puisqu'on va tester la disponibilité de module requis avec la directive &lt;code&gt;requires&lt;/code&gt; avant de vouloir utiliser sa classe. Mais il faut bien tester les droits qu'on a enlevés, pour cela on va ajouter une règle dans le fichier &lt;strong&gt;\src\My.php&lt;/strong&gt; du module :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
declare(strict_types=1);

namespace Dotclear\Plugin\attachments;

use Dotclear\App;
use Dotclear\Module\MyPlugin;
use Dotclear\Plugin\pages\Pages;

class My extends MyPlugin
{
   // On va gérer des droits particuliers
    public static function checkCustomContext(int $context): ?bool
    {
       // On recherche le contexte de droit
        return match($context) {
            // On utilise le nouveau contexte de droit global pour autoriser un utilisateur avec les droits sur les billets et les pages
            // Attention ici le test demande si on est côté admin avec des droits ou côté public sans besoin de droits !
            self::MODULE =&amp;gt; !App::task()-&amp;gt;checkContext(&amp;#039;BACKEND&amp;#039;)
                || (
                    App::blog()-&amp;gt;isDefined()
                    &amp;amp;&amp;amp; App::auth()-&amp;gt;check(App::auth()-&amp;gt;makePermissions([
                        App::auth()::PERMISSION_USAGE,
                        App::auth()::PERMISSION_CONTENT_ADMIN,
                        Pages::PERMISSION_PAGES,
                    ]), App::blog()-&amp;gt;id())
                ),

            // Pour tous les autres contextes, on laisse les droits par défaut
            default =&amp;gt; null,
        };
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On voit ici que du fait de cette nouvelle gestion, les constantes de module comme les permissions ou les noms de tables de bases de données n'ont plus besoin d'être dans un fichier spécial à la racine du module puisque dorénavant on teste ces permissions après le chargement des modules et donc on a accès  à toutes les classes des modules pour les tests. Les constantes de permissions et de tables des modules de la distribution ont donc été déplacés dans leurs classes principales, c'est le cas de &lt;strong&gt;Antispam&lt;/strong&gt;, &lt;strong&gt;Blogroll&lt;/strong&gt; et &lt;strong&gt;Pages&lt;/strong&gt;.&lt;/p&gt;

&lt;h5&gt;Second exemple&lt;/h5&gt;

&lt;p&gt;Exemple du fichier &lt;strong&gt;\_define.php&lt;/strong&gt; du plugin tags de la distribution :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
use Dotclear\App;

$this-&amp;gt;registerModule(
    // ...
    [
        &amp;#039;permissions&amp;#039; =&amp;gt; &amp;#039;App::auth()-&amp;gt;makePermissions([
                    App::auth()::PERMISSION_USAGE,
                    App::auth()::PERMISSION_CONTENT_ADMIN,
                ])&amp;#039;,
        // ...
    ]
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Qui deviendra simplement :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
$this-&amp;gt;registerModule(
    // ...
    [
        &amp;#039;permissions&amp;#039; =&amp;gt; &amp;#039;My&amp;#039;,
        // ...
    ]
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Quand au fichier &lt;strong&gt;\src\My.php&lt;/strong&gt; du module, il ne changera pas puisqu'on vérifiait déjà ces droits :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
declare(strict_types=1);

namespace Dotclear\Plugin\tags;

use Dotclear\App;
use Dotclear\Module\MyPlugin;

class My extends MyPlugin
{
    public static function checkCustomContext(int $context): ?bool
    {
        return match ($context) {
            // On indique que la page de gestion et le menu sont autorisés à un utilisateur ayant les droits usage ou content admin
            // On n&amp;#039;a pas eu besoin de changer quoi que ce soit ici
            self::MANAGE, self::MENU =&amp;gt; App::task()-&amp;gt;checkContext(&amp;#039;BACKEND&amp;#039;)
                &amp;amp;&amp;amp; App::blog()-&amp;gt;isDefined()
                &amp;amp;&amp;amp; App::auth()-&amp;gt;check(App::auth()-&amp;gt;makePermissions([
                    App::auth()::PERMISSION_USAGE,
                    App::auth()::PERMISSION_CONTENT_ADMIN,
                ]), App::blog()-&amp;gt;id()),

            default =&amp;gt; null,
        };
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Un petit tour dans les fichiers &lt;strong&gt;My&lt;/strong&gt; des plugins de la distribution donnera un bon aperçu des différents cas possibles.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;&lt;q&gt;Le contenu de ce document a été écrit suivant le code de la version 2.28 de Dotclear.&lt;/q&gt;&lt;/em&gt;&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Configuration de l'application</title>
        <link>https://dotclear.watch/Billet/Configuration-de-l-application-en-2.28</link>
        <guid isPermaLink="false">urn:md5:27df6568bc908f79b480552f7e11d2c5</guid>
        <pubDate>Fri, 13 Oct 2023 08:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.28</category>
                          <category>2.28</category>
                  <category>config</category>
                <description>&lt;p&gt;La &lt;a href=&quot;https://dotclear.watch/Billet/Release-2.28&quot;&gt;version 2.28&lt;/a&gt; de Dotclear ajoute une nouvelle classe de visualisation de sa configuration..&lt;/p&gt; &lt;p&gt;Auparavant il fallait chercher les différentes ressources de configuration de Dotclear un peu partout, dans les fichier index, dans le fichier de config, dans des constantes, etc. Depuis la version 2.28, toutes ces informations sont accessibles depuis une seule classe et ses méthodes. Cette classe n'est pas modifiable, n'est pas remplaçable, aucune de ses propriétés n'est accessible. Elle va récupérer toutes les informations, notamment depuis le fichier config.php (qui ne change pas), les traiter et les proposer via ses méthodes avec un typage de retour strict et défini. Elle va également faire les premières vérifications de ces valeurs.&lt;br /&gt;
Il n'est plus utile de lire les constantes de Dotclear, toutes les constantes de la version 2.27 existent toujours mais ont leurs méthodes associées en 2.28 dans App::config(), de part ce fait ces valeurs existent toujours et ont un type fixe ce qui facilite leurs utilisations.&lt;/p&gt;

&lt;h5&gt;Liste des informations disponibles :&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;startTime(): float;&lt;/code&gt; &lt;del&gt;DC_START_TIME&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cliMode(): bool;&lt;/code&gt; &lt;del&gt;CLI_MODE&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;debugMode(): bool;&lt;/code&gt; &lt;del&gt;DC_DEBUG&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;devMode(): bool;&lt;/code&gt; &lt;del&gt;DC_DEV&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;errorFile(): string;&lt;/code&gt; &lt;del&gt;DC_ERRORFILE&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blogId(): string;&lt;/code&gt; &lt;del&gt;DC_BLOG_ID&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dotclearRoot(): string;&lt;/code&gt; &lt;del&gt;DC_ROOT&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dotclearVersion(): string;&lt;/code&gt; &lt;del&gt;DC_VERSION&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dotclearName(): string;&lt;/code&gt; &lt;del&gt;DC_NAME&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hasConfig(): bool;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configPath(): string;&lt;/code&gt; &lt;del&gt;DC_RC_PATH&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;digestsRoot(): string;&lt;/code&gt; &lt;del&gt;DC_DIGESTS&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;l10nRoot(): string;&lt;/code&gt; &lt;del&gt;DC_L10N_ROOT&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;l10nUpdateUrl(): string;&lt;/code&gt; &lt;del&gt;DC_L10N_UPDATE_URL&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;distributedPlugins(): string;&lt;/code&gt; &lt;del&gt;DC_DISTRIB_PLUGINS&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;distributedThemes(): string;&lt;/code&gt; &lt;del&gt;DC_DISTRIB_THEMES&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defaultTheme(): string;&lt;/code&gt; &lt;del&gt;DC_DEFAULT_THEME&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defaultTplset(): string;&lt;/code&gt; &lt;del&gt;DC_DEFAULT_TPLSET&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defaultJQuery(): string;&lt;/code&gt; &lt;del&gt;DC_DEFAULT_JQUERY&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;minRequiredPhp(): string;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;minRequiredMysql(): string;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;minRequiredPgsql(): string;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nextRequiredPhp(): string;&lt;/code&gt; &lt;del&gt;DC_NEXT_REQUIRED_PHP&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vendorName(): string;&lt;/code&gt; &lt;del&gt;DC_VENDOR_NAME&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xmlrpcUrl(): string;&lt;/code&gt; &lt;del&gt;DC_XMLRPC_URL&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sessionTtl(): ?string;&lt;/code&gt; &lt;del&gt;DC_SESSION_TTL&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sessionName(): string;&lt;/code&gt; &lt;del&gt;DC_SESSION_NAME&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;adminSsl(): bool;&lt;/code&gt; &lt;del&gt;DC_ADMIN_SSL&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;adminUrl(): string;&lt;/code&gt; &lt;del&gt;DC_ADMIN_URL&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;adminMailfrom(): string;&lt;/code&gt; &lt;del&gt;DC_ADMIN_MAILFROM&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbDriver(): string;&lt;/code&gt; &lt;del&gt;DC_DBDRIVER&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbHost(): string;&lt;/code&gt; &lt;del&gt;DC_DBHOST&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbUser(): string;&lt;/code&gt; &lt;del&gt;DC_DBUSER&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbPassword(): string;&lt;/code&gt; &lt;del&gt;DC_DBPASSWORD&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbName(): string;&lt;/code&gt; &lt;del&gt;DC_DBNAME&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbPrefix(): string;&lt;/code&gt; &lt;del&gt;DC_DBPREFIX&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dbPersist(): bool;&lt;/code&gt; &lt;del&gt;DC_DBPERSIST&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;masterKey(): string;&lt;/code&gt; &lt;del&gt;DC_MASTER_KEY&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cryptAlgo(): string;&lt;/code&gt; &lt;del&gt;DC_CRYPT_ALGO&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coreUpdateUrl(): string;&lt;/code&gt; &lt;del&gt;DC_UPDATE_URL&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coreUpdateCanal(): string;&lt;/code&gt; &lt;del&gt;DC_UPDATE_VERSION&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coreNotUpdate(): bool;&lt;/code&gt; &lt;del&gt;DC_NOT_UPDATE&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;allowMultiModules(): bool;&lt;/code&gt; &lt;del&gt;DC_ALLOW_MULTI_MODULES&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;storeNotUpdate(): bool;&lt;/code&gt; &lt;del&gt;DC_STORE_NOT_UPDATE&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;allowRepositories(): bool;&lt;/code&gt; &lt;del&gt;DC_ALLOW_REPOSITORIES&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;allowRestServices(): bool;&lt;/code&gt; &lt;del&gt;DC_REST_SERVICES&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cacheRoot(): string;&lt;/code&gt; &lt;del&gt;DC_TPL_CACHE&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;varRoot(): string;&lt;/code&gt; &lt;del&gt;DC_VAR&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;backupRoot(): string;&lt;/code&gt; &lt;del&gt;DC_BACKUP_PATH&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coreUpgrade(): string;&lt;/code&gt; &lt;del&gt;DC_UPGRADE&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pluginsRoot(): string;&lt;/code&gt; &lt;del&gt;DC_PLUGINS_ROOT&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxUploadSize(): int;&lt;/code&gt; &lt;del&gt;DC_MAX_UPLOAD_SIZE&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;queryTimeout(): int;&lt;/code&gt; &lt;del&gt;DC_QUERY_TIMEOUT&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;showHiddenDirs(): bool;&lt;/code&gt; &lt;del&gt;DC_SHOW_HIDDEN_DIRS&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;httpScheme443(): bool;&lt;/code&gt; &lt;del&gt;DC_FORCE_SCHEME_443&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;httpReverseProxy(): bool;&lt;/code&gt; &lt;del&gt;DC_REVERSE_PROXY&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;checkAddBlocker(): bool;&lt;/code&gt; &lt;del&gt;DC_ADBLOCKER_CHECK&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cspReportFile(): string;&lt;/code&gt; &lt;del&gt;DC_CSP_LOGFILE&lt;/del&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour en savoir plus sur la signification de ces méthodes, il est recommandé de lire le contenu du fichier &lt;strong&gt;src/Interface/ConfigInterface.php&lt;/strong&gt;. (&lt;a href=&quot;https://git.dotclear.org/dev/dotclear/src/branch/master/src/Interface/ConfigInterface.php&quot; hreflang=&quot;fr&quot; title=&quot;Fichier ConfigInterface sur Gitea&quot;&gt;Visible sur le dépôt git&lt;/a&gt;.)&lt;br /&gt;
Pour accéder à une de ces valeurs, il suffit de faire &lt;code&gt;App::config()-&amp;gt;cacheRoot();&lt;/code&gt;.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Attention&lt;/h5&gt;

&lt;p&gt;Là où souvent il fallait tester la présence d'une valeur, par exemple :&lt;br /&gt;
&lt;code&gt;if (defined('DC_DEFAULT_TPLSET')) { $tpl = DC_DEFAULT_TPLSET; }&lt;/code&gt;&lt;br /&gt;
Désormais cette valeur existe toujours, on peut éventuellement tester si elle est vide :&lt;br /&gt;
&lt;code&gt;if (!empty(App::config()-&amp;gt;defaultTplset())) { }&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>dcCore déprécié</title>
        <link>https://dotclear.watch/Billet/Les-d%C3%A9pr%C3%A9ci%C3%A9s-du-core-en-2.28</link>
        <guid isPermaLink="false">urn:md5:0f195f3f078eb49a5629ae30d771e192</guid>
        <pubDate>Fri, 13 Oct 2023 08:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.28</category>
                          <category>2.28</category>
                  <category>déprécié</category>
                <description>&lt;p&gt;Dans la &lt;a href=&quot;https://dotclear.watch/Billet/Release-2.28&quot;&gt;version 2.28&lt;/a&gt; de Dotclear, la classe historique du moteur de blog, alias dcCore, passe en dépréciée.&lt;/p&gt; &lt;p&gt;La classe dcCore, le cœur de Dotclear n'est plus. Cette classe, avec toutes ses propriétés et méthodes, passe en déprécié au profit d'un nouveau système utilisant un simple &lt;a href=&quot;https://dotclear.watch/Billet/Le-conteneur-principal-en-2.28&quot;&gt;conteneur de classe&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Resources&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;resources&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;resources()&lt;/code&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Le tableau des ressources d'aide de l'interface d'administration est remplacé par une nouvelle classe &lt;code&gt;\Dotclear\Core\Backend\Resources&lt;/code&gt; et se déplace vers le Backend. Pour ajouter une ressource depuis un thème ou plugin, cela se fait toujours depuis le fichiers &lt;strong&gt;locales/xx/resources.php&lt;/strong&gt; mais on doit désormais utiliser une méthode de la nouvelle classe qui est instanciée dans &lt;code&gt;App::backend()-&amp;gt;resources()&lt;/code&gt;.&lt;br /&gt;
Exemple du plugin aboutConfig de la distribution :&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// Avant :
// if (!isset(dcCore::app()-&amp;gt;resources[&amp;#039;help&amp;#039;][&amp;#039;aboutConfig&amp;#039;])) {
//    dcCore::app()-&amp;gt;resources[&amp;#039;help&amp;#039;][&amp;#039;aboutConfig&amp;#039;] = __DIR__ . &amp;#039;/help/help.html&amp;#039;;
//}
// à remplacer par :
\Dotclear\App::backend()-&amp;gt;resources()-&amp;gt;set(&amp;#039;help&amp;#039;, &amp;#039;aboutConfig&amp;#039;, __DIR__ . &amp;#039;/help/help.html&amp;#039;);&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;Lang&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;lang&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::lang()-&amp;gt;getLang()&lt;/code&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;lang = 'en'&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::lang()-&amp;gt;setlang('en')&lt;/code&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Behavior&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes en rapport à la gestion des behaviors sont désormais dans une instance de classe Behavior.&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;addBehavior()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::behavior()-&amp;gt;addBehavior()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;addBehaviors()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::behavior()-&amp;gt;addBehaviors()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;hasBehavior()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::behavior()-&amp;gt;hasBehavior()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getBehaviors()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::behavior()-&amp;gt;getBehaviors()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getBehaviors(xxx)&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::behavior()-&amp;gt;getBehavior(xxx)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;callBehavior()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::behavior()-&amp;gt;callBehavior()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La méthode getBehaviors est scindée en deux pour obtenir un typage de retour de méthode plus propre. Les anciens alias en &lt;q&gt;ou&lt;/q&gt; disparaissent.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Nonce&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes en rapport à la gestion en base de Nonce sont désormais dans une instance de classe Nonce.&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getNonce()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::nonce()-&amp;gt;getNonce()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;checkNonce()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::nonce()-&amp;gt;checkNonce()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;formNonce(true)&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::nonce()-&amp;gt;getFormNonce()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;formNonce(false)&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::nonce()-&amp;gt;formNonce()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cette dernière méthode est scindée en deux avec d'un coté le renvoi de l'élément Form\Hidden et de l'autre le renvoi du code HTML.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Version&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes en rapport à la gestion des versions en base sont désormais dans une instance de classe Nonce.&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getVersion()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::version()-&amp;gt;getVersion()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getVersions()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::version()-&amp;gt;getVersions()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;setVersion()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::version()-&amp;gt;setVersion()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;testVersion()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::version()-&amp;gt;compareVersion()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;newVersion()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::version()-&amp;gt;newerVersion()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;delVersion()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::version()-&amp;gt;unsetVersion()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Formater&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes en rapport à la gestion des formateurs sont désormais dans une instance de classe Formater.&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;addEditorFormater()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;addEditorFormater()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;addFormater()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;addEditorFormater('dcLegacyEditor', ...)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;addFormaterName()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;addFormaterName()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getFormaterName()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;getFormaterName()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getEditors()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;getEditors()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getFormaters()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;getFormaters()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getFormaters(xxx)&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;getFormater(xxx)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;callEditorFormater()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;callEditorFormater()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;callFormater()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()-&amp;gt;callEditorFormater('dcLegacyEditor', ...)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La méthode &lt;strong&gt;getFormaters&lt;/strong&gt; est scindée en deux pour retourner soit un formateur soit tous.&lt;br /&gt;
Les méthodes spécifiques à dcLegacyEditor, qui sont &lt;strong&gt;addFormater&lt;/strong&gt; et &lt;strong&gt;callFormater&lt;/strong&gt;, sont supprimées au profit des génériques &lt;code&gt;addEditorFormater&lt;/code&gt; et &lt;code&gt;callEditorFormater&lt;/code&gt; auxquelles il faudra indiquer le formateur dcLegacyEditor.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Wiki et HTML filter&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes en rapport aux filtres wiki et HTML sont désormais dans un instance de classe Filter. De même pour la propriété wiki.&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;wiki&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;wiki()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;wiki2xhtml&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;wiki()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;wikiTransform()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;wikiTransform()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;initWikiPost()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;initWikiPost()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;initWikiSimpleComment()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;initWikiSimpleComment()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;initWikiComment()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;initWikiComment()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;wikiPostLink()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;wikiPostLink()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;HTMLfilter()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;HTMLfilter()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Une modification bloquante a été introduite en utilisant l'état non initialisé des propriétés de classe, il ne faut plus tester si wiki est une instance de WikiToHtml mais si il existe, cela donne :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;//avant :
//if (dcCore::app()-&amp;gt;wiki instanceof WikiToHtml) { }

// Après :
if (isset(App::filter()-&amp;gt;wiki)) { }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ce cas se retrouve sur plusieurs autres appels, PHP vous indiquera que vous faites appel à une propriété non initialisée, il faudra alors utiliser isset().&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Post types&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes en rapport à la gestion des types de posts sont désormais dans une instance de classe PostTypes. Et un type de post n'est plus un tableau mais une classe de description PostType.&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getPostAdminURL()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;get(type)-&amp;gt;adminUrl()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getPostPublicURL()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;get(type)-&amp;gt;publicUrl()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;setPostType()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;set(new PostType())&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getPostTypes()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;dump()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;De plus, une nouvelle méthode est ajoutée pour tester si un type de post existe: &lt;code&gt;App::postTypes()-&amp;gt;exists(type)&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
Exemple du plugin pages de la distribution :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// Dans la méthode process() du fichier src/Prepend.php
App::postTypes()-&amp;gt;set(new PostType(
    &amp;#039;page&amp;#039;,
    &amp;#039;&amp;#039;,
    App::url()-&amp;gt;getURLFor(&amp;#039;pages&amp;#039;, &amp;#039;%s&amp;#039;),
    &amp;#039;Pages&amp;#039;
));
// Dans la méthode process() du fichier src/Backend.php
App::postTypes()-&amp;gt;set(new PostType(
    &amp;#039;page&amp;#039;,
    urldecode(My::manageUrl([&amp;#039;p&amp;#039; =&amp;gt; &amp;#039;pages&amp;#039;, &amp;#039;act&amp;#039; =&amp;gt; &amp;#039;page&amp;#039;, &amp;#039;id&amp;#039; =&amp;gt; &amp;#039;%d&amp;#039;], &amp;#039;&amp;amp;&amp;#039;)),
    App::url()-&amp;gt;getURLFor(&amp;#039;pages&amp;#039;, &amp;#039;%s&amp;#039;),
    &amp;#039;Pages&amp;#039;
));&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On remarque ici qu'on déclare deux fois le type de post, une fois dans le Prepend SANS la définition d'url admin car elle n'est pas encore accessible. Et une fois dans le fichier Backend AVEC la définition de l'url admin.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Blogs&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes en rapport aux blogs sont désormais dans une instance de classe Blogs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getAllBlogStatus()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blogs()-&amp;gt;getAllBlogStatus()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getBlogStatus()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()s-&amp;gt;getBlogStatus()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getBlogPermissions()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;getBlogPermissions()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getBlog()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;getBlog()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getBlogs()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;getBlogs()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;addBlog()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;addBlog()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;updBlog()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;updBlog()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;delBlog()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;delBlog()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;blogExists()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;blogExists()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;countBlogPosts()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()-&amp;gt;countBlogPosts()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Users&lt;/h5&gt;

&lt;p&gt;Toutes les méthodes en rapport aux utilisateurs sont désormais dans une instance de classe Users.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getUser()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;getUser()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getUsers()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;getUsers()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;addUser()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;addUser()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;updUser()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;updUser()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;delUser()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;delUser()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;userExists()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;userExists()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getUserPermissions()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;getUserPermissions()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;setUserPermissions()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;setUserPermissions()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;setUserBlogPermissions()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;setUserBlogPermissions()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;setUserDefaultBlog()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()s-&amp;gt;setUserDefaultBlog()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;removeUsersDefaultBlogs()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;removeUsersDefaultBlogs()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;userDefaults()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()-&amp;gt;userDefaults()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Cache&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;emptyTemplatesCache()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::cache()-&amp;gt;emptyTemplatesCache()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;cache&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::cache()-&amp;gt;xxx()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Autres&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()::SESSION_TABLE_NAME&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::session()::SESSION_TABLE_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()::VERSION_TABLE_NAME&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::version()::VERSION_TABLE_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;con()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::con()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;prefix&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::con()-&amp;gt;prefix()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;blog&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blog()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;auth&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::auth()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;session&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::session()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;url&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::url()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;rest&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::rest()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;wiki&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()-&amp;gt;wiki&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;plugins&lt;/strong&gt; =&amp;gt; &lt;code&gt;App:plugins()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;themes&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::themes()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;media&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::media()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;postmedia&lt;/strong&gt; &lt;code&gt;App::postMedia() App::media()-&amp;gt;postMedia()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;meta&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::meta()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;error&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::error()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;notices&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::notice()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;log&lt;/strong&gt; =&amp;gt; &lt;code&gt;App:log()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;admin&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;adminurl&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;url()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;favs&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;favorites()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;menu&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;menus()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;public&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::frontend()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;tpl&lt;/strong&gt; =&amp;gt; &lt;code&gt;App:frontend()-&amp;gt;template()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;ctx&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::frontend()-&amp;gt;context()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;spamfilters&lt;/strong&gt; =&amp;gt; Use AntispamInitFilters behavior&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;killAdminSession()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::backend()-&amp;gt;killAdminSession()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getAllBlogStatus()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blogs()-&amp;gt;getAllBlogStatus()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;getBlogStatus()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blogs()-&amp;gt;getBlogStatus()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;blogDefaults()&lt;/strong&gt; =&amp;gt; &lt;code&gt;\Dotclear\Core\Install\Utils::blogDefault()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;enableRestServer()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::rest()-&amp;gt;enableRestServer()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dcCore::app()-&amp;gt;serveRestRequests()&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::rest()-&amp;gt;serveRestRequests()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
L'ancienne écriture des appels décrits dans cette page reste valable encore pour quelques versions en tant que dépréciée.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;&lt;q&gt;Le contenu de ce document a été écrit suivant le code de la version 2.28 de Dotclear.&lt;/q&gt;&lt;/em&gt;&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Déplacement de classes</title>
        <link>https://dotclear.watch/Billet/D%C3%A9placement-de-classes-en-2.28</link>
        <guid isPermaLink="false">urn:md5:1638e8243b1372300dcc00498f457792</guid>
        <pubDate>Fri, 13 Oct 2023 08:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>2.28</category>
                          <category>2.28</category>
                  <category>class</category>
                  <category>déplacé</category>
                <description>&lt;p&gt;La &lt;a href=&quot;https://dotclear.watch/Billet/Release-2.28&quot;&gt;version 2.28&lt;/a&gt; de Dotclear continuant la transition vers les espaces de noms PHP, la plupart des classes restantes dans le répertoire &lt;code&gt;inc&lt;/code&gt; a été déplacée vers le dossier &lt;code&gt;src&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;Voici la liste des classes changeant de nom dans cette version.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Frontend :&lt;/h5&gt;
&lt;pre&gt;
    &amp;#039;dcTemplate&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Core\Frontend\Tpl&amp;#039;,
    &amp;#039;dcUrlHandlers&amp;#039; =&amp;gt; &amp;#039;Dotclear\Core\Frontend\Url&amp;#039;,
    &amp;#039;context&amp;#039;       =&amp;gt; &amp;#039;Dotclear\Core\Frontend\Ctx&amp;#039;,

    &amp;#039;rsExtPostPublic&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Schema\Extension\PostPublic&amp;#039;,
    &amp;#039;rsExtCommentPublic&amp;#039; =&amp;gt; &amp;#039;Dotclear\Schema\Extension\CommentPublic&amp;#039;,
&lt;/pre&gt;

&lt;h5&gt;Core :&lt;/h5&gt;
&lt;pre&gt;
    &amp;#039;dcAuth&amp;#039; =&amp;gt; &amp;#039;Dotclear\Core\Auth&amp;#039;,
    &amp;#039;dcBlog&amp;#039; =&amp;gt; &amp;#039;Dotclear\Core\Blog&amp;#039;,
    &amp;#039;dcCategories&amp;#039;   =&amp;gt; &amp;#039;Dotclear\Core\Categories&amp;#039;,
    &amp;#039;dcDeprecated&amp;#039; =&amp;gt; &amp;#039;Dotclear\Core\Deprecated&amp;#039;,
    &amp;#039;dcError&amp;#039;        =&amp;gt; &amp;#039;Dotclear\Core\Error&amp;#039;,
    &amp;#039;dcLog&amp;#039;          =&amp;gt; &amp;#039;Dotclear\Core\Log&amp;#039;,
    &amp;#039;dcMedia&amp;#039;        =&amp;gt; &amp;#039;Dotclear\Core\Media&amp;#039;,
    &amp;#039;dcMeta&amp;#039;         =&amp;gt; &amp;#039;Dotclear\Core\Meta&amp;#039;,
    &amp;#039;dcModuleDefine&amp;#039; =&amp;gt; &amp;#039;Dotclear\Module\ModuleDefine&amp;#039;,
    &amp;#039;dcModules&amp;#039;      =&amp;gt; &amp;#039;Dotclear\Module\Modules&amp;#039;,
    &amp;#039;dcNamespace&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Core\BlogWorkspace&amp;#039;,
    &amp;#039;dcNotices&amp;#039;      =&amp;gt; &amp;#039;Dotclear\Core\Notice&amp;#039;,
    &amp;#039;dcPlugins&amp;#039;   =&amp;gt; &amp;#039;Dotclear\Module\Plugins&amp;#039;,
    &amp;#039;dcPostMedia&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Core\PostMedia&amp;#039;,
    &amp;#039;dcPrefs&amp;#039;        =&amp;gt; &amp;#039;Dotclear\Core\UserPreferences&amp;#039;,
    &amp;#039;dcRestServer&amp;#039;   =&amp;gt; &amp;#039;Dotclear\Core\Rest&amp;#039;,
    &amp;#039;dcSettings&amp;#039;     =&amp;gt; &amp;#039;Dotclear\Core\BlogSettings&amp;#039;,
    &amp;#039;dcStore&amp;#039;       =&amp;gt; &amp;#039;Dotclear\Module\Store&amp;#039;,
    &amp;#039;dcStoreParser&amp;#039; =&amp;gt; &amp;#039;Dotclear\Module\StoreParser&amp;#039;,
    &amp;#039;dcStoreReader&amp;#039; =&amp;gt; &amp;#039;Dotclear\Module\StoreReader&amp;#039;,
    &amp;#039;dcThemes&amp;#039;      =&amp;gt; &amp;#039;Dotclear\Module\Themes&amp;#039;,
    &amp;#039;dcTrackback&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Core\Trackback&amp;#039;,
    &amp;#039;dcUpdate&amp;#039; =&amp;gt; &amp;#039;Dotclear\Core\Backend\Update&amp;#039;,
    &amp;#039;dcWorkspace&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Core\UserWorkspace&amp;#039;,
    &amp;#039;dcXmlRpc&amp;#039; =&amp;gt; &amp;#039;Dotclear\Core\Frontend\XmlRpc&amp;#039;,

    &amp;#039;rsExtPost&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Schema\Extension\Post&amp;#039;,
    &amp;#039;rsExtComment&amp;#039; =&amp;gt; &amp;#039;Dotclear\Schema\Extension\Comment&amp;#039;,
    &amp;#039;rsExtDates&amp;#039;   =&amp;gt; &amp;#039;Dotclear\Schema\Extension\Dates&amp;#039;,
    &amp;#039;rsExtUser&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Schema\Extension\User&amp;#039;,
    &amp;#039;rsExtBlog&amp;#039;    =&amp;gt; &amp;#039;Dotclear\Schema\Extension\Blog&amp;#039;,

    &amp;#039;dcTraitDynamicProperties&amp;#039; =&amp;gt; &amp;#039;Dotclear\Helper\TraitDynamicProperties&amp;#039;,
&lt;/pre&gt;

&lt;h5&gt;Nouvelles classes ;&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\Blogs&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::blogs()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\Cache&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::cache()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\Filter&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::filter()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\Formater&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::formater()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\Nonce&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::nonce()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\PostType&lt;/strong&gt; =&amp;gt; &lt;code&gt;new PostType(type, admin_url, public_url, label);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\PostTypes&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::postTypes()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\Users&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::users()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dotclear\Core\Version&lt;/strong&gt; =&amp;gt; &lt;code&gt;App::version()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Plugins&lt;/h5&gt;

&lt;p&gt;Avec la nouvelle gestion des permissions des modules, leurs constantes se sont déplacées&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;initBlogroll::PERMISSION_BLOGROLL&lt;/strong&gt; =&amp;gt; &lt;code&gt;\Dotclear\Plugin\blogroll\Blogroll::PERMISSION_BLOGROLL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;initBlogroll::LINK_TABLE_NAME&lt;/strong&gt; =&amp;gt; &lt;code&gt;\Dotclear\Plugin\blogroll\Blogroll::LINK_TABLE_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;initAntispam::SPAMRULE_TABLE_NAME&lt;/strong&gt; =&amp;gt; &lt;code&gt;\Dotclear\Plugin\antispam\Antispam::SPAMRULE_TABLE_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;initPages::PERMISSION_PAGES&lt;/strong&gt; =&amp;gt; &lt;code&gt;\Dotclear\Plugin\pages\Pages::PERMISSION_PAGES&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;En savoir plus :&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dotclear.watch/Billet/Le-conteneur-principal-en-2.28&quot;&gt;Les classes de premiers niveau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dotclear.watch/Billet/D%C3%A9placement-de-classes&quot;&gt;Les classes déplacées en version 2.27&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;em&gt;&lt;q&gt;Le contenu de ce document a été écrit suivant le code de la version 2.28 de Dotclear.&lt;/q&gt;&lt;/em&gt;&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Remplacer une classe de premier niveau</title>
        <link>https://dotclear.watch/Billet/Remplacer-une-classe-de-premier-niveau-en-2.28</link>
        <guid isPermaLink="false">urn:md5:b4b07c44e57f9060b7c9e721709fea02</guid>
        <pubDate>Fri, 13 Oct 2023 08:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>Articles</category>
                          <category>2.28</category>
                  <category>container</category>
                  <category>core</category>
                  <category>factory</category>
                <description>&lt;p&gt;Dans cet article nous allons voir de façon très succincte comment remplacer une des classes du cœur de Dotclear en utilisant un conteneur de services.&lt;/p&gt; &lt;p&gt;Autant le dire tout de suite, ça ne va pas servir à tout le monde, et uniquement pour des cas bien précis, par des utilisateurs connaissant cette façon de coder.&lt;/p&gt;

&lt;h5&gt;Définition&lt;/h5&gt;


&lt;blockquote&gt;&lt;p&gt;- Mais c'est quoi un conteneur, un service, une usine ?&lt;br /&gt;
- C'est un &lt;a href=&quot;https://fr.wikipedia.org/wiki/Patron_de_conception&quot; hreflang=&quot;fr&quot; title=&quot;Définition de Design Partern su rWikipedia&quot;&gt;patron de conception&lt;/a&gt; aka design pattern.&lt;br /&gt;
- Mais encore ?&lt;br /&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Profitant du passage aux espaces de nom PHP, le cœur de Dotclear, appelé &lt;strong&gt;core&lt;/strong&gt; ou &lt;strong&gt;dcCore&lt;/strong&gt;, a disparu au profit d'un conteneur qui s'occupe uniquement de fournir &lt;a href=&quot;https://dotclear.watch/Billet/Le-conteneur-principal&quot;&gt;les classes maitresses&lt;/a&gt; de Dotclear, ces classes sont définies et leur objets générés par le conteneur, appelé &lt;strong&gt;Core&lt;/strong&gt;. (Original comme nom !) Tout ce petit monde suivant des règles bien précises écrites dans des interfaces.&lt;br /&gt;
Pour faire simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un service est un ensemble de méthodes dédiées à une tâche, par exemple la gestion des behaviors, regroupées dans une classe&lt;/li&gt;
&lt;li&gt;Le conteneur &lt;strong&gt;Container&lt;/strong&gt; fournit à l'utilisateur les objets prêt à l'emploi, ici App:: avec App::unService()&lt;/li&gt;
&lt;li&gt;L'usine &lt;strong&gt;Factory&lt;/strong&gt; fournit ces classes, sans que l'utilisateur sache lesquelles sont réellement chargées.&lt;/li&gt;
&lt;li&gt;Les interfaces &lt;strong&gt;xxxInterface&lt;/strong&gt; définissent les règles que doivent suivre les classes de l'usine. exemple: BehaviorInterface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cette technique va permettre de remplacer toutes les classes accessibles depuis App::xxx()&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Déclaration&lt;/h5&gt;

&lt;p&gt;Il faut commencer par déclarer notre service, une classe dédiée &lt;code&gt;\Dotclear\Helper\Container\Factories&lt;/code&gt; est là pour ça, on va lui dire d'ajouter notre service. Le plus simple est de lui dire depuis le fichier &lt;code&gt;inc/config.php&lt;/code&gt; de l'installation, dans l'exemple qui suit, on veut simplement remplacer une seule méthode de la classe &lt;strong&gt;Error&lt;/strong&gt; :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
//... contenu du fichier inc/config.php

// Notre service n&amp;#039;utilise pas d&amp;#039;espace de nom, on le récupère directement
require_once __DIR__ . &amp;#039;/../MyError.php&amp;#039;;

// On dit à la maison mère que notre service va être utilisé dans le core de Dotclear pour le service ErrorInterface::class
\Dotclear\Helper\Container\Factories::addService(&amp;#039;core&amp;#039;, ErrorInterface::class, MyError::class);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Voilà notre service remplace celui de Dotclear.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Service&lt;/h5&gt;

&lt;p&gt;Passons à notre service. Il doit obligatoirement suivre des règles strictes pour pouvoir être utilisé à la place d'un autre, voici le contenu de notre fichier &lt;code&gt;MyError.php&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
// On va reprendre la classe d&amp;#039;erreur et ses méthodes
use Dotclear\Core\Error;
// Pas besoin d&amp;#039;implémenter l&amp;#039;interface qui l&amp;#039;est déjà par la classe Error
//use Dotclear\Interface\Core\ErrorInterface;

// on crée notre classe d&amp;#039;erreur qui va étendre celle par défaut.
class MyError extends Error
{
    // on remplace uniquement la méthode qui nous intéresse
    public function add(string $msg): void
    {
        // notre classe va arrêter net le script sur une erreur au lieu de renvoyer un bandeau par exemple
        exit($msg);
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cet exemple est simple, il permet de montrer la mécanique d'utilisation de &lt;code&gt;Factories&lt;/code&gt;, si vous souhaitez remplacer la gestion de connexion à la base de données cela va être bien plus compliqué !&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Liste des classes maîtresses&lt;/h5&gt;

&lt;p&gt;Voici la liste des appels depuis l'application et des interfaces associées :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;App::auth(): &lt;code&gt;\Dotclear\Interface\Core\AuthInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::behavior(): &lt;code&gt;\Dotclear\Interface\Core\BehaviorInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::blog(): &lt;code&gt;\Dotclear\Interface\Core\BlogInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::blogSettings(): &lt;code&gt;\Dotclear\Interface\Core\BlogSettingsInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::blogs(): &lt;code&gt;\Dotclear\Interface\Core\BlogsInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::blogWorkspace(): &lt;code&gt;\Dotclear\Interface\Core\BlogWorkspaceInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::categories(): &lt;code&gt;\Dotclear\Interface\Core\CategoriesInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::cache(): &lt;code&gt;\Dotclear\Interface\Core\CacheInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::con(): &lt;code&gt;\Dotclear\Interface\Core\ConnectionInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::error(): &lt;code&gt;\Dotclear\Interface\Core\ErrorInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::filter(): &lt;code&gt;\Dotclear\Interface\Core\FilterInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::formater(): &lt;code&gt;\Dotclear\Interface\Core\FormaterInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::lang(): &lt;code&gt;\Dotclear\Interface\Core\LangInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::log(): &lt;code&gt;\Dotclear\Interface\Core\LogInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::media(): &lt;code&gt;\Dotclear\Interface\Core\MediaInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::meta(): &lt;code&gt;\Dotclear\Interface\Core\MetaInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::nonce(): &lt;code&gt;\Dotclear\Interface\Core\NonceInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::notice(): &lt;code&gt;\Dotclear\Interface\Core\NoticeInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::plugins(): &lt;code&gt;\Dotclear\Interface\Module\ModulesInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::postMedia(): &lt;code&gt;\Dotclear\Interface\Core\PostMediaInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::postTypes(): &lt;code&gt;\Dotclear\Interface\Core\PostTypesInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::rest(): &lt;code&gt;\Dotclear\Interface\Core\RestInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::session(): &lt;code&gt;\Dotclear\Interface\Core\SessionInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::themes(): &lt;code&gt;\Dotclear\Interface\Module\ModulesInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::trackback(): &lt;code&gt;\Dotclear\Interface\Core\TrackbackInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::url(): &lt;code&gt;\Dotclear\Interface\Core\UrlInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::users(): &lt;code&gt;\Dotclear\Interface\Core\UsersInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::userPreferences(): &lt;code&gt;\Dotclear\Interface\Core\UserPreferencesInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::userWorkspace(): &lt;code&gt;\Dotclear\Interface\Core\UserWorkspaceInterface&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;App::version(): &lt;code&gt;\Dotclear\Interface\Core\VersionInterface&lt;/code&gt;,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Le nom de l'interface sera le nom du service dans l'usine.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;&lt;q&gt;Le contenu de ce document a été écrit suivant le code de la version 2.28 de Dotclear.&lt;/q&gt;&lt;/em&gt;&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/Remplacer-une-classe-de-premier-niveau-en-2.28#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/Remplacer-une-classe-de-premier-niveau-en-2.28#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/33</wfw:commentRss>
              </item>
          <item>
        <title>2.28</title>
        <link>https://dotclear.watch/Billet/Release-2.28</link>
        <guid isPermaLink="false">urn:md5:524b11a410a9976e870cb9d4742c0f06</guid>
        <pubDate>Fri, 13 Oct 2023 08:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>Versions</category>
                          <category>2.28</category>
                  <category>release</category>
                <description>&lt;p&gt;Sortie le 15 novembre 2023, &lt;a href=&quot;https://fr.dotclear.org/blog/post/2023/11/15/Dotclear-2.28&quot; hreflang=&quot;fr&quot; title=&quot;Annonce officielle de Dotclear 2.28&quot;&gt;cette version de Dotclear&lt;/a&gt; passe les prérequis de PHP de la version 7.4 à la version 8.1 minimum !&lt;/p&gt; &lt;h5&gt;Résumé&lt;/h5&gt;

&lt;p&gt;Cette version boucle &lt;em&gt;quasiment&lt;/em&gt; la transition vers les espaces de noms PHP avec le transfert du cœur de Dotclear et commence à en tirer partie. Le typage des variables, des propriétés de classes et méthodes devient plus strict et précis grâce au passage à PHP 8.1. La gestion du cœur de Dotclear est entièrement remaniée. Une nouvelle classe de lectures des valeurs de configuration fait son apparition. L'utilisation de My pour les modules est de plus en plus nécessaire et recommandé…&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Nouveautés :&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Utilisation des avancées de PHP 8.1,&lt;/li&gt;
&lt;li&gt;Nombreuses classes &lt;a href=&quot;https://dotclear.watch/Billet/D%C3%A9placement-de-classes-en-2.28&quot;&gt;Déplacées&lt;/a&gt;, principalement liées au Core,&lt;/li&gt;
&lt;li&gt;Nombreuses variables, fonctions, méthodes et classes &lt;a href=&quot;https://dotclear.watch/Billet/Les-d%C3%A9pr%C3%A9ci%C3%A9s-en-2.28&quot;&gt;dépréciées&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Passage de &lt;a href=&quot;https://dotclear.watch/Billet/Les-d%C3%A9pr%C3%A9ci%C3%A9s-du-core-en-2.28&quot;&gt;dcCore en déprécié&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;Nouvelle classe d'&lt;a href=&quot;https://dotclear.watch/Billet/Configuration-de-l-application-en-2.28&quot;&gt;accès aux valeurs de configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nouvel accès aux &lt;a href=&quot;https://dotclear.watch/Billet/Le-conteneur-principal-en-2.28&quot;&gt;classes de premier niveau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dotclear.watch/Billet/Remplacer-une-classe-de-premier-niveau-en-2.28&quot;&gt;Système de services&lt;/a&gt; pour les classes de premier niveau&lt;/li&gt;
&lt;li&gt;Nouvelles classes d'&lt;a href=&quot;https://dotclear.watch/Billet/Les-exceptions-de-premier-niveau-en-2.28&quot;&gt;Exception de premier niveau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dotclear.watch/Billet/Permissions-de-modules-en-2.28&quot;&gt;Permissions de modules&lt;/a&gt; entièrement gérées par My&lt;/li&gt;
&lt;li&gt;Ajout du &lt;a href=&quot;https://dotclear.watch/Billet/Le-plugin-Uninstaller&quot;&gt;plugin Uninstaller&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Renforcement du typage des arguments et retours de méthodes.&lt;/li&gt;
&lt;li&gt;Travail sur la &lt;a href=&quot;https://dev.dotclear.org/code/2/&quot; hreflang=&quot;en&quot; title=&quot;Documentation doxygen Dotclear&quot;&gt;documentation doxygen&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Travail sur le niveau d'erreur d'analyseurs phpstan (niveau 8!), phpunit, psalm.&lt;/li&gt;
&lt;li&gt;Support du format media Avif&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Incompatibilités :&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Les constructeurs des classes du Core ont de nouveaux arguments, les plugins instanciant eux-mêmes ces classes provoqueront un arrêt du script.&lt;/li&gt;
&lt;li&gt;Les tests de nullité sur des propriétés ou objets du Core (principalement) ne sont plus permis (des méthodes les remplacent) et provoqueront un arrêt du script.&lt;/li&gt;
&lt;li&gt;Des nombreuses méthodes ont vu leur typage explicitement déclaré, un arrêt du script sera provoqué par une classe qui étend une de ces classes sans avoir été mise à jour.&lt;/li&gt;
&lt;li&gt;La classe de gestion d'erreurs fatales introduite en 2.27 n'est plus compatible, ces anciennes méthodes sont simplement supprimées . (Seule la distribution l'utilise à ce jour)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
&lt;strong&gt;&lt;ins&gt;Information importante pour les développeurs :&lt;/ins&gt;&lt;/strong&gt;&lt;br /&gt;
C'est la première version nécessitant PHP 8.1 minimum, et PHP 8.2.x est supporté, et PHP 8.3.0 devrait l'être.&lt;br /&gt;
&lt;br /&gt;
Les informations distillées ici sont non exhaustives et pourront être complétées à l'avenir.&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;</description>
        
              </item>
          <item>
        <title>Le plugin Uninstaller</title>
        <link>https://dotclear.watch/Billet/Le-plugin-Uninstaller</link>
        <guid isPermaLink="false">urn:md5:55fb5b47a5cfa50068daecfa0e19133e</guid>
        <pubDate>Tue, 22 Aug 2023 12:00:00 +0200</pubDate>
        <dc:creator>Jean-Christian Denis</dc:creator>
                  <category>Articles</category>
                          <category>2.28</category>
                  <category>module</category>
                  <category>plugin</category>
                  <category>suppression</category>
                  <category>theme</category>
                <description>&lt;p&gt;La prochaine version 2.28 de Dotclear embarque un nouveau plugin nommé Uninstaller.&lt;/p&gt; &lt;h5&gt;But&lt;/h5&gt;

&lt;p&gt;Le gestionnaire de modules, incorporé au core de Dotclear et servant à la gestion des thèmes et plugins, permet d'installer des modules avec une gestion des actions liées à l'installation à travers le fichier &lt;strong&gt;src/Install.php&lt;/strong&gt; et sa classe idoine, mais lorsqu'il s'agit de désinstaller des plugins ou thèmes, la seule action effectuée est la suppression des fichiers du module.  À aucun moment on ne tient compte de ce que le module a pu ajouter dans les paramètres, les tables, le cache, etc...&lt;br /&gt;
&lt;br /&gt;
Ce manque est désormais comblé par le plugin &lt;strong&gt;Uninstaller&lt;/strong&gt; qui va permettre d'affiner la désinstallation d'un module, en proposant des outils préétablis de suppressions. Il y a deux points de départ de ces désinstallations, soit depuis le gestionnaire de plugins|thèmes avec un bouton &lt;strong&gt;Désinstallation&lt;/strong&gt; qui donnera le choix au super admin de supprimer telle ou telle partie du module, soit directement lors de l'action de suppression d'un module auquel cas des actions définies par le module lui-même seront effectuées directement sans demande de confirmation.&lt;br /&gt;&lt;/p&gt;&lt;a href=&quot;https://dotclear.watch/public/Articles/sshot-uninstaller-01.jpg&quot; title=&quot;Plugin Uninstaller, août 2023&quot;&gt;&lt;figure class=&quot;media-center&quot;&gt;&lt;img src=&quot;https://dotclear.watch/public/Articles/.sshot-uninstaller-01_m.jpg&quot; alt=&quot;Plugin Uninstaller, août 2023&quot; title=&quot;Plugin Uninstaller, août 2023&quot; /&gt;&lt;figcaption&gt;Interface utilisateur du plugin Uninstaller&lt;/figcaption&gt;&lt;/figure&gt;&lt;/a&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;Actions&lt;/h5&gt;

&lt;p&gt;Une tâche (Cleaner) permet d'effectuer une action ciblée, les groupes et tâches prédéfinis sont les suivants :&lt;br /&gt;
&lt;strong&gt;Caches :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;caches.delete&lt;/code&gt; : Effacer le répertoire de caches créé par le module,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;caches.empty&lt;/code&gt; : Vider le répertoire de caches créé par le module,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Logs :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;logs.delete_all&lt;/code&gt; : Effacer les logs créés par le module,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Plugins :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;plugins.delete&lt;/code&gt; : Effacer les fichiers du plugins,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Preferences :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;preferences.delete_global&lt;/code&gt; : Effacer les préférences pour les utilisateurs créées par le module,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preferences.delete_local&lt;/code&gt; : Effacer les préférences globales créées par le module,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preferences.delete_all&lt;/code&gt; : Effacer les préférences globales et utilisateurs créées par le module,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preferences.delete_related&lt;/code&gt; : Effacer une préférence ciblée créé par le module,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Settings :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;settings.delete_global&lt;/code&gt; : Effacer les préférences pour les blogs créées par le module,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings.delete_local&lt;/code&gt; : Effacer les préférences globales créées par le module,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings.delete_all&lt;/code&gt; : Effacer les préférences globales et blogs créées par le module,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings.delete_related&lt;/code&gt; : Effacer une préférence ciblée créé par le module,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tables :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tables.delete&lt;/code&gt; : Supprimer une table créée par le module,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tables.empty&lt;/code&gt; : Vider une table créée par le module,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Themes :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;themes.delete&lt;/code&gt; : Effacer les fichiers du thème,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Vars :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vars.delete&lt;/code&gt; : Effacer ou vider le sous répertoire de DC_VAR créé par le module,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Versions :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;versions.delete&lt;/code&gt; : Supprimer le numéro de version du module ne base&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Intégration&lt;/h5&gt;

&lt;p&gt;Pour utiliser les fonctions de désinstallation prédéfinis, il suffit d'ajouter un fichier &lt;strong&gt;src\Uninstall.php&lt;/strong&gt; contenant sa classe idoine Uninstall dans le module. Le plugin Uninstaller saura trouver et utiliser ce fichier sans déclaration supplémentaire.&lt;br /&gt;
La méthode &lt;strong&gt;addUserAction&lt;/strong&gt; va ajouter une action avec demande de confirmation tandis que la méthode &lt;strong&gt;addDirectAction&lt;/strong&gt; ajoutera une action directe lors de la suppression d'un module.
Exemple complet de fichier :&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
declare(strict_types=1);

namespace Dotclear\Theme\monTheme;

use Dotclear\App;
use Dotclear\Core\Process;
use Dotclear\Plugin\Uninstaller\Uninstaller;

class Uninstall extends Process
{
    public static function init(): bool
    {
        return self::status(My::checkContext(My::UNINSTALL));
    }

    public static function process(): bool
    {
        // Par sécurtié, on vérifie l&amp;#039;existence du plugin Uninstaller, même si c&amp;#039;est lui qui a dû appeler ce script
        if (!self::status() || !App::plugins()-&amp;gt;moduleExists(&amp;#039;Uninstaller&amp;#039;)) {
            return false;
        }

        // On récupère l&amp;#039;instance singleton de Uninstaller
        Uninstaller::instance()
            // Action utilisateur pour effacer les paramètres aillant l&amp;#039;espace de nom du module
            -&amp;gt;addUserAction(
                &amp;#039;settings&amp;#039;,
                &amp;#039;delete_all&amp;#039;,
                My::id()
            )
            // Action utilisateur pour effacer les fichiers du module
            -&amp;gt;addUserAction(
                &amp;#039;plugins&amp;#039;,
                &amp;#039;delete&amp;#039;,
                My::id()
            )
            // Action utilisateur pour effacer le numéro de version en base du module
            -&amp;gt;addUserAction(
                &amp;#039;versions&amp;#039;,
                &amp;#039;delete&amp;#039;,
                My::id()
            )
            // Action directe pour effacer les fichiers du module
            -&amp;gt;addDirectAction(
                &amp;#039;plugins&amp;#039;,
                &amp;#039;delete&amp;#039;,
                My::id()
            )
            // Action directe pour effacer le numéro de version en base du module
            -&amp;gt;addDirectAction(
                &amp;#039;versions&amp;#039;,
                &amp;#039;delete&amp;#039;,
                My::id()
            )
        ;

        // aucune action spécifique, on retourne donc false
        return false;
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;Extensions&lt;/h5&gt;

&lt;p&gt;Il est possible d'aller plus loin en ajoutant des actions spécifiques qui n'existent pas dans la livraison du plugin Uninstaller.&lt;br /&gt;
Pour des actions avec confirmation utilisateur on va simplement compléter la classe précédente comme suit :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
declare(strict_types=1);

namespace Dotclear\Theme\monTheme;

use Dotclear\App;
use Dotclear\Core\Process;
use Dotclear\Helper\Html\Form\Para;
use Dotclear\Helper\Html\Form\Checkbox;
use Dotclear\Helper\Html\Form\Label;
use Dotclear\Plugin\Uninstaller\Uninstaller;

class Uninstall extends Process
{
    public static function init(): bool
    {
        return self::status(My::checkContext(My::UNINSTALL));
    }

    public static function process(): bool
    {
        // Par sécurtié, on vérifie l&amp;#039;existence du plugin Uninstaller, même si c&amp;#039;est lui qui a dû appeler ce script
        if (!self::status() || !App::plugins()-&amp;gt;moduleExists(&amp;#039;Uninstaller&amp;#039;)) {
            return false;
        }

        // ... ici les actions prédéfinies utilisateur et directes ne sont pas affichées cf exemple ci-dessus

        if (!empty($_POST[&amp;#039;mon_action_perso&amp;#039;]) {

            // Ici on exécute la tâche de supprimer la choucroute

        }

        // on retourne true pour indiquer qu&amp;#039;on a un formulaire
        return true;
    }

    public static function render(): void
    {
        if (!self::status()) {
            return;
        }

        // On affiche le formulaire spécial
        echo (new Para())
            -&amp;gt;items([
                (new Checkbox(&amp;#039;mon_action_perso&amp;#039;, true))
                    -&amp;gt;value(1),
                (new Label(&amp;#039;supprimer la choucroute&amp;#039;, Label::OUTSIDE_LABEL_AFTER))
                    -&amp;gt;for(&amp;#039;mon_action_perso&amp;#039;)
                    -&amp;gt;class(&amp;#039;classic&amp;#039;),
            ])
            -&amp;gt;render(); 
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Il est possible d'aller encore plus loin pour créer des actions spécifiques plus poussées, il faut alors créer un Cleaner et le déclarer de la même manière que ceux du plugin Uninstaller. Voir les fichiers &lt;strong&gt;Prepend.php&lt;/strong&gt; pour la déclaration d'un Cleaner et le répertoire &lt;strong&gt;/src/Task&lt;/strong&gt; pour des exemples de tâches.&lt;br /&gt;&lt;/p&gt;

&lt;h5&gt;NOTE&lt;/h5&gt;

&lt;p&gt;Pour des raisons techniques les actions directes ne sont pas effectuées sur les modules installés en double, et ce même si le bouton &lt;q&gt;Désinstaller&lt;/q&gt; est présent.&lt;br /&gt;
&lt;br /&gt;
Les informations distillées ici sont non exhaustives et pourront être complétées à l'avenir, elles ont été écrites d'après la version 2.28 de Dotclear.&lt;br /&gt;&lt;/p&gt;</description>
        
                  <comments>https://dotclear.watch/Billet/Le-plugin-Uninstaller#comment-form</comments>
          <wfw:comment>https://dotclear.watch/Billet/Le-plugin-Uninstaller#comment-form</wfw:comment>
          <wfw:commentRss>https://dotclear.watch/feed/atom/comments/46</wfw:commentRss>
              </item>
      </channel>
</rss>
