PHPackages                             vimatech/laravel-membership - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. vimatech/laravel-membership

ActiveLibrary[Database &amp; ORM](/categories/database)

vimatech/laravel-membership
===========================

Polymorphic memberships for Laravel.

v1.0.0(2w ago)380↓50%MITPHPPHP ^8.3CI passing

Since May 21Pushed 1w agoCompare

[ Source](https://github.com/vimatech-io/laravel-membership)[ Packagist](https://packagist.org/packages/vimatech/laravel-membership)[ RSS](/packages/vimatech-laravel-membership/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (8)Versions (5)Used By (0)

Laravel Membership
==================

[](#laravel-membership)

[![Tests](https://github.com/vimatech-io/laravel-membership/actions/workflows/tests.yml/badge.svg)](https://github.com/vimatech-io/laravel-membership/actions/workflows/tests.yml)[![PHPStan](https://github.com/vimatech-io/laravel-membership/actions/workflows/phpstan.yml/badge.svg)](https://github.com/vimatech-io/laravel-membership/actions/workflows/phpstan.yml)[![Pint](https://github.com/vimatech-io/laravel-membership/actions/workflows/pint.yml/badge.svg)](https://github.com/vimatech-io/laravel-membership/actions/workflows/pint.yml)[![Latest Version on Packagist](https://camo.githubusercontent.com/eadb78cf2c1a1a5df7fbc82b2cb9c715557e3e31b46bf80b36f6c005fe45f939/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f76696d61746563682f6c61726176656c2d6d656d626572736869702e737667)](https://packagist.org/packages/vimatech/laravel-membership)[![Total Downloads](https://camo.githubusercontent.com/d608cc40149e6bd03c178b1b058f3f26a22028c518289c0f239243d59812cf65/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f76696d61746563682f6c61726176656c2d6d656d626572736869702e737667)](https://packagist.org/packages/vimatech/laravel-membership)[![License](https://camo.githubusercontent.com/dce833e83cf07cd0d76775711592ea177a7b5bad1a0146d699123bc43f687ae3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f76696d61746563682f6c61726176656c2d6d656d626572736869702e737667)](https://packagist.org/packages/vimatech/laravel-membership)

**Polymorphic memberships for Laravel.**

Laravel Membership lets you attach members and roles to any Eloquent model — organizations, teams, projects, workspaces, communities, or anything else.

It answers **who belongs to what** and **with which role** — nothing more.

Why Laravel Membership?
-----------------------

[](#why-laravel-membership)

Most Laravel apps eventually need to answer:

- Who belongs to this organization?
- What role does this user have in this project?
- Can we prevent removing the last owner?
- Can the same membership logic work for teams, projects and workspaces?

Laravel Membership provides a small backend-only layer for that.

Feature Matrix
--------------

[](#feature-matrix)

FeatureSupportedPolymorphic memberships✅Enum roles✅Role hierarchy✅Guards (last owner, etc.)✅Events✅Scopes✅Soft deletes✅Policy helpers✅Invitations❌Permissions❌ (use Spatie)Billing❌UI❌Laravel Membership vs Permissions
---------------------------------

[](#laravel-membership-vs-permissions)

Laravel Membership manages:

- **who** belongs to **what**
- **which role** they have

Permission packages (like Spatie) manage:

- **what** users **can do**

They are complementary, not competing.

Use Cases
---------

[](#use-cases)

- SaaS organizations
- Teams
- Projects
- Workspaces
- Communities
- Collaborative apps
- Multi-tenant applications
- Agency client portals
- Internal company tools

Installation
------------

[](#installation)

### Requirements

[](#requirements)

- PHP 8.3+
- Laravel 11, 12 or 13

```
composer require vimatech/laravel-membership
```

### Publish config

[](#publish-config)

```
php artisan vendor:publish --tag=membership-config
```

### Publish migrations

[](#publish-migrations)

```
php artisan vendor:publish --tag=membership-migrations
php artisan migrate
```

Usage
-----

[](#usage)

### Make a model have members

[](#make-a-model-have-members)

```
use Vimatech\Membership\Concerns\HasMembers;

class Organization extends Model
{
    use HasMembers;
}
```

### Make a model act as a member

[](#make-a-model-act-as-a-member)

```
use Vimatech\Membership\Concerns\HasMemberships;

class User extends Authenticatable
{
    use HasMemberships;
}
```

### Create a roles enum (optional)

[](#create-a-roles-enum-optional)

```
use Vimatech\Membership\Contracts\MembershipRole;

enum OrganizationRole: string implements MembershipRole
{
    case Owner = 'owner';
    case Admin = 'admin';
    case Member = 'member';

    public function level(): int
    {
        return match ($this) {
            self::Owner => 100,
            self::Admin => 50,
            self::Member => 10,
        };
    }

    public function label(): string
    {
        return match ($this) {
            self::Owner => 'Owner',
            self::Admin => 'Admin',
            self::Member => 'Member',
        };
    }
}
```

You can also use plain strings — enums are optional.

### Add a member

[](#add-a-member)

```
$organization->addMember($user, OrganizationRole::Owner);

// With metadata
$organization->addMember($user, OrganizationRole::Member, metadata: ['source' => 'invitation']);

// With invited_by
$organization->addMember($user, OrganizationRole::Member, invitedBy: $currentUser);
```

### Remove a member

[](#remove-a-member)

```
$organization->removeMember($user);
```

### Update a role

[](#update-a-role)

```
$organization->updateMemberRole($user, OrganizationRole::Admin);
```

### Check membership

[](#check-membership)

```
// From entity side
$organization->hasMember($user);
$organization->isAdmin($user);
$organization->hasMemberWithRole($user, OrganizationRole::Owner);

// From member side
$user->isMemberOf($organization);
$user->hasRole($organization, OrganizationRole::Admin);
$user->hasAnyRole($organization, [OrganizationRole::Admin, OrganizationRole::Owner]);
$user->hasRoleAtLeast($organization, OrganizationRole::Member);
```

### Query members

[](#query-members)

```
$organization->members();
$organization->membersWithRole(OrganizationRole::Admin);
$organization->admins();
$organization->owners();
```

### Query memberships from member side

[](#query-memberships-from-member-side)

```
$user->memberships()->get();
$user->membershipFor($organization);
$user->ownedMemberships()->get();
$user->adminMemberships()->get();
$user->membershipables();
```

### Scopes

[](#scopes)

```
use Vimatech\Membership\Models\Membership;

Membership::forMember($user)->get();
Membership::forMembershipable($organization)->get();
Membership::withRole(OrganizationRole::Admin)->get();
Membership::withAnyRole([OrganizationRole::Admin, OrganizationRole::Owner])->get();
Membership::owners()->get();
Membership::admins()->get();
Membership::joined()->get();
Membership::recent()->get();
```

### Policy helpers

[](#policy-helpers)

```
use Vimatech\Membership\Support\MembershipGate;

// In a Policy
public function update(User $user, Project $project): bool
{
    return MembershipGate::for($user)->isAdmin($project);
}

public function delete(User $user, Organization $organization): bool
{
    return MembershipGate::for($user)->isOwner($organization);
}

public function view(User $user, Project $project): bool
{
    return MembershipGate::for($user)->isMemberOf($project);
}

// Check a specific role
MembershipGate::for($user)->hasRole($project, 'editor');
```

### Facade (optional)

[](#facade-optional)

```
use Vimatech\Membership\Facades\Membership;

Membership::add($user, $organization, 'admin');
Membership::remove($user, $organization);
Membership::has($user, $organization);
Membership::role($user, $organization); // returns 'admin'
```

Complete Example
----------------

[](#complete-example)

```
use Vimatech\Membership\Concerns\HasMembers;
use Vimatech\Membership\Concerns\HasMemberships;
use Vimatech\Membership\Contracts\MembershipRole;

// 1. Define your models
class Organization extends Model
{
    use HasMembers;
}

class User extends Authenticatable
{
    use HasMemberships;
}

// 2. Define your roles
enum OrganizationRole: string implements MembershipRole
{
    case Owner = 'owner';
    case Admin = 'admin';
    case Member = 'member';

    public function level(): int
    {
        return match ($this) {
            self::Owner => 100,
            self::Admin => 50,
            self::Member => 10,
        };
    }

    public function label(): string
    {
        return $this->name;
    }
}

// 3. Use it
$organization = Organization::create(['name' => 'Vimatech']);
$user = User::create(['name' => 'Adel']);

$organization->addMember($user, OrganizationRole::Owner);

$user->isMemberOf($organization);                              // true
$user->hasRole($organization, OrganizationRole::Owner);        // true
$user->hasRoleAtLeast($organization, OrganizationRole::Admin); // true

$organization->isAdmin($user);  // true (owner is admin)
$organization->owners();        // Collection with $user
```

Events
------

[](#events)

The following events are dispatched:

EventWhen`MemberAdded`After a member is added`MemberRemoved`After a member is removed`MemberRoleUpdated`After a member's role is changedEach event contains the `Membership` instance and an optional `$actor`.

Guards
------

[](#guards)

Guards are configurable protections in `config/membership.php`:

```
'guards' => [
    'prevent_removing_last_owner' => true,   // Enabled by default
    'prevent_removing_last_admin' => false,
    'prevent_self_demotion' => false,
    'prevent_role_escalation' => false,
],
```

When `prevent_self_demotion` or `prevent_role_escalation` are enabled, pass an `$actor`:

```
$organization->updateMemberRole(
    member: $user,
    role: OrganizationRole::Member,
    actor: $currentUser,
);
```

Configuration
-------------

[](#configuration)

```
// config/membership.php

return [
    'models' => [
        'membership' => \Vimatech\Membership\Models\Membership::class,
    ],

    'tables' => [
        'memberships' => 'memberships',
    ],

    // Fallback role levels (used when roles are plain strings)
    'roles' => [
        'owner' => 100,
        'admin' => 50,
        'member' => 10,
    ],

    'owner_roles' => ['owner'],
    'admin_roles' => ['owner', 'admin'],

    'guards' => [
        'prevent_removing_last_owner' => true,
        'prevent_removing_last_admin' => false,
        'prevent_self_demotion' => false,
        'prevent_role_escalation' => false,
    ],

    'soft_deletes' => false,
];
```

Soft Deletes
------------

[](#soft-deletes)

By default, removing a member permanently deletes the row. To keep membership history instead, enable soft deletes:

1. Set `'soft_deletes' => true` in `config/membership.php`
2. If your app is already in production, create a migration:

```
php artisan make:migration add_soft_deletes_to_memberships_table
```

```
Schema::table('memberships', function (Blueprint $table) {
    $table->softDeletes();
});
```

> If you enable `soft_deletes` **before** running your initial migration, the column is added automatically.

Once enabled:

```
$organization->removeMember($user); // soft deletes (sets deleted_at)

$membership = Membership::withoutGlobalScopes()->forMember($user)->first();
$membership->restore();             // restores the membership
$membership->forceDelete();         // permanently deletes
$membership->trashed();             // true if soft deleted
```

Philosophy
----------

[](#philosophy)

Laravel Membership is intentionally minimal.

The package focuses on:

- Memberships
- Roles
- Role hierarchy
- Membership guards

Design principles:

- Backend-only, UI agnostic
- No auth assumptions
- No User model assumptions
- No permissions system
- No billing assumptions
- Enum-friendly roles
- Polymorphic by default
- Laravel-native API
- Clean and testable actions

It does not aim to become a permissions framework, a billing system, a UI framework, or a complete SaaS platform.

Possible Future Extensions
--------------------------

[](#possible-future-extensions)

- Invitation bridge
- Audit logs
- Membership expiration
- Filament integrations
- Livewire components

Future extensions may be released as separate packages to keep the core package small and focused.

Testing
-------

[](#testing)

```
composer test
```

Contributing
------------

[](#contributing)

Contributions are welcome.

Please ensure:

- Tests pass (`composer test`)
- PHPStan passes (`composer analyse`)
- Code style is formatted with Pint (`composer format`)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

Credits
-------

[](#credits)

Built and maintained by [Vimatech](https://vimatech.io). Created by [Adel Zemzemi](https://github.com/adelzemzemi).

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance97

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 85.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

19d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3283664f06a0db1bfdbf282b2691363365c2f73569bcd99d63f5aaa52900ff55?d=identicon)[adelzemzemi](/maintainers/adelzemzemi)

---

Top Contributors

[![adelzemzemi](https://avatars.githubusercontent.com/u/272534830?v=4)](https://github.com/adelzemzemi "adelzemzemi (6 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

eloquentlaravellaravel-packagemembershipmulti-tenantorganizationsphprolessaasteamslaravelrolesmembershipTeamspolymorphicorganizations

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/vimatech-laravel-membership/health.svg)

```
[![Health](https://phpackages.com/badges/vimatech-laravel-membership/health.svg)](https://phpackages.com/packages/vimatech-laravel-membership)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k51.0M7.4k](/packages/larastan-larastan)[laravel/ai

The official AI SDK for Laravel.

9782.1M153](/packages/laravel-ai)[spatie/laravel-health

Monitor the health of a Laravel application

88011.3M149](/packages/spatie-laravel-health)[watson/validating

Eloquent model validating trait.

9743.4M53](/packages/watson-validating)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

436834.4k1](/packages/clickbar-laravel-magellan)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
