---
title: "Connectable models — Connections for Laravel | Roundly"
description: "Add the HasConnections trait and Connectable contract to any model, scaffold with make:connectable, and use the trait verbs."
url: https://roundly-consulting.com/open-source/docs/connections-for-laravel/connectable-models
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Connections for Laravel](https://roundly-consulting.com/open-source/docs/connections-for-laravel.md)

# Connectable models

Add the HasConnections trait and implement the Connectable contract on every model that should take part in connections:

```php
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:

```php
$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

```bash
php artisan make:connectable Organisation        # writes app/Models/Organisation.php
php artisan make:connectable User --existing      # prints the lines to add to an existing model
```

Without --existing, the command writes a new model — into app/Models when that directory exists — that already uses the trait and implements the contract:

```php
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:

```php
$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 crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## 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.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/connections-for-laravel.md)
