├── tests ├── .gitkeep └── ActivityLogSupervisorTest.php ├── .gitignore ├── scrutinizer.yml ├── .travis.yml ├── src ├── Spatie │ └── Activitylog │ │ ├── LogsActivityInterface.php │ │ ├── ActivitylogFacade.php │ │ ├── Handlers │ │ ├── BeforeHandlerInterface.php │ │ ├── ActivitylogHandlerInterface.php │ │ ├── DefaultLaravelHandler.php │ │ └── EloquentHandler.php │ │ ├── LogsActivity.php │ │ ├── Models │ │ └── Activity.php │ │ ├── ActivitylogServiceProvider.php │ │ └── ActivitylogSupervisor.php ├── migrations │ └── create_activity_log_table.stub └── config │ └── activitylog.php ├── phpunit.xml ├── CHANGELOG.md ├── composer.json ├── LICENSE ├── CONTRIBUTING.md └── README.md /tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | 5 | -------------------------------------------------------------------------------- /scrutinizer.yml: -------------------------------------------------------------------------------- 1 | tools: 2 | external_code_coverage: false 3 | checks: 4 | php: 5 | code_rating: true 6 | duplication: true 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | - hhvm 8 | - 7 9 | 10 | before_script: 11 | - travis_retry composer self-update 12 | - travis_retry composer install --prefer-source --no-interaction --dev 13 | 14 | script: vendor/bin/phpunit 15 | -------------------------------------------------------------------------------- /src/Spatie/Activitylog/LogsActivityInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Spatie/Activitylog/Handlers/ActivitylogHandlerInterface.php: -------------------------------------------------------------------------------- 1 | increments('id'); 15 | $table->integer('user_id')->nullable(); 16 | $table->string('text'); 17 | $table->string('ip_address', 64); 18 | $table->timestamps(); 19 | }); 20 | } 21 | 22 | /** 23 | * Reverse the migrations. 24 | */ 25 | public function down() 26 | { 27 | Schema::drop('activity_log'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/activitylog", 3 | "description": "A very simple activity logger to monitor the users of your website or application", 4 | "homepage": "https://github.com/spatie/activitylog", 5 | "abandoned" : "This package has been replaced by spatie/laravel-activitylog", 6 | "keywords": 7 | [ 8 | "log", 9 | "user", 10 | "activity", 11 | "laravel" 12 | ], 13 | "authors": [ 14 | { 15 | "name": "Freek Van der Herten", 16 | "email": "freek@spatie.be" 17 | } 18 | ], 19 | "require": { 20 | "php": ">=5.4.0", 21 | "illuminate/support": "5.*" 22 | 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "~4.0", 26 | "mockery/mockery": "0.9.*" 27 | }, 28 | "autoload": { 29 | "classmap": [ 30 | "src/migrations" 31 | ], 32 | "psr-0": { 33 | "Spatie\\Activitylog\\": "src/" 34 | } 35 | }, 36 | "license": "MIT" 37 | } 38 | -------------------------------------------------------------------------------- /src/Spatie/Activitylog/Handlers/DefaultLaravelHandler.php: -------------------------------------------------------------------------------- 1 | getActivityDescriptionForEvent($eventName); 15 | 16 | if ($message != '') { 17 | Activity::log($message); 18 | } 19 | }); 20 | } 21 | } 22 | 23 | /** 24 | * Set the default events to be recorded if the $recordEvents 25 | * property does not exist on the model. 26 | * 27 | * @return array 28 | */ 29 | protected static function getRecordActivityEvents() 30 | { 31 | if (isset(static::$recordEvents)) { 32 | return static::$recordEvents; 33 | } 34 | 35 | return [ 36 | 'created', 'updated', 'deleting', 'deleted', 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Freek Van der Herten 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 | -------------------------------------------------------------------------------- /src/Spatie/Activitylog/Handlers/EloquentHandler.php: -------------------------------------------------------------------------------- 1 | $text, 24 | 'user_id' => ($userId == '' ? null : $userId), 25 | 'ip_address' => $attributes['ipAddress'], 26 | ] 27 | ); 28 | 29 | return true; 30 | } 31 | 32 | /** 33 | * Clean old log records. 34 | * 35 | * @param int $maxAgeInMonths 36 | * 37 | * @return bool 38 | */ 39 | public function cleanLog($maxAgeInMonths) 40 | { 41 | $minimumDate = Carbon::now()->subMonths($maxAgeInMonths); 42 | Activity::where('created_at', '<=', $minimumDate)->delete(); 43 | 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Spatie/Activitylog/Models/Activity.php: -------------------------------------------------------------------------------- 1 | belongsTo($this->getAuthModelName(), 'user_id'); 26 | } 27 | 28 | public function getAuthModelName() 29 | { 30 | if (config('activitylog.userModel')) { 31 | return config('activitylog.userModel'); 32 | } 33 | 34 | //laravel 5.0 - 5.1 35 | if (! is_null(config('auth.model'))) { 36 | return config('auth.model'); 37 | } 38 | 39 | //laravel 5.2 40 | if (! is_null(config('auth.providers.users.model'))) { 41 | return config('auth.providers.users.model'); 42 | } 43 | 44 | throw new Exception('could not determine the model name for users'); 45 | } 46 | 47 | protected $guarded = ['id']; 48 | } 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/thephpleague/laravel-backup). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | vendor/bin/phpunit 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /tests/ActivityLogSupervisorTest.php: -------------------------------------------------------------------------------- 1 | logHandler = Mockery::mock('\Spatie\Activitylog\Handlers\EloquentHandler'); 15 | $this->config = Mockery::mock('\Illuminate\Config\Repository'); 16 | $this->auth = Mockery::mock('Illuminate\Contracts\Auth\Guard'); 17 | 18 | $this->config->shouldReceive('get')->andReturn(false); 19 | $this->activityLogSupervisor = new ActivitylogSupervisor($this->logHandler, $this->config, $this->auth); 20 | } 21 | 22 | /** 23 | * @test 24 | */ 25 | public function it_normalizes_an_empty_user_id_when_noone_is_logged_in() 26 | { 27 | $this->auth->shouldReceive('check')->andReturn(false); 28 | 29 | $normalizedUserId = $this->activityLogSupervisor->normalizeUserId(''); 30 | 31 | $this->assertSame('', $normalizedUserId); 32 | } 33 | 34 | /** 35 | * @test 36 | */ 37 | public function it_normalizes_an_empty_user_id_when_someone_is_logged_in() 38 | { 39 | $user = json_decode(json_encode(['id' => 123]), false); 40 | 41 | $this->auth->shouldReceive('check')->andReturn(true); 42 | $this->auth->shouldReceive('user')->andReturn($user); 43 | 44 | $normalizedUserId = $this->activityLogSupervisor->normalizeUserId(''); 45 | 46 | $this->assertSame(123, $normalizedUserId); 47 | } 48 | 49 | /** 50 | * @test 51 | */ 52 | public function it_normalizes_a_numeric_user_id() 53 | { 54 | $normalizedUserId = $this->activityLogSupervisor->normalizeUserId(123); 55 | 56 | $this->assertSame(123, $normalizedUserId); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Spatie/Activitylog/ActivitylogServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 23 | __DIR__ . '/../../config/activitylog.php' => config_path('activitylog.php'), 24 | ], 'config'); 25 | 26 | if (!$this->migrationHasAlreadyBeenPublished()) { 27 | // Publish migration 28 | $timestamp = date('Y_m_d_His', time()); 29 | 30 | $this->publishes([ 31 | __DIR__ . "/../../migrations/create_activity_log_table.stub" => database_path("/migrations/{$timestamp}_create_activity_log_table.php"), 32 | ], 'migrations'); 33 | } 34 | } 35 | 36 | /** 37 | * Register the service provider. 38 | */ 39 | public function register() 40 | { 41 | $this->app->bind( 42 | 'activity', 43 | 'Spatie\Activitylog\ActivitylogSupervisor' 44 | ); 45 | 46 | $this->app->bind( 47 | 'Spatie\Activitylog\Handlers\ActivitylogHandlerInterface', 48 | 'Spatie\Activitylog\Handlers\EloquentHandler' 49 | ); 50 | } 51 | 52 | /** 53 | * Get the services provided by the provider. 54 | * 55 | * @return array 56 | */ 57 | public function provides() 58 | { 59 | return []; 60 | } 61 | 62 | /** 63 | * @return bool 64 | */ 65 | protected function migrationHasAlreadyBeenPublished() 66 | { 67 | $files = glob(database_path('/migrations/*_create_activity_log_table.php')); 68 | 69 | return count($files) > 0; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/config/activitylog.php: -------------------------------------------------------------------------------- 1 | true, 15 | 16 | /* 17 | |-------------------------------------------------------------------------- 18 | | Max age in months for log records 19 | |-------------------------------------------------------------------------- 20 | | 21 | | When running the cleanLog-command all recorder older than the number of months 22 | | specified here will be deleted 23 | | 24 | */ 25 | 'deleteRecordsOlderThanMonths' => 2, 26 | 27 | /* 28 | |-------------------------------------------------------------------------- 29 | | Fallback user id if no user is logged in 30 | |-------------------------------------------------------------------------- 31 | | 32 | | If you don't specify a user id when logging some activity and no 33 | | user is logged in, this id will be used. 34 | | 35 | */ 36 | 'defaultUserId' => '', 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Handler that is called before logging is done 41 | |-------------------------------------------------------------------------- 42 | | 43 | | If you want to disable logging based on some custom conditions, create 44 | | a handler class that implements the BeforeHandlerInterface and 45 | | reference it here. 46 | | 47 | */ 48 | 'beforeHandler' => null, 49 | 50 | /* 51 | |-------------------------------------------------------------------------- 52 | | The class name for the related user model 53 | |-------------------------------------------------------------------------- 54 | | 55 | | This can be a class name or null. If null the model will be determined 56 | | from Laravel's auth configuration. 57 | | 58 | */ 59 | 'userModel' => null, 60 | ]; 61 | -------------------------------------------------------------------------------- /src/Spatie/Activitylog/ActivitylogSupervisor.php: -------------------------------------------------------------------------------- 1 | config = $config; 34 | 35 | $this->logHandlers[] = $logHandler; 36 | 37 | if ($this->config->get('activitylog.alsoLogInDefaultLog')) { 38 | $this->logHandlers[] = new DefaultLaravelHandler(); 39 | } 40 | 41 | $this->auth = $auth; 42 | } 43 | 44 | /** 45 | * Log some activity to all registered log handlers. 46 | * 47 | * @param $text 48 | * @param string $userId 49 | * 50 | * @return bool 51 | */ 52 | public function log($text, $userId = '') 53 | { 54 | $userId = $this->normalizeUserId($userId); 55 | 56 | if (! $this->shouldLogCall($text, $userId)) { 57 | return false; 58 | } 59 | 60 | $ipAddress = Request::getClientIp(); 61 | 62 | foreach ($this->logHandlers as $logHandler) { 63 | $logHandler->log($text, $userId, compact('ipAddress')); 64 | } 65 | 66 | return true; 67 | } 68 | 69 | /** 70 | * Clean out old entries in the log. 71 | * 72 | * @return bool 73 | */ 74 | public function cleanLog() 75 | { 76 | foreach ($this->logHandlers as $logHandler) { 77 | $logHandler->cleanLog(Config::get('activitylog.deleteRecordsOlderThanMonths')); 78 | } 79 | 80 | return true; 81 | } 82 | 83 | /** 84 | * Normalize the user id. 85 | * 86 | * @param object|int $userId 87 | * 88 | * @return int 89 | */ 90 | public function normalizeUserId($userId) 91 | { 92 | if (is_numeric($userId)) { 93 | return $userId; 94 | } 95 | 96 | if (is_object($userId)) { 97 | return $userId->id; 98 | } 99 | 100 | if ($this->auth->check()) { 101 | return $this->auth->user()->id; 102 | } 103 | 104 | if (is_numeric($this->config->get('activitylog.defaultUserId'))) { 105 | return $this->config->get('activitylog.defaultUserId'); 106 | }; 107 | 108 | return ''; 109 | } 110 | 111 | /** 112 | * Determine if this call should be logged. 113 | * 114 | * @param $text 115 | * @param $userId 116 | * 117 | * @return bool 118 | */ 119 | protected function shouldLogCall($text, $userId) 120 | { 121 | $beforeHandler = $this->config->get('activitylog.beforeHandler'); 122 | 123 | if (is_null($beforeHandler) || $beforeHandler == '') { 124 | return true; 125 | } 126 | 127 | return app($beforeHandler)->shouldLog($text, $userId); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Log the activity of your users 2 | 3 | [![Latest Version](https://img.shields.io/github/release/spatie/activitylog.svg?style=flat-square)](https://github.com/spatie/activitylog/releases) 4 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 5 | [![Build Status](https://img.shields.io/travis/spatie/activitylog/master.svg?style=flat-square)](https://travis-ci.org/spatie/activitylog) 6 | [![SensioLabsInsight](https://img.shields.io/sensiolabs/i/c48809c7-cdb3-4e86-974b-ad9c6282bc3c.svg)](https://insight.sensiolabs.com/projects/c48809c7-cdb3-4e86-974b-ad9c6282bc3c) 7 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/activitylog.svg?style=flat-square)](https://packagist.org/packages/spatie/activitylog) 8 | 9 | ## EOL-warning 10 | 11 | This package has been abandoned on 2016-06-28. Please use [laravel-activitylog](https://github.com/spatie/laravel-activitylog) instead. 12 | 13 | ## Description 14 | 15 | This Laravel 5 package provides a very easy to use solution to log the activities of the users of your Laravel 5 app. All the activities will be logged in a db-table. Optionally the activities can also be logged against the default Laravel Log Handler. 16 | 17 | Spatie is a webdesign agency in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 18 | 19 | ### Note: 20 | 21 | If you're using Laravel 4, take a look at version 0.3.0 of this package. 22 | 23 | ## Postcardware 24 | 25 | You're free to use this package (it's [MIT-licensed](LICENSE.md)), but if it makes it to your production environment you are required to send us a postcard from your hometown, mentioning which of our package(s) you are using. 26 | 27 | Our address is: Spatie, Samberstraat 69D, 2060 Antwerp, Belgium. 28 | 29 | The best postcards will get published on the open source page on our website. 30 | 31 | ## Installation 32 | 33 | This package can be installed through Composer. 34 | ```bash 35 | composer require spatie/activitylog 36 | ``` 37 | 38 | 39 | This service provider must be registered. 40 | ```php 41 | // config/app.php 42 | 43 | 'providers' => [ 44 | '...', 45 | 'Spatie\Activitylog\ActivitylogServiceProvider', 46 | ]; 47 | ``` 48 | 49 | 50 | You'll also need to publish and run the migration in order to create the db-table. 51 | ``` 52 | php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="migrations" 53 | php artisan migrate 54 | ``` 55 | 56 | 57 | Activitylog also comes with a facade, which provides an easy way to call it. 58 | ```php 59 | // config/app.php 60 | 61 | 'aliases' => [ 62 | ... 63 | 'Activity' => 'Spatie\Activitylog\ActivitylogFacade', 64 | ]; 65 | ``` 66 | 67 | 68 | Optionally you can publish the config file of this package. 69 | ``` 70 | php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="config" 71 | ``` 72 | The configuration will be written to ```config/activitylog.php```. The options provided are self explanatory. 73 | 74 | 75 | ## Usage 76 | 77 | ### Manual logging 78 | 79 | Logging some activity is very simple. 80 | ```php 81 | //at the top of your file you should import the facade. 82 | use Activity; 83 | ... 84 | /* 85 | The log-function takes two parameters: 86 | - $text: the activity you wish to log. 87 | - $user: optional can be an user id or a user object. 88 | if not proved the id of Auth::user() will be used 89 | 90 | */ 91 | Activity::log('Some activity that you wish to log'); 92 | ``` 93 | The string you pass to function gets written in a db-table together with a timestamp, the ip address and the user agent of the user. 94 | 95 | ### Log model events 96 | This package can log the events from your models. To do so your model must use the `LogsActivity`-trait and implement `LogsActivityInterface`. 97 | 98 | ```php 99 | use Spatie\Activitylog\LogsActivityInterface; 100 | use Spatie\Activitylog\LogsActivity; 101 | 102 | class Article implements LogsActivityInterface { 103 | 104 | use LogsActivity; 105 | ... 106 | ``` 107 | 108 | The interface expects you to implement the `getActivityDescriptionForEvent`-function. 109 | 110 | Here's an example of a possible implementation. 111 | 112 | ```php 113 | /** 114 | * Get the message that needs to be logged for the given event name. 115 | * 116 | * @param string $eventName 117 | * @return string 118 | */ 119 | public function getActivityDescriptionForEvent($eventName) 120 | { 121 | if ($eventName == 'created') 122 | { 123 | return 'Article "' . $this->name . '" was created'; 124 | } 125 | 126 | if ($eventName == 'updated') 127 | { 128 | return 'Article "' . $this->name . '" was updated'; 129 | } 130 | 131 | if ($eventName == 'deleted') 132 | { 133 | return 'Article "' . $this->name . '" was deleted'; 134 | } 135 | 136 | return ''; 137 | } 138 | ``` 139 | The result of this function will be logged, unless the result is an empty string. 140 | 141 | ### Using a before handler. 142 | If you want to disable logging under certain conditions, 143 | such as for a specific user, create a class in your application 144 | namespace that implements the `Spatie\Activitylog\Handlers\BeforeHandlerInterface`. 145 | 146 | This interface defines an `shouldLog()` method in which you can code any custom logic to determine 147 | whether logging should be ignored or not. You must return `true` the call should be logged. 148 | 149 | To en the namespaced class nameto the `beforeHandler` field in the configuration file: 150 | ```php 151 | 'beforeHandler' => '\App\Handlers\BeforeHandler', 152 | ``` 153 | 154 | For example, this callback class could look like this to disable 155 | logging a user with id of 1: 156 | ```php 157 | latest()->limit(100)->get(); 181 | ``` 182 | 183 | ### Cleaning up the log 184 | 185 | Over time your log will grow. To clean up the database table you can run this command: 186 | ```php 187 | Activity::cleanLog(); 188 | ``` 189 | By default records older than 2 months will be deleted. The number of months can be modified in the config-file of the package. 190 | 191 | ## Contributing 192 | 193 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 194 | 195 | ## Security 196 | 197 | If you discover any security related issues, please email freek@spatie.be instead of using the issue tracker. 198 | 199 | ## Credits 200 | 201 | - [Freek Van der Herten](https://github.com/freekmurze) 202 | - [All Contributors](../../contributors) 203 | 204 | ## About Spatie 205 | Spatie is a webdesign agency in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 206 | 207 | ## License 208 | 209 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 210 | --------------------------------------------------------------------------------