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

Connection Bundle Laravel Package

kitano/connection-bundle

Symfony bundle for managing multiple database connections. Configure named connections, switch between them at runtime, and centralize connection setup—useful for multi-tenant apps or services that need to talk to more than one database.

View on GitHub
Deep Wiki
Context7

Getting Started

First, reconcile the mismatch: this is a Symfony bundle, not a Laravel package. There is no ConnectionServiceProvider, no config/connection.php to publish, no facade, and no composer require that resolves cleanly against Laravel 10/11's PHP 8.1+ floor. Kitano\ConnectionBundle ships Symfony Bundle/DI extension classes and Doctrine ORM mappings. For a Laravel team there are exactly two honest starting points:

  1. Consume it from a Symfony service your Laravel app talks to over HTTP/queue — only worth it if you already run one.
  2. Treat it as a reference implementation and port the schema + manager into your own Eloquent package. This is the recommended default.

If you take the reference path, budget a 2–3 day spike before writing anything:

  1. Clone and read Resources/config/services.yml to find the manager service (typically kitano.connection.manager). That service is the entire API surface — read it first.
  2. Read the Connection entity mapping. It is the whole point of the package: a polymorphic adjacency edge — sourceType, sourceId, destinationType, destinationId, and a type/name discriminator on one table. That schema is the deliverable.
  3. Read the repository and any traversal code. Note whether traversal is query-per-hop or load-all-then-walk; this determines whether you can port it or should reimplement BFS.
  4. Check composer.json. PHP/Symfony/Doctrine constraints from the Symfony 2.x era will frequently hard-conflict with modern stacks. Clear this gate in an hour or don't start.

First use case for the ported version: you need a many-to-many relation to objects of other classes and don't want a join table per combination. "Tag this Post with these Tags", "User likes this Comment", "Attachment belongs to this Invoice" — one connections table, one service, done.

Implementation Patterns

Model the edge explicitly, don't hide it behind a relation. The core schema for the Eloquent port:

Schema::create('connections', function (Blueprint $t) {
    $t->id();
    $t->string('source_type');
    $t->unsignedBigInteger('source_id');
    $t->string('target_type');
    $t->unsignedBigInteger('target_id');
    $t->string('type');          // 'follow', 'like', 'tagged-with' …
    $t->json('meta')->nullable(); // direction, weight, timestamps, etc.
    $t->timestamps();
    $t->unique(['source_type','source_id','target_type','target_id','type'], 'conn_unique');
    $t->index(['source_type','source_id','type'], 'conn_out');
    $t->index(['target_type','target_id','type'], 'conn_in');
});

The unique index prevents duplicate parallel edges; the two composite indexes cover outbound and inbound adjacency lookups — the two query patterns you will actually issue.

Route every write through a service, never the model. A Laravel port wants a small ConnectionService (bound as a singleton in a provider) exposing:

$edges->connect($post, $tag, 'tagged-with', ['weight' => 3]);
$edges->disconnect($post, $tag, 'tagged-with');
$edges->targets($post, 'tagged-with');          // direct edges only
$edges->sources($user, 'follow');

Model-level create() calls on the edge table are how you end up with orphaned rows and duplicate edges — the service is the enforcement point.

Namespace your edge types religiously. A shared table with follow, like, parent-of, and tagged-with in the type column gets unreadable fast. Every read and write goes through the typed methods above; never let a bare where('type', ...) leak into a controller.

Traverse breadth-first with a visited set and a hard max-depth. If the ported code has a traversal method, verify it has both. Your own guard:

public function reachable($start, string $type, int $maxDepth = 3): Collection
{
    $seen    = collect([spl_object_id($start)]);
    $frontier = collect([$start]);
    $depth   = 0;
    while ($frontier->isNotEmpty() && $depth++ < $maxDepth) {
        $next = $this->targetsForMany($frontier, $type);
        $next = $next->reject(fn ($n) => $seen->contains(spl_object_id($n)));
        $seen = $seen->merge($next->map(fn ($n) => spl_object_id($n)));
        $frontier = $next;
    }
    return $seen;
}

Batch per hop, don't loop. targetsForMany() should issue a single whereIn keyed on (source_type, source_id) pairs — per-object targets() calls in a loop is the N+1 that makes adjacency tables look slow.

Use it as the substrate for feature after feature. Once the edge table exists and the service is in place, the tag/follow/like/related-product features stop requiring new migrations. This is the whole ROI argument for the pattern — it pays out on the fourth relationship, not the first.

Gotchas and Tips

  • The PHP/Doctrine gate is a stop sign, not a speed bump. Check the floor before any port work. If you find yourself planning a Doctrine-plus-Eloquent coexistence layer, stop — that "bridge" becomes permanent and doubles the persistence surface.
  • Polymorphic edges cannot carry foreign keys. Deleting a Post leaves its edges in place. Add an application-level cascade on delete (or a model observer on every connectable class) and a scheduled integrity job. Instrument for orphan rows; they silently inflate traversal counts.
  • Cycles produce infinite traversal, not an error. Enforce the visited set plus the max-depth guard, and alert when the depth limit is hit — silent truncation looks like "no results" in production.
  • Unbounded fan-out is the other footgun. A popular user with 500k followers will OOM a naive targets() call. Cap per-node expansion and paginate wide nodes at the service layer, not the view.
  • There is no upstream maintenance path. 13 stars, 0 dependents, dormant vendor org. If you fork, name an owner, put it in org-controlled VCS, add declare(strict_types=1), add a test suite + CI matrix (PHP 8.1+, Laravel 10/11), and verify the license before vendoring. No CVE feed means no patches arrive unprompted.
  • Do not add it to composer.json on modern Symfony or Laravel. Constraint resolution alone will exceed the cost of writing the edge table — the abstraction is thinner than the integration tax.
  • This is a shallow-graph tool. It handles adjacency lookups. It does not handle shortest path, transitive closure, or ranking over millions of edges — for those, use PostgreSQL recursive CTEs (or staudenmeir/laravel-adjacency-list), or a graph store.
  • Cache hot neighborhoods, invalidate on write. The service is the single place both writes and cache busts belong; a TTL alone will hand users stale adjacency.
  • Skip it entirely if you have one or two stable relations. morphToMany and native join tables already solve the small case, are supported, and are free. The generic edge model earns its keep when relationship types keep appearing — not before.
  • Write the ADR. Undocumented ported vendor code raises the onboarding tax for every engineer who later touches the graph path. Document the schema, the guardrails, and the fork owner as a condition of adoption.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource