dibakar / laravel-ownership
Flexible ownership management package for Laravel with single & multiple ownership support. with traits, scopes, and policies.
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/dibakar/laravel-ownership
Requires
- php: ^8.1
- illuminate/contracts: ^9.0|^10.0|^11.0|^12.0
- illuminate/database: ^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^7.0|^8.0
This package is auto-updated.
Last update: 2025-10-16 11:27:21 UTC
README
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.
Features
- Dual Ownership Modes: Support for both single and multiple ownership models
- Role-based Access Control: Define custom roles with specific permissions
- Flexible Configuration: Highly customizable to fit any application needs
- Event-driven Architecture: Built-in events for all ownership changes
- Powerful Query Scopes: Filter models by ownership with ease
- Performance Optimized: Built-in caching for ownership checks
- Type Safety: Strict type declarations and modern PHP features
- Laravel Integration: Seamless integration with Laravel's authentication system
- Morphable Owners: Support for any model as an owner
- Bulk Operations: Manage multiple owners at once with sync methods
- Bidirectional Relationships: Both owners and ownable models have access to each other
Installation
- Install the package via Composer:
composer require dibakar/laravel-ownership
- Publish the configuration file:
php artisan vendor:publish --provider="Dibakar\\Ownership\\OwnershipServiceProvider" --tag=config
- Publish and run the migrations:
php artisan vendor:publish --provider="Dibakar\\Ownership\\OwnershipServiceProvider" --tag=migrations
php artisan migrate
IsOwner Trait Methods
Check Ownership
// 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 Owned Items
// 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 Ownership
// Transfer all documents to another user $user->transferOwnershipTo($newUser); // Transfer only specific type of items $user->transferOwnershipTo($newUser, Document::class);
Count Owned Items
// 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');
Ownership Relationship
// Get all ownership records $ownerships = $user->ownerships; // Get all owned items through the relationship $items = $user->ownerships->map->ownable;
Configuration
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', ], ];
Usage
Single Ownership Mode
Basic Usage
For Ownable Models (Models that can be owned)
Add the HasOwnership
trait to your model:
use Illuminate\Database\Eloquent\Model; use Dibakar\Ownership\Traits\HasOwnership; class Document extends Model { use HasOwnership; // ... }
For Owner Models (Models that can own other models)
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();
Multiple Ownership Mode
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; // ... }
Managing Multiple Owners
// 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();
Events
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 });
Middleware
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 });
Blade Directives
{{-- 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
Events
The package dispatches several events that you can listen to:
Dibakar\Ownership\Events\OwnershipCreated
Dibakar\Ownership\Events\OwnershipUpdated
Dibakar\Ownership\Events\OwnershipDeleted
Dibakar\Ownership\Events\OwnershipTransferred
Example listener:
namespace App\Listeners; use Dibakar\Ownership\Events\OwnershipCreated; class LogOwnershipCreated { public function handle(OwnershipCreated $event) { // Handle the event } }
Testing
Run the tests with:
composer test
Security
If you discover any security related issues, please email dibakarmitra07@gmail.com instead of using the issue tracker.
License
Example Usage
User Model
use Illuminate\Foundation\Auth\User as Authenticatable; use Dibakar\Ownership\Traits\IsOwner; class User extends Authenticatable { use IsOwner; // ... }
Document Model
use Illuminate\Database\Eloquent\Model; use Dibakar\Ownership\Traits\HasOwnership; class Document extends Model { use HasOwnership; // ... }
Controller Example
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.
Contributing
Please see CONTRIBUTING for details.