<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Georges Cubas</title>
    <description>The latest articles on DEV Community by Georges Cubas (@shagshag).</description>
    <link>https://dev.to/shagshag</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F321413%2Fddee429a-eb7c-41ce-9d24-b932a6e4dfd0.jpeg</url>
      <title>DEV Community: Georges Cubas</title>
      <link>https://dev.to/shagshag</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shagshag"/>
    <language>en</language>
    <item>
      <title>`class:` ou `alias:`, un choix de conteneur Symfony, et un choix d'ingénierie</title>
      <dc:creator>Georges Cubas</dc:creator>
      <pubDate>Thu, 10 Sep 2026 13:58:05 +0000</pubDate>
      <link>https://dev.to/shagshag/class-ou-alias-un-choix-de-conteneur-symfony-et-un-choix-dingenierie-2ljk</link>
      <guid>https://dev.to/shagshag/class-ou-alias-un-choix-de-conteneur-symfony-et-un-choix-dingenierie-2ljk</guid>
      <description>&lt;p&gt;&lt;em&gt;Pourquoi un fake S3 jetable peut être préférable à MinIO&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Deux décisions se sont posées en recettant un pipeline d'import qui écrit sur S3, sans le moindre accès AWS en local.&lt;/p&gt;

&lt;p&gt;La première est une question technique : pourquoi &lt;code&gt;alias:&lt;/code&gt; fonctionne alors que &lt;code&gt;class:&lt;/code&gt; échoue dans un override &lt;code&gt;when@dev&lt;/code&gt; ?&lt;/p&gt;

&lt;p&gt;La seconde est une décision d'architecture : pourquoi choisir un double maison jetable plutôt que &lt;a href="https://addons.ddev.com/addons/ddev/ddev-minio" rel="noopener noreferrer"&gt;MinIO&lt;/a&gt; ?&lt;/p&gt;

&lt;p&gt;Le S3 n'est finalement qu'un prétexte. Les deux réponses se généralisent à bien d'autres situations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le contexte
&lt;/h2&gt;

&lt;p&gt;Une plateforme Symfony 5.3 importe des fichiers d'achats déposés par une centrale. Les lignes qui référencent une entité encore inconnue sont mises de côté dans un fichier de rejets &lt;strong&gt;sur S3&lt;/strong&gt; ; un écran d'administration permet ensuite de résoudre l'entité, puis de &lt;strong&gt;réimporter&lt;/strong&gt; ces lignes.&lt;/p&gt;

&lt;p&gt;Le service qui parle à S3, &lt;code&gt;AwsService&lt;/code&gt;, tire ses credentials du rôle de tâche ECS (&lt;code&gt;CredentialProvider::ecsCredentials()&lt;/code&gt;), donc d'une infrastructure AWS uniquement disponible en production. Le nom du bucket vient quant à lui d'une ligne de paramétrage en base.&lt;/p&gt;

&lt;p&gt;En local, avec DDEV : aucune variable &lt;code&gt;AWS_*&lt;/code&gt;, aucun conteneur MinIO.&lt;/p&gt;

&lt;p&gt;Tout appel à &lt;code&gt;read()&lt;/code&gt;, &lt;code&gt;putPro()&lt;/code&gt; ou &lt;code&gt;move()&lt;/code&gt; est donc voué à l'échec. Pire : &lt;code&gt;getBucket()&lt;/code&gt; renvoie &lt;code&gt;null&lt;/code&gt; et le service échoue &lt;strong&gt;silencieusement&lt;/strong&gt; (&lt;code&gt;return false&lt;/code&gt;, sans exception).&lt;/p&gt;

&lt;p&gt;Une recette qui se contente de constater que « ça n'a pas planté » peut donc passer sans que rien ne se soit réellement produit.&lt;/p&gt;

&lt;p&gt;Il fallait exercer ce flux pour trois tickets successifs sur le même périmètre, à chaque fois sur une implémentation prête mais pas encore livrée.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deux solutions, toutes les deux valables
&lt;/h2&gt;

&lt;p&gt;Deux approches étaient possibles.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MinIO.&lt;/strong&gt; Ajouter un conteneur S3-compatible au &lt;code&gt;.ddev/config.yaml&lt;/code&gt; de l'équipe, et faire accepter à &lt;code&gt;AwsService&lt;/code&gt; un endpoint et des credentials statiques en environnement de développement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Un double maison.&lt;/strong&gt; Créer un &lt;em&gt;fake&lt;/em&gt; de &lt;code&gt;AwsService&lt;/code&gt; qui redirige les opérations vers le système de fichiers local (&lt;code&gt;var/fake-s3/&lt;/code&gt;), puis le brancher à la place du vrai service par un bloc &lt;code&gt;when@dev&lt;/code&gt; non commité. Une fois la recette terminée, le double disparaît.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Les deux sont valables.&lt;/p&gt;

&lt;p&gt;Le choix n'est donc pas une question de faisabilité mais une question de &lt;strong&gt;contexte&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;when@dev&lt;/code&gt; : substituer une implémentation pour un seul environnement
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://symfony.com/doc/current/configuration.html#configuration-environments" rel="noopener noreferrer"&gt;&lt;code&gt;when@&amp;lt;env&amp;gt;&lt;/code&gt;&lt;/a&gt; (introduit dans Symfony 5.3) permet de scoper de la configuration à un environnement &lt;strong&gt;dans un fichier de configuration normal&lt;/strong&gt;, plutôt que dans un fichier séparé sous &lt;code&gt;config/services/dev/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Le bloc n'est pris en compte que lorsque &lt;code&gt;kernel.environment&lt;/code&gt; correspond à l'environnement &lt;code&gt;&amp;lt;env&amp;gt;&lt;/code&gt; ciblé et il est traité après le corps principal du fichier. Il peut donc redéfinir des services existants.&lt;/p&gt;

&lt;p&gt;En production, ce bloc n'est pas pris en compte : le conteneur de production ne contient aucune définition issue de cet override.&lt;/p&gt;

&lt;p&gt;C'est précisément ce qui en fait un bon réceptacle pour un hack temporaire : tout l'override tient dans &lt;strong&gt;un bloc contigu et greppable&lt;/strong&gt;, en fin d'un seul fichier.&lt;/p&gt;

&lt;p&gt;On le voit facilement au &lt;code&gt;git diff&lt;/code&gt; et le supprimer est trivial. De toute façon c'est pour un test, normalement on ne livre rien à la fin.&lt;/p&gt;

&lt;p&gt;Le plus petit changement réversible possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ─── TEMPORAIRE — recette locale, NE PAS COMMITER ───&lt;/span&gt;
&lt;span class="na"&gt;when@dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;App\Service\AwsService&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;class:&lt;/code&gt; contre &lt;code&gt;alias:&lt;/code&gt; : redéfinir, ou simplement pointer ailleurs
&lt;/h2&gt;

&lt;p&gt;Classiquement un override consiste à remplacer la classe utilisée par le service de test :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;when@dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;App\Service\AwsService&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;App\Service\FakeAwsServiceForManualTesting&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Dans le cas rencontré, cette configuration aboutit à une erreur au premier appel :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Too few arguments to function&lt;br&gt;&lt;br&gt;
App\Service\FakeAwsServiceForManualTesting::__construct(),&lt;br&gt;&lt;br&gt;
0 passed ... and exactly 3 expected&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pourquoi ?&lt;/p&gt;

&lt;p&gt;Il faut regarder comment le conteneur a été construit.&lt;/p&gt;

&lt;p&gt;Le  &lt;a href="https://symfony.com/doc/current/service_container.html#the-default-service-configuration" rel="noopener noreferrer"&gt;&lt;code&gt;services.yaml&lt;/code&gt;&lt;/a&gt; par défaut contient notamment des &lt;code&gt;_defaults&lt;/code&gt; (&lt;code&gt;autowire: true&lt;/code&gt;, &lt;code&gt;autoconfigure: true&lt;/code&gt;, &lt;code&gt;bind:&lt;/code&gt;...) puis une ressource :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# default configuration for services in *this* file&lt;/span&gt;
    &lt;span class="na"&gt;_defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;autowire&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;autoconfigure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="c1"&gt;# makes classes in src/ available to be used as services&lt;/span&gt;
    &lt;span class="na"&gt;App\&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;../src/'&lt;/span&gt;

    &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Cette ressource enregistre notamment &lt;code&gt;App\Service\AwsService&lt;/code&gt; et &lt;code&gt;App\Service\FakeAwsServiceForManualTesting&lt;/code&gt; comme services, avec leurs définitions issues de l'auto-découverte.&lt;/p&gt;

&lt;p&gt;Mais une configuration placée sous &lt;code&gt;when@dev.services&lt;/code&gt; constitue une nouvelle couche de configuration. Il faut donc être prudent lorsqu'on y redéfinit un service : &lt;strong&gt;on ne doit pas supposer que toute la configuration implicite de la définition initiale sera conservée telle quelle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Dans le cas rencontré, la redéfinition avec &lt;code&gt;class:&lt;/code&gt; n'a pas conservé la configuration nécessaire au constructeur du fake. Le service s'est retrouvé avec une définition qui ne savait plus résoudre ses trois dépendances.&lt;/p&gt;

&lt;p&gt;On pourrait rendre cette redéfinition fonctionnelle en lui redonnant ce dont elle a besoin, par exemple avec &lt;code&gt;autowire: true&lt;/code&gt; ou des &lt;code&gt;arguments:&lt;/code&gt; explicites.&lt;/p&gt;

&lt;p&gt;Mais ce n'est pas ce que l'on cherche ici, on ne veut pas &lt;strong&gt;redéfinir&lt;/strong&gt; &lt;code&gt;AwsService&lt;/code&gt;.&lt;br&gt;
On veut dire :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;« Quand quelqu'un demande &lt;code&gt;AwsService&lt;/code&gt; en développement, donne-lui plutôt ce service-là. »&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;C'est exactement le rôle d'un alias.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;when@dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;App\Service\AwsService&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;App\Service\FakeAwsServiceForManualTesting&lt;/span&gt;
            &lt;span class="na"&gt;public&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Un &lt;strong&gt;alias&lt;/strong&gt; n'est pas une nouvelle définition. C'est un pointeur : l'identifiant &lt;code&gt;App\Service\AwsService&lt;/code&gt; se résout vers le service enregistré sous &lt;code&gt;App\Service\FakeAwsServiceForManualTesting&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La définition du fake existe déjà grâce à l'auto-découverte de &lt;code&gt;src/&lt;/code&gt;. Elle conserve donc sa propre configuration et son &lt;a href="https://symfony.com/doc/current/service_container/autowiring.html" rel="noopener noreferrer"&gt;autowiring&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On ne rouvre aucune définition : on change simplement &lt;strong&gt;vers laquelle le conteneur pointe&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;public: true&lt;/code&gt; est nécessaire ici parce qu'une commande console jetable va également récupérer le service par son identifiant.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  
&lt;h3&gt;
  
  
  En bref
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;class:&lt;/code&gt; sert à configurer une définition ; &lt;code&gt;alias:&lt;/code&gt; sert à dire « à cet endroit, utilise cette autre implémentation ».&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ce n'est pas une règle absolue pour toutes les substitutions Symfony, mais c'est un excellent réflexe lorsqu'on dispose déjà de deux services correctement définis : si le besoin est simplement de faire pointer un identifiant vers une autre implémentation, l'alias est l'expression la plus étroite de l'intention.&lt;/p&gt;

&lt;p&gt;On ne reconstruit pas ce qui existe déjà. On change le pointeur.&lt;br&gt;

&lt;/p&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Choisir en fonction du contexte, pas des capacités
&lt;/h2&gt;

&lt;p&gt;MinIO est plus fidèle à une infrastructure S3 réelle. Ça n'en fait pas le bon choix ici.&lt;br&gt;
Les axes qui ont tranché sont les suivants.&lt;/p&gt;
&lt;h3&gt;
  
  
  Rayon d'impact
&lt;/h3&gt;

&lt;p&gt;La solution MinIO modifie &lt;code&gt;AwsService&lt;/code&gt; qui est déjà commité, partagé par toute la plateforme, présent dans tous les environnements, y compris les chemins S3 de production.&lt;/p&gt;

&lt;p&gt;La solution avec le double ne touche aucun code commité : un fichier neuf et un bloc &lt;code&gt;when@dev&lt;/code&gt;, tous deux jetés à la fin.&lt;/p&gt;

&lt;p&gt;Le coût d'une erreur est donc borné par ce qu'on met en jeu.&lt;/p&gt;
&lt;h3&gt;
  
  
  Amortissement, ou sur-ingénierie
&lt;/h3&gt;

&lt;p&gt;MinIO est un &lt;strong&gt;investissement&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Il devient intéressant si l'équipe doit régulièrement tester des flux S3 en local. Le besoin réel ici était beaucoup plus petit : trois tickets sur deux semaines, puis probablement plus rien avant des mois.&lt;/p&gt;

&lt;p&gt;Sans récurrence pour l'amortir, construire le harnais MinIO revient à payer un coût d'infrastructure, de configuration et de maintenance pour une capacité que personne n'a demandée.&lt;/p&gt;

&lt;p&gt;Le besoin est temporaire, la solution peut donc l'être aussi.&lt;/p&gt;
&lt;h3&gt;
  
  
  Demi-vie et réversibilité
&lt;/h3&gt;

&lt;p&gt;Le hack a une demi-vie de quelques jours. Le retirer, c'est supprimer le bloc et le fake, puis éventuellement vider le cache.&lt;/p&gt;

&lt;p&gt;La modification MinIO est permanente par construction. Or une chose permanente réclame un propriétaire, de la documentation, une ligne d'onboarding et de la maintenance.&lt;/p&gt;

&lt;p&gt;Une branche &lt;code&gt;endpoint&lt;/code&gt; dans &lt;code&gt;AwsService&lt;/code&gt;, que plus personne n'exerce quelques mois plus tard, est exactement le genre de code qui peut finir par accueillir un bug sans que personne ne s'en aperçoive.&lt;/p&gt;
&lt;h3&gt;
  
  
  Alignement des modes de défaillance
&lt;/h3&gt;

&lt;p&gt;Le double échoue comme le comportement attendu par le métier :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fichier absent → lecture vide → badge « non importé ».
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pas de faux vert.&lt;/p&gt;

&lt;p&gt;MinIO, lui, peut échouer pour des raisons qui n'ont rien à voir avec le métier : mauvais bucket, mauvais endpoint, path-style, région, credentials...&lt;/p&gt;

&lt;p&gt;On se retrouve alors à tester le &lt;strong&gt;harnais de test&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fidélité consommée
&lt;/h3&gt;

&lt;p&gt;La recette valide ici du métier :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;le moteur de réimport parse-t-il correctement le fichier de rejets ?&lt;/li&gt;
&lt;li&gt;insère-t-il les bonnes lignes ?&lt;/li&gt;
&lt;li&gt;bascule-t-il correctement l'état ?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ce métier est indifférent à l'origine des octets.&lt;/p&gt;

&lt;p&gt;Reproduire fidèlement la sémantique S3 (cohérence, multipart, ACL, etc.) ajoute donc une fidélité que le test ne lit jamais.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La fidélité qu'on ne consomme pas est un coût, pas une qualité.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Coût de communication
&lt;/h3&gt;

&lt;p&gt;Un relecteur qui voit &lt;code&gt;FakeAwsServiceForManualTesting&lt;/code&gt; et un bloc &lt;code&gt;NE PAS COMMITER&lt;/code&gt; a tout compris en trente secondes.&lt;/p&gt;

&lt;p&gt;MinIO demande davantage : une note de conception, une explication en équipe, une mise à jour du guide d'onboarding, et potentiellement une réponse à la question :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;« C'est quoi ce paramètre &lt;code&gt;endpoint&lt;/code&gt; sur &lt;code&gt;AwsService&lt;/code&gt; ? »&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Et cela, pendant toute la durée de vie de la solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce que le double contient
&lt;/h2&gt;

&lt;p&gt;Le double ne cherche pas à reproduire S3.&lt;br&gt;
Il reproduit uniquement &lt;strong&gt;la surface publique réellement appelée par le code sous test&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Les helpers privés (&lt;code&gt;put&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;check&lt;/code&gt;) ne peuvent pas être surchargés ; on surcharge donc les wrappers publics utilisés par l'application :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FakeAwsServiceForManualTesting&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AwsService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;KernelInterface&lt;/span&gt; &lt;span class="nv"&gt;$kernel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;LoggerInterface&lt;/span&gt; &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;ParametersService&lt;/span&gt; &lt;span class="nv"&gt;$parametersService&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$kernel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$parametersService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$kernel&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProjectDir&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/var/fake-s3'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$folder&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$folder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;is_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;putPro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$folder&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$folder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mo"&gt;0777&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;file_put_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// putShop / putFTP / copy / delete* / list* :&lt;/span&gt;
    &lt;span class="c1"&gt;// même forme, sur var/fake-s3/.&lt;/span&gt;

    &lt;span class="c1"&gt;// move() n'est pas surchargée :&lt;/span&gt;
    &lt;span class="c1"&gt;// la classe mère la fait en copy()+delete().&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ce n'est pas un émulateur S3 et c'est volontaire. Le double implémente uniquement ce que le flux testé consomme.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tester le métier sans navigateur
&lt;/h2&gt;

&lt;p&gt;Pour piloter les actions du contrôleur sans passer par le navigateur, une commande console jetable injecte le &lt;strong&gt;même service métier&lt;/strong&gt; que le contrôleur.&lt;/p&gt;

&lt;p&gt;Ce service est désormais backé par le fake grâce à l'alias.&lt;/p&gt;

&lt;p&gt;La commande appelle donc les mêmes méthodes que le parcours applicatif.&lt;/p&gt;

&lt;p&gt;Tout le cahier de test peut se dérouler en CLI ; le navigateur ne sert plus qu'à confirmer l'UI.&lt;/p&gt;

&lt;p&gt;C'est aussi ce qui rend défendable l'argument :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;On a validé le métier, pas S3.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Le principe
&lt;/h2&gt;

&lt;p&gt;Deux réflexes de séniorité ressortent de cette expérience, l'un technique, l'autre architectural.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pour &lt;strong&gt;substituer&lt;/strong&gt; une implémentation, on ne redéfinit pas sa configuration si l'on peut simplement pointer vers une autre définition existante. &lt;code&gt;alias:&lt;/code&gt; exprime cette intention ; &lt;code&gt;class:&lt;/code&gt; est à utiliser lorsqu'on veut réellement configurer ou redéfinir une définition.&lt;/li&gt;
&lt;li&gt;On choisit la solution dont le coût, &lt;strong&gt;humain autant que technique&lt;/strong&gt;, est proportionné à la taille et à la durée de vie réelles du problème : rayon d'impact, maintenance, onboarding, réversibilité, fréquence d'utilisation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Un jetable assumé bat souvent un permanent mal entretenu.&lt;/p&gt;

&lt;p&gt;Et quand le contexte change, on refait le calcul.&lt;/p&gt;

&lt;p&gt;Ici, le besoin était temporaire. Le double l'était aussi.&lt;/p&gt;

&lt;p&gt;Le signe que le choix était bon est peut-être le plus concret : le pattern a été capturé dans la base de connaissances de l'équipe, puis réutilisé tel quel sur les deux tickets suivants.&lt;/p&gt;

&lt;p&gt;Vingt minutes de mise en place, trois fois, contre un chantier de plusieurs jours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ce n'était pas la solution la plus complète. C'était la solution proportionnée.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>french</category>
      <category>testing</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Anonymiser les données de PrestaShop</title>
      <dc:creator>Georges Cubas</dc:creator>
      <pubDate>Mon, 18 Jul 2022 12:25:48 +0000</pubDate>
      <link>https://dev.to/shagshag/anonymiser-les-donnees-de-prestashop-24g4</link>
      <guid>https://dev.to/shagshag/anonymiser-les-donnees-de-prestashop-24g4</guid>
      <description>&lt;p&gt;Pour créer un environnement de développement, on duplique celui de production. Sauf qu’il ne faut pas garder les infos personnelles des clients. Déjà c’est dangereux, si vous gérez mal votre affaire vous risquez d’envoyer des mails aux clients et ça force tous les développeur et intervenant à faire attention au RGPD.&lt;/p&gt;

&lt;p&gt;Donc on anonymise tout, c’est plus simple.&lt;/p&gt;

&lt;p&gt;Voici un script MariaDB qui anonymise les données clients : noms, prénoms, adresses, téléphones, e-mails, ip, communications. Il remplace les lettres par xxx en respectant la casse, les n° de téléphone par 0 en respectant le format et passe les IP en 127.0.0.1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;ps_address&lt;/span&gt; &lt;span class="n"&gt;pa&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[0-9]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone_mobile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone_mobile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[0-9]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vat_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vat_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[0-9]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dni&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dni&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[0-9]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;ps_customer&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id_customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'@example.com'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;ps_customer&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; 
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip_registration_newsletter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'127.0.0.1'&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip_registration_newsletter&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip_registration_newsletter&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;ps_customer_message&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REGEXP_REPLACE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[a-z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'(?-i)[A-Z]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2130706433'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;ps_customer_thread&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id_customer&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id_customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'@example.com'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La syntaxe de REGEXP_REPLACE n’est pas la même pour &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-replace" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt; et &lt;a href="https://mariadb.com/kb/en/regexp_replace/" rel="noopener noreferrer"&gt;MariaBD&lt;/a&gt;, donc il faudra adapter.&lt;/p&gt;

</description>
      <category>anonymisation</category>
      <category>développement</category>
      <category>prestashop</category>
      <category>sql</category>
    </item>
    <item>
      <title>Programmer les popups de Popup Builder</title>
      <dc:creator>Georges Cubas</dc:creator>
      <pubDate>Wed, 20 Oct 2021 10:18:03 +0000</pubDate>
      <link>https://dev.to/shagshag/programmer-les-popups-de-popup-builder-5cca</link>
      <guid>https://dev.to/shagshag/programmer-les-popups-de-popup-builder-5cca</guid>
      <description>&lt;p&gt;La version gratuite du plugin &lt;a href="https://wordpress.org/plugins/popup-builder/" rel="noopener noreferrer"&gt;WordPress Popup Builder&lt;/a&gt; ne permet pas programmer l’affichage des popups. Cependant elle créé le &lt;a href="https://developer.wordpress.org/plugins/hooks/filters/" rel="noopener noreferrer"&gt;filtre&lt;/a&gt; sgpbOtherConditions qui permet de les désactiver.&lt;/p&gt;

&lt;p&gt;Ce filtre est appelé pour chaque popup qui peut s’afficher sur la page et si l’argument ‘status’ à &lt;code&gt;false&lt;/code&gt; est ajouté à ceux existants, la popup ne s’affiche pas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="cd"&gt;/**
     * Check Popup conditions
     *
     * @since 1.0.0
     *
     * @return array
     *
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;isSatisfyForOtherConditions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$popup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPopup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$popupOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$popup&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getOptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$popupId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$popup&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$dontAlowOpenPopup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;apply_filters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sgpbOtherConditions'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$popupId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'popupOptions'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$popupOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'popupObj'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$popup&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$dontAlowOpenPopup&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour désactiver automatiquement vos popups, vous pouvez ajouter ce code à &lt;a href="https://developer.wordpress.org/themes/basics/theme-functions/" rel="noopener noreferrer"&gt;functions.php&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sgpbOtherConditions'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'my_sgpbOtherConditions'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// update popin status&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;my_sgpbOtherConditions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// if popup is already unactive, do nothing&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;17938&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// summer holiday active between 2021-07-30 and 2021-08-01&lt;/span&gt;
            &lt;span class="nv"&gt;$now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// for time zone, can be improved&lt;/span&gt;
            &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtotime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2021-07-30 00:00:00'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtotime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2021-08-02 00:00:00'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// if we are not between 2021-07-30 and 2021-08-01 desactivate the popup&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;$now&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$now&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;           
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;16412&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;// covid reassurance unactive between 2021-07-30 and 2021-08-01&lt;/span&gt;
            &lt;span class="nv"&gt;$now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// for time zone, can be improved&lt;/span&gt;
            &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtotime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2021-07-30 00:00:00'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtotime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2021-08-02 00:00:00'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// if we are between 2021-07-30 and 2021-08-01 desactivate the popup&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;$now&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$now&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ainsi la popup 17938 ne sera active qu’entre le 30 juillet et le 1 août 2021 alors que la 16412 ne le sera que le reste du temps.&lt;/p&gt;

</description>
      <category>php</category>
      <category>wordpress</category>
      <category>wordpresspopupbuilder</category>
      <category>french</category>
    </item>
    <item>
      <title>Sauvegarde automatique sur FTP</title>
      <dc:creator>Georges Cubas</dc:creator>
      <pubDate>Wed, 20 Oct 2021 09:31:49 +0000</pubDate>
      <link>https://dev.to/shagshag/sauvegarde-automatique-sur-ftp-4f42</link>
      <guid>https://dev.to/shagshag/sauvegarde-automatique-sur-ftp-4f42</guid>
      <description>&lt;p&gt;A force je pense avoir un script de sauvegarde FTP efficace.&lt;/p&gt;

&lt;p&gt;Il sauvegarde les bases de données ainsi qu’un dossier du serveur et les envoi sur un serveur FTP. Si le serveur FTP est plein, il supprime les sauvegardes les plus anciennes jusqu’à avoir assez de place pour mettre la nouvelle.&lt;/p&gt;

&lt;p&gt;Si une erreur arrive, il envoi un mail d’alerte.&lt;/p&gt;

&lt;p&gt;Le script nécessite &lt;a href="https://doc.ubuntu-fr.org/curlftpfs" rel="noopener noreferrer"&gt;curlftpfs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilisation :
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Modifiez le script dans la partie configuration&lt;/li&gt;
&lt;li&gt;Enregistrez le sur le serveur, par exemple dans /opt/scripts/backup.sh&lt;/li&gt;
&lt;li&gt;Donnez les droits d’execution au fichier : &lt;code&gt;chmod +x /opt/scripts/backup.sh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ajoutez une tâche cron : &lt;code&gt;02 00 * * * /bin/bash /opt/scripts/backup.sh &amp;gt; /var/log/backup.log 2&amp;gt;&amp;amp;1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Also on: &lt;a href="https://gist.github.com/Shagshag/acd208c48253b3b43ca941ceb4f3ad9a" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backup</category>
      <category>bash</category>
      <category>sysadmin</category>
      <category>french</category>
    </item>
    <item>
      <title>Autoriser les images avec des longs ID dans PrestaShop</title>
      <dc:creator>Georges Cubas</dc:creator>
      <pubDate>Wed, 09 Jun 2021 09:56:37 +0000</pubDate>
      <link>https://dev.to/shagshag/autoriser-les-images-avec-des-longs-id-dans-prestashop-631</link>
      <guid>https://dev.to/shagshag/autoriser-les-images-avec-des-longs-id-dans-prestashop-631</guid>
      <description>&lt;p&gt;Par construction PrestaShop ne peut pas gérer les images avec des ID supérieurs à 9 999 999 (7 chiffres). C’est déjà beaucoup et on a pas souvent besoin de plus mais j’ai eu affaire à un script d’import qui impose les ID d’images et donc ça arrive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pourquoi PrestaShop ne les gèrent pas ?
&lt;/h3&gt;

&lt;p&gt;En fait, PrestaShop n’a pas de soucis avec les ID de 8 chiffres ou plus, tant que la base de données l’accepte, lui aussi. Le problème vient de la façon d’accéder aux images.&lt;/p&gt;

&lt;p&gt;L’URL d’une image est &lt;code&gt;https://example.com/123-large/mon-image.jpg&lt;/code&gt; soit &lt;code&gt;[url de la boutique]/[ID de l'image]-[format à afficher]/[texte pour le référencement].jpg&lt;/code&gt; et &lt;a href="https://httpd.apache.org/docs/2.4/howto/htaccess.html" rel="noopener noreferrer"&gt;le fichier &lt;code&gt;.htaccess&lt;/code&gt;&lt;/a&gt; explique au serveur que quand on a une url de ce type, il faut aller chercher le fichier qu’il faut dans le dossier des images &lt;code&gt;/img/p/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Le fichier .htaccess de PrestaShop ressemble à ça&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/p/$1/$1$2$3.jpg [L]
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/p/$1/$2/$1$2$3$4.jpg [L]
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/p/$1/$2/$3/$1$2$3$4$5.jpg [L]
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/p/$1/$2/$3/$4/$1$2$3$4$5$6.jpg [L]
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/p/$1/$2/$3/$4/$5/$1$2$3$4$5$6$7.jpg [L]
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/p/$1/$2/$3/$4/$5/$6/$1$2$3$4$5$6$7$8.jpg [L]
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/p/$1/$2/$3/$4/$5/$6/$7/$1$2$3$4$5$6$7$8$9.jpg [L]Code language: JavaScript (javascript)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Donc quand le serveur reçoit l’URL &lt;code&gt;https://example.com/123-large/mon-image.jpg&lt;/code&gt; il affiche le fichier &lt;code&gt;/img/p/1/2/3/123-large.jpg&lt;/code&gt;. C’est rapide et ça ne demande pas de ressource, PrestaShop n’est même pas appelé quand on veut afficher une image produit.&lt;/p&gt;

&lt;p&gt;Mais &lt;a href="https://stackoverflow.com/a/5849017/2530962" rel="noopener noreferrer"&gt;on ne peut pas utiliser $10 dans un fichier .htaccess&lt;/a&gt;, il est interprété comme $1 puis le caractère 0. Comme dans la dernière ligne de l’extrait ci-dessus on utilise $9, on ne peut pas aller plus loin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ma solution
&lt;/h3&gt;

&lt;p&gt;Si on appelle l’URL &lt;code&gt;https://example.com/123456789-large/mon-image.jpg&lt;/code&gt;, le serveur ne reconnait pas ce format et essaye simplement d’afficher le fichier &lt;code&gt;/123456789-large/mon-image.jpg&lt;/code&gt; qui n’existe pas et renvoie donc une erreur 404. PrestaShop affiche donc une jolie page pour dire que le fichier n’a pas été trouvée.&lt;/p&gt;

&lt;p&gt;L’astuce consiste à utiliser cette page pour afficher l’image demandée en &lt;a href="https://devdocs.prestashop.com/1.7/modules/concepts/overrides/" rel="noopener noreferrer"&gt;complétant&lt;/a&gt; &lt;a href="https://github.com/PrestaShop/PrestaShop/blob/develop/controllers/front/PageNotFoundController.php" rel="noopener noreferrer"&gt;le controller PageNotFound&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PageNotFoundController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PageNotFoundControllerCore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;initContent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'?'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'REQUEST_URI'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/([0-9]+)(\-[_a-zA-Z0-9-]*)?\/.*\.jpg/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_PS_ROOT_DIR_&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/img/p/'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'.jpg'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type: '&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;mime_content_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?:&lt;/span&gt;&lt;span class="s1"&gt;'image/jpg'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nb"&gt;readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;die&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'HTTP/1.1 404 Not Found'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Status: 404 Not Found'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type: image/gif'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nb"&gt;readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_PS_ROOT_DIR_&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/img/404.gif'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;die&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;initContent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code à placer dans &lt;code&gt;/override/controllers/front/PageNotFoundController.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Le principe est le suivant :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;quand le controller PageNotFound est appelé, on regarde si l’URL correspond à celle d’une image produit,&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;si oui on regarde si elle existe, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;si oui on l’affiche et c’est terminé&lt;/li&gt;
&lt;li&gt;si non on affiche une image d’erreur&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;si non on laisse le controller gérer&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sources :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devdocs.prestashop.com/1.7/modules/concepts/overrides/" rel="noopener noreferrer"&gt;Overrides dans PrestaShop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://httpd.apache.org/docs/2.4/howto/htaccess.html" rel="noopener noreferrer"&gt;Format du fichier .htaccess&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also on: &lt;a href="https://gist.github.com/Shagshag/9b7ca766e6a855ba17d8af9c71412076" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>prestashop</category>
      <category>php</category>
      <category>french</category>
    </item>
    <item>
      <title>Rediriger les fiches produits dans WooCommerce</title>
      <dc:creator>Georges Cubas</dc:creator>
      <pubDate>Wed, 09 Jun 2021 09:00:39 +0000</pubDate>
      <link>https://dev.to/shagshag/rediriger-les-fiches-produits-dans-woocommerce-30f7</link>
      <guid>https://dev.to/shagshag/rediriger-les-fiches-produits-dans-woocommerce-30f7</guid>
      <description>&lt;p&gt;Dans WooCommerce chaque produit a &lt;a href="https://docs.woocommerce.com/document/marketing-product-pages-writing/#section-4" rel="noopener noreferrer"&gt;une page dédiée&lt;/a&gt;. Dans le panier, les produits renvoient à celles-ci.&lt;/p&gt;

&lt;p&gt;Si vous voulez désactiver cette fonctionnalité et afficher une page avec tous vos produits, vous pouvez ajouter ce code à &lt;a href="https://developer.wordpress.org/themes/basics/theme-functions/" rel="noopener noreferrer"&gt;functions.php&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// redirige les pages produits&lt;/span&gt;
&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'prevent_access_to_product_page'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;prevent_access_to_product_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;is_product&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;wp_redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;get_permalink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;269&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ainsi toutes les pages produits redirigeront vers la page 269.&lt;/p&gt;

&lt;p&gt;Source : &lt;a href="https://stackoverflow.com/q/44197739" rel="noopener noreferrer"&gt;How to disable/hide woocommerce single product page?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also on: &lt;a href="https://stackoverflow.com/a/67885098/2530962" rel="noopener noreferrer"&gt;Stack Overflow&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>woocommerce</category>
      <category>wordpress</category>
      <category>french</category>
    </item>
  </channel>
</rss>
