Flexible ownership management package for Laravel with single & multiple ownership support. with traits, scopes, and policies.
dibakar/laravel-ownership is a Laravel package for flexible ownership management package for laravel with single & multiple ownership support. with traits, scopes, and policies..
It currently has 2 GitHub stars and 3 downloads on Packagist (latest version v1.0.1).
Install it with composer require dibakar/laravel-ownership.
Discover more Laravel packages by dibakar
or browse all Laravel packages to compare alternatives.
Last updated
A comprehensive ownership management system for Laravel applications. This package provides an elegant way to handle both single and multiple ownership scenarios with role-based permissions, events, and query scopes.
composer require dibakar/laravel-ownership
php artisan vendor:publish --provider="Dibakar\\Ownership\\OwnershipServiceProvider" --tag=config
php artisan vendor:publish --provider="Dibakar\\Ownership\\OwnershipServiceProvider" --tag=migrations
php artisan migrate
// Check if the user owns a document
$user->owns($document);
// Check if the user owns a document with a specific role
$user->owns($document, 'admin');
// Get all documents owned by the user
$documents = $user->getOwnedItems(Document::class);
// Get all documents where user has a specific role
$adminDocuments = $user->getOwnedItems(Document::class, 'admin');
// Transfer all documents to another user
$user->transferOwnershipTo($newUser);
// Transfer only specific type of items
$user->transferOwnershipTo($newUser, Document::class);
// Count all owned items
$count = $user->countOwnedItems();
// Count items of a specific type
$docCount = $user->countOwnedItems(Document::class);
// Count items with a specific role
$adminDocCount = $user->countOwnedItems(Document::class, 'admin');
// Get all ownership records
$ownerships = $user->ownerships;
// Get all owned items through the relationship
$items = $user->ownerships->map->ownable;
The configuration file (config/ownership.php) allows you to customize various aspects of the package. Here are the main configuration options:
return [
/*
|--------------------------------------------------------------------------
| Morph Name
|--------------------------------------------------------------------------
|
| This is the name of the polymorphic relationship used for ownership.
| You can change this to 'user', 'team', 'organization', etc.
*/
'morph_name' => 'owner',
/*
|--------------------------------------------------------------------------
| Global Scope
|--------------------------------------------------------------------------
|
| When enabled, a global scope will be applied to automatically scope
| queries to the current owner in single ownership mode.
*/
'apply_global_scope' => true,
/*
|--------------------------------------------------------------------------
| Authentication Guard
|--------------------------------------------------------------------------
|
| The authentication guard used to retrieve the currently authenticated user.
*/
'guard' => 'web',
/*
|--------------------------------------------------------------------------
| Ownership Mode
|--------------------------------------------------------------------------
|
| Set to 'single' for one owner per model or 'multiple' for many owners.
*/
'mode' => 'single',
/*
|--------------------------------------------------------------------------
| Cache Configuration
|--------------------------------------------------------------------------
*/
'cache' => [
'enabled' => true,
'ttl' => 3600, // Cache time-to-live in seconds
],
/*
|--------------------------------------------------------------------------
| Multiple Ownership Configuration
|--------------------------------------------------------------------------
*/
'multiple_ownership' => [
'table_name' => 'ownerships',
'roles' => [
'owner' => [
'display_name' => 'Owner',
'permissions' => ['*'], // Wildcard means all permissions
],
'editor' => [
'display_name' => 'Editor',
'permissions' => ['edit', 'view'],
],
'viewer' => [
'display_name' => 'Viewer',
'permissions' => ['view'],
],
],
'default_role' => 'viewer',
],
];
Add the HasOwnership trait to your model:
use Illuminate\Database\Eloquent\Model;
use Dibakar\Ownership\Traits\HasOwnership;
class Document extends Model
{
use HasOwnership;
// ...
}
Add the IsOwner trait to models that can own other models (like User, Team, etc.):
use Illuminate\Database\Eloquent\Model;
use Dibakar\Ownership\Traits\IsOwner;
class User extends Authenticatable
{
use IsOwner;
// ...
}
class Post extends Model { use HasOwnership;
// ...
}
#### Basic Operations
```php
// Creating a new post with the current user as owner
$post = Post::create([
'title' => 'My First Post',
'content' => 'This is my first post.'
]);
// Explicitly set the owner
$post->setOwner($user);
// Check ownership
if ($post->isOwnedBy($user)) {
// User owns the post
}
// Get the owner
$owner = $post->owner;
// Transfer ownership
$post->transferOwnership($currentOwner, $newOwner);
// Clear the owner
$post->clearOwner();
First, update your config to use multiple ownership mode:
// config/ownership.php
return [
'mode' => 'multiple',
// ... rest of the config
];
Then add the HasOwnership trait to your model:
use Illuminate\Database\Eloquent\Model;
use Dibakar\Ownership\Traits\HasOwnership;
class Project extends Model
{
use HasOwnership;
// ...
}
// Add an owner with a specific role
$project->addOwner($user, 'owner');
// Add multiple owners at once
$project->addOwners([$user1, $user2, $user3], 'editor', ['custom_permission']);
// Remove an owner
$project->removeOwner($user);
// Check if a user is an owner
if ($project->hasOwner($user)) {
// User is an owner
}
// Get all owners with their roles
$owners = $project->getOwners();
// Get owners with a specific role
$editors = $project->getOwnersWithRole('editor');
// Check if a user has a specific role
if ($project->hasOwnerWithRole($user, 'admin')) {
// User has admin role
}
// Update a user's role
$project->updateOwnerRole($user, 'admin');
// Sync owners (removes any owners not in the list)
$project->syncOwners([
$user1,
$user2,
$user3,
], 'owner');
// Clear all owners
$project->clearAllOwners();
}
### Query Scopes
The package provides several query scopes to filter models by ownership:
```php
// Get all posts owned by the current user
$posts = Post::ownedByCurrent()->get();
// Get all posts owned by a specific user
$userPosts = Post::ownedBy($user)->get();
// In multiple ownership mode, get projects where user has a specific role
$projects = Project::whereHasOwnerWithRole($user, 'editor')->get();
// Get models where user has specific permission
$editablePosts = Post::whereUserHasPermission($user, 'edit')->get();
The package dispatches events when ownership changes occur:
use Dibakar\Ownership\Events\OwnershipCreated;
use Dibakar\Ownership\Events\OwnershipUpdated;
use Dibakar\Ownership\Events\OwnershipDeleted;
use Dibakar\Ownership\Events\OwnershipTransferred;
// Listen for ownership events
Event::listen(OwnershipCreated::class, function (OwnershipCreated $event) {
$model = $event->model;
$owner = $event->owner;
$role = $event->role;
// Handle the event
});
Protect your routes with the ownership middleware:
// routes/web.php
Route::middleware(['auth', 'ownership:post,edit'])
->group(function () {
Route::get('/posts/{post}/edit', 'PostController@edit');
Route::put('/posts/{post}', 'PostController@update');
});
// With custom ownership check
Route::middleware(['auth', 'ownership:post,edit,App\Policies\CustomPostPolicy'])
->group(function () {
// Your routes
});
{{-- Check if current user owns the model --}}
@owned($post)
<a href="{{ route('posts.edit', $post) }}">Edit</a>
@endowned
{{-- Check specific user ownership --}}
@owned($post, $specificUser)
<span>Owned by {{ $specificUser->name }}</span>
@endowned
{{-- Check if user has specific permission --}}
@can('edit', $post)
<a href="{{ route('posts.edit', $post) }}">Edit</a>
@endcan
@owned($model, $user = null)
This content is only visible to the owner
@endowned
@canOwn($model, 'edit', $user = null)
This content is only visible to users with edit permission
@endCanOwn
@isOwner($model, $user = null)
This content is only visible to an owner
@endIsOwner
The package dispatches several events that you can listen to:
Dibakar\Ownership\Events\OwnershipCreatedDibakar\Ownership\Events\OwnershipUpdatedDibakar\Ownership\Events\OwnershipDeletedDibakar\Ownership\Events\OwnershipTransferredExample listener:
namespace App\Listeners;
use Dibakar\Ownership\Events\OwnershipCreated;
class LogOwnershipCreated
{
public function handle(OwnershipCreated $event)
{
// Handle the event
}
}
Run the tests with:
composer test
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
use Illuminate\Foundation\Auth\User as Authenticatable;
use Dibakar\Ownership\Traits\IsOwner;
class User extends Authenticatable
{
use IsOwner;
// ...
}
use Illuminate\Database\Eloquent\Model;
use Dibakar\Ownership\Traits\HasOwnership;
class Document extends Model
{
use HasOwnership;
// ...
}
class DocumentController extends Controller
{
public function store(Request $request)
{
$document = Document::create($request->all());
// Set the current user as the owner with admin role
$document->addOwner(auth()->user(), 'admin');
return response()->json($document, 201);
}
public function transfer(Document $document, User $newOwner)
{
$this->authorize('update', $document);
// Transfer ownership
$document->getOwner()->transferOwnershipTo($newOwner);
return response()->json(['message' => 'Ownership transferred']);
}
}
The MIT License (MIT). Please see License File for more information.
Please see CONTRIBUTING for details.