NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Connections for Laravel

Querying connections

Ask either side of a connection:

$user->isConnectedTo($team);                       // bool
$user->isConnectedToAny($team->getMorphClass());   // bool
$team->hasConnector($user);                        // bool
$team->hasConnectorFromAny($user->getMorphClass());// bool

$user->connections;  // connections this model initiated
$team->connectors;   // connections pointing at this model
  • isConnectedTo(), isConnectedToAny(), hasConnector() and hasConnectorFromAny() count only active connections while enforce_active_on_check is on.
  • isConnectedToAny() and hasConnectorFromAny() take a morph type — pass $model->getMorphClass() so morph-map aliases resolve.
  • connections and connectors are plain MorphMany relations over every non-deleted row, whatever its status — chain constraints and eager-load the other side through them.
$user->connections()->with('connectable')->get();   // eager-load the other side
$team->connectors()->with('connector')->get();
$team->connectors()->where('status', 'pending')->count();

Scopes & constrained relations

// Constrained relations (return MorphMany you can chain ->get()/->count()).
$user->activeConnections();                 // accepted + not expired
$user->expiredConnections();                // past expiry
$user->expiringConnections($days = 7);      // expiring within N days
$user->connectionsWithPermission('publish'); // honours '*' / 'posts.*'; active only while enforced

// Eloquent scopes on the model / relation.
$user->connections()->active()->get();
$user->connections()->expiringSoon(14)->get();
$user->connections()->withPermission('posts.edit')->get(); // exact, '*', 'posts.*' — any status

// Across every connector.
Connections::expiring(14)->get();
ScopeTrait relationMatches
active()activeConnections()Status accepted and expires_at null or in the future.
expired()expiredConnections()expires_at set and in the past, whatever the status.
expiringSoon($days = 7)expiringConnections($days = 7)expires_at within the next N days.
withPermission($permission)connectionsWithPermission($permission)A stored permission grants it — the exact string, * or a trailing segment wildcard such as posts.*. The scope matches any status; the relation counts only active connections while enforce_active_on_check is on.

The scopes are regular Eloquent scopes on the Connection model, so they work on any query:

use RoundlyConsulting\Connections\Models\Connection;

Connection::query()->active()->withPermission('publish')->count();
Connection::query()->expiringSoon(3)->with(['connector', 'connectable'])->get();

Typed fetches

connectablesOfType() and connectorsOfType() return the connected models themselves instead of Connection rows. Pass a fully-qualified class name or a registered morph alias:

// Fetch the connected models of a given type (FQCN or morph alias), not the Connection rows.
// Like isConnectedTo() / hasConnector(), only active links count while enforce_active_on_check is on.
$user->connectablesOfType(Team::class);   // Collection<Team>
$user->connectablesOfType('team');        // the same, via a morph-map alias
$team->connectorsOfType(User::class);     // Collection<User>

Like isConnectedTo() and hasConnector(), typed fetches only count active links while enforce_active_on_check is on; with the flag off they include every non-deleted connection of that type.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.