PrestaShop à Sylius : un changement de paradigme technique

De PrestaShop à Sylius : comprendre le changement de paradigme technique

Si vous développez sur PrestaShop depuis plusieurs années, passer à Sylius c'est bien plus qu'un simple changement d'outil. C'est une évolution vers une architecture moderne, basée sur des standards éprouvés. Cet article détaille les différences conceptuelles et techniques entre les deux plateformes pour vous aider à appréhender cette transition.

Sommaire

Une idée, un projet ?

Nous sommes à votre disposition pour discuter.

Contactez-nous

Sommaire

Architecture globale, du monolithe au modulaire

PrestaShop et son architecture monolithique historique

PrestaShop a été conçu comme une solution tout-en-un. Le code métier, la logique de présentation et la couche de données sont étroitement couplés. Cette approche présente des avantages pour démarrer rapidement, mais révèle des limites sur certains projets.

Caractéristiques de l'architecture PrestaShop :

  • Framework propriétaire basé sur le pattern MVC (partiellement)
  • Couplage fort entre les composants
  • Classes globales accessibles partout (ContextDbConfiguration)
  • Logique métier souvent mélangée avec la présentation
  • Système de modules qui s'appuient sur des hooks

Exemple typique en PrestaShop :

// Récupération d'un produit dans PrestaShop
$product = new Product($id_product, true, $id_lang);
$price = Product::getPriceStatic($id_product, true);

// Utilisation du contexte global
$cart = Context::getContext()->cart;
$customer = Context::getContext()->customer;

Le contexte global (Context::getContext()) est omniprésent, ce qui facilite l'accès aux données mais crée des dépendances cachées et complique les tests unitaires.

Sylius et son architecture modulaire basée sur Symfony

Sylius est construit sur Symfony, framework PHP de référence qui implémente les principes SOLID et favorise l'injection de dépendances. L'architecture est découplée en composants indépendants.

Caractéristiques de l'architecture Sylius :

  • Framework Symfony 6.x/7.x
  • Architecture hexagonale (séparation domaine/infrastructure)
  • Injection de dépendances systématique
  • Séparation claire des responsabilités
  • Composants réutilisables (Product, Order, Customer, etc.)
  • Event-driven architecture

Même exemple en Sylius :

// Récupération d'un produit dans Sylius
class ProductController extends AbstractController
{
    public function __construct(
        private ProductRepositoryInterface $productRepository,
        private OrderItemQuantityModifierInterface $orderItemQuantityModifier
    ) {}

    public function showAction(Request $request): Response
    {
        $product = $this->productRepository->find($request->get('id'));
        // Pas de contexte global, tout passe par l'injection de dépendances
    }
}

Les dépendances sont explicites, injectées via le constructeur. Le code est testable, maintenable et suit les standards modernes.

Gestion des données de ObjectModel à Doctrine

PrestaShop : ObjectModel, un ORM maison

PrestaShop utilise ObjectModel, un système d'abstraction de base de données développé en interne. Chaque entité hérite de cette classe de base.

class Product extends ObjectModel
{
    public $id_product;
    public $name;
    public $price;

    public static $definition = [
        'table' => 'product',
        'primary' => 'id_product',
        'multilang' => true,
        'fields' => [
            'price' => ['type' => self::TYPE_FLOAT, 'validate' => 'isPrice'],
            'active' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'],
        ],
    ];

    // Les requêtes SQL se font souvent manuellement
    public static function getProducts($id_lang, $start, $limit)
    {
        return Db::getInstance()->executeS('
            SELECT p.* FROM '._DB_PREFIX_.'product p
            WHERE p.active = 1
            LIMIT '.(int)$start.', '.(int)$limit
        );
    }
}

Ce système est fonctionnel mais limité :

  • Pas de relations complexes gérées automatiquement
  • Requêtes SQL souvent écrites manuellement
  • Difficultés avec les jointures complexes
  • Pas de lazy loading
  • Multi-langues géré de façon propriétaire

Sylius : Doctrine ORM, l'ORM de référence PHP

Sylius utilise Doctrine, l'ORM standard de l'écosystème Symfony. Les entités sont des POPO (Plain Old PHP Objects) annotées ou configurées via YAML/XML.

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Product\Model\Product as BaseProduct;

#[ORM\Entity]
#[ORM\Table(name: 'sylius_product')]
class Product extends BaseProduct
{
    // Les propriétés et relations sont définies via attributs
    #[ORM\Column(type: 'decimal', precision: 10, scale: 2)]
    private float $price;

    #[ORM\ManyToOne(targetEntity: Taxon::class)]
    private ?Taxon $mainTaxon = null;

    #[ORM\OneToMany(mappedBy: 'product', targetEntity: ProductVariant::class)]
    private Collection $variants;
}

Avantages de Doctrine :

  • Gestion automatique des relations (OneToMany, ManyToMany, etc.)
  • DQL (Doctrine Query Language) au lieu de SQL brut
  • Lazy loading et eager loading optimisés
  • Migrations de schéma versionnées
  • Support natif des locales via extensions (Translatable)
  • Cache de second niveau

Exemple de requête avec Doctrine :

// Repository Doctrine
$products = $this->productRepository->createQueryBuilder('p')
    ->leftJoin('p.variants', 'v')
    ->where('p.enabled = :enabled')
    ->andWhere('v.onHand > :stock')
    ->setParameter('enabled', true)
    ->setParameter('stock', 0)
    ->getQuery()
    ->getResult();

Le DQL est plus lisible, sécurisé (paramètres bindés automatiquement) et permet l'utilisation du cache de requêtes.

Modules vs bundles, deux philosophies d'extension

PrestaShop : le système de modules

Les modules PrestaShop sont des dossiers autonomes contenant une classe principale héritant de Module. Ils interagissent avec le core via un système de hooks.

class MyModule extends Module
{
    public function __construct()
    {
        $this->name = 'mymodule';
        $this->tab = 'front_office_features';
        $this->version = '1.0.0';
        parent::__construct();
    }

    public function install()
    {
        return parent::install()
            && $this->registerHook('displayHeader')
            && $this->registerHook('actionProductSave');
    }

    public function hookDisplayHeader($params)
    {
        // Ajout de CSS/JS
        $this->context->controller->addCSS($this->_path.'views/css/style.css');
    }

    public function hookActionProductSave($params)
    {
        // Logique métier lors de la sauvegarde produit
        $product = $params['object'];
        // ...
    }
}

Les limites du système PrestaShop :

  • Namespace global, risques de conflits
  • Difficile de surcharger proprement les classes du core
  • Hooks parfois insuffisants, nécessitant des overrides
  • Pas de gestion de dépendances entre modules
  • Tests difficiles à mettre en place

Sylius : les bundles Symfony

Dans Sylius, les extensions sont des bundles Symfony. Un bundle est un ensemble cohérent de code (contrôleurs, entités, services, templates) qui peut enrichir ou modifier l'application.

namespace App\Bundle\CustomBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class CustomBundle extends Bundle
{
    // Le bundle est automatiquement enregistré dans config/bundles.php
}

Configuration des services dans un bundle :

# config/services.yaml
services:
    App\EventListener\ProductListener:
        tags:
            - { name: kernel.event_listener, event: sylius.product.pre_create, method: onProductPreCreate }

Listener d'événement :

namespace App\EventListener;

use Sylius\Bundle\ResourceBundle\Event\ResourceControllerEvent;

class ProductListener
{
    public function onProductPreCreate(ResourceControllerEvent $event): void
    {
        $product = $event->getSubject();
        // Logique métier avant création
    }
}

Avantages des bundles :

  • Namespaces propres, pas de conflits
  • Injection de dépendances native
  • Système d'événements structuré
  • Testabilité maximale
  • Composer pour gérer les dépendances
  • Override propre via configuration

Templating, de Smarty à Twig

PrestaShop : Smarty, le moteur de templates historique

PrestaShop utilise Smarty, un moteur de templates séparant PHP et HTML.

{* templates/catalog/product.tpl *}
<div class="product">
    <h1>{$product.name}</h1>
    <p class="price">{$product.price}</p>

    {if $product.images}
        <div class="images">
            {foreach from=$product.images item=image}
                <img src="{$image.url}" alt="{$product.name}">
            {/foreach}
        </div>
    {/if}

    {hook h='displayProductButtons'}
</div>

Smarty est fonctionnel mais vieillissant. La syntaxe est parfois verbeuse et les performances peuvent être un point faible sur des catalogues volumineux.

Sylius : Twig, le standard Symfony

Sylius utilise Twig, le moteur de templates moderne de Symfony. Twig est plus rapide, plus sécurisé (échappement automatique) et mieux intégré.

{# templates/product/show.html.twig #}
<div class="product">
    <h1>{{ product.name }}</h1>
    <p class="price">{{ product.price|sylius_format_money }}</p>

    {% if product.images is not empty %}
        <div class="images">
            {% for image in product.images %}
                <img src="{{ image.path|imagine_filter('sylius_large') }}"
                     alt="{{ product.name }}">
            {% endfor %}
        </div>
    {% endif %}

    {{ sylius_template_event('sylius.shop.product.show.buttons', {'product': product}) }}
</div>

Avantages de Twig :

  • Syntaxe claire et concise
  • Échappement automatique (sécurité XSS)
  • Héritage de templates puissant
  • Filtres et fonctions extensibles
  • Cache natif très performant
  • Intégration parfaite avec Symfony

Héritage de templates :

{# templates/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
    {% block stylesheets %}
        <link rel="stylesheet" href="/css/main.css">
    {% endblock %}
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>

{# templates/product/show.html.twig #}
{% extends 'base.html.twig' %}

{% block content %}
    <div class="product">
        {{ product.name }}
    </div>
{% endblock %}

Hooks vs Event Dispatcher, du couplage au découplage

PrestaShop : les hooks

Les hooks PrestaShop permettent aux modules d'injecter du code à des points précis de l'application.

// Dans le core PrestaShop
Hook::exec('displayProductButtons', ['product' => $product]);

// Dans un module
public function hookDisplayProductButtons($params)
{
    $product = $params['product'];
    return $this->display(__FILE__, 'views/templates/hook/product-button.tpl');
}

Limites des hooks :

  • Nombre limité de hooks disponibles
  • Impossible de modifier les données en profondeur
  • Ordre d'exécution parfois problématique
  • Difficile de débugger une chaîne de hooks
  • Couplage fort avec les positions dans le code

Sylius : Event Dispatcher et Template Events

Sylius utilise le composant EventDispatcher de Symfony, basé sur le pattern Observer. N'importe quelle action peut déclencher un événement, et plusieurs listeners peuvent y réagir.

Événements métier :

// Dispatch d'un événement
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

class ProductService
{
    public function __construct(
        private EventDispatcherInterface $eventDispatcher
    ) {}

    public function createProduct(Product $product): void
    {
        // Logique de création

        $this->eventDispatcher->dispatch(
            new ProductCreatedEvent($product),
            'app.product.created'
        );
    }
}

// Listener
class SendProductNotificationListener
{
    public function onProductCreated(ProductCreatedEvent $event): void
    {
        $product = $event->getProduct();
        // Envoi notification, mise à jour cache, etc.
    }
}

Template Events (équivalent des hooks d'affichage) :

# config/packages/sylius_ui.yaml
sylius_ui:
    events:
        sylius.shop.product.show.buttons:
            blocks:
                custom_button:
                    template: '@App/Product/_customButton.html.twig'
                    priority: 10
{# templates/Product/_customButton.html.twig #}
<button class="custom-action">Custom Action</button>

Avantages :

  • Découplage total entre émetteur et récepteurs
  • Priorités d'exécution configurables
  • Événements typés (auto-complétion IDE)
  • Possibilité de modifier les données via événements
  • Débuggage facilité (profiler Symfony)

Overrides vs Decoration, modifier le comportement

PrestaShop : les overrides

PrestaShop permet de surcharger des classes du core via le système d'overrides.

// override/classes/Product.php
class Product extends ProductCore
{
    public function add($autodate = true, $nullValues = false)
    {
        // Logique custom avant
        $result = parent::add($autodate, $nullValues);
        // Logique custom après
        return $result;
    }
}

Problèmes des overrides :

  • Conflits entre modules (deux modules ne peuvent pas override la même classe)
  • Difficile à maintenir lors des mises à jour
  • Impossible à tester unitairement
  • Modification globale sans contrôle fin
  • Casse facilement lors des montées de version

Sylius : decoration pattern et interfaces

Sylius privilégie le decoration pattern, basé sur l'injection de dépendances et les interfaces.

Exemple : décorer un service de calcul de prix

// Service original (interface)
interface ProductPriceCalculatorInterface
{
    public function calculate(ProductInterface $product): int;
}

// Décorateur
class CustomProductPriceCalculator implements ProductPriceCalculatorInterface
{
    public function __construct(
        private ProductPriceCalculatorInterface $decoratedCalculator
    ) {}

    public function calculate(ProductInterface $product): int
    {
        $basePrice = $this->decoratedCalculator->calculate($product);

        // Logique custom : réduction de 10% si produit en promo
        if ($product->hasPromotion()) {
            return (int) ($basePrice * 0.9);
        }

        return $basePrice;
    }
}

Configuration du décorateur :

# config/services.yaml
services:
    App\Calculator\CustomProductPriceCalculator:
        decorates: 'sylius.calculator.product_price'
        arguments:
            $decoratedCalculator: '@.inner'

Avantages :

  • Pas de conflit entre décorateurs (ils s'empilent)
  • Testable unitairement (mock de l'interface)
  • Modification ciblée d'un comportement
  • Compatible avec les mises à jour
  • Respecte le principe Open/Closed (SOLID)

Routing, de dispatcher.php aux routes Symfony

PrestaShop : routing dynamique

PrestaShop utilise un système de routing propriétaire basé sur les contrôleurs et la réécriture d'URL.

// URL : /product/123-mon-produit
// Route vers : ProductController
// Paramètres extraits de l'URL rewritée

Les friendly URLs sont gérées via la table ps_meta et le .htaccess. Ajouter des routes personnalisées nécessite des configurations complexes.

Sylius : système de routing Symfony

Sylius utilise le composant Routing de Symfony. Les routes sont déclaratives, typées et versionnées.

# config/routes/shop.yaml
app_shop_product_show:
    path: /products/{slug}
    methods: [GET]
    defaults:
        _controller: sylius.controller.product:showAction
        _sylius:
            template: '@SyliusShop/Product/show.html.twig'

Route avec attributs PHP :

namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class ProductController extends AbstractController
{
    #[Route('/products/{slug}', name: 'app_product_show', methods: ['GET'])]
    public function show(string $slug): Response
    {
        // Logic
    }
}

Avantages :

  • Routes clairement définies et documentées
  • Génération d'URL automatique ({{ path('app_product_show', {slug: product.slug}) }})
  • Contraintes sur les paramètres (regex, type)
  • Préfixes et groupes de routes
  • Débuggage facile (bin/console debug:router)

Gestion du catalogue, concepts produits

PrestaShop : produit avec combinaisons

Dans PrestaShop, un produit peut avoir des "combinaisons" (déclinaisons).

Produit : T-shirt
  ├─ Combinaison : Taille S, Couleur Rouge (SKU: TSHIRT-S-RED)
  ├─ Combinaison : Taille M, Couleur Rouge (SKU: TSHIRT-M-RED)
  └─ Combinaison : Taille S, Couleur Bleu (SKU: TSHIRT-S-BLUE)

Chaque combinaison a son propre stock, prix, référence. Les attributs (taille, couleur) sont partagés entre produits.

Limites :

  • Gestion complexe des attributs interdépendants
  • Difficile de gérer des variantes avec des caractéristiques très différentes
  • Stock géré au niveau combinaison, pas toujours intuitif

Sylius : Product et ProductVariant

Sylius sépare clairement Product (concept) et ProductVariant (SKU réel).

Product : T-shirt (concept marketing)
  └─ ProductVariant : T-shirt S Rouge (SKU, prix, stock)
  └─ ProductVariant : T-shirt M Rouge
  └─ ProductVariant : T-shirt S Bleu

Modèle d'entités :

class Product
{
    private string $code;  // Identifiant unique
    private Collection $variants;  // Toutes les variantes
    private Collection $attributes;  // Attributs produit (matière, etc.)
}

class ProductVariant
{
    private string $code;  // SKU
    private Product $product;
    private int $onHand;  // Stock physique
    private int $onHold;  // Stock réservé
    private Collection $optionValues;  // Taille S, Couleur Rouge
}

class ProductOption
{
    private string $code;  // 'taille' ou 'couleur'
    private Collection $values;  // S, M, L ou Rouge, Bleu
}

Avantages :

  • Séparation claire concept/SKU
  • Gestion fine du stock (onHand, onHold, reserved)
  • Options de variantes configurables
  • Support natif des produits configurables
  • Possibilité d'avoir des variantes très différentes

Système de prix et promotions

PrestaShop : prix spécifiques et règles panier

PrestaShop gère les prix via :

  • Prix de base produit
  • Prix spécifiques (par groupe, pays, devise, quantité)
  • Règles panier (codes promo, réductions automatiques)
// Calcul de prix dans PrestaShop
$price = Product::getPriceStatic(
    $id_product,
    $usetax,
    $id_product_attribute,
    $decimals,
    $divisor,
    $only_reduc,
    $usereduc,
    $quantity,
    $force_associated_tax,
    $id_customer,
    $id_cart,
    $id_address
);

Cette méthode statique avec 12 paramètres illustre la complexité accumulée au fil des versions.

Sylius : système de pricing unifié

Sylius utilise un système de pricing moderne basé sur des services dédiés.

// Calculateurs de prix injectés
class ProductController
{
    public function __construct(
        private ProductVariantPriceCalculatorInterface $calculator
    ) {}

    public function showAction(ProductVariant $variant): Response
    {
        $price = $this->calculator->calculate($variant, [
            'channel' => $this->getChannel(),
        ]);
    }
}

ChannelPricing : prix par canal

class ChannelPricing
{
    private Channel $channel;
    private int $price;  // En centimes
    private ?int $originalPrice;  // Prix barré
}

Chaque variante a un prix par canal (boutique). Le prix peut varier selon le canal, sans confusion.

Promotions : système d'actions et de règles

// Promotion : -10% sur la catégorie T-shirts
$promotion = new CatalogPromotion();
$promotion->addScope(new ForTaxonsScopeConfiguration(['tshirts']));
$promotion->addAction(new PercentageDiscountActionConfiguration(0.1));

Les promotions sont des entités à part entière, avec priorités, dates de validité, et règles composables.

Gestion des commandes, workflow et états

PrestaShop : états de commande linéaires

PrestaShop définit des états de commande via une table de configuration (ps_order_state).

En attente de paiement → Paiement accepté → En préparation → Expédié → Livré

Les transitions sont souvent gérées manuellement ou via hooks. Il n'y a pas de validation automatique des transitions possibles.

Sylius : State Machine (Workflow Symfony)

Sylius utilise le composant Workflow de Symfony pour gérer les états de commande, paiement et expédition.

Configuration du workflow :

# config/packages/sylius_order.yaml
winzou_state_machine:
    sylius_order_checkout:
        class: Sylius\Component\Core\Model\Order
        property_path: checkoutState
        states:
            cart: ~
            addressed: ~
            shipping_selected: ~
            payment_selected: ~
            completed: ~
        transitions:
            address:
                from: [cart]
                to: addressed
            select_shipping:
                from: [addressed]
                to: shipping_selected
            select_payment:
                from: [shipping_selected]
                to: payment_selected
            complete:
                from: [payment_selected]
                to: completed

Utilisation dans le code :

use SM\Factory\FactoryInterface;

class CheckoutService
{
    public function __construct(
        private FactoryInterface $stateMachineFactory
    ) {}

    public function completeCheckout(OrderInterface $order): void
    {
        $stateMachine = $this->stateMachineFactory->get($order, 'sylius_order_checkout');

        if ($stateMachine->can('complete')) {
            $stateMachine->apply('complete');
            // Events dispatched automatiquement
        }
    }
}

Avantages :

  • Transitions validées automatiquement
  • Impossible de passer d'un état invalide à un autre
  • Événements déclenchés sur chaque transition
  • Visualisation graphique du workflow
  • Callbacks avant/après transition

Multi-boutiques, des approches différentes

PrestaShop : système multi-boutiques intégré

PrestaShop permet de gérer plusieurs boutiques partageant la même installation.

Multistore PrestaShop
  ├─ Boutique FR (URL: fr.example.com)
  ├─ Boutique EN (URL: en.example.com)
  └─ Boutique B2B (URL: b2b.example.com)

Chaque boutique peut avoir :

  • Son propre catalogue (ou partagé)
  • Ses propres clients (ou partagés)
  • Ses propres commandes
  • Ses propres thèmes

Configuration : interface graphique dans le back-office.

Sylius : système de channels

Sylius utilise le concept de "channel" (canal de vente).

class Channel
{
    private string $code;
    private string $name;
    private Locale $defaultLocale;
    private Collection $locales;
    private Collection $currencies;
    private Currency $baseCurrency;
    private string $hostname;
    private string $color;  // Pour l'admin
}

Un channel représente un point de vente :

  • Site web classique
  • Application mobile
  • Point de vente physique
  • Marketplace

Avantages :

  • Prix par canal (même produit, prix différent selon canal)
  • Promotions par canal
  • Thème par canal
  • Inventaire partagé ou séparé
  • Gestion fine des locales et devises par canal

Configuration déclarative :

# config/packages/sylius_channel.yaml
sylius_channel:
    default_channel: web_fr
    channels:
        web_fr:
            locales: [fr_FR]
            currencies: [EUR]
            hostname: www.example.fr
        web_en:
            locales: [en_US, en_GB]
            currencies: [USD, GBP]
            hostname: www.example.com

API : de webservices à API Platform

PrestaShop : Webservices XML

PrestaShop propose une API XML/REST basique.

GET /api/products/1

<?xml version="1.0" encoding="UTF-8"?>
<prestashop>
    <product>
        <id>1</id>
        <name>
            <language id="1">Product Name</language>
        </name>
        <price>19.99</price>
    </product>
</prestashop>

Limites :

  • Format XML imposé (JSON limité)
  • Authentification par clé simple
  • Pas de pagination moderne
  • Pas de filtres avancés
  • Documentation basique
  • Performances limitées

Sylius : API Platform (JSON-LD, GraphQL)

Sylius 1.12+ intègre API Platform, framework de référence pour les API REST/GraphQL.

GET /api/v2/shop/products/tshirt-slug

{
  "@context": "/api/v2/contexts/Product",
  "@id": "/api/v2/shop/products/tshirt-slug",
  "@type": "Product",
  "code": "TSHIRT",
  "name": "T-Shirt Premium",
  "slug": "tshirt-slug",
  "variants": [
    {
      "@id": "/api/v2/shop/product-variants/tshirt-s-red",
      "code": "TSHIRT-S-RED",
      "price": 1999,
      "stock": 15
    }
  ]
}

Caractéristiques :

  • JSON-LD (Linked Data) avec hypermedia
  • GraphQL disponible
  • Authentification JWT
  • Filtres, tris, pagination automatiques
  • Documentation OpenAPI générée automatiquement
  • Performances optimisées (cache HTTP, Varnish)
  • Extensibilité totale

Définir une ressource API :

use ApiPlatform\Core\Annotation\ApiResource;

#[ApiResource(
    collectionOperations: ['get', 'post'],
    itemOperations: ['get', 'put', 'delete'],
    attributes: ['pagination_items_per_page' => 30]
)]
class Product extends BaseProduct
{
    // L'API est générée automatiquement
}

Tests : de l'artisanal à l'industriel

PrestaShop : tests limités

PrestaShop propose quelques tests unitaires et fonctionnels, mais la couverture est partielle. Tester du code custom est complexe à cause des dépendances globales.

// Difficile à tester à cause du contexte global
class MyModule extends Module
{
    public function processOrder($id_cart)
    {
        $cart = new Cart($id_cart);
        $customer = Context::getContext()->customer;
        // Impossible de mocker Context
    }
}

Sylius : tests omniprésents

Sylius est conçu pour être testé. L'injection de dépendances permet de mocker facilement.

Test unitaire :

use PHPUnit\Framework\TestCase;

class ProductPriceCalculatorTest extends TestCase
{
    public function testCalculateWithPromotion(): void
    {
        $product = $this->createMock(ProductInterface::class);
        $product->method('hasPromotion')->willReturn(true);

        $calculator = new CustomProductPriceCalculator($basePriceCalculator);
        $price = $calculator->calculate($product);

        $this->assertEquals(900, $price); // 10% de réduction
    }
}

Test fonctionnel (Behat) :

Feature: Shopping cart
    In order to buy products
    As a customer
    I need to be able to add products to cart

    Scenario: Adding a product to cart
        Given there is a product "T-Shirt" priced at €20
        When I add this product to the cart
        Then I should have 1 item in my cart
        And my cart total should be €20

Sylius inclut Behat et PHPUnit par défaut, avec des contextes pré-configurés pour tester les scénarios e-commerce.

Migration progressive : stratégies possibles

Approche Big Bang (recommandée)

Développer entièrement Sylius en parallèle, migrer les données, puis basculer d'un coup.

Avantages : migration propre, pas de systèmes hybrides complexes.
Inconvénient : nécessite une phase de développement complète avant bascule

Approche hybride (déconseillée mais possible)

Utiliser PrestaShop et Sylius en parallèle avec synchronisation de données.

Cas d'usage : migration très progressive, tests A/B 
Complexité : très élevée, nécessite une synchronisation bidirectionnelle

Synthèse : changement de culture technique

Passer de PrestaShop à Sylius, c'est adopter :

AspectPrestaShopSylius
FrameworkPropriétaireSymfony (standard)
ArchitectureMonolithiqueModulaire/Hexagonale
ORMObjectModelDoctrine
TemplatesSmartyTwig
ExtensionModules + HooksBundles + Events
OverrideClasses globalesDecoration Pattern
APIXML/REST basiqueAPI Platform (REST/GraphQL)
TestsLimitéPHPUnit + Behat natifs
DIContexte globalInjection de dépendances
RoutingDynamique propriétaireRouting Symfony
WorkflowÉtats manuelsState Machine

Ce que cela implique pour un développeur PrestaShop :

  1. Apprendre Symfony : framework, composants, bonnes pratiques
  2. Maîtriser Doctrine : ORM, DQL, relations, migrations
  3. Adopter les design patterns modernes : DI, Decoration, Repository
  4. Penser en événements plutôt qu'en hooks
  5. Écrire du code testable dès le départ
  6. Utiliser Composer pour gérer les dépendances
  7. Suivre les standards PSR (PSR-4, PSR-12, etc.)

Ressources pour approfondir

Formation Symfony

Documentation Sylius

  • Sylius Documentation : https://docs.sylius.com/
  • Sylius Cookbook : recettes pour cas spécifiques
  • Sylius Plus : version entreprise avec fonctionnalités avancées

Communauté

  • Sylius Slack : échanges avec la communauté
  • GitHub Discussions : questions techniques
  • Sylius France : meetups et conférences

Dans notre dernier article, on détaille comment migrer ses données de PrestaShop vers Sylius, pas à pas.


Sources et références

Publié le 16/04/2026 à 17:25
Pour continuer votre lecture
De PrestaShop à Sylius : comprendre le changement de paradigme technique
Voici les dernières actualités du monde tech, avec notre veille techno des mois de mars et avril ! 
Au…
De PrestaShop à Sylius : comprendre le changement de paradigme technique
Dans un projet de passage de PrestaShop à Sylius, la migration des données constitue l'étape la plus critique. Cet article…
De PrestaShop à Sylius : comprendre le changement de paradigme technique
Depuis plusieurs mois, ACSEO industrialise un workflow IA qui transforme la manière d'intégrer et de développer des Frontends. Le résultat…
Pour continuer votre lecture
De PrestaShop à Sylius : comprendre le changement de paradigme technique
Voici les dernières actualités du monde tech, avec notre veille techno des mois de mars et avril ! 
Au…
De PrestaShop à Sylius : comprendre le changement de paradigme technique
Dans un projet de passage de PrestaShop à Sylius, la migration des données constitue l'étape la plus critique. Cet article…
De PrestaShop à Sylius : comprendre le changement de paradigme technique
Depuis plusieurs mois, ACSEO industrialise un workflow IA qui transforme la manière d'intégrer et de développer des Frontends. Le résultat…
Une idée, un projet ? Nous sommes à votre disposition pour discuter. Contactez-nous