Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Customer Bundle Laravel Package

softspring/customer-bundle

Softspring Customer Bundle is a PHP/Symfony package for modeling and managing customer accounts, profiles, addresses, and contact data. It offers reusable entities, services, and forms to speed up building customer management features in Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Before anything else, confirm the stack fit — it defines what "day-to-day" even means here:

  • Symfony app: this is a normal composer require + bundle registration, and you get Doctrine entities, forms, and services you can use immediately.
  • Laravel app: there is no Laravel integration. No service provider, no config file, no Eloquent, no migrations publish tag you can trust. Your day-to-day use is reading the source as a domain reference and porting it, not depending on it.

For a Symfony host, the minimal path:

composer require softspring/customer-bundle

If Symfony Flex has no recipe (likely, given zero adoption), register it manually in config/bundles.php:

return [
    // ...
    Softspring\CustomerBundle\SoftspringCustomerBundle::class => ['all' => true],
];

Then read the source in this order — it's the only documentation you have:

  1. src/Entity/ — the customer, address, and contact models. This is the whole value of the bundle.
  2. src/Resources/config/ — service definitions and any bundle configuration (entity class parameters are common in these bundles).
  3. src/Form/ — the form types and their validation constraints.
  4. Any Migrations/ or mapping files (*.orm.xml, *.yaml, or PHP attributes) to see the exact schema the entities imply.

First use case: in a Symfony app, wire a controller that uses the bundle's customer entity and create form to persist a customer with a primary address. That single flow (create customer → attach address → validate → persist) exercises the entity relations, the form, and the validation constraints — i.e. the entire useful surface of the bundle — and tells you within an hour whether the model matches your domain.

In Laravel, the equivalent "first use case" is writing one migration plus one Eloquent model for customers and addresses, copied from the bundle's field list and relations. Do that before deciding whether to port more.

Implementation Patterns

Entity-first CRUD (Symfony). The bundle's centre of gravity is the data model. The pattern is: inject the entity manager, instantiate (or fetch) the customer entity, hand it to the bundle's form type, validate, persist. Don't fight the forms — if the bundle's form type doesn't cover a field you need, create a form type in your own app that extends or wraps it rather than editing vendor code.

Doctrine mapping overrides. These bundles almost always let you swap the entity class via configuration (a class parameter or a doctrine.orm.mapping override). If you need extra columns on a customer — a stripe_id, an external_ref, a GDPR deleted_at — prefer subclassing or mapping-extension over forking the bundle. Check src/Resources/config/ for whether the entity class is a parameter before you assume it's hard-coded.

Wrap it behind your own service. Create a CustomerManager (or repository) in your app that is the only thing calling the bundle's services. Controllers and other domain code talk to your wrapper. This is the single most valuable pattern here: with zero upstream maintenance, you want the blast radius of replacing or forking the bundle to be one class, not every controller.

Reuse the validation constraints, not just the entities. The form types carry the validation logic (required fields, address format, contact rules). When you build your own API or console command that creates customers outside the forms, apply the same constraints explicitly — otherwise you get customer records that violate the invariants the forms enforce, and the bundle won't protect you.

Porting pattern (Laravel). Treat the bundle's entity definitions as a spec, then rebuild in your own idioms:

  • Doctrine ManyToOne customer→address becomes an Eloquent belongsTo / hasMany, plus a is_default boolean you manage with a scope.
  • Doctrine embeddables (contact details are usually embedded, not a separate table) become plain columns on customers — do not blindly create a contacts table.
  • The bundle's form constraints become FormRequest rules and/or model-level validation.
  • The bundle's lifecycle bits (account state fields) become an enum cast plus a small state-transition method on the model.

Write a short spec first: field list, nullability, relations, and who owns default-address enforcement. That document is the real deliverable if you go the port route.

Typical workflow, end to end:

  1. Spike: install into a throwaway Symfony branch, run doctrine:schema:validate, generate a diff, create a customer with an address.
  2. Extract the schema and invariants to a written spec.
  3. Decide: depend (Symfony, clean spike) or port (Laravel, or noisy spike).
  4. If depending: pin the exact version in composer.json, commit the lock, wrap behind your service, and record a compatibility matrix (PHP × Symfony major × bundle tag × DB driver).
  5. If porting: migrations → models → request validation → the create/update flow → admin UI last.

Gotchas and Tips

The stack mismatch is not a detail, it's the headline. Every "saving" from this bundle evaporates if you're in Laravel: Eloquent and Doctrine do not interoperate, and you will spend more time bridging than writing the two models yourself. Decide this before you write any integration code.

Bundle-shipped migrations vs yours. If the bundle ships migrations or a full schema, do not generate competing first-party migrations for the same tables. Pick one owner. Mixing them produces schema drift that is painful to untangle later, especially once customer rows exist.

Entity class hard-coding is the common trap. Confirm whether the customer/address classes are configurable. If they aren't, your "extend the entity" plan becomes "fork the bundle" — worth knowing on day one, not week three.

Debugging the container. Most failures on a dormant Symfony bundle are container-compilation errors, not runtime errors. When something breaks after a dependency bump: bin/console cache:clear, then bin/console debug:container | grep -i customer, then composer why-not softspring/customer-bundle to see the actual constraint conflict. Don't debug the code until you've ruled out resolution and cache.

Check the declared support matrix yourself. Look at composer.json for php and symfony/* constraints before assuming it works on your Symfony 6/7 app. An unmaintained bundle pinned to an older major is a silent blocker.

PII defaults you didn't author. This is customer data — names, addresses, contact details, potentially account state. Read the entity defaults and any controller/service logic that serialises customers (e.g. for admin screens) before pointing it at production data. Defaults around soft-deletes, logging of entities, and serialisation groups are where leaks hide.

Zero upstream maintenance is a design constraint. No stars, no dependents, no visible release cadence. Assume "fork on first bug." Budget an owner, a fork under your org, and a documented patch process. If you're not prepared to own this code, don't depend on it — copy the schema.

Extension points worth knowing, in order of preference: (1) override the entity class via config, (2) subclass the entity/form type in your app, (3) decorate the bundle's services, (4) fork. Editing files in vendor/ is never the answer — it's lost on the next composer update, and with no upstream, there is no "next update" to carry your patch forward.

Profile before launch. Customer-to-address relations are the classic N+1 in this shape of bundle. Fetch a page of customers with their addresses and count the queries. If the bundle doesn't eager-load by default, add fetch="EAGER" at your mapping layer or eager-load explicitly in your repository — not in the bundle.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect