---
title: Arquitectura PS 9 vs PS 8 — Guia de diferencias
section: ps91
slug: architecture
description: "Comparativa completa de arquitectura PS 8 vs PS 9: Symfony 6.4, CQRS, DI, Context, legacy vs modern, estructura de modulo y feature flags."
last_updated: 2026-04
source_url: "https://ayudaprestashop.es/ps91/architecture"
---

# Arquitectura PS 9 vs PS 8 — Guia de diferencias

> Comparativa completa de arquitectura PS 8 vs PS 9: Symfony 6.4, CQRS, DI, Context, legacy vs modern, estructura de modulo y feature flags.

## 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.

| Aspecto | PS 8.x | PS 9.x |
| --- | --- | --- |
| Symfony version | 4.4 LTS / 5.4 LTS | 6.4 LTS |
| PHP minimo | 7.2 (8.0 recomendado) | 8.1 (8.5 recomendado) |
| Admin controllers | Legacy + Symfony ambos validos | Symfony preferido, legacy solo retrocompat |
| Service Locator | $this->get() disponible | $this->get() deprecated → Constructor Injection |
| Context statico | Permitido | Evitar en servicios, inyectar datos necesarios |
| CQRS | Opcional | Obligatorio para nueva arquitectura admin |
| Tema por defecto | Classic (BS4 alpha) | Hummingbird (BS5.3.3) |
| jQuery | Obligatorio | Deprecated (sera eliminado en PS 10) |
| Domain separation | Recomendada | Obligatoria en nuevo codigo |
| Product page | V1 (legacy) + V2 (8.1+) | Solo V2 |
| Feature flags | Basico | Sistema 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

| Componente | Legacy (aun funciona) | Modern (preferido en PS 9) |
| --- | --- | --- |
| Admin controllers | AdminController extends ModuleAdminController | Symfony Controller + routing YAML |
| Formularios | HelperForm / HelperList | Symfony FormType + Grid System |
| ORM | ObjectModel | Doctrine ORM entities |
| Queries | Db::getInstance()->executeS() | Doctrine DBAL / Repository |
| Templates BO | Smarty .tpl | Twig .html.twig |
| Templates FO | Smarty .tpl | Smarty .tpl (Twig previsto para PS 10) |
| Traducciones | $this->l('...') | $this->trans('...', [], 'Modules.X.Admin') |
| Eventos | Hook dispatcher | Hook dispatcher + Symfony EventDispatcher |
| Config | Configuration::get/updateValue() | Igual + DataConfiguration pattern |
| CLI | — | bin/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

| Comando | Descripcion |
| --- | --- |
| prestashop:thumbnails:regenerate | Regenerar thumbnails de imagenes de producto |
| prestashop:search:index | Reconstruir el indice de busqueda desde CLI |
| prestashop:module:export-translations | Exportar 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:

| Flag | Estado | Descripcion |
| --- | --- | --- |
| improved_shipment | Beta | Sistema Multi-Shipment (multiples envios por pedido) |
| discount | Beta | Nuevo sistema de descuentos con 4 tipos |
| tag | Beta | Sistema 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);
}
```


---

*Fuente: [https://ayudaprestashop.es/ps91/architecture](https://ayudaprestashop.es/ps91/architecture). Version Markdown generada automaticamente para consumo por LLMs.*
