diff --git a/README.md b/README.md index 1f8d398..b7b6e74 100644 --- a/README.md +++ b/README.md @@ -22,24 +22,9 @@ You can install the package via composer: composer require hackeresq/laravel-settings ``` -In Laravel 5.5+ the service provider will automatically get registered and you can skip this step. In older versions of the framework just add the service provider in `config/app.php` file: +Since Laravel 5.5+, service providers and aliases will automatically get registered and you can skip this step. To use this package with older versions, please use release < 2.0. -```php -'providers' => [ - // ... - hackerESQ\Settings\SettingsServiceProvider::class, -]; -``` -The same is true for the alias. If you're running Laravel 5.5+, you can also skip this step. In older versions of the framework just add the alias in `config/app.php` file: - -```php -'aliases' => [ - // ... - 'Settings' => hackerESQ\Settings\Facades\Settings::class, -]; -``` - -You can publish [the migration](https://github.com/hackerESQ/settings/blob/master/database/migrations/create_settings_table.php) and [config](https://github.com/hackerESQ/settings/blob/master/config/settings.php) files, then migrate the new settings table all in one go using: +You can publish [the migration](https://github.com/hackerESQ/settings/blob/master/database/migrations/create_settings_table.php) and [config](https://github.com/hackerESQ/settings/blob/master/config/settings.php) files, then migrate the new settings table all in one go, using: ```bash php artisan vendor:publish --provider="hackerESQ\Settings\SettingsServiceProvider" --tag=migrations && php artisan vendor:publish --provider="hackerESQ\Settings\SettingsServiceProvider" --tag=config && php artisan migrate @@ -52,13 +37,13 @@ php artisan vendor:publish --provider="hackerESQ\Settings\SettingsServiceProvide Settings can be accessed using the easy-to-remember Facade, "Settings." ### Set new setting -You can set new settings using the "set" method, which accepts an associative array of one or more key/value pairs. +You can set new settings using the "set" method, which accepts an associative array of one or more key/value pairs. For security reasons, this will first check to see if such a setting key exists in your "settings" table or in the cache. If such a key exists, it will update the key to the new value. If the key does not exist, it will disregard the change. So, if this is a fresh install, do not expect the following to work: ```php Settings::set(['firm_name'=>'new']); ``` -For security reasons, this will first check to see if such a setting key exists in your "settings" table or in the cache. If such a key exists, it will update the key to the new value. If the key does not exist, it will disregard the change. If you wish to force set a new setting, you should pass an array for the second parameter like so: + If you wish to force set a new setting, you should pass an array for the second parameter like so: ```php Settings::set(['firm_name'=>'new'],['force'=>true]); @@ -116,20 +101,31 @@ You can define keys that should be encrypted automatically within the [config/se ``` ## Multi-tenancy -This package can be used in a multi-tenant environment. The [set](#set-new-setting), [get](#get-all-settings), and [has](#check-if-a-setting-is-set) methods all accept an array as the second parameter. This array can contain a 'tenant' attribute, like this: +This package can be used in a multi-tenant environment. The [set](#set-new-setting), [get](#get-all-settings), and [has](#check-if-a-setting-is-set) methods all read an internal 'tenant' attribute that can be set with the `tenant()` method. You can set the 'tenant' attribute by calling the `tenant()` method first, like this: ```php -Settings::get('firm_name',['tenant'=>'example-tenant']); +Settings::tenant('tenant_name')->set(['firm_name'=>'foo bar']); + +// returns true (i.e. successfully set `firm name`) + ``` -The 'tenant' attribute passed in an array to the second parameter above can be alphanumeric. Although 'tenant' is not strictly typed, and will be passed to the database query as a string. +```php +Settings::tenant('tenant_name')->get('firm_name'); + +// returns 'foo bar' -If you are using the [get](#get-all-settings) method without a first parameter (which will returns all settings), you must pass 'null' as the first parameter: +``` ```php -Settings::get(null,['tenant'=>'example-tenant']); +Settings::tenant('tenant_name')->has('firm_name'); + +// returns true + ``` +The 'tenant' attribute passed can be any alphanumeric string. The 'tenant' attribute can also be left blank to have, for example, settings saved to a so-called "central" tenant. Note: the 'tenant' attribute is not strictly typed, and will be passed to the database query as a string. + ## Disable cache Depending on your use case, you may like to disable the cache (enabled by default). Disable the cache by modifying the [config/settings.php](https://github.com/hackerESQ/settings/blob/master/config/settings.php) file as such: diff --git a/composer.json b/composer.json index 8b09258..34b5dca 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "hackeresq/laravel-settings", "description": "Super simple key/value settings for Laravel 5+", - "version": "2.0.1", + "version": "3.0.0", "keywords": [ "settings", "laravel", @@ -17,8 +17,7 @@ }, "require": { "php" : ">=7.0", - "laravel/framework": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", - "doctrine/dbal": "^2.8" + "laravel/framework": "^6.0|^7.0|^8.0" }, "require-dev": { "phpunit/phpunit": "4.8.*" diff --git a/database/migrations/update_settings_table.php b/database/migrations/update_settings_table.php index abcdd02..349e501 100644 --- a/database/migrations/update_settings_table.php +++ b/database/migrations/update_settings_table.php @@ -13,19 +13,18 @@ class UpdateSettingsTable extends Migration */ public function up() { - if (!Schema::hasColumn('settings', 'tenant')) { - Schema::table('settings', function (Blueprint $table) { + Schema::table('settings', function (Blueprint $table) { - $table->string('key')->index()->change(); - $table->string('tenant')->nullable()->index(); - $table->dropPrimary('key'); - $table->dropUnique('settings_key_unique'); - - $table->primary(['key', 'tenant']); - $table->unique(['key', 'tenant']); - - }); - } + $table->string('key')->index()->change(); + $table->string('tenant')->nullable(); + $table->dropPrimary('key'); + $table->dropUnique('settings_key_unique'); + + $table->primary(['key', 'tenant']); + $table->unique(['key', 'tenant']); + + }); + } @@ -37,6 +36,6 @@ public function up() */ public function down() { - Schema::dropIfExists('settings'); + // } } diff --git a/src/Controllers/SettingController.example.php b/src/Controllers/SettingController.example.php index e0dc773..9950d81 100644 --- a/src/Controllers/SettingController.example.php +++ b/src/Controllers/SettingController.example.php @@ -4,7 +4,7 @@ use Illuminate\Http\Request; use App\Http\Controllers\Controller; -use Settings; +use hackerESQ\Settings\Facades\Settings; class SettingController extends Controller { diff --git a/src/Settings.php b/src/Settings.php index 86d83c0..7388688 100644 --- a/src/Settings.php +++ b/src/Settings.php @@ -2,38 +2,48 @@ namespace hackerESQ\Settings; -use DB; -use Cache; +use Illuminate\Support\Arr; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Cache; class Settings { + protected string $tenant = ''; /** * Get settings from the database - * @param string $tenant * @return array */ - public function resolveDB($tenant) { + public function resolveDB() + { + return DB::table('settings')->where('tenant',$this->tenant)->pluck('value', 'key')->toArray(); + } - return DB::table('settings')->where('tenant','=',$tenant)->pluck('value', 'key')->toArray(); - + /** + * Set the tenant + * @param string $tenant (optional) + * @return Settings $this + */ + public function tenant($tenant='') + { + $this->tenant = $tenant; + + return $this; } /** * Get settings from the cache - * @param string $tenant * @return array */ - public function resolveCache($tenant) { - + public function resolveCache() + { if (config('settings.cache')) { - return Cache::rememberForever('settings'.$tenant, function () use ($tenant) { - return $this->resolveDB($tenant); + return Cache::rememberForever('settings'.$this->tenant, function () { + return $this->resolveDB(); }); - } else { - return $this->resolveDB($tenant); } - + + return $this->resolveDB(); } /** @@ -41,37 +51,29 @@ public function resolveCache($tenant) { * @param array $settings * @return array */ - public function decryptHandler($settings) { - + public function decryptHandler($settings) + { // DO WE NEED TO DECRYPT ANYTHING? foreach ($settings as $key => $value) { if ( in_array( $key, config('settings.encrypt',[]) ) && !empty($value) ) { - array_set($settings, $key, decrypt($settings[$key])); + Arr::set($settings, $key, decrypt($settings[$key])); } } return $settings; - } /** * Get value of settings by key - * @param string $key - * @param array $options + * @param string $key * @return mixed string|boolean */ - public function get($key = NULL, $options = []) + public function get($key = NULL) { - // is this multitenant? - $tenant = isset($options['tenant']) ? $options['tenant'] : ''; - - $settings = $this->decryptHandler($this->resolveCache($tenant)); + $settings = $this->decryptHandler($this->resolveCache()); // no key passed, assuming get all settings - if ($key == NULL) { - - return $settings; - } + if ($key == NULL) return $settings; // array of keys passed, return those settings only if (is_array($key)) { @@ -88,88 +90,71 @@ public function get($key = NULL, $options = []) } return false; - } /** * Check if a given key exists - * @param string $key - * @param array $options + * @param string $key * @return boolean */ - public function has($key, $options = []) + public function has($key) { - - // is this multitenant? - $tenant = isset($options['tenant']) ? $options['tenant'] : ''; - - $settings = $this->decryptHandler($this->resolveCache($tenant)); + $settings = $this->decryptHandler($this->resolveCache()); return array_key_exists($key, $settings); } /** * Set value of setting - * @param array $changes - * @param array $options + * @param array $changes + * @param array $options (optional) * @return boolean */ public function set($changes, $options = []) { - - $force = isset($options['force']) ? $options['force'] : false; - $encrypt = isset($options['encrypt']) ? $options['encrypt'] : false; - - // is this multitenant? - $tenant = isset($options['tenant']) ? $options['tenant'] : ''; + $force = $options['force'] ?? false; + $encrypt = $options['encrypt'] ?? false; // DO WE NEED TO ENCRYPT ANYTHING? foreach ($changes as $key => $value) { if ( ( in_array($key, config('settings.encrypt') ) || $encrypt ) && !empty($value)) { - array_set($changes, $key, encrypt($value)); + Arr::set($changes, $key, encrypt($value)); } } // ARE WE FORCING? OR SHOULD WE BE SECURE? if (config('settings.force') || $force) { - foreach ($changes as $key => $value) { - - DB::table('settings')->where([ - ['key', '=', $key], - ['tenant', '=', $tenant] - ])->delete(); - - DB::table('settings')->insert([ + DB::table('settings')->updateOrInsert([ + 'key'=>$key, + 'tenant'=>$this->tenant + ], + [ 'key'=>$key, 'value'=>$value, - 'tenant'=>$tenant + 'tenant'=>$this->tenant ]); } - } else { - - $settings = $this->resolveCache($tenant); + $settings = $this->resolveCache(); // array_only() - will return only the specified key-value pairs from the given array // array_keys() - will return all the keys or a subset of the keys of an array // this passes array_keys() to array_only() to give current/valid settings only //checks and see if passed settings are valid options - foreach (array_only($changes, array_keys($settings)) as $key => $value) { + foreach (Arr::only($changes, array_keys($settings)) as $key => $value) { DB::table('settings')->where([ ['key', '=', $key], - ['tenant', '=', $tenant] + ['tenant', '=', $this->tenant] ])->update(['value'=>$value]); } } + // clear cache if (config('settings.cache')) { - Cache::forget('settings'.$tenant); + Cache::forget('settings'.$this->tenant); } return true; - } - -} - +} \ No newline at end of file diff --git a/src/SettingsServiceProvider.php b/src/SettingsServiceProvider.php index 7c7128d..e94eee2 100644 --- a/src/SettingsServiceProvider.php +++ b/src/SettingsServiceProvider.php @@ -3,8 +3,6 @@ namespace hackerESQ\Settings; use Illuminate\Support\ServiceProvider; -use Route; -use Illuminate\Http\Request; class SettingsServiceProvider extends ServiceProvider { @@ -45,14 +43,9 @@ public function boot() */ public function register () { - // bind 'settings' to the class named 'settings' in the IOC container $this->app->singleton('settings','hackerESQ\Settings\Settings'); - - } - - }