Table des matières :
- Compatibilité Symfony 6.4 dans PrestaShop 9 : ce qui casse réellement côté modules
- Composer, autoloading et isolation des dépendances : éviter les collisions Symfony
- Déclarer proprement services, routes et contrôleurs Symfony dans un module
- Admin API PrestaShop : authentification, scopes, contrats OpenAPI et intégration module
- Tests de compatibilité et CI : matrice PrestaShop/PHP, dépréciations Symfony, tests de contrat API
Dans PrestaShop 9.x (testé ici sur 9.1/9.2) avec PHP 8.3, « compatibilité Symfony 6.4 » ne veut pas dire « mon module ne fait pas d’erreur 500 ». Ça veut dire : pas de collision de dépendances Composer, pas d’usage de fonctionnalités Symfony retirées/dépréciées, et une intégration correcte au container et à la couche Admin (legacy + Symfony) — tout en gardant une voie propre vers l’Admin API.
Un bon réflexe : considérer la compatibilité comme un contrat de cohabitation avec le cœur PrestaShop. Votre module n’est pas une application Symfony autonome : il vit dans un runtime partagé (autoload, container, cache, BO). Les échecs « invisibles » arrivent souvent au moment où la boutique reconstruit le container, vide le cache, ou exécute un controller BO Symfony — pas forcément lors d’un simple install().
Compatibilité Symfony 6.4 dans PrestaShop 9 : ce qui casse réellement côté modules
Le premier piège, c’est de croire que Symfony 6.4 n’impacte que les modules qui « font du Symfony ». Faux : même un module 100% legacy peut casser indirectement si ses vendors embarquent des composants Symfony (ou PSR) incompatibles avec ceux du cœur, parce que l’autoload est global. PrestaShop 9 s’appuie sur Symfony 6.4 et a donc figé un ensemble de versions de composants ; votre module doit s’aligner (ou s’isoler) plutôt que d’essayer de « mettre à jour Symfony dans son coin ». Pour le contexte de migration (versions, prérequis PHP), voir : PrestaShop 9 : guide de migration Symfony 6.4 et PHP 8.3.
Dans la pratique, ce qui casse le plus côté modules sur PrestaShop 9 n’est pas « Symfony » au sens abstrait, mais des incompatibilités transverses :
| Cause fréquente | Symptôme typique | Pourquoi ça arrive | Correctif recommandé |
|---|---|---|---|
Une lib embarquée tire symfony/* en version non alignée |
Fatal error: Declaration ... must be compatible with ... ou erreurs de types |
Les signatures évoluent, et un composant du module “passe devant” celui du cœur | Éviter symfony/* en dépendance directe, ou isoler (prefixing) |
Mauvaise isolation PSR (psr/container, psr/log, psr/http-message) |
Exceptions dans le container, logs silencieux, types incompatibles | PrestaShop et vos libs attendent la même major, mais vous shippez une autre | Contraintes strictes + tests CI |
| Dépréciations ignorées | Rien en dev, puis rupture après mise à jour patch/minor | Les dépréciations finissent par devenir des suppressions | Traiter les dépréciations comme des échecs de test |
Le deuxième point, c’est la surface d’intégration : en Back-Office, vous avez encore du legacy (controllers Admin*Controller, HelperList, etc.) et une couche Symfony (controllers, services, formulaire, routing). Un module « moderne » doit décider explicitement ce qu’il implémente : une page BO Symfony (recommandé), une extension d’une page existante via hooks, ou un service consommé par une commande/cron.
Un exemple très courant en contexte francophone (agence / e-commerçant) : un module “ERP” ajouté pour pousser les commandes vers un outil externe. Si vous l’implémentez uniquement via un bouton BO legacy et du code procédural, vous aurez rapidement :
- des problèmes de permissions (qui a le droit d’envoyer ?),
- des timeouts (appel HTTP dans le thread BO),
- et des effets de bord lors des mises à jour (token BO, refactoring interne).
Alors qu’une approche « Symfony 6.4 friendly » consiste à :
- déplacer l’appel ERP dans un service testable,
- déclencher via une commande/cron ou une queue (si disponible),
- exposer une UI BO Symfony minimale pour le suivi (dernier envoi, erreurs, relance).
Les bricolages par override sont à traiter comme un risque technique, pas comme une stratégie : PrestaShop 9.2 : bonnes pratiques d’override et tests de compatibilité.
Le troisième point, c’est la gestion des dépréciations. Symfony 6.4 est une LTS ; sa promesse est la stabilité, pas l’absence d’évolution. La bonne pratique, c’est de traiter les dépréciations comme des « tests qui échouent », sinon vous reportez la dette jusqu’au jour où PrestaShop monte de patch/minor et vous prenez un mur. Le blog Symfony l’exprime explicitement dans l’annonce de 6.4 : « Symfony 6.4 is the next Long-Term Support (LTS) version » (Symfony Blog, 2023) — implication : vous avez un socle stable, donc aucune excuse pour shipper des intégrations fragiles. Source : https://symfony.com/blog/symfony-6-4-0-released
Composer, autoloading et isolation des dépendances : éviter les collisions Symfony
Le problème n°1 côté modules PrestaShop en 2026 reste Composer : un module qui embarque symfony/* (ou des libs qui tirent symfony/*) sans contrainte stricte peut forcer Composer à résoudre des versions incompatibles, ou pire, à charger des classes inattendues via l’autoload. Le pattern défensif : ne dépendez pas de composants Symfony déjà fournis par le cœur, sauf si vous êtes certain de rester dans les contraintes de PrestaShop. Et si vous devez embarquer des libs qui dépendent de Symfony, isolez-les (voir plus bas).
Point à ne pas sous-estimer : même si votre module “vend” son propre vendor/, vous avez souvent plusieurs autoloaders enregistrés dans le processus PHP. Un module qui fait un require vendor/autoload.php ajoute un autoloader à la pile SPL. Si une classe existe à la fois dans le module et dans le cœur, l’ordre de résolution peut suffire à créer un bug non déterministe (selon les appels et le cache).
Concrètement, dans le composer.json de votre module, vous voulez :
- une contrainte PHP alignée sur le support réel (sur PrestaShop 9 : PHP 8.2/8.3 selon version et hébergement) ;
- des contraintes strictes sur les packages “sensibles” (PSR, Symfony contracts, doctrine annotations si encore utilisé par une dépendance legacy) ;
- un
conflictexplicite si vous savez qu’un composant Symfony en version 7+ casserait le cœur ; - et idéalement, un build reproductible (composer.lock versionné) pour éviter “ça marche sur ma machine”.
Exemple minimaliste (à adapter à votre périmètre fonctionnel) :
{
"name": "vendor/ps_mymodule",
"type": "prestashop-module",
"require": {
"php": "^8.2 || ^8.3",
"psr/log": "^3.0",
"psr/http-client": "^1.0",
"psr/http-message": "^2.0"
},
"conflict": {
"symfony/http-kernel": ">=7.0",
"symfony/dependency-injection": ">=7.0"
},
"autoload": {
"psr-4": {
"Vendor\\MyModule\\": "src/"
}
}
}
Checklist “anti-collision” (très utile en revue de code module) :
- Vérifier si vos dépendances tirent
symfony/*(viacomposer why symfony/http-kernelpendant le build). - Éviter d’embarquer des polyfills déjà présents côté cœur sauf nécessité.
- Ne pas “relâcher” des contraintes majeures sur PSR (
^1|^2|^3) sans raison : préférez une cible claire. - Si vous utilisez un client HTTP, décider : PSR-18 (portable) ou Symfony HttpClient (aligné écosystème). Mélanger sans stratégie augmente le risque.
Si votre module doit embarquer un SDK (paiement, ERP, etc.) qui amène une arborescence de dépendances potentiellement conflictuelles, la solution propre en 2026 n’est pas “on croise les doigts” : c’est le prefixing (ex. PHP-Scoper) ou une isolation par autoloader dédié. Ça coûte du build, mais ça évite les cas réels où un vendor du module « shadow » une classe Symfony/PSR utilisée par le cœur.
Un mini-signal d’alerte concret : si votre SDK amène symfony/serializer, symfony/property-access ou symfony/event-dispatcher et que vous ne contrôlez pas strictement les versions, vous êtes statistiquement proche d’un incident à la prochaine montée PrestaShop.
C’est la même logique que celle qu’on applique en durcissement supply-chain (SBOM, contrôle de dépendances) : PrestaShop : sécuriser APIs et modules avec SBOM, WAF et CI/CD.
Déclarer proprement services, routes et contrôleurs Symfony dans un module
Sur PrestaShop 9 (Symfony 6.4), vous voulez viser une intégration “container-first” : vos classes métier sont des services, vos controllers Symfony n’instancient rien à la main, et vous évitez les singletons historiques. Le point clé : autowiring et autoconfiguration sont vos alliés, mais uniquement si vous gardez un graphe de dépendances maîtrisé. Pour des modules destinés à être maintenus, un src/ propre (Domain/UseCase/Infrastructure) vaut mieux qu’un classes/ fourre-tout.
Une règle simple qui évite beaucoup de dette : tout ce qui parle à l’extérieur (HTTP, DBAL spécifique, filesystem, API) doit être derrière une interface et injecté. Ça permet :
- de tester sans toucher à la boutique,
- de remplacer l’implémentation si PrestaShop change,
- et de gérer les timeouts/retries proprement (notamment si vous ciblez l’Admin API).
Au niveau configuration, le pattern classique côté module est d’exposer un fichier de services (YAML ou PHP) chargé par PrestaShop pour le BO. Selon votre structure, vous définissez des _defaults et vous taggez vos controllers pour l’injection d’arguments. Exemple (idée) :
# config/services.yml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Vendor\MyModule\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
Vendor\MyModule\Controller\Admin\:
resource: '../src/Controller/Admin/'
tags: ['controller.service_arguments']
public: true
Deux précautions “compat Symfony 6.4” souvent oubliées :
- Ne rendez pas tout public “pour que ça marche”. Les services publics masquent les erreurs de design (et compliquent les migrations).
- Évitez d’injecter directement le container (
ContainerInterface) dans vos services : ça vous verrouille et rend les tests difficiles.
Troisième point : routes et sécurité. En Symfony 6.4, les attributs (#[Route]) sont la voie standard ; évitez de dépendre d’annotations Sensio (souvent héritées d’anciens modules) parce que c’est un angle mort lors des montées de version. Pour les pages BO, appuyez-vous sur les mécanismes natifs PrestaShop (tokens, permissions, tabs) plutôt que de bricoler des guards Symfony.
Un scénario classique : vous ajoutez une page “Réglages” Symfony pour votre module. Les points à valider pour que ce soit robuste :
- la Tab BO est créée/supprimée proprement (install/uninstall),
- le controller vérifie les droits (profil employé),
- les formulaires sont CSRF-safe (mécanismes Symfony),
- et les liens de navigation ne dépendent pas d’URL “en dur” (préférez le router).
Et si vous devez toucher à la logique BO existante, privilégiez les hooks et services plutôt que l’override “au cutter” (cf. lien override plus haut), parce que l’override vous bloque dès qu’un contrôleur Symfony interne change de signature.
Admin API PrestaShop : authentification, scopes, contrats OpenAPI et intégration module
L’Admin API change la donne par rapport au Webservice historique : elle vise l’automatisation et les intégrations “back-office” modernes (headless, ERP, ops), avec un modèle d’authentification et d’autorisations plus fin. En pratique, ça force les modules à se poser deux questions : (1) est-ce que mon module consomme l’Admin API (pour piloter PrestaShop depuis un service externe ou une app) ? (2) est-ce que mon module expose des ressources supplémentaires via l’Admin API (si votre module ajoute un domaine métier) ? Pour le socle, vous avez déjà de la matière : PrestaShop Admin API : environnement de développement Docker et Swagger et PrestaShop Admin API : sécuriser secret et scopes par client.
Pour cadrer techniquement : l’Admin API s’appuie sur des conventions d’API modernes (contrat OpenAPI, outillage type Swagger). Si vous exposez des endpoints (ou si vous en consommez), l’objectif n’est pas juste “retourner du JSON” : c’est tenir un contrat et le valider. La référence normative est la spécification OpenAPI : https://spec.openapis.org/oas/latest.html
Côté auth, traitez ça comme de l’OAuth 2.0 “classique” (au minimum client credentials selon votre cas), et appliquez les mêmes exigences que pour n’importe quelle API admin : secret stocké hors Git, rotation, scopes minimaux, et journalisation. Le RFC définit OAuth 2.0 comme « The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service » (RFC 6749). Source : https://www.rfc-editor.org/rfc/rfc6749
Exemple concret (module qui consomme l’Admin API) : un module de reporting installé sur plusieurs boutiques d’un groupe. Si vous accordez un scope trop large “par facilité”, vous créez un risque : une fuite de secret donne potentiellement accès à des opérations d’administration. Le bon compromis est souvent :
- 1 client OAuth par application (voire par boutique),
- scopes minimaux par fonctionnalité,
- et une rotation planifiée (même simple : tous les X mois) avec alerte si échec.
D’un point de vue module, la compatibilité Symfony 6.4 + Admin API se joue aussi sur la robustesse HTTP : utilisez un client PSR-18 (ou Symfony HttpClient si vous restez strictement dans l’écosystème du cœur), gérez les timeouts, retries bornés, et l’idempotence côté write (si vous avez des webhooks). Ne parsez pas “à la main” des réponses sans valider le schéma attendu : sur une API versionnée, les changements non-breaking existent (champs optionnels, pagination). Deux détails qui évitent des bugs “production only” :
- Tolérer des champs supplémentaires (ne pas échouer sur “unknown fields” si votre DTO est strict).
- Implémenter correctement la pagination/tri : un import peut fonctionner en dev (peu de données) et s’écrouler en prod.
Et si vous devez rester compatible PrestaShop 8 (sans Admin API), prévoyez une stratégie de fallback vers le Webservice legacy : API Webservice PrestaShop : guide CRUD et ressources développeur.
Tests de compatibilité et CI : matrice PrestaShop/PHP, dépréciations Symfony, tests de contrat API
Si votre module vise PrestaShop 9.1/9.2, la compatibilité Symfony 6.4 se valide surtout avec : (a) une matrice d’exécution (versions PrestaShop + PHP), (b) des tests fonctionnels BO (routing, permissions), (c) la chasse aux dépréciations. Le but n’est pas “100% coverage”, le but est de capturer les régressions probables : container compilation, cache Symfony, chargement des services du module, et compatibilité PHP 8.3 (types, readonly, changements d’extensions). Pour une approche CI/CD pragmatique sur PrestaShop : PrestaShop CI/CD : générer des démos à la demande en minutes.
Une matrice minimale réaliste (à ajuster selon votre support commercial) ressemble à :
- PrestaShop 9.1 + PHP 8.2
- PrestaShop 9.1 + PHP 8.3
- PrestaShop 9.2 + PHP 8.3
À chaque job, validez au moins ces points (c’est souvent là que ça casse “après mise à jour”) :
cache:clear/rebuild du cache BO (container compilé),- installation/désinstallation du module (création Tab, permissions, fixtures si besoin),
- appel d’une route Symfony du module (200 attendu) + contrôle d’accès (403 attendu selon profil),
- et si Admin API : un test de contrat (au moins “auth + 1 endpoint read + 1 endpoint write” dans un environnement Docker).
Sur Symfony, activez explicitement la détection de dépréciations en test via symfony/phpunit-bridge (quand applicable à votre setup) et faites échouer le pipeline si le compteur dépasse un seuil. C’est le seul moyen de ne pas “découvrir” une rupture le jour où une boutique passe de 9.1 à 9.2. En parallèle, ajoutez une analyse statique (PHPStan/Psalm) avec un niveau réaliste : sur du code module, un niveau moyen mais strict sur votre src/ est souvent plus utile qu’un niveau maximal sur des legacy helpers impossibles à typer.
Enfin, pour l’Admin API, ajoutez des tests de contrat : générez un client depuis l’OpenAPI (ou validez vos réponses/requests contre le schéma) et exécutez-les contre un environnement Docker de référence. Ça évite les erreurs “ça marche en dev” liées à une config incomplète (scopes, secret, base URL, reverse proxy). En sécurité, ne vous contentez pas de “HTTPS obligatoire” : OWASP rappelle que les APIs cassent d’abord sur l’authorization. L’OWASP API Security Top 10 2023 place « Broken Object Level Authorization » en tête (API1:2023). Source : https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/
Si vous cherchez un cadrage opérationnel pour éviter les régressions d’infra (cache, opcache, TTFB) pendant les tests, croisez vos pipelines avec des environnements réalistes : Staging PrestaShop : créer un environnement Docker fidèle à la production et, côté perfs serveur, PrestaShop lent : diagnostic TTFB, bots et optimisation serveur.




