libre-informatique/ecommerce-bundle
PHP ecommerce bundle providing reusable components for products, carts, orders, payments, and store management. Add flexible commerce functionality to your application with clean integration, sensible defaults, and developer-friendly building blocks for custom online shops.
Know what you are actually installing. libre-informatique/ecommerce-bundle is a Symfony 2 bridge bundle — glue between Libre Informatique's own bundles and Sylius components. It is not a standalone storefront engine and it is not a Laravel package. "Leveraging" it day-to-day only happens under two scenarios: (a) you are maintaining/inheriting a Symfony 2 app that already wires together librinfo + Sylius, or (b) you are mining it as a domain-model reference while building a catalog natively. Anything else is a porting project.
Minimal steps, in dependency order:
composer.json first, not the README. Look at three blocks: the symfony/* constraints (expect ~2.3–2.8), the sylius/* entry (component-level or the full sylius/sylius — this determines how much of Sylius you inherit), and the libre-informatique/* entries. That graph is the real API surface. If the constraints conflict with any modern package you already require, stop here.*Bundle class and its Resources/config/. This is where service wiring, DI aliases, and routing/validation YAML live. Map each registered service to the Sylius or librinfo service it decorates or implements — the bundle's whole job is adaptation, so its value is the mapping layer, not bespoke logic.Entity/ and Form/Type/ directories. These are your actual model and UI contracts: products, variants, orders, checkout form types. Read the entity associations before reading any service — the schema tells you what the system can and cannot represent.*Events:: constants are listened to; that is the workflow you will be maintaining or reimplementing.First use case. Point the app at the catalog path (product CRUD with variant/attribute selection and a category assignment) and render it through the bundle's Twig templates. This exercises Doctrine mappings, form types, and the Twig layer simultaneously and is the fastest way to confirm the bundle boots and the DI config resolves. Do this in a throwaway environment first — it is the cheapest possible smoke test before any commitment.
If your target is Laravel, do not attempt install. Open Entity/Product.php, Entity/Variant.php, and the form types, write down the fields, relations, and validation rules, and treat that document as the spec for native Eloquent models. Budget it as a two-day research spike; delete the clone afterward.
Pattern 1 — Legacy Symfony 2 maintenance (the only real integration). Register the bundle in AppKernel::registerBundles() in the correct order relative to the Sylius and librinfo bundles it bridges — ordering here is load-bearing because DI parameters are overridden by later bundles. Keep configuration in app/config/config.yml under the bundle's declared root key, and prefer overriding services via services.yml compiler passes over editing vendor code, so upgrades (such as they are) remain possible. Treat any local patch to the bundle's own Resources/config as a fork: track it in a patches/ directory with rationale in the commit message, because no upstream will ever merge it back.
Pattern 2 — Service decoration for custom business logic. The bundle's extensibility story is Symfony's decoration mechanism. To add pricing rules, tax logic, or inventory checks, implement your own service and decorate the bundle's existing service ID rather than subclassing entities. This keeps the Doctrine mapping untouched (schema churn on a legacy system is the highest-risk change you can make) and confines your custom code to a directory you can lift into a replacement system later.
Pattern 3 — Extract, don't import (Laravel target). Model the catalog as: Product → hasMany Variant; Variant → belongsToMany AttributeValue; Product → belongsToMany Category; Price and Inventory as separate tables keyed to Variant. Mirror the bundle's associations, then re-decide the behaviours: Eloquent has no identity map, so the Doctrine-style "load aggregate, mutate, flush" workflow does not translate. Use explicit service classes with database transactions and DTOs at the boundaries instead of letting models carry the workflow.
Pattern 4 — Repository adapter for a staged migration. If you must run both systems concurrently, define a narrow Laravel-side interface (CatalogRepository with findBySku, listForCategory, variantAvailability) and implement it twice: once against the Doctrine repository via a thin bridge, once against Eloquent. Consumers depend only on the interface, so the cut-over is a container binding change, not a code sweep. Keep the Doctrine-side implementation read-only — dual-write across two ORMs is where these migrations fail.
Pattern 5 — Checkout/order as an explicit state machine. The bundle's order workflow is event-driven. Whatever you build, encode order states as an explicit enum with guarded transitions rather than scattering if ($order->getState() === …) checks. This is the single highest-value lesson to carry forward, because a legacy event-driven workflow with no visible state table is the hardest thing to reason about when bugs surface.
Integration tips that apply to every pattern:
composer.lock committed and never run a blanket composer update on this codebase.docs/domain.md capturing the entity model and state transitions; this is the artifact that survives when the bundle does not.NOASSERTION means redistribution is unclear. Do not copy entity or service code into an internal Laravel repo until legal has signed off in writing — writing an original implementation from a read of the schema is a different (and safer) act than copying files. Keep the two activities separate and documented.with(); flush semantics are transactional batches, not per-save; and UnitOfWork change tracking has no equivalent. Any timing or correctness assumption inherited from the Doctrine side is unvalidated.stopPropagation do not map onto Laravel's events. If you are porting workflow logic, re-read each listener as an explicit step in a pipeline rather than trying to preserve the event graph.NOASSERTION also means no security process. Assume every transitive dependency carries known CVEs with no patch path. Run a scanner on day one and record the baseline; if the list is long, that is your argument for replacement.debug:container --show-private in that era) and compare against the vendor services.yml rather than guessing.How can I help you explore Laravel packages today?