├── CHANGELOG.md ├── LICENSE ├── README.md ├── UPGRADING.md ├── composer.json ├── contracts ├── CanBeOwner.php ├── Exceptions │ ├── InvalidDefaultOwner.php │ └── InvalidOwnerType.php └── Ownable.php └── src ├── Observers └── OwnableObserver.php ├── Providers └── OwnershipServiceProvider.php └── Traits ├── HasMorphOwner.php └── HasOwner.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `cybercog/laravel-ownership` are documented in [Laravel Ownership releases] page. 4 | 5 | [Laravel Ownership releases]: https://github.com/cybercog/laravel-ownership/releases 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020, Anton Komarev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![cog-laravel-ownership](https://cloud.githubusercontent.com/assets/1849174/21737911/ee344682-d48e-11e6-9ace-eea37026ae6d.png) 2 | 3 |

4 | Discord 5 | Build 6 | StyleCI 7 | Releases 8 | License 9 |

10 | 11 | ## Introduction 12 | 13 | Laravel Ownership simplify management of Eloquent model's owner. 14 | Group can be an owner of event, user can be an owner of chat room, organization can own licenses. 15 | It can be used for many cases not limited by authorship. 16 | Make any model as owner and create ownable models in a minutes! 17 | 18 | ## Contents 19 | 20 | - [Features](#features) 21 | - [Installation](#installation) 22 | - [Usage](#usage) 23 | - [Prepare ownable model with strict ownership](#prepare-ownable-model-with-strict-ownership) 24 | - [Prepare ownable model with polymorphic ownership](#prepare-ownable-model-with-polymorphic-ownership) 25 | - [Available methods](#available-methods) 26 | - [Scopes](#scopes) 27 | - [Set authenticated user as owner automatically](#set-authenticated-user-as-owner-automatically) 28 | - [Changelog](#changelog) 29 | - [Upgrading](#upgrading) 30 | - [Contributing](#contributing) 31 | - [Testing](#testing) 32 | - [Security](#security) 33 | - [Credits](#credits) 34 | - [Alternatives](#alternatives) 35 | - [License](#license) 36 | - [About CyberCog](#about-cybercog) 37 | 38 | ## Features 39 | 40 | - Designed to work with Laravel Eloquent models 41 | - Using contracts to keep high customization capabilities 42 | - Each model can has owners of one type or use polymorphism 43 | - Option to auto-assigning current authenticated user on model creation as owner 44 | - Configurable auto-owner resolve strategy on model creation 45 | - Option to manually assign owner on model creation 46 | - Option to manually skip auto-assigning current user 47 | - Transfer ownership (change owner) 48 | - Make model orphaned (abandon owner) 49 | - Various ownership checks and query scopes 50 | - Following PHP Standard Recommendations: 51 | - [PSR-2 (Coding Style Guide)](http://www.php-fig.org/psr/psr-2/). 52 | - [PSR-4 (Autoloading Standard)](http://www.php-fig.org/psr/psr-4/). 53 | - Covered with unit tests 54 | 55 | ## Installation 56 | 57 | First, pull in the package through Composer. 58 | 59 | ```shell 60 | composer require cybercog/laravel-ownership 61 | ``` 62 | 63 | #### Register Package Manually (optional) 64 | 65 | If you disabled package auto-discovery you can register it manually. 66 | 67 | Include the service provider within `app/config/app.php`. 68 | 69 | ```php 70 | 'providers' => [ 71 | Cog\Laravel\Ownership\Providers\OwnershipServiceProvider::class, 72 | ]; 73 | ``` 74 | 75 | ## Usage 76 | 77 | Laravel Ownership allows model to have strict owner model type (`HasOwner` trait) or use polymorphic relation (`HasMorphOwner` trait). 78 | 79 | Strict ownership is useful when model can belong to only one model type. Attempt to set owner of not defined model type will throw an exception `InvalidOwnerType`. 80 | *Example: Only users allowed to create posts.* 81 | 82 | Polymorphic ownership is useful when model can belong to owners of different types. 83 | *Example: Users and Organizations can upload applications to marketplace.* 84 | 85 | ### Prepare owner model 86 | 87 | At the owner model use `CanBeOwner` contract and implement it: 88 | 89 | ```php 90 | use Cog\Contracts\Ownership\CanBeOwner as CanBeOwnerInterface; 91 | use Illuminate\Foundation\Auth\User as Authenticatable; 92 | 93 | class User extends Authenticatable implements CanBeOwnerInterface 94 | { 95 | // ... 96 | } 97 | ``` 98 | 99 | ### Prepare ownable model with strict ownership 100 | 101 | Use `Ownable` contract in model which will get ownership behavior and implement it or just use `HasOwner` trait. 102 | 103 | ```php 104 | use Cog\Contracts\Ownership\Ownable as OwnableInterface; 105 | use Cog\Laravel\Ownership\Traits\HasOwner; 106 | use Illuminate\Database\Eloquent\Model; 107 | 108 | class Article extends Model implements OwnableInterface 109 | { 110 | use HasOwner; 111 | } 112 | ``` 113 | 114 | Ownable model with strict ownership must have in database additional nullable column to store owner relation: 115 | 116 | ```php 117 | Schema::table('articles', function (Blueprint $table) { 118 | $table->integer('owned_by_id')->unsigned()->nullable(); 119 | 120 | $table->index('owned_by_id'); 121 | }); 122 | ``` 123 | 124 | #### Overwrite strict ownership owner's foreign key 125 | 126 | By default, owner model will be the same as `config('auth.providers.users.model')` provides. 127 | 128 | To override default owner model in strict ownership, it's primary key or foreign key extend your ownable model with additional attributes: 129 | 130 | ```php 131 | use Cog\Contracts\Ownership\Ownable as OwnableInterface; 132 | use Cog\Laravel\Ownership\Traits\HasOwner; 133 | use Illuminate\Database\Eloquent\Model; 134 | 135 | class Article extends Model implements OwnableInterface 136 | { 137 | use HasOwner; 138 | 139 | protected $ownerModel = Group::class; 140 | protected $ownerPrimaryKey = 'gid'; 141 | protected $ownerForeignKey = 'group_id'; 142 | } 143 | ``` 144 | 145 | ### Prepare ownable model with polymorphic ownership 146 | 147 | Use `Ownable` contract in model which will get polymorphic ownership behavior and implement it or just use `HasMorphOwner` trait. 148 | 149 | ```php 150 | use Cog\Contracts\Ownership\Ownable as OwnableInterface; 151 | use Cog\Laravel\Ownership\Traits\HasMorphOwner; 152 | use Illuminate\Database\Eloquent\Model; 153 | 154 | class Article extends Model implements OwnableInterface 155 | { 156 | use HasMorphOwner; 157 | } 158 | ``` 159 | 160 | Ownable model with polymorphic ownership must have in database additional nullable columns to store owner relation: 161 | 162 | ```php 163 | Schema::table('articles', function (Blueprint $table) { 164 | $table->nullableMorphs('owned_by'); 165 | }); 166 | ``` 167 | 168 | ### Available methods 169 | 170 | #### Get owner relation 171 | 172 | ```php 173 | $article->ownedBy(); 174 | $article->owner(); 175 | ``` 176 | 177 | #### Get model owner 178 | 179 | ```php 180 | $article->getOwner(); 181 | $article->ownedBy; 182 | $article->owner; 183 | ``` 184 | 185 | #### Change (set) owner 186 | 187 | ```php 188 | $article->changeOwnerTo($owner); 189 | ``` 190 | 191 | #### Abandon (unset) owner 192 | 193 | ```php 194 | $article->abandonOwner(); 195 | ``` 196 | 197 | #### Check if has owner 198 | 199 | ```php 200 | $article->hasOwner(); 201 | ``` 202 | 203 | #### Check if owned by owner 204 | 205 | ```php 206 | $article->isOwnedBy($owner); 207 | ``` 208 | 209 | #### Check not owned by owner 210 | 211 | ```php 212 | $article->isNotOwnedBy($owner); 213 | ``` 214 | 215 | #### Manually define default owner on model creation 216 | 217 | ```php 218 | $article = new Article; 219 | $article->withDefaultOwner()->save(); 220 | ``` 221 | 222 | *Will use `resolveDefaultOwner()` method under the hood.* 223 | 224 | Or provide concrete owner: 225 | 226 | ```php 227 | $user = User::where('name', 'admin')->first(); 228 | $article = new Article; 229 | $article->withDefaultOwner($user)->save(); 230 | ``` 231 | 232 | #### Skip defining default owner on model creation 233 | 234 | ```php 235 | $article = new Article; 236 | $article->withoutDefaultOwner()->save(); 237 | ``` 238 | 239 | ### Scopes 240 | 241 | #### Scope models by owner 242 | 243 | ```php 244 | Article::whereOwnedBy($owner)->get(); 245 | ``` 246 | 247 | #### Scope models by not owned by owner 248 | 249 | ```php 250 | Article::whereNotOwnedBy($owner)->get(); 251 | ``` 252 | 253 | ### Set authenticated user as owner automatically 254 | 255 | To set currently authenticated user as owner for ownable model create - extend it with attribute `withDefaultOwnerOnCreate`. It works for both strict and polymorphic ownership behavior. 256 | 257 | ```php 258 | use Cog\Contracts\Ownership\Ownable as OwnableInterface; 259 | use Cog\Laravel\Ownership\Traits\HasOwner; 260 | use Illuminate\Database\Eloquent\Model; 261 | 262 | class Article extends Model implements OwnableInterface 263 | { 264 | use HasOwner; 265 | 266 | protected $withDefaultOwnerOnCreate = true; 267 | } 268 | ``` 269 | 270 | To override strategy of getting default owner extend ownable model with `resolveDefaultOwner` method: 271 | 272 | ```php 273 | use Cog\Contracts\Ownership\Ownable as OwnableInterface; 274 | use Cog\Laravel\Ownership\Traits\HasOwner; 275 | use Illuminate\Database\Eloquent\Model; 276 | 277 | class Article extends Model implements OwnableInterface 278 | { 279 | use HasOwner; 280 | 281 | public $withDefaultOwnerOnCreate = true; 282 | 283 | /** 284 | * Resolve entity default owner. 285 | * 286 | * @return \Cog\Contracts\Ownership\CanBeOwner|null 287 | */ 288 | public function resolveDefaultOwner() 289 | { 290 | return \App\User::where('name', 'admin')->first(); 291 | } 292 | } 293 | ``` 294 | 295 | ## Changelog 296 | 297 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 298 | 299 | ## Upgrading 300 | 301 | Please see [UPGRADING](UPGRADING.md) for detailed upgrade instructions. 302 | 303 | ## Contributing 304 | 305 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 306 | 307 | ## Testing 308 | 309 | Run the tests with: 310 | 311 | ```shell 312 | vendor/bin/phpunit 313 | ``` 314 | 315 | ## Security 316 | 317 | If you discover any security related issues, please email open@cybercog.su instead of using the issue tracker. 318 | 319 | ## Credits 320 | 321 | | ![@antonkomarev](https://avatars.githubusercontent.com/u/1849174?s=110)
Anton Komarev
| ![@soap](https://avatars.githubusercontent.com/u/1073690?s=110)
Prasit Gebsaap
| 322 | | :---: |:---------------------------------------------------------------------------------------------------------------------------------:| 323 | 324 | [Laravel Ownership contributors list](../../contributors) 325 | 326 | ## Alternatives 327 | 328 | *Feel free to add more alternatives as Pull Request.* 329 | 330 | ## License 331 | 332 | - `Laravel Ownership` package is open-sourced software licensed under the [MIT license](LICENSE) by [Anton Komarev]. 333 | - `Intellectual Property` image licensed under [Creative Commons 3.0](https://creativecommons.org/licenses/by/3.0/us/) by Arthur Shlain. 334 | - `Fat Boss` image licensed under [Creative Commons 3.0](https://creativecommons.org/licenses/by/3.0/us/) by Gan Khoon Lay. 335 | 336 | ## About CyberCog 337 | 338 | [CyberCog](https://cybercog.su) is a Social Unity of enthusiasts. Research the best solutions in product & software development is our passion. 339 | 340 | - [Follow us on Twitter](https://twitter.com/cybercog) 341 | - [Read our articles on Medium](https://medium.com/cybercog) 342 | 343 | CyberCog 344 | 345 | [Anton Komarev]: https://komarev.com 346 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | 3 | - [Upgrading From 4.0 To 5.0](#upgrade-5.0) 4 | - [Upgrading From 3.0 To 4.0](#upgrade-4.0) 5 | - [Upgrading From 2.0 To 3.0](#upgrade-3.0) 6 | 7 | 8 | ## Upgrading From 4.0 To 5.0 9 | 10 | - Find all `Cog\Contracts\Laravel\Ownership` and replace with `Cog\Contracts\Ownership` 11 | 12 | 13 | ## Upgrading From 3.0 To 4.0 14 | 15 | - Find all `Cog\Ownership\Contracts\HasOwner` and replace with `Cog\Contracts\Laravel\Ownership\Ownable` 16 | - Find all `Cog\Ownership\Observers\ModelObserver` and replace with `Cog\Laravel\Ownership\Observers\OwnableObserver` 17 | - Find all `Cog\Ownership\Contracts` and replace with `Cog\Contracts\Laravel\Ownership` 18 | - Find all `Cog\Ownership` and replace with `Cog\Laravel\Ownership` 19 | 20 | 21 | ## Upgrading From 2.0 To 3.0 22 | 23 | You need to upgrade only if you have models with Strict Ownership and you are using default `owned_by` column names. 24 | 25 | - Rename database columns `owned_by` to `owned_by_id` for all the ownable models with strict ownership. 26 | - If you have raw DB queries - don't forget to modify them as well. 27 | 28 | ### What if I want to keep old naming?! 29 | 30 | You are able to keep old naming without any database changes. Overwrite foreign keys in ownable models by adding `$ownerForeignKey` property: 31 | 32 | ```php 33 | protected $ownerForeignKey = 'owned_by'; 34 | ``` 35 | 36 | [See example of foreign key overwrite](https://github.com/cybercog/laravel-ownership#overwrite-strict-ownership-owners-foreign-key) 37 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cybercog/laravel-ownership", 3 | "description": "Laravel Ownership simplify management of Eloquent model's owner.", 4 | "type": "library", 5 | "license": "MIT", 6 | "keywords": [ 7 | "cybercog", 8 | "cog", 9 | "laravel", 10 | "eloquent", 11 | "trait", 12 | "ownership", 13 | "owned", 14 | "owner", 15 | "ownable", 16 | "author", 17 | "maker", 18 | "copyright", 19 | "proprietor", 20 | "domain", 21 | "creator", 22 | "master", 23 | "polymorphic", 24 | "morph" 25 | ], 26 | "authors": [ 27 | { 28 | "name": "Anton Komarev", 29 | "email": "anton@komarev.com", 30 | "homepage": "http://komarev.com", 31 | "role": "Developer" 32 | } 33 | ], 34 | "homepage": "https://komarev.com/sources/laravel-ownership", 35 | "support": { 36 | "email": "open@cybercog.su", 37 | "issues": "https://github.com/cybercog/laravel-ownership/issues", 38 | "wiki": "https://github.com/cybercog/laravel-ownership/wiki", 39 | "source": "https://github.com/cybercog/laravel-ownership", 40 | "docs": "https://github.com/cybercog/laravel-ownership/wiki" 41 | }, 42 | "require": { 43 | "php": "^8.0", 44 | "illuminate/database": "^9.0|^10.0|^11.0|^12.0", 45 | "illuminate/support": "^9.0|^10.0|^11.0|^12.0" 46 | }, 47 | "require-dev": { 48 | "mockery/mockery": "^1.0", 49 | "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", 50 | "phpunit/phpunit": "^9.6|^10.5|^11.5.3" 51 | }, 52 | "autoload": { 53 | "psr-4": { 54 | "Cog\\Contracts\\Ownership\\": "contracts/", 55 | "Cog\\Laravel\\Ownership\\": "src/" 56 | } 57 | }, 58 | "autoload-dev": { 59 | "psr-4": { 60 | "Cog\\Tests\\Laravel\\Ownership\\": "tests/", 61 | "Cog\\Tests\\Laravel\\Ownership\\Database\\Factories\\": "tests/database/factories/" 62 | } 63 | }, 64 | "scripts": { 65 | "test": "vendor/bin/phpunit" 66 | }, 67 | "config": { 68 | "sort-packages": true 69 | }, 70 | "extra": { 71 | "laravel": { 72 | "providers": [ 73 | "Cog\\Laravel\\Ownership\\Providers\\OwnershipServiceProvider" 74 | ] 75 | } 76 | }, 77 | "minimum-stability": "dev", 78 | "prefer-stable": true 79 | } 80 | -------------------------------------------------------------------------------- /contracts/CanBeOwner.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cog\Contracts\Ownership; 13 | 14 | /** 15 | * Interface CanBeOwner. 16 | * 17 | * @package Cog\Contracts\Ownership 18 | */ 19 | interface CanBeOwner 20 | { 21 | /** 22 | * Get the value of the model's primary key. 23 | * 24 | * @return mixed 25 | */ 26 | public function getKey(); 27 | 28 | /** 29 | * Get the class name for polymorphic relations. 30 | * 31 | * @return string 32 | */ 33 | public function getMorphClass(); 34 | } 35 | -------------------------------------------------------------------------------- /contracts/Exceptions/InvalidDefaultOwner.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cog\Contracts\Ownership\Exceptions; 13 | 14 | use Cog\Contracts\Ownership\Ownable as OwnableContract; 15 | use Exception; 16 | 17 | /** 18 | * Class InvalidDefaultOwner. 19 | * 20 | * @package Cog\Contracts\Ownership\Exceptions 21 | */ 22 | class InvalidDefaultOwner extends Exception 23 | { 24 | /** 25 | * Default owner for ownable model is null. 26 | * 27 | * @param \Cog\Contracts\Ownership\Ownable $ownable 28 | * @return static 29 | */ 30 | public static function isNull(OwnableContract $ownable) 31 | { 32 | return new static(sprintf('Model `%s` default owner is null.', get_class($ownable))); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/Exceptions/InvalidOwnerType.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cog\Contracts\Ownership\Exceptions; 13 | 14 | use Cog\Contracts\Ownership\CanBeOwner as CanBeOwnerContract; 15 | use Cog\Contracts\Ownership\Ownable as OwnableContract; 16 | use Exception; 17 | 18 | /** 19 | * Class InvalidOwnerType. 20 | * 21 | * @package Cog\Contracts\Ownership\Exceptions 22 | */ 23 | class InvalidOwnerType extends Exception 24 | { 25 | /** 26 | * Owner of the provided type is not allowed to own this model. 27 | * 28 | * @param \Cog\Contracts\Ownership\Ownable $ownable 29 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 30 | * @return static 31 | */ 32 | public static function notAllowed(OwnableContract $ownable, CanBeOwnerContract $owner) 33 | { 34 | return new static(sprintf('Model `%s` not allows owner of type `%s`.', get_class($ownable), get_class($owner))); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/Ownable.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cog\Contracts\Ownership; 13 | 14 | use Cog\Contracts\Ownership\CanBeOwner as CanBeOwnerContract; 15 | use Illuminate\Database\Eloquent\Builder; 16 | 17 | /** 18 | * Interface Ownable. 19 | * 20 | * @package Cog\Contracts\Ownership 21 | */ 22 | interface Ownable 23 | { 24 | /** 25 | * Owner of the model. 26 | * 27 | * @return mixed 28 | */ 29 | public function ownedBy(); 30 | 31 | /** 32 | * Get the model owner. Alias for `ownedBy()` method. 33 | * 34 | * @return mixed 35 | */ 36 | public function owner(); 37 | 38 | /** 39 | * Get the model owner. 40 | * 41 | * @return \Cog\Contracts\Ownership\CanBeOwner 42 | */ 43 | public function getOwner(); 44 | 45 | /** 46 | * Get default owner. 47 | * 48 | * @return null|\Cog\Contracts\Ownership\CanBeOwner 49 | */ 50 | public function defaultOwner(); 51 | 52 | /** 53 | * Set owner as default for entity. 54 | * 55 | * @param null|\Cog\Contracts\Ownership\CanBeOwner $owner 56 | * @return \Cog\Contracts\Ownership\Ownable 57 | */ 58 | public function withDefaultOwner(CanBeOwnerContract $owner = null); 59 | 60 | /** 61 | * Remove default owner for entity. 62 | * 63 | * @return \Cog\Contracts\Ownership\Ownable 64 | */ 65 | public function withoutDefaultOwner(); 66 | 67 | /** 68 | * If default owner should be set on entity create. 69 | * 70 | * @return bool 71 | */ 72 | public function isDefaultOwnerOnCreateRequired(); 73 | 74 | /** 75 | * Resolve entity default owner. 76 | * 77 | * @return null|\Cog\Contracts\Ownership\CanBeOwner 78 | */ 79 | public function resolveDefaultOwner(); 80 | 81 | /** 82 | * Changes owner of the model. 83 | * 84 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 85 | * @return \Cog\Contracts\Ownership\Ownable 86 | */ 87 | public function changeOwnerTo(CanBeOwnerContract $owner); 88 | 89 | /** 90 | * Abandons owner of the model. 91 | * 92 | * @return \Cog\Contracts\Ownership\Ownable 93 | */ 94 | public function abandonOwner(); 95 | 96 | /** 97 | * Determines if model has owner. 98 | * 99 | * @return bool 100 | */ 101 | public function hasOwner(); 102 | 103 | /** 104 | * Checks if model owned by given owner. 105 | * 106 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 107 | * @return bool 108 | */ 109 | public function isOwnedBy(CanBeOwnerContract $owner); 110 | 111 | /** 112 | * Checks if model not owned by given owner. 113 | * 114 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 115 | * @return bool 116 | */ 117 | public function isNotOwnedBy(CanBeOwnerContract $owner); 118 | 119 | /** 120 | * Scope a query to only include models by owner. 121 | * 122 | * @param \Illuminate\Database\Eloquent\Builder $query 123 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 124 | * @return \Illuminate\Database\Eloquent\Builder 125 | */ 126 | public function scopeWhereOwnedBy(Builder $query, CanBeOwnerContract $owner); 127 | 128 | /** 129 | * Scope a query to only include models by owner. 130 | * 131 | * @param \Illuminate\Database\Eloquent\Builder $query 132 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 133 | * @return \Illuminate\Database\Eloquent\Builder 134 | */ 135 | public function scopeWhereNotOwnedBy(Builder $query, CanBeOwnerContract $owner); 136 | } 137 | -------------------------------------------------------------------------------- /src/Observers/OwnableObserver.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cog\Laravel\Ownership\Observers; 13 | 14 | use Cog\Contracts\Ownership\Ownable as OwnableContract; 15 | 16 | /** 17 | * Class OwnableObserver. 18 | * 19 | * @package Cog\Laravel\Ownership\Observers 20 | */ 21 | class OwnableObserver 22 | { 23 | /** 24 | * Handle the deleted event for the model. 25 | * 26 | * @param \Cog\Contracts\Ownership\Ownable $ownable 27 | * @return void 28 | */ 29 | public function creating(OwnableContract $ownable) 30 | { 31 | if ($ownable->isDefaultOwnerOnCreateRequired()) { 32 | $ownable->withDefaultOwner(); 33 | } 34 | 35 | if ($owner = $ownable->defaultOwner()) { 36 | $ownable->changeOwnerTo($owner); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Providers/OwnershipServiceProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cog\Laravel\Ownership\Providers; 13 | 14 | use Cog\Contracts\Ownership\CanBeOwner as CanBeOwnerContract; 15 | use Illuminate\Contracts\Foundation\Application as ApplicationContract; 16 | use Illuminate\Support\ServiceProvider; 17 | 18 | /** 19 | * Class OwnershipServiceProvider. 20 | * 21 | * @package Cog\Laravel\Ownership\Providers 22 | */ 23 | class OwnershipServiceProvider extends ServiceProvider 24 | { 25 | /** 26 | * Indicates if loading of the provider is deferred. 27 | * 28 | * @var bool 29 | */ 30 | protected $defer = true; 31 | 32 | /** 33 | * Register the service provider. 34 | * 35 | * @return void 36 | */ 37 | public function register() 38 | { 39 | $this->bindUserModel(); 40 | } 41 | 42 | /** 43 | * Bind User model from config to Owner contract. 44 | * 45 | * @return void 46 | */ 47 | protected function bindUserModel() 48 | { 49 | $this->app->bind(CanBeOwnerContract::class, function (ApplicationContract $app) { 50 | $config = $app->make('config'); 51 | 52 | return $config->get('auth.providers.users.model', $config->get('auth.model')); 53 | }); 54 | } 55 | 56 | /** 57 | * Get the services provided by the provider. 58 | * 59 | * @return array 60 | */ 61 | public function provides() 62 | { 63 | return [ 64 | CanBeOwnerContract::class, 65 | ]; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Traits/HasMorphOwner.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cog\Laravel\Ownership\Traits; 13 | 14 | use Cog\Contracts\Ownership\CanBeOwner as CanBeOwnerContract; 15 | use Cog\Contracts\Ownership\Exceptions\InvalidDefaultOwner; 16 | use Cog\Laravel\Ownership\Observers\OwnableObserver; 17 | use Illuminate\Database\Eloquent\Builder; 18 | use Illuminate\Support\Facades\Auth; 19 | 20 | /** 21 | * Class HasMorphOwner. 22 | * 23 | * @package Cog\Laravel\Ownership\Traits 24 | */ 25 | trait HasMorphOwner 26 | { 27 | /** 28 | * @var null|\Cog\Contracts\Ownership\CanBeOwner 29 | */ 30 | private $defaultOwner; 31 | 32 | /** 33 | * Boot the HasMorphOwner trait for a model. 34 | * 35 | * @return void 36 | */ 37 | public static function bootHasMorphOwner() 38 | { 39 | static::observe(OwnableObserver::class); 40 | } 41 | 42 | /** 43 | * Owner of the model. 44 | * 45 | * @return \Illuminate\Database\Eloquent\Relations\MorphTo 46 | */ 47 | public function ownedBy() 48 | { 49 | return $this->morphTo('owned_by'); 50 | } 51 | 52 | /** 53 | * Get the model owner. Alias for `ownedBy()` method. 54 | * 55 | * @return \Illuminate\Database\Eloquent\Relations\MorphTo 56 | */ 57 | public function owner() 58 | { 59 | return $this->ownedBy(); 60 | } 61 | 62 | /** 63 | * Get the model owner. 64 | * 65 | * @return \Cog\Contracts\Ownership\CanBeOwner 66 | */ 67 | public function getOwner() 68 | { 69 | return $this->ownedBy; 70 | } 71 | 72 | /** 73 | * Get default owner. 74 | * 75 | * @return null|\Cog\Contracts\Ownership\CanBeOwner 76 | */ 77 | public function defaultOwner() 78 | { 79 | return $this->defaultOwner; 80 | } 81 | 82 | /** 83 | * Set owner as default for entity. 84 | * 85 | * @param null|\Cog\Contracts\Ownership\CanBeOwner $owner 86 | * @return $this 87 | */ 88 | public function withDefaultOwner(CanBeOwnerContract $owner = null) 89 | { 90 | $this->defaultOwner = $owner ?: $this->resolveDefaultOwner(); 91 | if (isset($this->withDefaultOwnerOnCreate)) { 92 | $this->withDefaultOwnerOnCreate = false; 93 | } 94 | 95 | return $this; 96 | } 97 | 98 | /** 99 | * Remove default owner for entity. 100 | * 101 | * @return $this 102 | */ 103 | public function withoutDefaultOwner() 104 | { 105 | $this->defaultOwner = null; 106 | if (isset($this->withDefaultOwnerOnCreate)) { 107 | $this->withDefaultOwnerOnCreate = false; 108 | } 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * If default owner should be set on entity create. 115 | * 116 | * @return bool 117 | */ 118 | public function isDefaultOwnerOnCreateRequired() 119 | { 120 | return isset($this->withDefaultOwnerOnCreate) ? (bool) $this->withDefaultOwnerOnCreate : false; 121 | } 122 | 123 | /** 124 | * Resolve entity default owner. 125 | * 126 | * @return null|\Cog\Contracts\Ownership\CanBeOwner 127 | */ 128 | public function resolveDefaultOwner() 129 | { 130 | return Auth::user(); 131 | } 132 | 133 | /** 134 | * Changes owner of the model. 135 | * 136 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 137 | * @return $this 138 | */ 139 | public function changeOwnerTo(CanBeOwnerContract $owner) 140 | { 141 | return $this->ownedBy()->associate($owner); 142 | } 143 | 144 | /** 145 | * Abandons owner of the model. 146 | * 147 | * @return $this 148 | */ 149 | public function abandonOwner() 150 | { 151 | $model = $this->ownedBy()->dissociate(); 152 | $this->load('ownedBy'); 153 | 154 | return $model; 155 | } 156 | 157 | /** 158 | * Determines if model has owner. 159 | * 160 | * @return bool 161 | */ 162 | public function hasOwner() 163 | { 164 | return !is_null($this->getOwner()); 165 | } 166 | 167 | /** 168 | * Checks if model owned by given owner. 169 | * 170 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 171 | * @return bool 172 | */ 173 | public function isOwnedBy(CanBeOwnerContract $owner) 174 | { 175 | if (!$this->hasOwner()) { 176 | return false; 177 | } 178 | 179 | return $owner->getKey() === $this->getOwner()->getKey() && $owner->getMorphClass() === $this->getOwner()->getMorphClass(); 180 | } 181 | 182 | /** 183 | * Checks if model not owned by given owner. 184 | * 185 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 186 | * @return bool 187 | */ 188 | public function isNotOwnedBy(CanBeOwnerContract $owner) 189 | { 190 | return !$this->isOwnedBy($owner); 191 | } 192 | 193 | /** 194 | * Determine if model owned by owner resolved as default. 195 | * 196 | * @return bool 197 | * 198 | * @throws \Cog\Contracts\Ownership\Exceptions\InvalidDefaultOwner 199 | */ 200 | public function isOwnedByDefaultOwner() 201 | { 202 | $owner = $this->resolveDefaultOwner(); 203 | if (!$owner) { 204 | throw InvalidDefaultOwner::isNull($this); 205 | } 206 | 207 | return $this->isOwnedBy($owner); 208 | } 209 | 210 | /** 211 | * Scope a query to only include models by owner. 212 | * 213 | * @param \Illuminate\Database\Eloquent\Builder $query 214 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 215 | * @return \Illuminate\Database\Eloquent\Builder 216 | */ 217 | public function scopeWhereOwnedBy(Builder $query, CanBeOwnerContract $owner) 218 | { 219 | return $query->where([ 220 | 'owned_by_id' => $owner->getKey(), 221 | 'owned_by_type' => $owner->getMorphClass(), 222 | ]); 223 | } 224 | 225 | /** 226 | * Scope a query to only include models by owner. 227 | * 228 | * @param \Illuminate\Database\Eloquent\Builder $query 229 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 230 | * @return \Illuminate\Database\Eloquent\Builder 231 | */ 232 | public function scopeWhereNotOwnedBy(Builder $query, CanBeOwnerContract $owner) 233 | { 234 | return $query->where(function (Builder $q) use ($owner) { 235 | $q->where('owned_by_id', '!=', $owner->getKey()) 236 | ->orWhere('owned_by_type', '!=', $owner->getMorphClass()); 237 | }); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/Traits/HasOwner.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Cog\Laravel\Ownership\Traits; 13 | 14 | use Cog\Contracts\Ownership\CanBeOwner as CanBeOwnerContract; 15 | use Cog\Contracts\Ownership\Exceptions\InvalidDefaultOwner; 16 | use Cog\Contracts\Ownership\Exceptions\InvalidOwnerType; 17 | use Cog\Laravel\Ownership\Observers\OwnableObserver; 18 | use Illuminate\Database\Eloquent\Builder; 19 | use Illuminate\Support\Facades\Auth; 20 | 21 | /** 22 | * Class HasOwner. 23 | * 24 | * @package Cog\Laravel\Ownership\Traits 25 | */ 26 | trait HasOwner 27 | { 28 | /** 29 | * @var null|\Cog\Contracts\Ownership\CanBeOwner 30 | */ 31 | private $defaultOwner; 32 | 33 | /** 34 | * Boot the HasOwner trait for a model. 35 | * 36 | * @return void 37 | */ 38 | public static function bootHasOwner() 39 | { 40 | static::observe(OwnableObserver::class); 41 | } 42 | 43 | /** 44 | * Owner of the model. 45 | * 46 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 47 | */ 48 | public function ownedBy() 49 | { 50 | return $this->belongsTo($this->getOwnerModel(), $this->getOwnerForeignKey(), $this->getOwnerPrimaryKey()); 51 | } 52 | 53 | /** 54 | * Get the model owner. Alias for `ownedBy()` method. 55 | * 56 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 57 | */ 58 | public function owner() 59 | { 60 | return $this->ownedBy(); 61 | } 62 | 63 | /** 64 | * Get the model owner. 65 | * 66 | * @return \Cog\Contracts\Ownership\CanBeOwner 67 | */ 68 | public function getOwner() 69 | { 70 | return $this->ownedBy; 71 | } 72 | 73 | /** 74 | * Get default owner. 75 | * 76 | * @return null|\Cog\Contracts\Ownership\CanBeOwner 77 | */ 78 | public function defaultOwner() 79 | { 80 | return $this->defaultOwner; 81 | } 82 | 83 | /** 84 | * Set owner as default for entity. 85 | * 86 | * @param null|\Cog\Contracts\Ownership\CanBeOwner $owner 87 | * @return $this 88 | */ 89 | public function withDefaultOwner(CanBeOwnerContract $owner = null) 90 | { 91 | $this->defaultOwner = $owner ?: $this->resolveDefaultOwner(); 92 | if (isset($this->withDefaultOwnerOnCreate)) { 93 | $this->withDefaultOwnerOnCreate = false; 94 | } 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * Remove default owner for entity. 101 | * 102 | * @return $this 103 | */ 104 | public function withoutDefaultOwner() 105 | { 106 | $this->defaultOwner = null; 107 | if (isset($this->withDefaultOwnerOnCreate)) { 108 | $this->withDefaultOwnerOnCreate = false; 109 | } 110 | 111 | return $this; 112 | } 113 | 114 | /** 115 | * If default owner should be set on entity create. 116 | * 117 | * @return bool 118 | */ 119 | public function isDefaultOwnerOnCreateRequired() 120 | { 121 | return isset($this->withDefaultOwnerOnCreate) ? (bool) $this->withDefaultOwnerOnCreate : false; 122 | } 123 | 124 | /** 125 | * Resolve entity default owner. 126 | * 127 | * @return null|\Cog\Contracts\Ownership\CanBeOwner 128 | */ 129 | public function resolveDefaultOwner() 130 | { 131 | return Auth::user(); 132 | } 133 | 134 | /** 135 | * Changes owner of the model. 136 | * 137 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 138 | * @return $this 139 | * 140 | * @throws \Cog\Contracts\Ownership\Exceptions\InvalidOwnerType 141 | */ 142 | public function changeOwnerTo(CanBeOwnerContract $owner) 143 | { 144 | $allowedOwnerType = $this->getOwnerModel(); 145 | if (!$owner instanceof $allowedOwnerType) { 146 | throw InvalidOwnerType::notAllowed($this, $owner); 147 | } 148 | 149 | return $this->ownedBy()->associate($owner); 150 | } 151 | 152 | /** 153 | * Abandons owner of the model. 154 | * 155 | * @return $this 156 | */ 157 | public function abandonOwner() 158 | { 159 | return $this->ownedBy()->dissociate(); 160 | } 161 | 162 | /** 163 | * Determines if model has owner. 164 | * 165 | * @return bool 166 | */ 167 | public function hasOwner() 168 | { 169 | return !is_null($this->getOwner()); 170 | } 171 | 172 | /** 173 | * Checks if model owned by given owner. 174 | * 175 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 176 | * @return bool 177 | */ 178 | public function isOwnedBy(CanBeOwnerContract $owner) 179 | { 180 | if (!$this->hasOwner()) { 181 | return false; 182 | } 183 | 184 | return $owner->getKey() === $this->getOwner()->getKey(); 185 | } 186 | 187 | /** 188 | * Checks if model not owned by given owner. 189 | * 190 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 191 | * @return bool 192 | */ 193 | public function isNotOwnedBy(CanBeOwnerContract $owner) 194 | { 195 | return !$this->isOwnedBy($owner); 196 | } 197 | 198 | /** 199 | * Determine if model owned by owner resolved as default. 200 | * 201 | * @return bool 202 | * 203 | * @throws \Cog\Contracts\Ownership\Exceptions\InvalidDefaultOwner 204 | */ 205 | public function isOwnedByDefaultOwner() 206 | { 207 | $owner = $this->resolveDefaultOwner(); 208 | if (!$owner) { 209 | throw InvalidDefaultOwner::isNull($this); 210 | } 211 | 212 | return $this->isOwnedBy($owner); 213 | } 214 | 215 | /** 216 | * Scope a query to only include models by owner. 217 | * 218 | * @param \Illuminate\Database\Eloquent\Builder $query 219 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 220 | * @return \Illuminate\Database\Eloquent\Builder 221 | */ 222 | public function scopeWhereOwnedBy(Builder $query, CanBeOwnerContract $owner) 223 | { 224 | return $query->where($this->getOwnerForeignKey(), $owner->getKey()); 225 | } 226 | 227 | /** 228 | * Scope a query to exclude models by owner. 229 | * 230 | * @param \Illuminate\Database\Eloquent\Builder $query 231 | * @param \Cog\Contracts\Ownership\CanBeOwner $owner 232 | * @return \Illuminate\Database\Eloquent\Builder 233 | */ 234 | public function scopeWhereNotOwnedBy(Builder $query, CanBeOwnerContract $owner) 235 | { 236 | return $query->where($this->getOwnerForeignKey(), '!=', $owner->getKey()); 237 | } 238 | 239 | /** 240 | * Get owner model name. 241 | * 242 | * @return string 243 | */ 244 | protected function getOwnerModel() 245 | { 246 | return $this->ownerModel ?: app(CanBeOwnerContract::class); 247 | } 248 | 249 | /** 250 | * Get owner model primary key. 251 | * 252 | * @return string 253 | */ 254 | protected function getOwnerPrimaryKey() 255 | { 256 | return $this->ownerPrimaryKey ?: 'id'; 257 | } 258 | 259 | /** 260 | * Get owner foreign key. 261 | * 262 | * @return string 263 | */ 264 | protected function getOwnerForeignKey() 265 | { 266 | return $this->ownerForeignKey ?: 'owned_by_id'; 267 | } 268 | } 269 | --------------------------------------------------------------------------------