├── .github ├── dependabot.yml └── workflows │ ├── automated-tests.yml │ ├── code-standards-inspection.yml │ └── update-changelog.yml ├── .styleci.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── UPGRADING.md ├── composer.json ├── config └── achievements.php ├── database └── migrations │ └── 2019_00_00_000000_create_achievements_table.php ├── src ├── Achievement.php ├── AchievementsServiceProvider.php ├── Console │ └── Commands │ │ └── MakeAchievement.php ├── Contracts │ └── AchievementContract.php ├── Models │ └── Achievement.php └── Traits │ └── Achiever.php └── stubs └── Achievement.stub /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" -------------------------------------------------------------------------------- /.github/workflows/automated-tests.yml: -------------------------------------------------------------------------------- 1 | name: Automated Tests 2 | on: 3 | pull_request: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: true 11 | matrix: 12 | php: [8.2, 8.3, 8.4] 13 | laravel: [^11.0, ^12.0] 14 | dependency-version: [prefer-lowest, prefer-stable] 15 | include: 16 | 17 | - laravel: ^11.0 18 | testbench: ^9.0 19 | phpunit: ^10.5 20 | 21 | - laravel: ^12.0 22 | testbench: ^10.0 23 | phpunit: ^11.5.3 24 | 25 | exclude: 26 | - php: 8.4 27 | laravel: ^11.0 28 | dependency-version: prefer-lowest 29 | 30 | name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - (${{ matrix.dependency-version }} 31 | 32 | steps: 33 | - name: Checkout code 34 | uses: actions/checkout@v4.1.1 35 | 36 | - name: Setup PHP 37 | uses: shivammathur/setup-php@2.28.0 38 | with: 39 | php-version: ${{ matrix.php }} 40 | tools: composer 41 | coverage: none 42 | 43 | - name: Install dependencies 44 | run: | 45 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "phpunit/phpunit:${{ matrix.phpunit }}" --dev --no-interaction --no-update 46 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction 47 | 48 | - name: Execute tests 49 | run: composer test -------------------------------------------------------------------------------- /.github/workflows/code-standards-inspection.yml: -------------------------------------------------------------------------------- 1 | name: Code Standards Inspection 2 | 3 | on: 4 | pull_request: 5 | branches-ignore: 6 | - 'dependabot/**' 7 | 8 | jobs: 9 | sniff: 10 | runs-on: ubuntu-latest 11 | 12 | concurrency: 13 | group: ${{ github.workflow }}-sniff-${{ github.ref }} 14 | cancel-in-progress: true 15 | 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v3 19 | 20 | - name: Set up PHP 21 | uses: shivammathur/setup-php@v2 22 | with: 23 | php-version: '8.2' 24 | tools: composer 25 | coverage: none 26 | 27 | - name: Install dependencies 28 | uses: ramsey/composer-install@v3 29 | 30 | - name: Sniff 31 | run: composer sniff -------------------------------------------------------------------------------- /.github/workflows/update-changelog.yml: -------------------------------------------------------------------------------- 1 | name: "Update Changelog" 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4.2.2 14 | with: 15 | ref: master 16 | 17 | - name: Update Changelog 18 | uses: stefanzweifel/changelog-updater-action@v1 19 | with: 20 | latest-version: ${{ github.event.release.name }} 21 | release-notes: ${{ github.event.release.body }} 22 | 23 | - name: Commit updated CHANGELOG 24 | uses: stefanzweifel/git-auto-commit-action@v5 25 | with: 26 | branch: master 27 | commit_message: Update CHANGELOG 28 | file_pattern: CHANGELOG.md -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel 2 | enabled: 3 | - length_ordered_imports 4 | disabled: 5 | - alpha_ordered_imports -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Any notable changes to `Laravel Achievements` will be documented in this file. 4 | 5 | ## v1.6.1 - 26-03-2023 6 | 7 | - Fix formatting in `composer.json` 8 | 9 | ## v1.6.0 - 26-03-2023 10 | 11 | - Add Laravel 10 support 12 | 13 | ## v1.5.0 - 21-04-2022 14 | 15 | - Add Laravel 9 support 16 | 17 | ## v1.4.0 - 07-03-2021 18 | 19 | - Add PHP 8 support 20 | - Add Laravel 8 support 21 | 22 | ## v1.3.1 - 20-05-2020 23 | 24 | - Add ramsey/uuid ^4.0 support 25 | 26 | ## v1.3.0 - 20-04-2020 27 | 28 | - Add support for unlocking achievement without an Achievement instance 29 | - Add support for unlocking achievement with specified data 30 | 31 | ## v1.2.0 - 07-03-2020 32 | 33 | - Add support for `Laravel 7` 34 | 35 | ## v1.1.0 - 06-02-2020 36 | 37 | - Add `hasAchievement` method to `Achiever` trait 38 | 39 | ## v1.0.0 - 01-01-2020 40 | 41 | - Release 42 | 43 | ## v0.8.0 - 23-11-2019 44 | 45 | - Add `Laravel 6` support 46 | 47 | ## v0.7.1 - 19-10-2019 48 | 49 | - Fix achievement contract 50 | 51 | ## v0.7.0 - 19-10-2019 52 | 53 | - Add `getIconAsAsset` as attribute to achievement model 54 | - Change data on achievements to be nullable 55 | - Fix achievement contract 56 | 57 | ## v0.6.0 - 19-10-2019 58 | 59 | - Change `getIcon` into a simple getter 60 | - Add `getIconAsAsset` to retrieve icon with a path 61 | 62 | ## v0.5.0 - 29-04-2019 63 | 64 | - Add missing icon attribute 65 | - Add way of getting name when no variable has been set 66 | 67 | ## v0.4.1 - 29-04-2019 68 | 69 | - Fix missing haystack 70 | 71 | ## v0.4.0 - 29-04-2019 72 | 73 | - Update README 74 | - Require Laravel 5.8 75 | - Add icon var and method 76 | 77 | ## v0.3.0 - 31-03-2019 78 | 79 | - Add functions to get achievement classes 80 | 81 | ## v0.2.0 - 31-03-2019 82 | 83 | - Update README 84 | - Update keywords in composer 85 | - Add name and description accessors to model 86 | - Fixed date and version for v0.1.0 in CHANGELOG 87 | 88 | ## v0.1.0 - 29-03-2019 89 | 90 | - Pre-release 91 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Pull requests are welcome. 4 | 5 | StyleCI and Scrutinizer checks must pass for pull requests to be accepted. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Peter C. Jørgensen 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://banners.beyondco.de/Laravel%20Achievements.jpeg?theme=light&packageManager=composer+require&packageName=tehwave%2Flaravel-achievements&pattern=wiggle&style=style_1&description=Simple%2C+elegant+Achievements+the+Laravel+way&md=1&showWatermark=1&fontSize=100px&images=https%3A%2F%2Flaravel.com%2Fimg%2Flogomark.min.svg) 2 | 3 | 4 | # Laravel Achievements 5 | 6 | Simple, elegant Achievements the Laravel way. 7 | 8 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) 9 | [![Automated Tests](https://github.com/tehwave/laravel-achievements/actions/workflows/automated-tests.yml/badge.svg)](https://github.com/tehwave/laravel-achievements/actions/workflows/automated-tests.yml) 10 | 11 | ## Requirements 12 | 13 | The package has been developed and tested to work with the latest supported versions of PHP and Laravel as well as the following minimum requirements: 14 | 15 | - Laravel 11 16 | - PHP 8.2 17 | 18 | ### Version Compatibility 19 | 20 | | Laravel | PHP | Branch | 21 | |---|---|---| 22 | | 11+ | 8.2+ | [master](https://github.com/tehwave/laravel-achievements/tree/master) | 23 | | 10 and below | 8.1 and below | [1.x](https://github.com/tehwave/laravel-achievements/tree/1.x) | 24 | 25 | ## Installation 26 | 27 | Install the package via Composer. 28 | 29 | ```bash 30 | composer require tehwave/laravel-achievements 31 | ``` 32 | 33 | Publish migrations. 34 | 35 | ```bash 36 | php artisan vendor:publish --tag="achievements-migrations" 37 | ``` 38 | 39 | Migrate the migrations. 40 | 41 | ```bash 42 | php artisan migrate 43 | ``` 44 | 45 | As an optional choice, you may publish config as well. 46 | 47 | ```bash 48 | php artisan vendor:publish --tag="achievements-config" 49 | ``` 50 | 51 | ## Usage 52 | 53 | `Laravel Achievements` work much like Laravel's [notifications](https://laravel.com/docs/notifications). 54 | 55 | ```php 56 | $user = \App\User::find(1); 57 | 58 | $user->achieve(new \App\Achievements\UsersFirstPost()); 59 | ``` 60 | 61 | ### Creating Achievements 62 | 63 | ```bash 64 | php artisan make:achievement UsersFirstPost 65 | ``` 66 | 67 | This command will place a fresh `Achievement` class in your new `app/Achievements` directory. 68 | 69 | Each `Achievement` class contains a `toDatabase` method, that you may use to store additional data with the achievement, and a few properties for basic meta information. 70 | 71 | ### Unlocking Achievements 72 | 73 | Use `Achiever` trait on models that can unlock achievements. 74 | 75 | ```php 76 | achieve(new \App\Achievements\UsersFirstPost()); 97 | ``` 98 | 99 | ...or use `Achievement` class to unlock achievements. 100 | 101 | ```php 102 | $user = \App\User::find(1); 103 | 104 | \tehwave\Achievements\Achievement::unlock($user, new \App\Achievements\UsersFirstPost()); 105 | ``` 106 | 107 | ### Accessing Achievements 108 | 109 | Retrieve all of the entity's unlocked achievements. 110 | 111 | ```php 112 | $user = \App\User::find(1); 113 | 114 | $user->achievements()->get(); 115 | ``` 116 | 117 | ### Checking if entity has Achievement 118 | 119 | On models with the `Achiever` trait, you may pass an `Achievement` instance to `hasAchievement` method to check if the specified achievement exist on the model. 120 | 121 | ```php 122 | $achievement = new \App\Achievements\UsersFirstPost(); 123 | 124 | $user = \App\User::find(1); 125 | 126 | $user->hasAchievement($achievement); 127 | // false 128 | 129 | $user->achieve($achievement); 130 | 131 | $user->hasAchievement($achievement); 132 | // true 133 | ``` 134 | 135 | Should you not want to pass an instance, you may also pass the class name. 136 | 137 | ```php 138 | $user->hasAchievement(\App\Achievements\UsersFirstPost::class); 139 | ``` 140 | 141 | ## Tests 142 | 143 | Run the following command to test the package. 144 | 145 | ```bash 146 | composer test 147 | ``` 148 | 149 | ## Security 150 | 151 | For any security related issues, send a mail to [peterchrjoergensen+achievements@gmail.com](mailto:peterchrjoergensen+achievements@gmail.com) instead of using the issue tracker. 152 | 153 | ## Changelog 154 | 155 | See [CHANGELOG](CHANGELOG.md) for details on what has changed. 156 | 157 | ## Upgrade Guide 158 | 159 | See [UPGRADING](UPGRADING.md) for details on how to upgrade. 160 | 161 | ## Contributions 162 | 163 | See [CONTRIBUTING](CONTRIBUTING.md) for details on how to contribute. 164 | 165 | ## Credits 166 | 167 | - [Peter Jørgensen](https://github.com/tehwave) 168 | - [All Contributors](../../contributors) 169 | 170 | Inspired by https://github.com/gstt/laravel-achievements 171 | 172 | ## About 173 | 174 | I work as a Web Developer in Denmark on Laravel and WordPress websites. 175 | 176 | Follow me [@tehwave](https://twitter.com/tehwave) on Twitter! 177 | 178 | ## License 179 | 180 | [MIT License](LICENSE) 181 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | For any security related issues, send a mail to [peterchrjoergensen+achievements@gmail.com](mailto:peterchrjoergensen+achievements@gmail.com) instead of using the issue tracker. 4 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | 3 | ## Upgrading from 1.x to 2.0 4 | 5 | ### Version Compatibility 6 | 7 | Older versions of Laravel and PHP have been dropped. 8 | 9 | Laravel 11 and 12 as well as PHP 8.2, 8.3, and 8.4 are now supported. 10 | 11 | | Laravel | PHP | Branch | 12 | |---|---|---| 13 | | 11+ | 8.2+ | [master](https://github.com/tehwave/laravel-achievements/tree/master) | 14 | | 10 and below | 8.1 and below | [1.x](https://github.com/tehwave/laravel-achievements/tree/1.x) | 15 | 16 | ### Incompatible Changes 17 | 18 | #### PHP and Laravel Version Requirements 19 | 20 | - The minimum PHP version has been increased to 8.2. 21 | - The minimum Laravel version has been increased to 11. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tehwave/laravel-achievements", 3 | "description": "Simple, elegant Achievements the Laravel way", 4 | "keywords": [ 5 | "php", 6 | "laravel", 7 | "package", 8 | "achievements", 9 | "badges", 10 | "tehwave" 11 | ], 12 | "homepage": "https://github.com/tehwave/laravel-achievements", 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "Peter Jørgensen", 17 | "email": "peterchrjoergensen@gmail.com", 18 | "homepage": "https://peterchrjoergensen.dk", 19 | "role": "Developer" 20 | } 21 | ], 22 | "require": { 23 | "php": "^8.2", 24 | "illuminate/console": "^11.0|^12.0", 25 | "illuminate/database": "^11.0|^12.0", 26 | "illuminate/filesystem": "^11.0|^12.0", 27 | "illuminate/support": "^11.0|^12.0" 28 | }, 29 | "require-dev": { 30 | "brianium/paratest": "^7.4", 31 | "laravel/pint": "^1.21", 32 | "orchestra/testbench": "^9.0|^10.0", 33 | "phpunit/phpunit": "^10.5|^11.5.3" 34 | }, 35 | "autoload": { 36 | "psr-4": { 37 | "tehwave\\Achievements\\": "src" 38 | } 39 | }, 40 | "autoload-dev": { 41 | "psr-4": { 42 | "tehwave\\Achievements\\Tests\\": "tests" 43 | } 44 | }, 45 | "scripts": { 46 | "test": "@php vendor/bin/phpunit", 47 | "coverage": "@php vendor/bin/phpunit --coverage-html coverage", 48 | "sniff": "@php vendor/bin/pint --test", 49 | "lint": "@php vendor/bin/pint", 50 | "paratest": "@php vendor/bin/paratest" 51 | }, 52 | "extra": { 53 | "laravel": { 54 | "providers": [ 55 | "tehwave\\Achievements\\AchievementsServiceProvider" 56 | ] 57 | } 58 | }, 59 | "config": { 60 | "sort-packages": true 61 | } 62 | } -------------------------------------------------------------------------------- /config/achievements.php: -------------------------------------------------------------------------------- 1 | 'achievements', 17 | ]; 18 | -------------------------------------------------------------------------------- /database/migrations/2019_00_00_000000_create_achievements_table.php: -------------------------------------------------------------------------------- 1 | uuid('id')->primary(); 17 | $table->string('type')->index(); 18 | $table->morphs('achiever'); 19 | $table->text('data')->nullable(); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists(config('achievements.table', 'achievements')); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Achievement.php: -------------------------------------------------------------------------------- 1 | name)) { 39 | return preg_replace( 40 | '/([a-z])([A-Z])/s', 41 | '$1 $2', 42 | class_basename($this) 43 | ); 44 | } 45 | 46 | return $this->name; 47 | } 48 | 49 | /** 50 | * Get the description of this achievement. 51 | * 52 | * @return string 53 | */ 54 | public function getDescription() 55 | { 56 | return $this->description; 57 | } 58 | 59 | /** 60 | * Get the icon of this achievement. 61 | * 62 | * @return string 63 | */ 64 | public function getIcon() 65 | { 66 | return $this->icon; 67 | } 68 | 69 | /** 70 | * Get the icon of this achievement with path. 71 | * 72 | * @return string 73 | */ 74 | public function getIconAsAsset() 75 | { 76 | if (Str::startsWith($this->icon, ['http://', 'https://', '//'])) { 77 | return $this->icon; 78 | } 79 | 80 | return asset($this->icon); 81 | } 82 | 83 | /** 84 | * Get the data of the achievement. 85 | * 86 | * @param mixed $achievement 87 | * @return array 88 | */ 89 | public function getData($achievement) 90 | { 91 | if (method_exists($achievement, 'toDatabase')) { 92 | return is_array($data = $achievement->toDatabase()) 93 | ? $data : $data->data; 94 | } 95 | } 96 | 97 | /** 98 | * Unlocks an achievement. 99 | * 100 | * @param mixed $achiever 101 | * @param mixed $achievement 102 | * @param array|null $data 103 | * @return object 104 | */ 105 | public static function unlock($achiever, $achievement, $data = null) 106 | { 107 | $type = $achievement; 108 | 109 | if ($achievement instanceof self) { 110 | $type = get_class($achievement); 111 | } 112 | 113 | return $achiever->achievements()->create([ 114 | 'id' => Str::uuid()->toString(), 115 | 'type' => $type, 116 | 'data' => $data ?? optional($achievement)->getData($achievement), 117 | ]); 118 | } 119 | 120 | /** 121 | * Get the all of the achievement classes. 122 | * 123 | * @return \Illuminate\Support\Collection 124 | */ 125 | public static function getClasses() 126 | { 127 | $directory = app()->path('Achievements'); 128 | 129 | return collect(scandir($directory)) 130 | ->diff(['..', '.']) 131 | ->values(); 132 | } 133 | 134 | /** 135 | * Get the all of the achievement classes in namespace. 136 | * 137 | * @return \Illuminate\Support\Collection 138 | */ 139 | public static function getNamespacedClasses() 140 | { 141 | return self::getClasses() 142 | ->transform(function ($class) { 143 | return sprintf( 144 | '%sAchievements\%s', 145 | app()->getNamespace(), 146 | rtrim($class, '.php') 147 | ); 148 | }); 149 | } 150 | 151 | /** 152 | * Get the all of the achievement classes instantiated. 153 | * 154 | * @return \Illuminate\Support\Collection 155 | */ 156 | public static function getClassesInstantiated() 157 | { 158 | return self::getNamespacedClasses() 159 | ->transform(function ($class) { 160 | return new $class; 161 | }); 162 | } 163 | 164 | /** 165 | * Shorthand function for getInstantiatedClasses. 166 | * 167 | * @return \Illuminate\Support\Collection 168 | */ 169 | public static function all() 170 | { 171 | return self::getClassesInstantiated(); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/AchievementsServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 18 | __DIR__.'/../config/achievements.php' => config_path('achievements.php'), 19 | ], 'achievements-config'); 20 | 21 | $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); 22 | 23 | $this->publishes([ 24 | __DIR__.'/../database/migrations/' => database_path('migrations'), 25 | ], 'achievements-migrations'); 26 | 27 | if ($this->app->runningInConsole()) { 28 | $this->commands([ 29 | MakeAchievement::class, 30 | ]); 31 | } 32 | } 33 | 34 | /** 35 | * Register the application services. 36 | * 37 | * @return void 38 | */ 39 | public function register() 40 | { 41 | $this->mergeConfigFrom(__DIR__.'/../config/achievements.php', 'achievements'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Console/Commands/MakeAchievement.php: -------------------------------------------------------------------------------- 1 | 'array', 37 | ]; 38 | 39 | /** 40 | * Get the table associated with the model. 41 | * 42 | * @return string 43 | */ 44 | public function getTable() 45 | { 46 | return config('achievements.table', 'achievements'); 47 | } 48 | 49 | /** 50 | * Get the achievement class associated with the model. 51 | * 52 | * @return object 53 | */ 54 | public function getClass() 55 | { 56 | return app($this->type); 57 | } 58 | 59 | /** 60 | * Get the achievement's name. 61 | * 62 | * @return string 63 | */ 64 | public function getNameAttribute() 65 | { 66 | return $this->getClass()->getName(); 67 | } 68 | 69 | /** 70 | * Get the achievement's description. 71 | * 72 | * @return string 73 | */ 74 | public function getDescriptionAttribute() 75 | { 76 | return $this->getClass()->getDescription(); 77 | } 78 | 79 | /** 80 | * Get the achievement's icon. 81 | * 82 | * @return string 83 | */ 84 | public function getIconAttribute() 85 | { 86 | return $this->getClass()->getIcon(); 87 | } 88 | 89 | /** 90 | * Get the achievement's icon as an asset. 91 | * 92 | * @return string 93 | */ 94 | public function getIconAsAssetAttribute() 95 | { 96 | return $this->getClass()->getIconAsAsset(); 97 | } 98 | 99 | /** 100 | * Get the achiever entity that the achievement belongs to. 101 | * 102 | * @return \Illuminate\Database\Eloquent\Relations\MorphTo 103 | */ 104 | public function achiever() 105 | { 106 | return $this->morphTo(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Traits/Achiever.php: -------------------------------------------------------------------------------- 1 | morphMany(AchievementModel::class, 'achiever'); 18 | } 19 | 20 | /** 21 | * Achieve an achievement. 22 | * 23 | * @param mixed $achievement 24 | * @return object 25 | */ 26 | public function achieve($achievement) 27 | { 28 | return Achievement::unlock($this, $achievement); 29 | } 30 | 31 | /** 32 | * Does the achievement exist on this entity? 33 | * 34 | * @param mixed $achievement 35 | * @return bool 36 | */ 37 | public function hasAchievement($achievement) 38 | { 39 | if ($achievement instanceof Achievement) { 40 | $achievement = get_class($achievement); 41 | } 42 | 43 | return $this->achievements()->where('type', $achievement)->exists(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /stubs/Achievement.stub: -------------------------------------------------------------------------------- 1 |