├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config ├── blame.php └── private_blame.php ├── database ├── factories │ └── ModelFactory.php └── migrations │ └── create_blame_table.php.stub ├── resources ├── stubs │ └── migration.add.blaming.int.fields.stub └── views │ └── .gitkeep └── src ├── Commands ├── BlameFieldsMigrationCommand.php ├── LaravelBlameCommand.php └── SystemUserCommand.php ├── Contracts ├── HandleEnvFile.php └── ModelBlame.php ├── Database └── Migrations │ └── BlameMigrationCreator.php ├── Facades └── LaravelBlame.php ├── LaravelBlame.php ├── LaravelBlameServiceProvider.php └── Traits ├── EnvFileHandler.php ├── ModelBlamer.php └── UserModelForAuth.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-blame` will be documented in this file. 4 | 5 | ## v2.0.0 - 2025-04-10 6 | 7 | Full compatibility with larael 9.x 8 | minimum php version 8.2 9 | 10 | ### What's Changed 11 | 12 | * Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/3 13 | * Bump dependabot/fetch-metadata from 1.3.6 to 1.4.0 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/5 14 | * Bump dependabot/fetch-metadata from 1.4.0 to 1.5.1 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/7 15 | * Bump aglipanci/laravel-pint-action from 1.0.0 to 2.3.0 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/6 16 | * Bump dependabot/fetch-metadata from 1.5.1 to 1.6.0 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/8 17 | * Bump stefanzweifel/git-auto-commit-action from 4 to 5 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/11 18 | * Bump actions/checkout from 3 to 4 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/10 19 | * Bump aglipanci/laravel-pint-action from 2.3.0 to 2.3.1 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/14 20 | * Bump aglipanci/laravel-pint-action from 2.3.1 to 2.4 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/15 21 | * Fix/GH-18 (#18) by @zenoandras in https://github.com/kamansoft/laravel-blame/pull/19 22 | * Bump dependabot/fetch-metadata from 1.6.0 to 2.2.0 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/17 23 | * Bump ramsey/composer-install from 2 to 3 by @dependabot in https://github.com/kamansoft/laravel-blame/pull/13 24 | * test only 8.2 to release branch by @lemyskaman in https://github.com/kamansoft/laravel-blame/pull/22 25 | * ensure working for laravel 9 to release branch by @lemyskaman in https://github.com/kamansoft/laravel-blame/pull/23 26 | * Releases/v2.0.0 to main by @lemyskaman in https://github.com/kamansoft/laravel-blame/pull/24 27 | 28 | ### New Contributors 29 | 30 | * @dependabot made their first contribution in https://github.com/kamansoft/laravel-blame/pull/3 31 | * @zenoandras made their first contribution in https://github.com/kamansoft/laravel-blame/pull/19 32 | * @lemyskaman made their first contribution in https://github.com/kamansoft/laravel-blame/pull/22 33 | 34 | **Full Changelog**: https://github.com/kamansoft/laravel-blame/compare/1.0.11...2.0.0 35 | 36 | ## v1.0.11 - 2023-01-04 37 | 38 | Fixed migrations name generation on blame make migration command 39 | Fixed composer json typo 40 | 41 | ## v1.0.1 - 2023-01-03 42 | 43 | Fixing some phpstan errors 44 | 45 | ## v1.0.0 - 2023-01-03 46 | 47 | Initial Release 48 | 49 | Model blame trait 50 | system user command 51 | blame field migration commad 52 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) kamansoft 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-blame 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/kamansoft/laravel-blame.svg?style=flat-square)](https://packagist.org/packages/kamansoft/laravel-blame) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/kamansoft/laravel-blame/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/kamansoft/laravel-blame/actions?query=workflow%3Arun-tests+branch%3Amain) 5 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/kamansoft/laravel-blame/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/kamansoft/laravel-blame/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/kamansoft/laravel-blame.svg?style=flat-square)](https://packagist.org/packages/kamansoft/laravel-blame) 7 | 8 | ## update_by and created_by fields in your laravel model ? 9 | 10 | This is a laravel package that will ease the usage of the normally called **created_by** and **update_by** extra fields used to stablish responsabilites on records persistance create or update events, with similar fashion as the "timestamp fields" on Eloquent's models, it automatically fills the fields with the primary key of the currently logged user or with a preconfigured system user id. 11 | 12 | 13 | ## Requirements 14 | 15 | This package was build taking in mind that you use laravel with an [eloquent **user model class** as auth provider](https://laravel.com/docs/9.x/authentication#introduction). So before installing, you must make sure that your user eloquent model is set on the providers section of your auth config file like this: 16 | 17 | ```php 18 | //config/auth.php 19 | 20 | 'providers' => [ 21 | 'users' => [ 22 | 'driver' => 'eloquent', 23 | 'model' => App\Models\User::class, // <-- this is the important part 24 | ], 25 | ], 26 | ``` 27 | ### Laravel version. 28 | The Lasted version of this package was tested with laravel 9. Should be compatible with versions above also it should work with laravel 8 too, if you find any issue please open an [issue on github](https://github.com/kamansoft/laravel-blame/issues) 29 | 30 | 31 | ## Installation 32 | 33 | 34 | 35 | You can install the package via composer: 36 | 37 | ```bash 38 | composer require kamansoft/laravel-blame 39 | ``` 40 | 41 | Sometimes your laravel application will perform actions that persist records on the database without an authenticated or logged-in user, You can call this user as System User or any other name you want, but you must specify its id or primary key. 42 | 43 | To do so, you can run the [system user command](#system-user-command) or the package install comand: 44 | 45 | ```bash 46 | php artisan blame:install 47 | ``` 48 | The above command will publish the package config file, and it will run the [system user command](#system-user-command) with no arguments. 49 | 50 | 51 | ## Usage 52 | 53 | 54 | You must first add the **update_by** and **created_by** fields to the table's migration field to use it in your models. 55 | 56 | ```php 57 | //dabase/migrations/2023_01_02_154102_create_somes_table 58 | 59 | use Illuminate\Database\Migrations\Migration; 60 | use Illuminate\Database\Schema\Blueprint; 61 | use Illuminate\Support\Facades\Schema; 62 | 63 | return new class extends Migration 64 | { 65 | public function up() 66 | { 67 | Schema::create('somes', function (Blueprint $table) { 68 | $table->uuid('id')->primary(); 69 | $table->string('name'); 70 | 71 | $system_user_id = env('BLAME_SYSTEM_USER_ID'); 72 | $table->unsignedBigInteger('created_by')->default($system_user_id); 73 | $table->unsignedBigInteger('updated_by')->default($system_user_id); 74 | $table->foreign('created_by')->references('id')->on('users'); 75 | $table->foreign('updated_by')->references('id')->on('users'); 76 | 77 | $table->timestamps(); 78 | }); 79 | } 80 | ``` 81 | 82 | Then make use of the [Modelblamer trait](https://github.com/kamansoft/laravel-blame/blob/c95967a0e15155562d1aa05a5fc6fb8e8d164ff8/src/Traits/ModelBlamer.php) on your eloquent models, and its [booting method](https://github.com/kamansoft/laravel-blame/blob/c95967a0e15155562d1aa05a5fc6fb8e8d164ff8/src/Traits/ModelBlamer.php#L11) will take care of the rest. Also for the seek of a good practice let your model implement the [BlameableInterface](https://github.com/kamansoft/laravel-blame/blob/main/src/Contracts/ModelBlame.php) on your models. Then your model should look something like this 83 | 84 | ```php 85 | //app/Models/SomeModel.php 86 | 87 | namespace App\Models; 88 | 89 | 90 | use Illuminate\Database\Eloquent\Model; 91 | use Kamansoft\LaravelBlame\Contracts\ModelBlame; 92 | use Kamansoft\LaravelBlame\Traits\ModelBlamer; 93 | 94 | class SomeModel extends Model implements ModelBlame 95 | { 96 | 97 | use ModelBlamer; // <-- this is the important part 98 | ``` 99 | 100 | 101 | 102 | 103 | ## Commands 104 | 105 | This package ships two artisan commands as tools to ease the package usage simplifying a repetitive task like creating or updating the system user or adding the updated by and created by fields to your model's table. 106 | 107 | ### Blame FIelds Migration command 108 | 109 | This command is primary intended to be used when you need to update an existing table, adding the created_by and updated_by fields; it needs an argument with the name of the table to update. 110 | 111 | ```bash 112 | php artisan blame:make:migration some_table_name 113 | ``` 114 | When run, the above command will create a new migration file in the database/migrations folder with the name **add_blame_fields_to_some_table_name_table** with a content similar to this: 115 | 116 | ```php 117 | //database/migrations/2023_01_02_154102_add_blame_fields_to_some_table_name_table.php 118 | return new class extends Migration 119 | { 120 | public function up() 121 | { 122 | 123 | Schema::table('some_table_name', function (Blueprint $table) { 124 | $system_user_id = env('BLAME_SYSTEM_USER_ID'); 125 | $table->unsignedBigInteger(config('blame.created_by_field_name'))->default($system_user_id); 126 | $table->unsignedBigInteger(config('blame.updated_by_field_name'))->default($system_user_id); 127 | }); 128 | Schema::table('some_table_name', function (Blueprint $table) { 129 | $table->unsignedBigInteger(config('blame.created_by_field_name'))->default(null)->change(); 130 | $table->unsignedBigInteger(config('blame.updated_by_field_name'))->default(null)->change(); 131 | }); 132 | Schema::table('some_table_name', function (Blueprint $table) { 133 | $table->foreign(config('blame.created_by_field_name'))->references('id')->on('users'); 134 | $table->foreign(config('blame.updated_by_field_name'))->references('id')->on('users'); 135 | }); 136 | } 137 | ``` 138 | 139 | 140 | ### System User Command 141 | 142 | When used with no param or arguments: 143 | ```bash 144 | php artisan blame:set:systemuser 145 | ``` 146 | This command creates a new laravel user to be used when no user can be retrived with Auth::user(). 147 | 148 | When run with a value through the optional "--key" param: 149 | ```bash 150 | php artisan blame:set:systemuser --key=some_user_id 151 | ``` 152 | The command will check if a user with that id exists, and if not, it will try to create one with that id. 153 | 154 | In both cases, the command will set the created system user primary key or id in the project .env file as BLAME_SYSTEM_USER_ID. 155 | 156 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kamansoft/laravel-blame", 3 | "description": "A tool to easily work with the updated_by and created_by fields on your laravel eloquent models ", 4 | "keywords": [ 5 | "kamansoft", 6 | "laravel", 7 | "laravel-blame" 8 | ], 9 | "homepage": "https://github.com/kamansoft/laravel-blame", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "lemys lopez", 14 | "email": "lemyskaman@gmail.com", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.2", 20 | "doctrine/dbal": "^3.5", 21 | "illuminate/contracts": "^9.0", 22 | "spatie/laravel-package-tools": "^1.19.0" 23 | }, 24 | "require-dev": { 25 | "laravel/pint": "^1.0", 26 | "nunomaduro/collision": "^6.0", 27 | "nunomaduro/larastan": "^2.0.1", 28 | "orchestra/testbench": "^7.0", 29 | "pestphp/pest": "^1.21", 30 | "pestphp/pest-plugin-laravel": "^1.1", 31 | "phpstan/extension-installer": "^1.1", 32 | "phpstan/phpstan-deprecation-rules": "^1.0", 33 | "phpstan/phpstan-phpunit": "^1.0", 34 | "phpunit/phpunit": "^9.5" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "Kamansoft\\LaravelBlame\\": "src/", 39 | "Kamansoft\\LaravelBlame\\Database\\Factories\\": "database/factories" 40 | } 41 | }, 42 | "autoload-dev": { 43 | "psr-4": { 44 | "Kamansoft\\LaravelBlame\\Tests\\": "tests" 45 | } 46 | }, 47 | "scripts": { 48 | "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", 49 | "analyse": "vendor/bin/phpstan analyse", 50 | "test": "vendor/bin/pest", 51 | "test-coverage": "vendor/bin/pest --coverage", 52 | "format": "vendor/bin/pint" 53 | }, 54 | "config": { 55 | "sort-packages": true, 56 | "allow-plugins": { 57 | "pestphp/pest-plugin": true, 58 | "phpstan/extension-installer": true 59 | } 60 | }, 61 | "extra": { 62 | "laravel": { 63 | "providers": [ 64 | "Kamansoft\\LaravelBlame\\LaravelBlameServiceProvider" 65 | ], 66 | "aliases": { 67 | "LaravelBlame": "Kamansoft\\LaravelBlame\\Facades\\LaravelBlame" 68 | } 69 | } 70 | }, 71 | "minimum-stability": "dev", 72 | "prefer-stable": true 73 | } 74 | -------------------------------------------------------------------------------- /config/blame.php: -------------------------------------------------------------------------------- 1 | env('BLAME_SYSTEM_USER_ID'), 6 | 'system_user_name' => env('BLAME_SYSTEM_USER_NAME', 'system'), 7 | 'system_user_email' => env('BLAME_SYSTEM_USER_EMAIL', 'system'.'@'.explode('/', config('app.url'))[2]), 8 | 'created_by_field_name' => 'created_by', 9 | 'updated_by_field_name' => 'updated_by', 10 | ]; 11 | -------------------------------------------------------------------------------- /config/private_blame.php: -------------------------------------------------------------------------------- 1 | env('BLAME_SYSTEM_USER_ID'), //do not modify this line 6 | 'migration_name_prefix' => 'add_blaming_fields_to_', 7 | 'migration_name_suffix' => '_table', 8 | 9 | ]; 10 | -------------------------------------------------------------------------------- /database/factories/ModelFactory.php: -------------------------------------------------------------------------------- 1 | id(); 13 | 14 | // add fields 15 | 16 | $table->timestamps(); 17 | }); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /resources/stubs/migration.add.blaming.int.fields.stub: -------------------------------------------------------------------------------- 1 | unsignedBigInteger(config('blame.created_by_field_name'))->default($system_user_id); 20 | $table->unsignedBigInteger(config('blame.updated_by_field_name'))->default($system_user_id); 21 | }); 22 | Schema::table('{{ table }}', function (Blueprint $table) { 23 | $table->unsignedBigInteger(config('blame.created_by_field_name'))->default(null)->change(); 24 | $table->unsignedBigInteger(config('blame.updated_by_field_name'))->default(null)->change(); 25 | }); 26 | Schema::table('{{ table }}', function (Blueprint $table) { 27 | $table->foreign(config('blame.created_by_field_name'))->references('id')->on('users'); 28 | $table->foreign(config('blame.updated_by_field_name'))->references('id')->on('users'); 29 | }); 30 | 31 | 32 | } 33 | 34 | /** 35 | * Reverse the migrations. 36 | * 37 | * @return void 38 | */ 39 | public function down() 40 | { 41 | Schema::table('{{ table }}', function (Blueprint $table) { 42 | $table->dropForeign('{{ table }}_'.config('blame.updated_by_field_name').'_foreign'); 43 | $table->dropForeign('{{ table }}_'.config('blame.created_by_field_name').'_foreign'); 44 | $table->dropColumn(config('blame.updated_by_field_name')); 45 | $table->dropColumn(config('blame.created_by_field_name')); 46 | }); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamansoft/laravel-blame/a84a876bcb2c70bc6c16da2fe881e93f8d8e193e/resources/views/.gitkeep -------------------------------------------------------------------------------- /src/Commands/BlameFieldsMigrationCommand.php: -------------------------------------------------------------------------------- 1 | creator = $creator; 45 | $this->composer = $composer; 46 | } 47 | 48 | /** 49 | * Execute the console command. 50 | */ 51 | public function handle(): int 52 | { 53 | if (! $this->checkIfTableExits($this->argument('table'))) { 54 | return self::FAILURE; 55 | } 56 | 57 | $migration_name = config('blame.migration_name_prefix').$this->argument('table').config('blame.migration_name_suffix'); 58 | 59 | $this->writeMigration($migration_name, $this->argument('table')); 60 | 61 | return self::SUCCESS; 62 | } 63 | 64 | public function checkIfTableExits(string $table_name): bool 65 | { 66 | if (Schema::hasTable($table_name)) { 67 | $this->info($table_name.' table exits..'); 68 | 69 | return true; 70 | } 71 | 72 | $this->error($table_name.' does NOT exits on db'); 73 | 74 | return false; 75 | } 76 | 77 | /** 78 | * Get migration path (either specified by '--path' option or default location). 79 | * 80 | * @return string 81 | */ 82 | protected function getMigrationPath() 83 | { 84 | if (! is_null($targetPath = $this->input->getOption('path'))) { 85 | return ! $this->usingRealPath() 86 | ? $this->laravel->basePath().'/'.$targetPath 87 | : $targetPath; 88 | } 89 | 90 | return parent::getMigrationPath(); 91 | } 92 | 93 | /** 94 | * Write the migration file to disk. 95 | */ 96 | protected function writeMigration($name, $table) 97 | { 98 | $file = $this->creator->create( 99 | $name, $this->getMigrationPath(), $table 100 | ); 101 | 102 | $this->line("Created Blame migration: {$file}"); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Commands/LaravelBlameCommand.php: -------------------------------------------------------------------------------- 1 | comment('All done'); 16 | 17 | return self::SUCCESS; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Commands/SystemUserCommand.php: -------------------------------------------------------------------------------- 1 | validateAuthEloquentModel()) { 38 | $this->line('systemuser set command execution aborted !'); 39 | 40 | return self::FAILURE; 41 | } 42 | 43 | $key = $this->option('key'); 44 | if (empty($key)) { 45 | $this->info('No user primary key value from command param'); 46 | if (empty(env(static::$system_user_id_const_name))) { 47 | $this->info('No user primary key value from env file'); 48 | } else { 49 | $this->info('Got user primary key value from env file'); 50 | $key = env(static::$system_user_id_const_name); 51 | } 52 | } else { 53 | $this->info('Got user primary key value from command param'); 54 | } 55 | 56 | if ($this->checkAndSetSystemUser($key)) { 57 | $this->line('System User set Successfully'); 58 | 59 | return self::SUCCESS; 60 | } 61 | 62 | $this->error('System User set fail'); 63 | 64 | return self::FAILURE; 65 | } 66 | 67 | public function createNewSystemUserUser($key = null) 68 | { 69 | $system_user_data = [ 70 | 'name' => config('blame.system_user_name'), 71 | 'email' => config('blame.system_user_email'), 72 | 'password' => '', // you cant log in with this user 73 | ]; 74 | $system_user = $this->getUserModelForAuthInstance()->fill($system_user_data); 75 | $pkname = $this->getUsersModelPkName(); 76 | if (! empty($key)) { 77 | $system_user->$pkname = $key; 78 | } 79 | $system_user->save(); 80 | 81 | return $system_user->getKey(); 82 | } 83 | 84 | public function checkAndSetSystemUser($key = null): bool 85 | { 86 | if (! $this->userWithPkExists($key)) { 87 | try { 88 | $key = $this->createNewSystemUserUser($key); 89 | } catch (\Exception $exception) { 90 | $this->error("Can't create new user"); 91 | $this->line($exception->getMessage()); 92 | 93 | return false; 94 | } 95 | } 96 | 97 | return $this->setEnvValue(static::$system_user_id_const_name, $key); 98 | } 99 | 100 | public function userWithPkExists($key): bool 101 | { 102 | $user_model = config('auth.providers.users.model'); 103 | 104 | return $user_model::where($this->getUsersModelPkName(), $key)->exists(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Contracts/HandleEnvFile.php: -------------------------------------------------------------------------------- 1 | files = $files; 40 | $this->customStubPath = $customStubPath; 41 | } 42 | 43 | /** 44 | * @param null $table 45 | * @return string 46 | */ 47 | public function create($name, $path, $table) 48 | { 49 | $this->ensureMigrationDoesntAlreadyExist($name, $path); 50 | 51 | // First we will get the stub file for the migration, which serves as a type 52 | // of template for the migration. Once we have those we will populate the 53 | // various place-holders, save the file, and run the post create event. 54 | $stub = $this->getstub($table); 55 | 56 | $path = $this->getPath($name, $path); 57 | 58 | $this->files->ensureDirectoryExists(dirname($path)); 59 | 60 | $this->files->put( 61 | $path, $this->populateStub($name, $stub, $table) 62 | ); 63 | 64 | // Next, we will fire any hooks that are supposed to fire after a migration is 65 | // created. Once that is done we'll be ready to return the full path to the 66 | // migration file so it can be used however it's needed by the developer. 67 | $this->firePostCreateHooks($table); 68 | 69 | return $path; 70 | } 71 | 72 | /** 73 | * Ensure that a migration with the given name doesn't already exist. 74 | * 75 | * @param string $name 76 | * @param string $migrationPath 77 | * @return void 78 | * 79 | * @throws \InvalidArgumentException 80 | */ 81 | protected function ensureMigrationDoesntAlreadyExist($name, $migrationPath = null) 82 | { 83 | if (! empty($migrationPath)) { 84 | $migrationFiles = $this->files->glob($migrationPath.'/*.php'); 85 | 86 | foreach ($migrationFiles as $migrationFile) { 87 | $this->files->requireOnce($migrationFile); 88 | } 89 | } 90 | 91 | if (class_exists($className = $this->getClassName($name))) { 92 | throw new \InvalidArgumentException("A {$className} class already exists."); 93 | } 94 | } 95 | 96 | /** 97 | * Get the migration stub file. 98 | * 99 | * @param string|null $table 100 | * @return string 101 | */ 102 | protected function getStub($table) 103 | { 104 | $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.add.blaming.int.fields.stub') 105 | ? $customPath 106 | : $this->stubPath().'/migration.add.blaming.int.fields.stub'; 107 | 108 | return $this->files->get($stub); 109 | } 110 | 111 | /** 112 | * Populate the place-holders in the migration stub. 113 | * 114 | * @param string $name 115 | * @param string $stub 116 | * @param string|null $table 117 | * @return string 118 | */ 119 | protected function populateStub($name, $stub, $table) 120 | { 121 | $stub = str_replace( 122 | ['DummyClass', '{{ class }}', '{{class}}'], 123 | $this->getClassName($name), $stub 124 | ); 125 | 126 | // Here we will replace the table place-holders with the table specified by 127 | // the developer, which is useful for quickly creating a tables creation 128 | // or update migration from the console instead of typing it manually. 129 | if (! is_null($table)) { 130 | $stub = str_replace( 131 | ['DummyTable', '{{ table }}', '{{table}}'], 132 | $table, $stub 133 | ); 134 | } 135 | 136 | return $stub; 137 | } 138 | 139 | /** 140 | * Get the class name of a migration name. 141 | * 142 | * @param string $name 143 | * @return string 144 | */ 145 | protected function getClassName($name) 146 | { 147 | return Str::studly($name); 148 | } 149 | 150 | /** 151 | * Get the full path to the migration. 152 | * 153 | * @param string $name 154 | * @param string $path 155 | * @return string 156 | */ 157 | protected function getPath($name, $path) 158 | { 159 | return $path.'/'.$this->getDatePrefix().'_'.$name.'.php'; 160 | } 161 | 162 | /** 163 | * Fire the registered post create hooks. 164 | * 165 | * @param string|null $table 166 | * @return void 167 | */ 168 | protected function firePostCreateHooks($table) 169 | { 170 | foreach ($this->postCreate as $callback) { 171 | $callback($table); 172 | } 173 | } 174 | 175 | /** 176 | * Register a post migration create hook. 177 | * 178 | * @return void 179 | */ 180 | public function afterCreate(\Closure $callback) 181 | { 182 | $this->postCreate[] = $callback; 183 | } 184 | 185 | /** 186 | * Get the date prefix for the migration. 187 | * 188 | * @return string 189 | */ 190 | protected function getDatePrefix() 191 | { 192 | return date('Y_m_d_His'); 193 | } 194 | 195 | /** 196 | * Get the path to the stubs. 197 | * 198 | * @return string 199 | */ 200 | public function stubPath() 201 | { 202 | return __DIR__.'/stubs'; 203 | } 204 | 205 | /** 206 | * Get the filesystem instance. 207 | * 208 | * @return Filesystem 209 | */ 210 | public function getFilesystem() 211 | { 212 | return $this->files; 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/Facades/LaravelBlame.php: -------------------------------------------------------------------------------- 1 | name('laravel-blame'); 23 | 24 | if (! config()->has('auth.providers.users.model')) { 25 | throw new \Exception($package->name.' package needs an eloquent model to handle users from your persistent storage, you might set this as the users.model value at providers section the of auth config files in your laravel project'); 26 | } 27 | $this->mergeConfigFrom(__DIR__.'/../config/private_blame.php', 'blame'); 28 | $this->registerBlameMigrationCreator(); 29 | $this->registerBlameMigrationCommandSingleton(); 30 | $package 31 | ->hasConfigFile() 32 | ->hasViews() 33 | // ->hasMigration('create_laravel-blame_table') 34 | ->hasCommands([ 35 | SystemUserCommand::class, 36 | BlameFieldsMigrationCommand::class, 37 | ]) 38 | ->hasInstallCommand(function (InstallCommand $command) { 39 | $command 40 | ->startWith(function (InstallCommand $command) { 41 | $command->line('creating system user'); 42 | Artisan::call('blame:set:systemuser'); 43 | }) 44 | ->publishConfigFile() 45 | ->askToStarRepoOnGitHub('kamansoft/laravel-blade'); 46 | }); 47 | } 48 | 49 | public function registerBlameMigrationCommandSingleton() 50 | { 51 | $this->app->singleton(BlameFieldsMigrationCommand::class, function ($app) { 52 | $creator = $app[BlameMigrationCreator::class]; 53 | $composer = $app['composer']; 54 | 55 | return new BlameFieldsMigrationCommand($creator, $composer); 56 | }); 57 | 58 | return $this; 59 | } 60 | 61 | public function registerBlameMigrationCreator() 62 | { 63 | $this->app->singleton(BlameMigrationCreator::class, function ($app) { 64 | return new BlameMigrationCreator($app['files'], __DIR__.'/../resources/stubs'); 65 | }); 66 | 67 | return $this; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Traits/EnvFileHandler.php: -------------------------------------------------------------------------------- 1 | getEnvFileContent(app_path('../.env')); 10 | 11 | return ! ($str !== false && ! str_contains($str, $constant)); 12 | } 13 | 14 | public function setEnvValue(string $constant, string $value = 'null'): bool 15 | { 16 | $this->info("Atempt to set $constant=$value to .env file"); 17 | $str = $this->getEnvFileContent(app_path('../.env')); 18 | 19 | if ($str !== false && ! str_contains($str, $constant)) { 20 | return (bool) file_put_contents(app_path('../.env'), $str.PHP_EOL.$constant.'='.$value.PHP_EOL); 21 | } 22 | 23 | if (str_contains($str, $constant) and $value === env($constant)) { 24 | $this->info("Constant already set to $value"); 25 | 26 | return true; 27 | } 28 | 29 | throw new \RuntimeException('Cant set new value of '.$constant.' entry on the project´s .env file, the constant was previously set in the past, please remove the line with: " '.$constant.'='.env($constant).' " from your .env file and run this command again '); 30 | } 31 | 32 | public function getEnvFileContent(string $file): string|false 33 | { 34 | if (! is_file($file)) { 35 | throw new \RuntimeException(static::class." $file is not a valid file"); 36 | } 37 | 38 | return file_get_contents($file); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Traits/ModelBlamer.php: -------------------------------------------------------------------------------- 1 | blameOnCreate(); 17 | }); 18 | static::updating(function ($model) { 19 | $model->blameOnUpdate(); 20 | }); 21 | } 22 | 23 | public function blameOnCreate(): void 24 | { 25 | $creator_field_name = config('blame.created_by_field_name'); 26 | $updater_field_name = config('blame.updated_by_field_name'); 27 | $blamed = $this->getUserToBlamePk(); 28 | Log::info(static::class.' on create, blames to user: '.$blamed); 29 | $this->$creator_field_name = $this->$updater_field_name = $blamed; 30 | } 31 | 32 | public function getUserToBlamePk(): string 33 | { 34 | $to_return = ''; 35 | if (Auth::check()) { 36 | $to_return = Auth::user()->getKey(); 37 | } else { 38 | Log::warning(static::class.' Not logged user using system user'); 39 | $to_return = config('blame.system_user_id'); 40 | } 41 | 42 | return $to_return; 43 | } 44 | 45 | public function blameOnUpdate(): void 46 | { 47 | $updater_field_name = config('blame.updated_by_field_name'); 48 | $blamed = $this->getUserToBlamePk(); 49 | Log::info(static::class.' on update, blames to user: '.$blamed); 50 | $this->$updater_field_name = $blamed; 51 | } 52 | 53 | /** 54 | * Relation with the user who created the model. 55 | */ 56 | public function creator(): BelongsTo 57 | { 58 | return $this->belongsTo(config('auth.providers.users.model'), config('blame.created_by_field_name'), $this->getUsersModelPkName()); 59 | } 60 | 61 | /** 62 | * Relation with the user who last updated the model. 63 | */ 64 | public function updater(): BelongsTo 65 | { 66 | return $this->belongsTo(config('auth.providers.users.model'), config('blame.updated_by_field_name'), $this->getUsersModelPkName()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Traits/UserModelForAuth.php: -------------------------------------------------------------------------------- 1 | validateAuthEloquentModel()) { 12 | throw new \RuntimeException(static::class.' Needs an eloquent model to handle users from your persistent storage, you might set this as the users.model value at providers section the of auth config file.'); 13 | } 14 | 15 | return app()->make(config('auth.providers.users.model')); 16 | } 17 | 18 | public function validateAuthEloquentModel(): bool 19 | { 20 | if (! config()->has('auth.providers.users.model')) { 21 | return false; 22 | } 23 | 24 | return true; 25 | } 26 | 27 | public function getUsersModelPkName(): string 28 | { 29 | if (empty($this->usersModelpkName)) { 30 | $this->usersModelpkName = $this->getUserModelForAuthInstance()->getKeyName(); 31 | } 32 | 33 | return $this->usersModelpkName; 34 | } 35 | } 36 | --------------------------------------------------------------------------------