🏗️ Arquitectura PS 9 vs PS 8 — Guia de diferencias

Actualizado: 2026-04

#Por que PS 9 es diferente

PrestaShop 9 marca la transicion definitiva de legacy a Symfony. Mientras PS 8 era un hibrido (legacy + Symfony coexistiendo), PS 9 establece que toda nueva funcionalidad debe ser Symfony. El legacy se mantiene por retrocompatibilidad pero no recibe mejoras.

AspectoPS 8.xPS 9.x
Symfony version4.4 LTS / 5.4 LTS6.4 LTS
PHP minimo7.2 (8.0 recomendado)8.1 (8.5 recomendado)
Admin controllersLegacy + Symfony ambos validosSymfony preferido, legacy solo retrocompat
Service Locator$this->get() disponible$this->get() deprecated → Constructor Injection
Context staticoPermitidoEvitar en servicios, inyectar datos necesarios
CQRSOpcionalObligatorio para nueva arquitectura admin
Tema por defectoClassic (BS4 alpha)Hummingbird (BS5.3.3)
jQueryObligatorioDeprecated (sera eliminado en PS 10)
Domain separationRecomendadaObligatoria en nuevo codigo
Product pageV1 (legacy) + V2 (8.1+)Solo V2
Feature flagsBasicoSistema completo con estados (beta/stable)

#Symfony 6.4 LTS

El salto de Symfony 4.4/5.4 a 6.4 trae cambios importantes:

#CQRS obligatorio en admin

PrestaShop 9 usa el patron CQRS (Command Query Responsibility Segregation) para todas las operaciones admin. Esto separa las lecturas (Queries) de las escrituras (Commands):

Ejemplo CQRS — obtener un producto
php
use PrestaShop\PrestaShop\Core\Domain\Product\Query\GetProductForEditing;
use PrestaShop\PrestaShop\Core\Domain\Product\QueryResult\ProductForEditing;

// Query — lectura
$query = new GetProductForEditing($productId);
/** @var ProductForEditing $result */
$result = $this->commandBus->handle($query);

$name = $result->getBasicInformation()->getLocalizedNames();
Ejemplo CQRS — actualizar un producto
php
use PrestaShop\PrestaShop\Core\Domain\Product\Command\UpdateProductCommand;

// Command — escritura
$command = new UpdateProductCommand($productId);
$command->setLocalizedNames([
    1 => 'Mi Producto Actualizado',
    2 => 'My Updated Product',
]);
$command->setPrice('29.99');

$this->commandBus->handle($command);

#Dependency Injection — el cambio central

El cambio mas importante para modulos: inyectar servicios via constructor, no via $this->get():

config/services.yml del modulo
yaml
services:
    _defaults:
        autowire: true
        autoconfigure: true

    MyModule\Controller\Admin\MyController:
        arguments:
            $commandBus: '@prestashop.core.command_bus'
            $queryBus: '@prestashop.core.query_bus'
            $translator: '@translator'
        tags:
            - { name: 'controller.service_arguments' }

    MyModule\Service\MyService:
        arguments:
            $configuration: '@prestashop.adapter.legacy.configuration'
            $entityManager: '@doctrine.orm.entity_manager'

#Context::getContext() — como evitarlo

En PS 9, Context::getContext() sigue funcionando en el module main class, pero no debe usarse dentro de servicios:

❌ Mal — Context en un servicio
php
class MyService
{
    public function getShopId(): int
    {
        return (int) Context::getContext()->shop->id; // ❌ Anti-pattern en PS 9
    }
}
✅ Bien — Inyectar lo necesario
php
class MyService
{
    public function __construct(
        private readonly ShopContext $shopContext,
    ) {}

    public function getShopId(): int
    {
        return $this->shopContext->getContextShopID(); // ✅
    }
}

// services.yml:
// MyModule\Service\MyService:
//     arguments:
//         $shopContext: '@prestashop.adapter.shop.context'

#Legacy vs Modern: que queda

ComponenteLegacy (aun funciona)Modern (preferido en PS 9)
Admin controllersAdminController extends ModuleAdminControllerSymfony Controller + routing YAML
FormulariosHelperForm / HelperListSymfony FormType + Grid System
ORMObjectModelDoctrine ORM entities
QueriesDb::getInstance()->executeS()Doctrine DBAL / Repository
Templates BOSmarty .tplTwig .html.twig
Templates FOSmarty .tplSmarty .tpl (Twig previsto para PS 10)
Traducciones$this->l('...')$this->trans('...', [], 'Modules.X.Admin')
EventosHook dispatcherHook dispatcher + Symfony EventDispatcher
ConfigConfiguration::get/updateValue()Igual + DataConfiguration pattern
CLIbin/console con comandos custom

#Modulo PS 9: estructura recomendada

Estructura de directorios moderna
text
mi_modulo/
├── mi_modulo.php              # Clase principal (install, hooks)
├── composer.json              # Autoloading PSR-4
├── config/
│   ├── routes.yml             # Rutas Symfony para controllers admin
│   └── services.yml           # Servicios, DI, autowiring
├── src/
│   ├── Controller/
│   │   └── Admin/             # Controladores Symfony admin
│   ├── Entity/                # Doctrine ORM entities
│   ├── Repository/            # Doctrine repositories
│   ├── Form/
│   │   ├── Type/              # FormType classes
│   │   └── DataConfiguration/ # Data providers
│   ├── Grid/
│   │   ├── Definition/        # Grid definitions
│   │   └── Query/             # Grid query builders
│   ├── Command/               # Console commands
│   └── Service/               # Business logic
├── views/
│   ├── templates/
│   │   ├── admin/             # Twig templates (BO)
│   │   └── front/             # Smarty templates (FO)
│   ├── css/
│   └── js/
├── upgrade/                   # Upgrade scripts
└── tests/                     # PHPUnit tests

#Nuevos comandos CLI en PS 9.1

ComandoDescripcion
prestashop:thumbnails:regenerateRegenerar thumbnails de imagenes de producto
prestashop:search:indexReconstruir el indice de busqueda desde CLI
prestashop:module:export-translationsExportar traducciones de un modulo a ficheros
Ejemplos de uso
bash
# Regenerar thumbnails
php bin/console prestashop:thumbnails:regenerate --all

# Reindexar busqueda
php bin/console prestashop:search:index

# Exportar traducciones de un modulo
php bin/console prestashop:module:export-translations mi_modulo

#Feature Flags system

PS 9.1 utiliza un sistema de feature flags para activar/desactivar funcionalidades experimentales. Los flags se almacenan en ps_feature_flag con estados: beta, stable.

Verificar feature flags en tu modulo
php
// Opcion 1: Via servicio (PS 9)
$featureFlagManager = $this->get('prestashop.core.feature_flag.manager');
if ($featureFlagManager->isEnabled('improved_shipment')) {
    // Funcionalidad de multi-shipment activa
}

// Opcion 2: Via SQL directo (compatible PS 8+9)
$isEnabled = (bool) Db::getInstance()->getValue(
    'SELECT state FROM ' . _DB_PREFIX_ . "feature_flag WHERE name = 'improved_shipment'"
);

Feature flags activos en PS 9.1:

FlagEstadoDescripcion
improved_shipmentBetaSistema Multi-Shipment (multiples envios por pedido)
discountBetaNuevo sistema de descuentos con 4 tipos
tagBetaSistema de tags modernizado con formularios Symfony

#Detectar version de PS en tu modulo

Patron de deteccion de version
php
// Detectar PS 9+
if (version_compare(_PS_VERSION_, '9.0.0', '>=')) {
    // PS 9 — usar arquitectura moderna
    // Constructor injection, CQRS, Twig admin
}

// Detectar PS 9.1+ (multi-shipment, discounts)
if (version_compare(_PS_VERSION_, '9.1.0', '>=')) {
    // PS 9.1 — nuevos hooks disponibles
    // Feature flags para shipment y discounts
}

// Detectar Hummingbird
$isHummingbird = (Context::getContext()->shop->theme_name === 'hummingbird');

// Patron hibrido PS 8 + PS 9
public function install()
{
    $hooks = [
        'displayHeader',
        'displayFooter',
        'actionValidateOrder',
    ];
    
    // Hooks solo PS 9.1+
    if (version_compare(_PS_VERSION_, '9.1.0', '>=')) {
        $hooks[] = 'actionModuleEnable';
        $hooks[] = 'actionModuleDisable';
        $hooks[] = 'actionConfigurationUpdateValueBefore';
    }
    
    return parent::install() && $this->registerHook($hooks);
}
Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.