kitpages/shop-bundle
KitpagesShopBundle is a Symfony bundle for building e-commerce shops, providing product catalogs, shopping carts, checkout flows, and order management with configurable entities and templates.
Start with a reality check before you write a single line of integration code: this is a Symfony 2 bundle in alpha, last tagged in July 2015, with no dependents. It will not install into a modern Laravel app — its composer.json will constrain symfony/* to 2.x components that conflict with Laravel's v6/v7 requirements, and even with --ignore-platform-reqs you inherit an unmaintained Doctrine/Symfony graph. Treat it as a reference implementation of a shop domain model, not a dependency.
What to do first:
Entity/ directory. That's where the value is: the bundle models cart, cart lines, order, order lines, invoice, shipping/delivery, and discount/voucher as Doctrine entities. Read these before anything else — the docs are thin and the tests are the real specification.Manager, Service, or Handler namespace). Controllers in this bundle are thin; the money logic and state transitions live behind those services.Your first concrete use case, if you're porting: reimplement the cart-to-order snapshot. That single flow exercises pricing, tax, discount ordering, and persistence — everything the rest of the bundle hangs off.
If you genuinely want to run it as-is, you need a Symfony 2.8 skeleton on PHP 5.6/7.0, Doctrine ORM, the bundle registered in AppKernel, and doctrine:schema:update --force (there are no migrations).
Aggregate with line items. Cart and Order are roots; lines are children with cascade persist/remove. Keep that shape in Eloquent: Cart hasMany CartLine, Order hasMany OrderLine, and never let lines be saved independently of their root. Line rows should carry a price snapshot (unit price, tax rate, discount share) taken at add-to-cart time, not a live FK to the current product price — otherwise historical orders mutate when you change a product.
Manager/service layer over fat models. The bundle puts transitions in services rather than entities or controllers. Mirror this with Laravel actions (AddToCart, ApplyVoucher, PlaceOrder) so the same logic is callable from HTTP, console, and jobs.
Status fields as a de facto state machine. Order status, invoice status, and shipping status are separate columns advanced by explicit service calls. In Laravel, promote this to symfony/workflow or a small enum + transition guard class — the bundle's implicit version is the most common source of "order stuck in limbo" bugs.
Event hooks for extension. The bundle leans on the Symfony event dispatcher for post-order hooks (invoice generation, notifications). Map these to Laravel events/listeners: OrderPlaced, InvoiceIssued, ShipmentCreated. Keep invoice PDF generation and email in queued listeners.
Discount and shipping as order-level adjustments. The pattern is: compute line subtotals → sum → apply discount → apply shipping → apply tax. Get the order of those operations fixed early and test it; it's the part every shop gets wrong once.
Payment is not here. Expect to implement the gateway integration yourself behind a small PaymentGateway interface, driven by an order state transition.
Security. Access to an order is not just "is logged in" — the bundle uses a user/session association plus (in Symfony) voters. In Laravel terms: a policy on Order checking user_id or a signed guest token stored on the cart.
composer require it.UnitOfWork change tracking, and lazy collections all differ. Budget real time for the mapping, or run Doctrine inside Laravel via laravel-doctrine/orm if you want the entities verbatim.sum(lines) - discount + shipping == total) in a test that runs over fixture carts. Totals drifting from their components is the signature bug in this class of bundle.How can I help you explore Laravel packages today?