Cosa si rompe davvero quando porti un modulo a PrestaShop 9
Stiamo portando il nostro catalogo di oltre 140 moduli a PrestaShop 9 dalla release 9.0 di giugno 2025, e la risposta onesta è: più di quanto suggerisca il changelog. Alcuni moduli hanno richiesto un pomeriggio. Alcuni quasi una settimana, perché gli admin controller erano stati scritti contro il service container globale e quel pattern non esiste più.

Questo non è un post marketing. È il documento che abbiamo costruito internamente durante la migrazione, con ogni breaking change che abbiamo davvero incontrato, il codice prima/dopo e le parti dove non siamo ancora sicuri al 100% che la migrazione sia completa. Se mantieni moduli, per clienti, per Addons o per i tuoi shop, leggilo prima di dire a qualcuno che il modulo è "compatibile PS 9". Abbiamo imparato nel modo duro che "si installa senza fatal error" non è la stessa cosa.
Ordina il modulo per rischio prima di toccare codice
L'errore più grande nelle prime tre migrazioni è stato riscrivere prima le parti facili e scoprire quelle difficili il giorno prima del rilascio. Non farlo. Guarda che tipo di modulo è e dove la superficie di cambiamento è più grande.
| Tipo modulo | Dove di solito si rompe in PS 9 | Cosa testare prima |
|---|---|---|
| Admin controller Symfony moderno | Container scoped, wiring servizi, attributi route, attributi security | Apri ogni controller in debug mode e conferma che i servizi iniettati nel costruttore si risolvano davvero |
| Legacy AdminController (Bootstrap / jQuery) | URL token, endpoint AJAX, bulk actions, helper lista | Prova filtri lista, azioni riga, modali, endpoint AJAX, export, bulk actions: tutti |
| Modulo front-office / tema | Assunzioni template solo Classic, differenze markup Hummingbird | Product card, carrello, checkout, account cliente e ogni hook front su Classic e Hummingbird |
| Checkout, pagamento o spedizione | Assunzioni su carrello, corriere, sconti e flusso ordine cambiate dai sistemi 9.1 | Esegui ordini reali di test: guest, account, con sconti, più corrieri |
| Integrazione / ERP / export | Webservice legacy vs nuova AdminAPI; warning strict PHP 8.5 | Smoke test su 8.2, 9.0 e 9.1 prima di cambiare il contratto integrazione |
| Email / notifiche | SwiftMailer è sparito; Symfony Mailer renderizza template in modo diverso | Invia ogni tipo di email transazionale e controlla header, variabili, allegati |
I nostri moduli di checkout-flow hanno richiesto più tempo. Qualsiasi cosa toccasse la pagina ordine admin o la selezione corriere è stata rivista riga per riga. Il "piccolo modulo utility che aggiunge solo un banner" ha richiesto mezza mattina.
Aggiornamento maggio 2026: ora il vero target è 9.1, non 9.0
Quando abbiamo iniziato la migrazione la risposta era "compatibile con 9.0". Un anno dopo, 9.1 è ciò che i merchant installano, e 9.0 è uno stepping stone da cui si aggiornano. Se la tua matrice CI è ancora fissata a 9.0, stai testando il PrestaShop di ieri.
9.1 dovrebbe essere backward compatible con 9.0, e in gran parte lo è. Ma aggiunge supporto PHP 8.5, porta Hummingbird come tema default per installazioni nuove, introduce nuovi lifecycle hook e hook di configurazione, aggiunge comandi CLI per miniature / ricerca / traduzioni e porta sistemi multi-shipment e discount dietro feature flag. Ognuna di queste cose può rompere in silenzio un modulo che funzionava su 9.0.
La maintenance release 9.1.3 di maggio 2026 ha portato aggiornamenti Symfony e Twig senza modifiche core: il tipo di patch release che "non dovrebbe influenzare i moduli" e poi lo fa, la prima volta che qualcuno passa un non-string a un filtro Twig. Testa sul ramo 9.x mantenuto, non solo sul tag 9.0 originale.
Cosa è cambiato tra 9.0 e 9.1, e cosa ritestiamo
| Area | Cosa è cambiato | Cosa ritestiamo |
|---|---|---|
| Runtime | 9.0 richiede PHP 8.1+ e supporta fino a 8.4; 9.1 aggiunge e raccomanda 8.5 | Esegui il modulo sulla versione PHP più bassa e più alta dichiarata dal composer.json |
| Stack Symfony | Symfony 4.4 → 6.4 LTS: si applicano i breaking change di Symfony 5 e 6 | Ereditarietà controller, annotazioni, eventi, definizioni servizi, package framework rimossi |
| Hook e CLI | 9.1 aggiunge lifecycle hook, hook update config e comandi CLI per miniature / ricerca / export traduzioni | Install, enable, disable, upgrade, salvataggio configurazione, rigenerazione miniature, reindex ricerca, export traduzioni |
| Hummingbird | Tema default nelle nuove installazioni 9.1; gli shop aggiornati mantengono il tema | Output front-office su Classic e Hummingbird: ogni template prodotto, carrello, checkout, account |
| Sconti | 9.1 introduce UI e architettura sconti ridisegnate sopra le regole carrello | Tutto ciò che legge, crea, combina, valida o mostra cart rules, voucher e promozioni |
| Database / ordini | 9.1 ha modifiche schema per multi-shipment e nuovo sistema sconti | Export ordine, fattura, fulfillment, corriere e codice ERP contro fixture ordine reali |
| Patch security | 9.1.3 ha aggiornato dipendenze Symfony e Twig | Regression pass rapido dopo ogni patch, soprattutto se tocchi YAML, XML, Twig o destinatari email |
Il salto a Symfony 6.4: perché è cambiato così tanto
Symfony 4.4 è andato end-of-life a novembre 2023. PrestaShop 8.x girava già su una versione framework non supportata, cosa scomoda per chi leggeva i log PHP. Saltare direttamente a 6.4 LTS, supportata fino a novembre 2027, era la scelta giusta, ma ha saltato due major framework in una release, e ogni breaking change di Symfony 5 e 6 arriva insieme.
Implicazioni pratiche:
- PHP 8.1 minimo: eventuali shim PHP 7.x nel modulo devono uscire. 8.2-8.4 sono supportati su 9.0; 9.1 aggiunge 8.5.
- I controller sono servizi veri: il pattern "container globale, prendi quello che serve" è morto. L'injection via costruttore è obbligatoria e il container passato al controller è scoped.
- Attributi, non annotazioni:
@Route,@AdminSecurity,@DemoRestricteddiventano sintassi attributi PHP 8.sensio/framework-extra-bundleè sparito. - Librerie bundle rimosse: Guzzle, SwiftMailer, Tactician. Se le usavi, devi includerle tu o migrare.
- Node 20 minimo per moduli con build step. 9.1 compila con Node 20.19.5, quindi fissa il tooling invece di sperare nel Node della macchina dev.
Breaking change #1: controller, il container globale è sparito
Questo è il cambiamento che ci ha mangiato più tempo. In PS 8 potevamo prendere qualunque servizio da qualunque controller con $this->get('service.name'). In PS 9 il container consegnato al controller è scoped: contiene solo i servizi dichiarati esplicitamente, e la chiamata nuda $this->get() lancia eccezione o restituisce null secondo il servizio.
Before (PrestaShop 8.x)
<?php
// modules/mymodule/src/Controller/Admin/MyController.php
use PrestaShopBundle\\Controller\\Admin\\FrameworkBundleAdminController;
class MyController extends FrameworkBundleAdminController
{
public function indexAction()
{
// Grab any service from the global container
$productRepository = $this->get('prestashop.core.product.repository');
$translator = $this->get('translator');
$configService = $this->get('my_module.config_service');
return $this->render('@Modules/mymodule/views/templates/admin/index.html.twig', [
'products' => $productRepository->findAll(),
]);
}
}
After (PrestaShop 9.x)
<?php
// modules/mymodule/src/Controller/Admin/MyController.php
use PrestaShopBundle\\Controller\\Admin\\PrestaShopAdminController;
use MyModule\\Service\\ConfigService;
use Symfony\\Component\\HttpFoundation\\Response;
class MyController extends PrestaShopAdminController
{
// Constructor injection for services you always need
public function __construct(
private readonly ConfigService $configService,
) {
}
// Method injection for request-specific services
public function indexAction(ProductRepository $productRepository): Response
{
return $this->render('@Modules/mymodule/views/templates/admin/index.html.twig', [
'products' => $productRepository->findAll(),
'config' => $this->configService->getAll(),
]);
}
// If you MUST use the service locator pattern (migration bridge)
public static function getSubscribedServices(): array
{
return parent::getSubscribedServices() + [
ConfigService::class => ConfigService::class,
];
}
}
I cambiamenti principali:
FrameworkBundleAdminControllerè deprecato. UsaPrestaShopAdminController.- L'injection via costruttore sostituisce
$this->get()per ciò che il controller usa sempre. - La method injection gestisce dipendenze specifiche dell'action.
getSubscribedServices()è la via di fuga per un controller mezzo migrato. Usala per tenere acceso il modulo mentre rifattorizzi, non come stato finale da spedire.
Una cosa che ci ha colpiti: se il servizio decora un core service, l'autowiring sulla versione decorata smette di funzionare appena un terzo modulo nella catena non autowira correttamente. È successo su un modulo che decora il cart calculator e abbiamo perso mezza giornata su un services.yml corretto prima di capire che il problema era un altro modulo installato. La service decoration in PS 9 non perdona l'ordine.
Breaking change #2: le annotazioni diventano attributi PHP 8
La dipendenza sensio/framework-extra-bundle è sparita. Routing e annotazioni security devono diventare attributi nativi. È quasi tutto meccanico, ma c'è una trappola.
Routing
// BEFORE (PS8) — Annotation syntax
use Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route;
/**
* @Route("/mymodule/settings", name="mymodule_settings")
*/
public function settingsAction()
// AFTER (PS9) — PHP 8 Attribute syntax
use Symfony\\Component\\Routing\\Annotation\\Route;
#[Route('/mymodule/settings', name: 'mymodule_settings', methods: ['GET'])]
public function settingsAction(): Response
Security
// BEFORE (PS8)
use PrestaShopBundle\\Security\\Annotation\\AdminSecurity;
use PrestaShopBundle\\Security\\Annotation\\DemoRestricted;
/**
* @AdminSecurity("is_granted('read', request.get('_legacy_controller'))")
* @DemoRestricted(redirectRoute="mymodule_settings")
*/
public function settingsAction()
// AFTER (PS9)
use PrestaShopBundle\\Security\\Attribute\\AdminSecurity;
use PrestaShopBundle\\Security\\Attribute\\DemoRestricted;
#[AdminSecurity("is_granted('read', request.get('_legacy_controller'))")]
#[DemoRestricted(redirectRoute: 'mymodule_settings')]
public function settingsAction(): Response
Il namespace passa da Security\Annotation\ a Security\Attribute\. Un find-and-replace copre quasi tutto. Se lo perdi, la route gira senza restrizioni di sicurezza: peggio di un crash, perché il modulo sembra funzionare e espone in silenzio un'azione admin senza autorizzazione. Fai grep del codebase per Security\Annotation dopo la migrazione.
Event listeners
// BEFORE (PS8) — YAML service definition + interface
# config/services.yml
services:
mymodule.event_listener:
class: MyModule\\EventListener\\ProductListener
tags:
- { name: kernel.event_listener, event: kernel.request }
// AFTER (PS9) — PHP attribute, no YAML needed
use Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener;
#[AsEventListener(event: 'kernel.request')]
class ProductListener
{
public function __invoke(RequestEvent $event): void
{
// ...
}
}
Breaking change #3: definizioni servizi, YAML funziona ancora ma PHP è più pulito
I servizi YAML continuano a funzionare in PS 9 e li abbiamo mantenuti dove erano già corretti. Il nuovo lavoro va in config PHP con autowiring, perché i vincoli che Symfony 6.4 mette sul service container sono più facili da soddisfare quando la config è nella stessa lingua dei servizi.
Before (PS 8 YAML)
# modules/mymodule/config/services.yml
services:
mymodule.config_service:
class: MyModule\\Service\\ConfigService
arguments:
- '@prestashop.adapter.legacy.configuration'
public: true
mymodule.admin_controller:
class: MyModule\\Controller\\Admin\\MyController
arguments:
- '@mymodule.config_service'
tags:
- { name: controller.service_arguments }
After (PS 9 PHP config with autowiring)
<?php
// modules/mymodule/config/services.php
use Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator;
return static function (ContainerConfigurator $container): void {
$services = $container->services();
$services->defaults()
->autowire()
->autoconfigure()
->public(false);
// Register all classes in src/ as services
$services->load('MyModule\\\\', '../src/')
->exclude('../src/{Entity}');
// Explicit service definition only when needed
$services->set(MyModule\\Service\\ConfigService::class)
->arg('$shopId', '%prestashop.shop_id%');
};
Con autowiring attivo scrivi definizioni esplicite solo per parametri scalari, binding di interfacce quando esistono più implementazioni e classi terze non autowirable. Se hai scritto definizioni servizi a mano per dieci anni, questa parte sembra sospetta. Funziona. Fidati.
Breaking change #4: librerie che non sono più incluse
PrestaShop 9 ha smesso di bundleizzare quattro librerie viste in molti moduli vecchi. Se il tuo composer.json le richiede come dipendenza top-level sei a posto: si installano per il modulo. Se assumevi fossero sempre disponibili perché PS 8 le includeva, hai lavoro da fare.
| Rimosso | Sostituto | Sforzo migrazione |
|---|---|---|
guzzlehttp/guzzle | symfony/http-client | Medio: API diversa |
swiftmailer/swiftmailer | symfony/mailer | Medio: nuova API oggetto Email |
league/tactician-bundle | symfony/messenger | Alto: diverso modello command bus |
pear/archive_tar | Bundlalo nel modulo o usa ext-zip | Basso |
Guzzle to Symfony HttpClient
// BEFORE — Guzzle
use GuzzleHttp\\Client;
$client = new Client(['base_uri' => 'https://api.example.com']);
$response = $client->request('GET', '/products', [
'query' => ['status' => 'active'],
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$data = json_decode($response->getBody()->getContents(), true);
// AFTER — Symfony HttpClient
use Symfony\\Contracts\\HttpClient\\HttpClientInterface;
// Inject via constructor
public function __construct(
private readonly HttpClientInterface $httpClient,
) {}
public function getProducts(string $token): array
{
$response = $this->httpClient->request('GET', 'https://api.example.com/products', [
'query' => ['status' => 'active'],
'auth_bearer' => $token,
]);
return $response->toArray(); // Auto-decodes JSON
}
SwiftMailer to Symfony Mailer
// BEFORE — SwiftMailer
$message = (new \\Swift_Message('Subject'))
->setFrom('shop@example.com')
->setTo('customer@example.com')
->setBody($htmlContent, 'text/html');
$this->get('mailer')->send($message);
// AFTER — Symfony Mailer
use Symfony\\Component\\Mime\\Email;
use Symfony\\Component\\Mailer\\MailerInterface;
public function __construct(
private readonly MailerInterface $mailer,
) {}
public function sendNotification(): void
{
$email = (new Email())
->from('shop@example.com')
->to('customer@example.com')
->subject('Subject')
->html($htmlContent);
$this->mailer->send($email);
}
Una cosa che la documentazione non urla abbastanza: la crittografia SSL per email è sparita in PS 9. Restano solo TLS o nessuna crittografia. Se lo shop di un cliente era configurato con SSL sul relay SMTP, le email in uscita possono smettere di funzionare dopo l'upgrade. Abbiamo visto un upgrade 9.0 passare pulito e poi i clienti non ricevere conferme ordine per due giorni. Controlla la configurazione mail su ogni shop che aggiorni.
Breaking change #5: i servizi Context tipizzati sostituiscono il singleton
Il singleton legacy Context::getContext() funziona ancora in PS 9: è deprecato, non rimosso. Il nuovo pattern sono servizi Context tipizzati iniettati dal container, e funziona in punti dove il singleton non ha mai funzionato bene (comandi CLI, worker async, ovunque il Context legacy non sia inizializzato dal front controller).
// BEFORE — Legacy Context singleton
$employee = Context::getContext()->employee;
$shop = Context::getContext()->shop;
$language = Context::getContext()->language;
$currency = Context::getContext()->currency;
// AFTER — Typed Context services (inject via constructor)
use PrestaShop\\PrestaShop\\Core\\Context\\EmployeeContext;
use PrestaShop\\PrestaShop\\Core\\Context\\ShopContext;
use PrestaShop\\PrestaShop\\Core\\Context\\LanguageContext;
use PrestaShop\\PrestaShop\\Core\\Context\\CurrencyContext;
public function __construct(
private readonly EmployeeContext $employeeContext,
private readonly ShopContext $shopContext,
private readonly LanguageContext $languageContext,
private readonly CurrencyContext $currencyContext,
) {}
public function someMethod(): void
{
$employee = $this->employeeContext->getEmployee();
$shopId = $this->shopContext->getId();
$langId = $this->languageContext->getId();
$currency = $this->currencyContext->getCurrency();
}
Il set completo dei servizi context in PS 9: EmployeeContext, ShopContext, LanguageContext, CurrencyContext, CountryContext, ApiClientContext, LegacyControllerContext. Il singleton legacy resta per ora e il codice esistente continua a girare. Noi migriamo modulo per modulo, non in un unico sweep, e va bene così.
Breaking change #6: l'auth admin ora è completamente Symfony
Il login back office è passato a Symfony Security. Se il modulo legge dati employee da Context::$cookie, cosa vista in molti moduli vecchi, quel percorso è inaffidabile in PS 9.
// BEFORE — Cookie-based auth (unreliable in PS9)
$employeeId = Context::getContext()->cookie->id_employee;
$profile = Context::getContext()->cookie->profile;
// AFTER — Session-based approach
use Symfony\\Component\\HttpFoundation\\RequestStack;
use PrestaShop\\PrestaShop\\Core\\Context\\EmployeeContext;
public function __construct(
private readonly RequestStack $requestStack,
private readonly EmployeeContext $employeeContext,
) {}
public function getEmployeeData(): array
{
// For employee identity
$employee = $this->employeeContext->getEmployee();
// For custom session data your module stores
$session = $this->requestStack->getCurrentRequest()?->getSession();
$myData = $session?->get('my_module_custom_data');
return [
'employee_id' => $employee->getId(),
'profile_id' => $employee->getProfileId(),
'custom_data' => $myData,
];
}
Breaking change #7: hook rimossi
Diversi hook del flusso login admin sono spariti senza sostituto diretto.

actionAdminLoginControllerBeforeactionAdminLoginControllerLoginBefore/actionAdminLoginControllerLoginAfteractionAdminLoginControllerForgotBefore/actionAdminLoginControllerForgotAfteractionAdminLoginControllerResetBefore/actionAdminLoginControllerResetAfter
Per personalizzare il form login, i nuovi hook sono:
actionBackOfficeLoginForm— modifica il form builder loginactionEmployeeRequestPasswordResetForm— modifica il form reset password
Anche tutti gli hook actionAdminProductsController* sono rimossi, perché la vecchia pagina prodotto legacy non esiste più. Se il modulo aggiungeva campi extra alla vecchia pagina prodotto tramite uno di questi hook, devi riscrivere quella parte contro la pagina prodotto Symfony: molto più che cambiare nome hook.
Breaking change #8: i template front-office ora usano dati Presenter
Diverse pagine front (categoria, produttore, fornitore, negozio) sono passate a classi Presenter. Le variabili Smarty esposte hanno forma diversa. Se il modulo sovrascrive o estende uno di questi template, i riferimenti variabile vanno cambiati.
{* BEFORE (PS8) — Manufacturer page *}
<img src="{$manufacturer.image}" alt="{$manufacturer.name}">
{$manufacturer.nb_products} products
{* AFTER (PS9) — Presenter-based data structure *}
<img src="{$manufacturer.image.medium.url}" alt="{$manufacturer.name}">
{l s='%number% product' sprintf=['%number%' => $manufacturer.nb_products] d='Shop.Theme.Catalog'}
Ogni pagina coinvolta ha un hook actionPresent* corrispondente per modificare i dati presentati invece di sovrascrivere il template. Usalo quando puoi: sopravvive ai cambi tema e alle riscritture template Hummingbird, e abbiamo perso abbastanza tempo a sistemare override dopo revisioni Hummingbird da preferire non possederli.
Breaking change #9: niente più endpoint PHP standalone a root modulo
Serve ancora il file PHP principale del modulo. Il pattern problematico è un ajax.php o callback.php direttamente chiamabile nella root del modulo che include a mano config/config.inc.php. Questi endpoint bypassano routing, token, rilevamento SSL, context cliente e il normale lifecycle request, e gli strumenti security di PS 9 li considerano un odore.
// BEFORE — Direct PHP file (modules/mymodule/ajax.php)
require_once dirname(__FILE__) . '/../../config/config.inc.php';
// Process AJAX request...
// AFTER — ModuleFrontController
// modules/mymodule/controllers/front/ajax.php
class MyModuleAjaxModuleFrontController extends ModuleFrontController
{
public function displayAjaxProcess()
{
$result = $this->module->processAjaxRequest();
$this->ajaxRender(json_encode($result));
}
}
// URL: index.php?fc=module&module=mymodule&controller=ajax&action=process
Breaking change #10: comandi console e split multi-kernel
PS 9 divide l'applicazione in tre kernel Symfony: admin, admin-api e front. I comandi console accettano --app-id per targetizzare un kernel specifico.
# Clear admin cache only
php bin/console cache:clear --env=prod --app-id=admin
# Debug front-office event listeners
php bin/console debug:event-dispatcher kernel.request --app-id=front
# List admin-api routes
php bin/console debug:router --app-id=admin-api
Se il modulo include un comando console, assicurati che sia registrato nel kernel giusto. Avevamo un comando CLI per reindicizzare la ricerca registrato senza specificare kernel: funzionava su PS 8, ma su PS 9 non veniva scoperto finché non abbiamo aggiunto il tag corretto.
Cosa non è cambiato (le parti che non abbiamo riscritto)
Non tutto si rompe. Questi pattern sopravvivono in PS 9 senza modifiche.
- Il sistema hook —
hookDisplayHeader(),hookActionProductUpdate()e tutti gli altri funzionano come prima. Vedi il nostro riferimento hook per i pattern sopravvissuti al salto versione. - Template Smarty front — la migrazione Twig è solo admin. Il front-office resta Smarty.
- Descriptor modulo —
$this->name,$this->version,$this->ps_versions_compliancynon cambiano. Db::getInstance()— query DB dirette sulle tabelle del tuo modulo continuano a funzionare.- ObjectModel per tabelle modulo — le tue sottoclassi ObjectModel per tabelle custom funzionano ancora. La deprecazione colpisce gli ObjectModel delle entity core, non i tuoi.
- Configuration API —
Configuration::get()/Configuration::updateValue()sono invariati.
La matrice di test che eseguiamo davvero
Una installazione verde su PS 9 non equivale a compatibilità. Lo abbiamo imparato su un modulo che superava lo smoke test, è arrivato su due shop cliente e poi crashava quando il merchant provava il pulsante bulk-action. Questa è la matrice che usiamo su ogni modulo commerciale prima di marcarlo "9.x compatible".
| Target | Perché conta | Cosa significa "pass" |
|---|---|---|
| PrestaShop 8.2 su PHP 8.1 / 8.2 | Molti shop production resteranno su PS 8 mentre testano 9 | La build stabile esistente si installa, aggiorna e gira senza rumore deprecation che blocca il lavoro normale |
| PrestaShop 9.0 su PHP 8.1–8.4 | Prova la migrazione major: Symfony 6.4, PHP 8.1 minimo, librerie rimosse | Ogni controller, hook, cron job, endpoint AJAX e percorso email gira su una 9.0 pulita |
| Ramo PrestaShop 9.1 | Il target pratico corrente, ciò che i merchant installano davvero | Il modulo sopravvive a Hummingbird default, cambi sconti/ordini e ultime patch release |
| Temi Classic e Hummingbird | Le nuove 9.1 usano Hummingbird, gli shop aggiornati mantengono temi derivati da Classic | Gli hook front renderizzano senza layout rotto, selector mancanti, contenuti duplicati o errori JS |
| Fresh install e upgrade da vecchia versione modulo | SQL upgrade e default config falliscono in modi diversi rispetto a installazioni fresche | Entrambi i percorsi producono stesse tabelle, configurazioni, tab, hook e permessi finali |
| Shop con debug mode attivo | Warning nascosti in prod diventano ticket supporto dopo | Nessun undefined index, warning dynamic property, deprecation o container exception nell'uso normale |
La riga "fresh install e upgrade" non è negoziabile. Molti dei peggiori bug spediti negli anni erano nel percorso upgrade: fresh install funzionava sempre perché testavamo fresh install. Lo shop che si rompeva era di un cliente esistente, con database pieno di valori che il nostro SQL upgrade non considerava.
La nostra checklist di migrazione
La teniamo in un file markdown in ogni repo modulo. Stampala, incollala, fanne ciò che vuoi.
- Versione PHP — testa su 8.1+. Rimuovi shim PHP 7.x.
- Annotazioni ad attributi — find-replace
Security\Annotation\conSecurity\Attribute\. Converti@Routein#[Route]. Grep per superstiti. - Classe base controller —
FrameworkBundleAdminControlleraPrestaShopAdminController. - Sostituisci
$this->get()— passa a constructor o method injection. - Librerie rimosse — Guzzle, SwiftMailer, Tactician, pear/archive_tar. Bundla o sostituisci.
- Definizioni servizi — conferma che autowiring funzioni.
bin/console debug:container MyService --app-id=admin. - Variabili template — testa override front contro la nuova forma Presenter.
- Hook rimossi — grep per hook login e product deprecati.
- Endpoint PHP standalone — sposta file AJAX o callback diretti a
ModuleFrontController. - Aggiorna compliancy — imposta
ps_versions_compliancyper includere 9.x:
$this->ps_versions_compliancy = [
'min' => '8.0.0',
'max' => '9.99.99',
];
Una nota onesta sull'ultimo punto: impostiamo l'upper bound a 9.99.99 solo sui moduli dove abbiamo eseguito la matrice completa contro l'ultima 9.1. Metterlo su un modulo solo smoke-tested è la bugia che rompe gli shop dei clienti.
Supportare PS 8 e PS 9 dalla stessa codebase
Per moduli commerciali non possiamo spedire due versioni e aspettarci che i clienti scelgano quella giusta. Il pattern che ha funzionato è un version check runtime con due code path e una compatibility base class.
// Check PrestaShop version at runtime
if (version_compare(_PS_VERSION_, '9.0.0', '>=')) {
// PS9 path — use new Context services
} else {
// PS8 path — use legacy Context singleton
}
// For controller base class, use a compatibility layer:
if (class_exists('PrestaShopBundle\\Controller\\Admin\\PrestaShopAdminController')) {
class MyModuleAdminControllerBase extends PrestaShopAdminController {}
} else {
class MyModuleAdminControllerBase extends FrameworkBundleAdminController {}
}
class MyActualController extends MyModuleAdminControllerBase
{
// Your controller code
}
Per i servizi puoi tenere sia services.yml (PS 8) sia services.php (PS 9) nello stesso modulo. PrestaShop carica il file PHP se esiste e ripiega su YAML.
Questo pattern dual-codebase vive nel nostro package condiviso prestashop-compat e lo estendiamo man mano che incontriamo differenze. Ogni metodo deprecato o rimosso in una versione futura viene wrappato, e il wrapper rileva la versione a runtime. Tools::displayPrice() è l'esempio canonico: sparito in 9.0, sostituito dal formatter locale-aware, wrappato in \MyPrestaRocks\Compat\PriceFormatter::format() così lo correggiamo in un solo posto.
Vincoli Composer che spediamo davvero
Risolvi le dipendenze contro la versione PHP più bassa che dichiari di supportare, poi testa separatamente contro la più alta. Altrimenti Composer sceglie felicemente librerie che richiedono 8.4 e la tua dichiarazione "8.1+" è finzione.
{
"require": {
"php": ">=8.1 <8.6",
"symfony/http-client": "^6.4"
},
"config": {
"platform": {
"php": "8.1.0"
}
}
}
matrix:
include:
- prestashop: "8.2"
php: "8.1"
- prestashop: "9.0"
php: "8.4"
- prestashop: "9.1"
php: "8.5"
theme: "hummingbird"
Cosa diremmo a uno sviluppatore alla prima migrazione PS 9
PrestaShop 9 è una piattaforma migliore di 8. Symfony 6.4 è attuale, i servizi context tipizzati sono più gradevoli del singleton, l'autowiring rimuove una classe di bug che avevamo spesso, e l'admin-api accanto al Webservice legacy dà agli integratori una strada avanti. Il costo è reale: da mezza giornata per un piccolo modulo utility a una settimana per qualsiasi cosa tocchi pagina prodotto admin o checkout flow.
Due cose su cui insisteremmo dopo averlo fatto tante volte. Non dichiarare compatibilità 9.x sulla speranza. Esegui la matrice completa o marca il modulo come "9.0 tested, 9.1 in progress" finché non lo hai davvero provato su 9.1 con Hummingbird. Abbiamo visto moduli del tipo "dovrebbe andare, non tocca l'admin" chiamare un hook che non esiste più. E non provare a fare tutto insieme. Scegli un modulo, fai la migrazione end-to-end, scrivi cosa hai imparato, e il secondo richiederà metà tempo. Il quinto diventa routine.
Parti dalla documentazione ufficiale sulle modifiche 9.0 e dalle note developer 9.1 per la lista canonica dell'impatto sui moduli. Testa in staging prima di avvicinarti a uno shop cliente. E se usi uno dei nostri moduli e incontri qualcosa non coperto qui, scrivici: probabilmente lo abbiamo già risolto su uno degli altri 147.
Commenti (8)
Lascia un commento
Condividi una domanda, un dettaglio di installazione o un feedback utile per un altro lettore.