Connectable models
Add the HasConnections trait and implement the Connectable contract on every model that should take part in connections:
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Connections\Concerns\HasConnections;
use RoundlyConsulting\Connections\Contracts\Connectable;
class User extends Model implements Connectable
{
use HasConnections;
}
class Team extends Model implements Connectable
{
use HasConnections;
}Connections are directed. The connector is the side that initiates the connection; the connectable is the side it points to. A model can be both — a user can connect to a team, and a team can connect to a project:
$user->connectTo($team, ['view']);
$user->hasPermissionThroughConnection($team, 'view'); // true — $user → $team exists
$team->hasPermissionThroughConnection($user, 'view'); // false — there is no $team → $user connection
$user->connections; // connections $user initiated (it is the connector)
$team->connectors; // connections pointing at $team (it is the connectable)Scaffold with make:connectable
php artisan make:connectable Organisation # writes app/Models/Organisation.php
php artisan make:connectable User --existing # prints the lines to add to an existing modelWithout --existing, the command writes a new model — into app/Models when that directory exists — that already uses the trait and implements the contract:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Connections\Concerns\HasConnections;
use RoundlyConsulting\Connections\Contracts\Connectable;
class Organisation extends Model implements Connectable
{
use HasConnections;
}Trait verbs
HasConnections exposes the same lifecycle as model methods — shorthand over the Connections facade. Every write goes through the ConnectionManager, so a manager you rebind and Connections::fake() see trait calls too:
$user->connectTo($team, ['view', 'edit'], now()->addMonth()); // Connection
$user->disconnectFrom($team); // void
$user->grantThroughConnection($team, 'publish'); // Connection
$user->revokeThroughConnection($team, 'publish'); // Connection
$user->syncConnectionPermissions($team, ['view']); // Connection
$user->clearConnectionPermissions($team); // Connection
$user->permissionsThroughConnection($team); // Collection<int, string>
$user->syncConnections([$teamA, $teamB]); // SyncResult| Method | Returns | Does |
|---|---|---|
connectTo($connectable, $permissions = null, $expiresAt = null, $meta = null) | Connection | Create the connection, or change only what you pass on the pair’s existing one. |
disconnectFrom($connectable) | void | Soft-delete; throws ConnectionNotFound when there is none. |
toggleConnection($connectable, $permissions = null) | ?Connection | Disconnect an active connection, otherwise connect. |
reconnectTo($connectable) | Connection | Restore the soft-deleted connection as it was, or connect afresh. |
inviteConnection($connectable) | Connection | Create a pending connection; throws InvalidStatusTransition over an accepted or blocked one. |
acceptConnectionFrom($connector) | Connection | Receiving side: accept the connection from $connector. |
blockConnectionFrom($connector) | Connection | Receiving side: block the connection from $connector. |
grantThroughConnection($connectable, ...$permissions) | Connection | Add permissions; creates the connection when absent. |
revokeThroughConnection($connectable, ...$permissions) | Connection | Remove permissions; throws ConnectionNotFound when absent. |
syncConnectionPermissions($connectable, $permissions) | Connection | Replace with exactly this set (array or Collection); creates when absent. |
clearConnectionPermissions($connectable) | Connection | Empty the permission set; throws ConnectionNotFound when there is no connection. |
syncConnections($connectables) | SyncResult | Reconcile the connector’s connections to exactly this set. |
permissionsThroughConnection($connectable) | Collection | The stored permission set, regardless of status. |
Checks (isConnectedTo(), hasPermissionThroughConnection() and friends) are covered in Permissions and Querying connections.
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 cryptoBy 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.