├── changelog.md ├── src ├── FireableAttributes.php └── Fireable.php ├── license.md ├── composer.json ├── readme.md └── .github └── workflows └── tests.yaml /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `Fireable` will be documented in this file. 4 | 5 | ## Version 1.0 6 | 7 | First version. -------------------------------------------------------------------------------- /src/FireableAttributes.php: -------------------------------------------------------------------------------- 1 | processAttributes($model); 16 | }); 17 | } 18 | 19 | /** 20 | * Get a list of model's "fireable" attributes. 21 | * 22 | * @return array 23 | */ 24 | public function getFireableAttributes(): array 25 | { 26 | return $this->fireableAttributes; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) Boris Lepikhin 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "envant/fireable", 3 | "description": "An elegant way to trigger events based on attributes changes", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Boris Lepikhin", 8 | "email": "info@envant.me", 9 | "homepage": "https://envant.me" 10 | } 11 | ], 12 | "homepage": "https://github.com/envant/fireable", 13 | "keywords": [ 14 | "Laravel", 15 | "Fireable", 16 | "event" 17 | ], 18 | "require": { 19 | "php": "^7.2|^8", 20 | "illuminate/support": "^5.8|^6|^7|^8|^9|^10.0", 21 | "illuminate/database": "^5.8|^6|^7|^8|^9|^10.0" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": "^7.5 || ^8 || ^9.5", 25 | "mockery/mockery": "^1.2", 26 | "orchestra/testbench": "^3.8 || ^4 || ^5 || ^6 || ^7|^8.0", 27 | "sempro/phpunit-pretty-print": "^1.1" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Envant\\Fireable\\": "src/" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Envant\\Fireable\\Tests\\": "tests" 37 | } 38 | }, 39 | "scripts": { 40 | "test": "phpunit" 41 | }, 42 | "config": { 43 | "sort-packages": true 44 | }, 45 | "minimum-stability": "dev", 46 | "prefer-stable": true 47 | } 48 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Fireable 2 | 3 | [![Latest Version on Packagist][ico-version]][link-packagist] 4 | [![StyleCI](https://styleci.io/repos/209407300/shield)](https://styleci.io/repos/209407300) 5 | [![Build Status](https://travis-ci.org/envant/fireable.svg?branch=master)](https://travis-ci.org/envant/fireable) 6 | [![Total Downloads][ico-downloads]][link-downloads] 7 | 8 | An elegant way to trigger events based on attributes changes. 9 | 10 | ## Installation 11 | 12 | Install package through Composer 13 | 14 | ``` bash 15 | $ composer require envant/fireable 16 | ``` 17 | 18 | ## Usage 19 | 20 | 1. Add the `FireableAttributes` trait to your model 21 | 2. Define the attributes with specified events via the `protected $fireableAttributes` property on the model 22 | 23 | ### Example 24 | 25 | Let's say we need to trigger specified events when specific model attributes are updated. 26 | 27 | For example, you need to notify user when he gets an "approved" status. Instead of observing model's "dirty" attributes and firing events manually we could do it more elegantly by assigning specified events to attributes or even certain values of attributes. 28 | 29 | ```php 30 | class User extends Authenticatable 31 | { 32 | use FireableAttributes; 33 | 34 | protected $fireableAttributes = [ 35 | 'status' => [ 36 | 'approved' => UserApproved::class, 37 | 'rejected' => UserRejected::class, 38 | ], 39 | ]; 40 | } 41 | ``` 42 | 43 | Also you may not need to track certain values, so you can assign an event directly to an attribute itself. So, in the example below, each time the user's email is changed, the appropriate event will be fired. 44 | 45 | ```php 46 | class User extends Authenticatable 47 | { 48 | use FireableAttributes; 49 | 50 | protected $fireableAttributes = [ 51 | 'email' => EmailUpdated::class, 52 | ]; 53 | } 54 | ``` 55 | 56 | ## Change log 57 | 58 | Please see the [changelog](changelog.md) for more information on what has changed recently. 59 | 60 | ## Testing 61 | 62 | ``` bash 63 | $ composer test 64 | ``` 65 | 66 | ## Contributing 67 | 68 | Please see [contributing.md](contributing.md) for details and a todolist. 69 | 70 | ## Security 71 | 72 | If you discover any security related issues, please email author email instead of using the issue tracker. 73 | 74 | ## Credits 75 | 76 | - [Boris Lepikhin][link-author] 77 | - [All Contributors][link-contributors] 78 | 79 | ## License 80 | 81 | license. Please see the [license file](license.md) for more information. 82 | 83 | [ico-version]: https://img.shields.io/packagist/v/envant/fireable.svg?style=flat-square 84 | [ico-downloads]: https://img.shields.io/packagist/dt/envant/fireable.svg?style=flat-square 85 | 86 | [link-packagist]: https://packagist.org/packages/envant/fireable 87 | [link-downloads]: https://packagist.org/packages/envant/fireable 88 | [link-author]: https://github.com/envant 89 | [link-contributors]: ../../contributors 90 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | jobs: 6 | tests: 7 | name: PHP ${{ matrix.php }}, Laravel ${{ matrix.laravel }} 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | php: [7.2, 7.3, 7.4, 8.0, 8.1] 13 | laravel: [5.8.*, 6.*, 7.*, 8.*, 9.*, 10.*] 14 | include: 15 | - laravel: 10.* 16 | testbench: 8.* 17 | - laravel: 5.8.* 18 | testbench: 3.8.* 19 | phpunit: ^7.5 20 | phpunit_printer: 'Sempro\PHPUnitPrettyPrinter\PrettyPrinter' 21 | - laravel: 6.* 22 | testbench: 4.* 23 | phpunit: ^8 24 | phpunit_printer: 'Sempro\PHPUnitPrettyPrinter\PrettyPrinter' 25 | - laravel: 7.* 26 | testbench: 5.* 27 | phpunit: ^8 28 | phpunit_printer: 'Sempro\PHPUnitPrettyPrinter\PrettyPrinter' 29 | - laravel: 8.* 30 | testbench: 6.* 31 | phpunit: ^9.5.10 32 | phpunit_printer: 'Sempro\PHPUnitPrettyPrinter\PrettyPrinterForPhpUnit9' 33 | - laravel: 9.* 34 | testbench: 7.* 35 | phpunit: ^9.5.10 36 | phpunit_printer: 'Sempro\PHPUnitPrettyPrinter\PrettyPrinterForPhpUnit9' 37 | exclude: 38 | - laravel: 10.* 39 | php: 7.2 40 | - laravel: 10.* 41 | php: 7.3 42 | - laravel: 10.* 43 | php: 7.4 44 | - laravel: 10.* 45 | php: 8.0 46 | - laravel: 5.8.* 47 | php: 8.0 48 | - laravel: 5.8.* 49 | php: 8.1 50 | - laravel: 6.* 51 | php: 8.1 52 | - laravel: 7.* 53 | php: 8.1 54 | - laravel: 8.* 55 | php: 7.2 56 | - laravel: 9.* 57 | php: 7.2 58 | - laravel: 9.* 59 | php: 7.3 60 | - laravel: 9.* 61 | php: 7.4 62 | steps: 63 | - name: Checkout Code 64 | uses: actions/checkout@v2 65 | - name: Cache dependencies 66 | uses: actions/cache@v1 67 | with: 68 | path: ~/.composer/cache/files 69 | key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 70 | - name: Setup PHP 71 | uses: shivammathur/setup-php@v2 72 | with: 73 | php-version: ${{ matrix.php }} 74 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick 75 | coverage: none 76 | - name: Install Dependencies 77 | run: | 78 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "phpunit/phpunit:${{ matrix.phpunit }}" --no-interaction --no-update 79 | composer update --prefer-stable --prefer-dist --no-interaction 80 | - name: Execute tests 81 | run: php vendor/bin/phpunit --printer "${{ matrix.phpunit_printer }}" tests/ 82 | -------------------------------------------------------------------------------- /src/Fireable.php: -------------------------------------------------------------------------------- 1 | model = $model; 28 | $this->fireableAttributes = $this->model->getFireableAttributes(); 29 | $this->updatedAttributes = $this->getUpdatedFireableAttributes(); 30 | 31 | $this->dispatchEvents(); 32 | } 33 | 34 | /** 35 | * Get a list of the attributes that were updated and have specified events. 36 | * 37 | * @return array 38 | */ 39 | private function getUpdatedFireableAttributes(): array 40 | { 41 | // get a list of updated attributes 42 | $updatedAttributes = $this->model->getDirty(); 43 | 44 | // get a list of updated attributes that should trigger events 45 | $updatedFireableAttributes = Arr::only($updatedAttributes, array_keys($this->fireableAttributes)); 46 | 47 | return $updatedFireableAttributes; 48 | } 49 | 50 | /** 51 | * Dispatch events for matched attributes. 52 | * 53 | * @return void 54 | */ 55 | private function dispatchEvents(): void 56 | { 57 | foreach ($this->updatedAttributes as $attribute => $value) { 58 | if ($eventName = $this->getEventName($attribute, $value)) { 59 | event(new $eventName($this->model)); 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * Get event name for specified attribute and assigned value pair. 66 | * 67 | * @param string $attribute 68 | * @param mixed $value 69 | * @return string|null 70 | */ 71 | private function getEventName(string $attribute, $value): ?string 72 | { 73 | return $this->getEventNameForAttribute($attribute) 74 | ?? $this->getEventNameForExactValue($attribute, $value); 75 | } 76 | 77 | /** 78 | * Get event name if values are not specified. 79 | * 80 | * @param string $attribute 81 | * @return string|null 82 | */ 83 | private function getEventNameForAttribute(string $attribute): ?string 84 | { 85 | return is_string($this->fireableAttributes[$attribute]) 86 | && class_exists($this->fireableAttributes[$attribute]) 87 | ? $this->fireableAttributes[$attribute] 88 | : null; 89 | } 90 | 91 | /** 92 | * Get event name if there are specified values. 93 | * 94 | * @param string $attribute 95 | * @param mixed $value 96 | * @return string|null 97 | */ 98 | private function getEventNameForExactValue(string $attribute, $value): ?string 99 | { 100 | return is_array($this->fireableAttributes[$attribute]) 101 | && isset($this->fireableAttributes[$attribute][$value]) 102 | ? $this->fireableAttributes[$attribute][$value] 103 | : null; 104 | } 105 | } 106 | --------------------------------------------------------------------------------