A powerful Laravel package to handle ownership relationships between Eloquent models with flexibility, history tracking, and automatic cleanup.
Everything you need to manage ownership relationships in your Laravel application
Any model can own any other model with polymorphic relationships
Seamlessly transfer ownership between different owners
Keep track of ownership changes over time with historical records
Easily retrieve the current owner of any ownable item
Automatically clean up ownership records when models are deleted
Use the convenient Owner facade for ownership operations
Make sure your environment meets these requirements
PHP ^8.0 or higher
Laravel ^9.0, ^10.0, ^11.0, or ^12.0
Get started with Laravel Ownable in just a few steps
Add the package to your Laravel project using Composer:
composer require sowailem/ownable
Publish the migration file to create the ownerships table:
php artisan vendor:publish --provider="Sowailem\Ownable\OwnableServiceProvider" --tag="ownable-migrations"
Execute the migration to create the database table:
php artisan migrate
Learn how to implement ownership relationships in your models
First, implement the contracts and use the traits in your models:
<?php
use Sowailem\Ownable\Traits\HasOwnables;
use Sowailem\Ownable\Contracts\Owner as OwnerContract;
class User extends Authenticatable implements OwnerContract
{
use HasOwnables;
// Your existing model code...
}
<?php
use Sowailem\Ownable\Traits\IsOwnable;
use Sowailem\Ownable\Contracts\Ownable as OwnableContract;
class Post extends Model implements OwnableContract
{
use IsOwnable;
// Your existing model code...
}
There are multiple ways to assign ownership:
$user = User::first();
$post = Post::first();
// Method 1: Using owner model
$user->giveOwnershipTo($post);
// Method 2: Using ownable model
$post->ownedBy($user);
// Method 3: Using facade
Owner::give($user, $post);
Verify if a user owns a specific item:
// Method 1: Using owner model
if ($user->owns($post)) {
// User owns this post
}
// Method 2: Using ownable model
if ($post->isOwnedBy($user)) {
// Post is owned by this user
}
// Method 3: Using facade
if (Owner::check($user, $post)) {
// Check ownership using facade
}
Transfer ownership from one user to another:
$newOwner = User::find(2);
// Method 1: Using current owner
$user->transferOwnership($post, $newOwner);
// Method 2: Using ownable model
$post->transferOwnershipTo($newOwner);
// Method 3: Using facade
Owner::transfer($user, $newOwner, $post);
// Get all items owned by a user
$ownedItems = $user->ownables()->get();
// Get current owner of an item
$currentOwner = $post->currentOwner();
// Get all owners (including historical)
$allOwners = $post->owners()->get();
// Get only current owners
$currentOwners = $post->owners()->wherePivot('is_current', true)->get();
// Get ownership history
$ownershipHistory = $post->ownerships()->with('owner')->get();
// Remove ownership completely
$user->takeOwnershipFrom($post);
// This will delete the ownership record entirely
Complete reference for all available methods and classes
Methods available on owner models that use the HasOwnables trait:
Get all ownership records where this model is the owner.
Get all ownable entities owned by this owner.
Check if this owner owns the given ownable entity.
Give ownership of an ownable entity to this owner.
Remove ownership of an ownable entity from this owner.
Transfer ownership of an ownable entity to a new owner.
Methods available on ownable models that use the IsOwnable trait:
Get all ownership records for this ownable entity.
Get all owners of this ownable entity.
Get the current owner of this ownable entity.
Assign ownership of this entity to the given owner.
Check if this entity is owned by the given owner.
Transfer ownership of this entity to a new owner.
Static methods available via the Owner facade:
Give ownership of an ownable entity to an owner.
Check if an owner owns a specific ownable entity.
Transfer ownership of an ownable entity from one owner to another.
The package creates an ownerships
table with the following structure:
Column | Type | Description |
---|---|---|
id | bigint | Primary key |
owner_id | bigint | ID of the owner model |
owner_type | varchar | Class name of the owner model |
ownable_id | bigint | ID of the ownable model |
ownable_type | varchar | Class name of the ownable model |
is_current | boolean | Flag indicating if this is the current ownership |
created_at | timestamp | When ownership was created |
updated_at | timestamp | When ownership was last updated |
Real-world scenarios and use cases
A complete example of implementing ownership in a blog system where users can own posts and transfer them to other users:
// User.php
class User extends Authenticatable implements OwnerContract
{
use HasOwnables;
protected $fillable = ['name', 'email', 'password'];
}
// Post.php
class Post extends Model implements OwnableContract
{
use IsOwnable;
protected $fillable = ['title', 'content', 'published_at'];
}
// Create a new post and assign ownership
$user = User::find(1);
$post = Post::create([
'title' => 'My First Blog Post',
'content' => 'This is the content of my blog post...',
'published_at' => now()
]);
// Assign ownership
$post->ownedBy($user);
// Or using the owner model
$user->giveOwnershipTo($post);
// PostController.php
public function edit(Post $post)
{
// Check if current user owns the post
if (!auth()->user()->owns($post)) {
abort(403, 'You do not own this post.');
}
return view('posts.edit', compact('post'));
}
public function transfer(Post $post, User $newOwner)
{
// Transfer ownership
if (auth()->user()->owns($post)) {
$post->transferOwnershipTo($newOwner);
return redirect()->back()->with('success', 'Post transferred successfully!');
}
return redirect()->back()->with('error', 'You cannot transfer this post.');
}
Managing product ownership in a multi-vendor e-commerce platform:
// Vendor.php
class Vendor extends Model implements OwnerContract
{
use HasOwnables;
protected $fillable = ['name', 'email', 'store_name'];
public function products()
{
return $this->ownables()->where('ownable_type', Product::class);
}
}
// Product.php
class Product extends Model implements OwnableContract
{
use IsOwnable;
protected $fillable = ['name', 'description', 'price', 'stock'];
public function vendor()
{
return $this->currentOwner();
}
}
// Create product and assign to vendor
$vendor = Vendor::find(1);
$product = Product::create([
'name' => 'Wireless Headphones',
'description' => 'High-quality wireless headphones...',
'price' => 99.99,
'stock' => 50
]);
$product->ownedBy($vendor);
// Get all products for a vendor
$vendorProducts = $vendor->products()->get();
// Transfer product to another vendor
$newVendor = Vendor::find(2);
$product->transferOwnershipTo($newVendor);
Managing file ownership with history tracking:
// File.php
class File extends Model implements OwnableContract
{
use IsOwnable;
protected $fillable = ['name', 'path', 'size', 'mime_type'];
public function getOwnershipHistory()
{
return $this->ownerships()
->with('owner')
->orderBy('created_at', 'desc')
->get();
}
}
// Usage
$file = File::find(1);
$history = $file->getOwnershipHistory();
foreach ($history as $ownership) {
echo "Owned by: " . $ownership->owner->name . " from " . $ownership->created_at;
}
Optional configuration for advanced usage
You can publish the configuration file to customize the package behavior:
php artisan vendor:publish --provider="Sowailem\Ownable\OwnableServiceProvider" --tag="ownable-config"
Default owner model class (default: 'App\Models\User')
Default ownable model class (default: 'App\Models\Model')
Database table name for ownership records (default: 'ownerships')