Getting Started
Reality check first: despite the "package" framing, integrated/channel-bundle is a Symfony bundle, not a Laravel package. It ships a *Bundle class, a DependencyInjection/Configuration.php tree, and service definitions wired through the Symfony container. There is no ServiceProvider, no config/channel-bundle.php, and no facade. A Laravel developer's realistic paths are:
- Read it as a reference implementation. Clone the repo, read the connector interface and two or three concrete connectors, and reimplement the contract natively in Laravel (
Connector interface + ConnectorConfig model + RunConnectorJob + schedule() entries). This is the default and usually the correct choice.
- Run it as an isolated Symfony service if the connector logic is non-trivial and vendor-maintained. Stand up a minimal Symfony app, wire connectors there, expose a narrow internal HTTP API, and hand off to Laravel via queue.
- Do not attempt in-process use inside a Laravel app. The
symfony/framework-bundle kernel dependency conflicts with Laravel's pinned symfony/console, symfony/http-foundation, and symfony/process versions.
First hour checklist:
- Read
composer.json: note the PHP constraint (a 7.x pin is an immediate disqualifier for Laravel 10/11), the required symfony/* majors, and whether framework-bundle is a hard dependency.
- Read the connector interface — that is the spec. Documentation does not exist beyond the README.
- Count the shipped connectors. If two or three map to your actual endpoints and the rest don't, you are porting, not adopting.
- Run
composer why-not against a Laravel skeleton in a scratch directory to confirm the conflict surface before you commit to anything.
- Check the commit history over the last 12 months. Zero stars and zero dependents means you own this code the moment it hits production.
First use case: internal tooling, secondary feeds, or marketing syndication. Do not put payment, order, or regulated-data flows behind this on day one.
Implementation Patterns
Pattern 1 — Native port (recommended). The bundle's conceptual model maps cleanly onto Laravel primitives. Freeze the vendor's connector interface, then:
- Define a
Connector contract (pull(): IngestedItem[], push(Payload): DistributionResult).
- Model
ConnectorConfig (driver, credentials, cadence, target) as a database row, not config files. Config files force a deploy for every credential rotation.
- Wrap execution in
RunConnectorJob on a dedicated queue. Schedule one job per connector via schedule() so cadences are independent.
- Use
Http:: with per-connector timeouts, retry backoff, and a RateLimiter keyed by connector slug.
- Fire domain events (
ConnectorSucceeded, ConnectorFailed, ContentIngested) so downstream hooks (indexing, notifications) stay out of the connector.
Pattern 2 — Isolated Symfony service. Only when the connector logic is large and genuinely vendor-maintained:
- One container, one deploy target, one env file holding connector credentials.
- Expose a narrow internal API:
POST /connectors/{slug}/run, GET /connectors/{slug}/status. Do not expose the whole container.
- Laravel owns scheduling and calls the service; the service owns protocol translation. Content flows back via queue, not synchronous response, so a slow connector cannot stall a web request.
- Treat the boundary as a hard seam: the Symfony side must not read or write the Laravel domain model. It deals in DTOs.
Pattern 3 — HTTP-only dependency. If the Integrated platform exposes a REST API for connector configuration, skip the code dependency entirely. The bundle is then just documentation of what the API expresses. This is often the cheapest path if it is available.
Workflow that works day-to-day:
- Add a connector = a config row + (if needed) a driver class + a scheduled job. No new service, no new deploy of a separate stack.
- Every connector writes a heartbeat row (
last_success_at, last_error, row counts) on every run. This single table is what makes on-call tractable.
- Every ingested record carries the external ID as a natural key with a unique index — dedupe at the database, not in application code.
- Every push has an idempotency check or a reconciliation job. Distribution is harder to make safe than ingestion; partial publishes and duplicate emits are the dominant failure mode.
- Credentials live in the database encrypted (
encrypted cast) or a secrets manager — never in config/channel-bundle.php-equivalents that get committed.
Gotchas and Tips
- The biggest trap is assuming Laravel adoption. There is no drop-in path. Anyone who tells you "just
composer require" has not read composer.json. Verify Symfony major compatibility with Laravel's pinned symfony/* packages before planning any work.
- Zero stars, zero dependents is a real signal. No Stack Overflow answers, no blog posts, no hiring leverage, no security review. Treat the opportunity score (6.59) as validation of the problem space — multi-channel connectors are real, recurring work — not of this package.
- Connector rot is fast. External APIs change auth schemes and deprecate endpoints with little notice. With no community and no vendor SLA, every upstream change is your ticket. Budget a periodic review (quarterly is a reasonable default) of each connected endpoint.
- Silent sync failure is the failure mode that bites hardest. A connector stops running, nobody notices, content goes stale for a week. Heartbeat metrics and a last-success alert per connector are non-optional, not "phase two."
- Credential expiry surfaces as generic 401s. OAuth refresh failures look identical to misconfiguration in logs. Add explicit handling that distinguishes "token expired," "token revoked," and "endpoint rejected us," and alert on each distinctly.
- Rate limits will trip if you poll naively across many connectors. Per-connector throttles, exponential backoff on 429, and jittered scheduling are cheaper to add up front than to retrofit after the first production incident.
- Version skew on Laravel or Symfony majors is the failure mode most likely to force a rewrite under deadline pressure. Forks of framework-coupled bundles are hard to bump. If you port, port only the connector contract and adapters — do not import the DI plumbing.
- Secrets, SSRF, and signature verification are all undocumented. If you run the isolated-service pattern, allow-list outbound hosts and verify webhook signatures yourself; do not assume the bundle does.
- Execution model is unclear from the metadata. Pull vs. push, cron vs. worker vs. synchronous request — read the code. If execution is synchronous-request-bound, wrap it in a job before putting it anywhere near user flows.
- Read the source with a plan. Start at the connector interface, then one concrete connector, then the DI extension. Do not read the compiler passes first — they are wiring noise until you understand the contract. Assume 2–3 days of context-building before a Laravel developer is productive on Symfony bundle conventions.
- The honest recommendation is to evaluate this as a reference implementation, not a dependency. Extract what is useful, own the result, and write a short internal design note before handing it to anyone else. That note — with the connector contract, expected cadence, and replay procedure — is your runbook.