Skip to content

Commit

Permalink
Merge pull request #13 from hackerESQ/3.0.0-next
Browse files Browse the repository at this point in the history
Preparation for releasing 3.0.0
  • Loading branch information
hackeresq authored Feb 3, 2021
2 parents 1bc597d + d27d4e1 commit 43725e0
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 114 deletions.
44 changes: 20 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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. <b><mark>For security reasons,</mark> 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, <i>it will disregard the change.</i> So, if this is a fresh install, do not expect the following to work:

```php
Settings::set(['firm_name'=>'new']);
```

<b><mark>For security reasons,</mark> 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, <i>it will disregard the change.</i> </b> If you wish to force set a new setting, you should pass an array for the second parameter like so:
</b> 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]);
Expand Down Expand Up @@ -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:

Expand Down
5 changes: 2 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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.*"
Expand Down
25 changes: 12 additions & 13 deletions database/migrations/update_settings_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']);

});

}


Expand All @@ -37,6 +36,6 @@ public function up()
*/
public function down()
{
Schema::dropIfExists('settings');
//
}
}
2 changes: 1 addition & 1 deletion src/Controllers/SettingController.example.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Settings;
use hackerESQ\Settings\Facades\Settings;

class SettingController extends Controller
{
Expand Down
117 changes: 51 additions & 66 deletions src/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,78 @@

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();
}

/**
* Decrypt any settings that need to be decrypted
* @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)) {
Expand All @@ -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;

}

}

}
7 changes: 0 additions & 7 deletions src/SettingsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
namespace hackerESQ\Settings;

use Illuminate\Support\ServiceProvider;
use Route;
use Illuminate\Http\Request;

class SettingsServiceProvider extends ServiceProvider {

Expand Down Expand Up @@ -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');



}



}

0 comments on commit 43725e0

Please sign in to comment.