smartbox/integration-framework-bundle
Smartbox Integration Framework Bundle is a structured PHP foundation for building and managing integrations. It offers reusable connectors, configurable services, and flexible workflows to simplify connecting external systems, APIs, and third-party services.
This is a Symfony bundle, not a Laravel package. Before anything else, confirm you actually want it in a Laravel app — you'll be pulling in Symfony DependencyInjection, Config, and possibly HttpKernel/EventDispatcher components alongside Laravel's container, and there is no service provider shipped for you. If you're in a Symfony app, the path is normal; if you're in Laravel, treat it as a library you wire manually (or isolate it behind a small adapter).
Minimal steps:
composer require smartbox/integration-framework-bundle — pin the version (2.5.0 is the latest release; the project is effectively a one-maintainer, low-traffic repo with 8 stars and 0 dependents, so pin explicitly and commit the lockfile).config/bundles.php (Symfony Flex will usually do this; verify it's there). For a non-Flex or Laravel setup, you'll instantiate Smartbox\IntegrationFrameworkBundle\IntegrationFrameworkBundle yourself and register its Extension.config/packages/integration_framework.yaml recipe — the authoritative config schema lives in src/DependencyInjection/Configuration.php. Open that file first; it tells you every option, default, and required env var in one place.bin/console debug:container --tag=<whatever tag the bundle defines> and bin/console list are your fastest way to discover the services, tagged integrations, and commands the bundle exposes. There is very little public documentation, so the container is the docs.Where to look first, in order: README.md → src/DependencyInjection/Configuration.php → src/DependencyInjection/*Extension.php → the integration/manager interfaces → src/Tools/Mapper/Mapper.php (the mapping layer you'll touch constantly) → the tests directory (often the only real usage examples in low-traffic bundles).
Define integrations, don't hardcode them. The whole point of an "integration framework" is that concrete partner integrations are registered artifacts (tagged services, attributes, or a registry/factory) rather than if/else branches in a service. Follow whatever registration mechanism the bundle uses and make your integrations thin: transport + mapping only, with business logic in your own services.
Façade over the framework. In controllers, commands, and jobs, depend on the bundle's manager/registry interface, not on concrete integration classes. This keeps your call sites stable if you later swap the bundle out or decorate it.
Use the mapper as a first-class layer, and reach for mergeMapping() for composite payloads. As of v2.5.0, Tools/Mapper/Mapper exposes mergeMapping(), which combines the output of map() (single object) and mapAll() (collection) into a supplied mapper instance. The shape this fits: a partner payload that is part header/single-entity and part line-item list — e.g. an order mapping (customer, totals) merged with the mapped collection of order lines — rather than hand-assembling two mapper results in your integration class. Keep one mapper per message shape, call map()/mapAll() for the parts, and let mergeMapping() produce the composite; don't let mapping logic leak back into the transport layer just because assembly is now one call. Read the method signature and tests in the repo before adopting it — the release note is one line, so the merge semantics (key collisions, ordering, whether the target mapper is mutated or returned) are spec'd in code, not docs.
Decorate before you fork. Because the community surface is tiny (0 dependents), you will hit behavior you want to change — including in the mapper. Symfony's service decoration and the bundle's extension points (compiler passes, overridable interfaces, config flags) should be your first move; vendor-forking the bundle is the last resort, but with this project's maintenance profile, be prepared for it.
Wire it into your async path. Integrations are I/O; call them from queued jobs/message handlers with retries, timeouts, and idempotency keys, not synchronously inside a request cycle. Keep the bundle responsible for "how to talk to partner X" and your app responsible for "when and how often."
Per-environment config. Use distinct credentials/sandbox endpoints per environment via the config tree (typically env vars). Keep integration config declarative (YAML in Symfony) and keep secrets in env, not in the config file.
Test with the framework's own seams. Inject a fake integration/transport through the registry in tests instead of mocking HTTP clients deep inside. If the bundle ships a sandbox/in-memory mode, use it; otherwise a test double registered under the same tag works well. For mapper work, test mappers with fixed input/output fixtures — that's cheap, fast, and gives you the regression safety net the bundle's own test suite won't give you across upgrades.
Versioning discipline. Since releases are sparse, treat upgrades as reviewable events: read the diff between tags, run your integration tests, and avoid depending on @internal classes — with this project's cadence, internals can change without a deprecation path.
ServiceProvider, no facade, no config/*.php publish command. You'll manually bridge the container and config. Budget real time for that, and consider running it in a separate Symfony service if the coupling gets ugly.Configuration.php class, the extension, and the test suite are the actual specification — read them before writing integration code, and keep notes; you'll be the team's documentation.mergeMapping() is a new surface — verify before you build on it. One-line release notes mean the contract is in the source and tests. Check what happens on key collisions between the map() and mapAll() sides, whether the target mapper is mutated or returned, and whether it's suitable outside the composite-payload case. Write a fixture test pinning the behavior you rely on; a patch release tightening merge semantics shouldn't silently reshape your outbound payloads.bin/console cache:clear; if a config option "doesn't work," you're usually looking at a stale container or an option silently ignored because it's under the wrong node.debug:container --tag=... is the first diagnostic, not the logs. The same holds for mappers if they're wired by tag — a missing mapper shows up as an empty/partial payload, not an exception.\Exception.*Interface you can implement or decorate. Map these out early — they're your escape hatch when the bundle's defaults don't fit.How can I help you explore Laravel packages today?