commit b3c03162f17e8a240f377dc2ce457d882f90ab14 Author: Alexander Demidov Date: Fri Nov 15 12:14:38 2019 +0300 Without share. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c37da9f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.idea +/vendor +composer.lock \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2588f04 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Efriandika Pratama + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..a599ab1 --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +[![Latest Stable Version](https://poser.pugx.org/efriandika/laravel-settings/v/stable.svg)](https://packagist.org/packages/efriandika/laravel-settings) +[![Total Downloads](https://poser.pugx.org/efriandika/laravel-settings/downloads.svg)](https://packagist.org/packages/efriandika/laravel-settings) +[![Latest Unstable Version](https://poser.pugx.org/efriandika/laravel-settings/v/unstable.svg)](https://packagist.org/packages/efriandika/laravel-settings) +[![License](https://poser.pugx.org/efriandika/laravel-settings/license.svg)](https://packagist.org/packages/efriandika/laravel-settings) + +# Laravel-Settings +Laravel 5.1.x Persistent Settings (Database + Cache) + +### Attention: for update to v1.2.0 +Re-Publish new migration file + + $ php artisan vendor:publish --provider="Efriandika\LaravelSettings\SettingsServiceProvider" --force + +And run + + $ php artisan migrate + +## How to Install +Require this package with composer ([Packagist](https://packagist.org/packages/efriandika/laravel-settings)) using the following command: + + composer require efriandika/laravel-settings + +or modify your `composer.json`: + + "require": { + "efriandika/laravel-settings": "1.*" + } + +then run `composer update`: + +After updating composer, Register the ServiceProvider to the `providers` array in `config/app.php` + + 'Efriandika\LaravelSettings\SettingsServiceProvider', + +Add an alias for the facade to `aliases` array in your `config/app.php` + + 'Settings' => Efriandika\LaravelSettings\Facades\Settings::class, + +Publish the config and migration files now (Attention: This command will not work if you don't follow previous instruction): + + $ php artisan vendor:publish --provider="Efriandika\LaravelSettings\SettingsServiceProvider" --force + +Change `config/settings.php` according to your needs. If you change `db_table`, don't forget to change the table's name +in the migration file as well. + +Create the `settings` table. + + $ php artisan migrate + + +## How to Use it? + +Set a value + + Settings::set('key', 'value'); + +Get a value + + $value = Settings::get('key'); + +Get a value with Default Value. + + $value = Settings::get('key', 'Default Value'); + +> Note: If key is not found (null) in cache or settings table, it will return default value + +Get a value via an helper + + $value = settings('key'); + $value = settings('key', 'default value'); + +Forget a value + + Settings::forget('key'); + +Forget all values + + Settings::flush(); + +## Fallback to Laravel Config (available in v1.2.0) + +How to activate? + + // Change your config/settings.php + 'fallback' => true + +Example + + /* + * If the value with key => mail.host is not found in cache or DB of Larave Settings + * it will return same value as config::get('mail.host'); + */ + Settings::get('mail.host'); + +> Note: It will work if default value in laravel setting is not set + +### Changelogs +v1.2.0 - Dec 16th, 2015 + +* Bugs fix +* Adding Feature: Fallback Value + + +### To Do + +- + +### License + +The Laravel 5 Persistent Settings is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..80c233d --- /dev/null +++ b/composer.json @@ -0,0 +1,33 @@ +{ + "name": "efriandika/laravel-settings", + "description": "Laravel 5 Persistent Settings", + "keywords": [ + "laravel", + "settings", + "persistent" + ], + "license": "MIT", + "authors": [ + { + "name": "Efriandika Pratama", + "email": "efriandika@gmail.com" + } + ], + "require": { + "php": ">=5.5.9", + "illuminate/support": "5.*" + }, + "require-dev": { + "phpunit/phpunit": "4.6.*", + "illuminate/database": ">=5.1 <6.0", + "illuminate/events": ">=4.1 <6.0" + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Efriandika\\LaravelSettings\\": "src/" + } + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100755 index 0000000..ead723d --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + + ./tests/ + + + \ No newline at end of file diff --git a/src/Cache.php b/src/Cache.php new file mode 100755 index 0000000..5ee679c --- /dev/null +++ b/src/Cache.php @@ -0,0 +1,143 @@ +cacheFile = $cacheFile; + $this->checkCacheFile(); + + $this->settings = $this->getAll(); + } + + /** + * Sets a value + * + * @param $key + * @param $value + * + * @return mixed + */ + public function set($key, $value) + { + $this->settings[$key] = $value; + $this->store(); + + return $value; + } + + /** + * Gets a value + * + * @param $key + * @param null $default + * + * @return mixed + */ + public function get($key, $default = null) + { + return (array_key_exists($key, $this->settings) ? $this->settings[$key] : $default); + } + + /** + * Checks if $key is cached + * + * @param $key + * + * @return bool + */ + public function hasKey($key) + { + return array_key_exists($key, $this->settings); + } + + /** + * Gets all cached settings + * + * @return array + */ + public function getAll() + { + $values = json_decode(file_get_contents($this->cacheFile), true); + foreach ($values as $key => $value) { + $values[$key] = unserialize($value); + } + return $values; + } + + /** + * Stores all settings to the cache file + * + * @return void + */ + private function store() + { + $settings = []; + foreach ($this->settings as $key => $value) { + $settings[$key] = serialize($value); + } + file_put_contents($this->cacheFile, json_encode($settings)); + } + + /** + * Removes a value + * + * @return void + */ + public function forget($key) + { + if (array_key_exists($key, $this->settings)) { + unset($this->settings[$key]); + } + $this->store(); + } + + /** + * Removes all values + * + * @return void + */ + public function flush() + { + file_put_contents($this->cacheFile, json_encode([])); + // fixed the set after immediately the flush, should be returned empty + $this->settings = []; + } + + /** + * Checks if the cache file exists and creates it if not + * + * @return void + */ + private function checkCacheFile() + { + if (!file_exists($this->cacheFile)) { + $this->flush(); + } + } +} diff --git a/src/Facades/Settings.php b/src/Facades/Settings.php new file mode 100755 index 0000000..89b8b2d --- /dev/null +++ b/src/Facades/Settings.php @@ -0,0 +1,14 @@ +database = $database; + $this->config = $config; + $this->cache = $cache; + } + + /** + * Gets a value + * + * @param string $key + * @param string $default + * + * @return mixed + */ + public function get($key, $default = null) + { + $value = $this->fetch($key); + + if(!is_null($value)) + return $value; + else if($default != null) + return $default; + else if($this->config['fallback']) + return Config::get($key, null); + else + return $default; + } + + /** + * @param $key + * + * @return mixed|null + */ + private function fetch($key) + { + + if ($this->cache->hasKey($key)) { + return $this->cache->get($key); + } + + $row = $this->database->table($this->config['db_table'])->where('setting_key', $key)->first(['setting_value']); + + return (!is_null($row)) ? $this->cache->set($key, unserialize($row->setting_value)) : null; + } + + + /** + * Checks if setting exists + * + * @param $key + * + * @return bool + */ + public function hasKey($key) + { + if ($this->cache->hasKey($key)) { + return true; + } + $row = $this->database->table($this->config['db_table'])->where('setting_key', $key)->first(['setting_value']); + + return (count($row) > 0); + } + + /** + * Store value into registry + * + * @param string $key + * @param mixed $value + * + * @return mixed + */ + public function set($key, $value) + { + $value = serialize($value); + + $setting = $this->database->table($this->config['db_table'])->where('setting_key', $key)->first(); + + if (is_null($setting)) { + $this->database->table($this->config['db_table']) + ->insert(['setting_key' => $key, 'setting_value' => $value]); + } else { + $this->database->table($this->config['db_table']) + ->where('setting_key', $key) + ->update(['setting_value' => $value]); + } + + $this->cache->set($key, unserialize($value)); + + return $value; + } + + + /** + * Remove a setting + * + * @param string $key + * + * @return void + */ + public function forget($key) + { + $this->database->table($this->config['db_table'])->where('setting_key', $key)->delete(); + $this->cache->forget($key); + } + + /** + * Remove all settings + * + * @return bool + */ + public function flush() + { + $this->cache->flush(); + + return $this->database->table($this->config['db_table'])->delete(); + } + + /** + * Fetch all values + * + * @return mixed + */ + public function getAll() + { + return $this->cache->getAll(); + } + + +} diff --git a/src/SettingsServiceProvider.php b/src/SettingsServiceProvider.php new file mode 100755 index 0000000..94ca76c --- /dev/null +++ b/src/SettingsServiceProvider.php @@ -0,0 +1,62 @@ +publishes([ + __DIR__ . '/config/settings.php' => config_path('settings.php') + ]); + $this->publishes([ + __DIR__ . '/database/migrations/' => base_path('/database/migrations') + ]); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->mergeConfigFrom( + __DIR__ . '/config/settings.php', 'settings' + ); + $this->app['settings'] = function ($app) { + + $config = $app->config->get('settings', [ + 'cache_file' => storage_path('settings.json'), + 'db_table' => 'settings' + ]); + + return new Settings($app['db'], new Cache($config['cache_file']), $config); + }; + } + + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return array ('settings'); + } + +} \ No newline at end of file diff --git a/src/config/settings.php b/src/config/settings.php new file mode 100644 index 0000000..d37f988 --- /dev/null +++ b/src/config/settings.php @@ -0,0 +1,33 @@ + storage_path('settings.json'), + + /* + |-------------------------------------------------------------------------- + | Table name to store settings + |-------------------------------------------------------------------------- + | + | Info: If you change this table name, dont forget to update your settings migrations file. + | + */ + 'db_table' => 'settings', + + /* + |-------------------------------------------------------------------------- + | Fallback setting + |-------------------------------------------------------------------------- + | + | Return Laravel config if the value with particular key is not found in cache or DB. + | It will work if default value in laravel setting is not set, and this value is set to true + | + */ + 'fallback' => true +]; \ No newline at end of file diff --git a/src/database/migrations/2015_04_13_020453_create_settings_table.php b/src/database/migrations/2015_04_13_020453_create_settings_table.php new file mode 100644 index 0000000..9ea1e9f --- /dev/null +++ b/src/database/migrations/2015_04_13_020453_create_settings_table.php @@ -0,0 +1,33 @@ +string('key', 100)->index()->unique('key'); + $table->text('value', 65535)->nullable(); + }); + } + + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('settings'); + } + +} diff --git a/src/database/migrations/2015_12_15_020453_alter_settings_table.php b/src/database/migrations/2015_12_15_020453_alter_settings_table.php new file mode 100644 index 0000000..2414537 --- /dev/null +++ b/src/database/migrations/2015_12_15_020453_alter_settings_table.php @@ -0,0 +1,34 @@ +renameColumn('key', 'setting_key'); + $table->renameColumn('value', 'setting_value'); + }); + } + + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function ($table) { + $table->renameColumn('setting_key', 'key'); + $table->renameColumn('setting_value', 'value'); + }); + } + +} diff --git a/src/helpers.php b/src/helpers.php new file mode 100644 index 0000000..9fbf62a --- /dev/null +++ b/src/helpers.php @@ -0,0 +1,20 @@ +cacheFile = storage_path('settings.json'); + $this->cache = new Cache($this->cacheFile); + } + + public function testSet() + { + $this->cache->set('key', 'value'); + + $contents = file_get_contents($this->cacheFile); + $this->assertEquals('{"key":"s:5:\"value\";"}', $contents); + } + public function testSetArray() + { + $set = ['value' => 1, 'value2' => 2]; + $this->cache->set('key', $set); + + $contents = file_get_contents($this->cacheFile); + $this->assertEquals('{"key":"a:2:{s:5:\"value\";i:1;s:6:\"value2\";i:2;}"}', $contents); + + $this->assertEquals($this->cache->get('key'), $set); + } + + public function testGet() + { + $this->cache->set('key', 'value'); + $this->assertEquals('value', $this->cache->get('key')); + } + + public function testGetAll() + { + $this->cache->set('key', 'value'); + $this->cache->set('key2', 'value2'); + + $this->assertEquals(['key' => 'value', 'key2' => 'value2'], $this->cache->getAll()); + } + + public function testFlush() + { + $this->cache->set('key', 'value'); + $this->cache->flush(); + $this->assertEquals([], $this->cache->getAll()); + } + + public function testHasKey() + { + $this->cache->set('key', 'value'); + $this->assertTrue($this->cache->hasKey('key')); + } + + public function testForget() + { + $this->cache->set('key', 'value'); + $this->cache->forget('key'); + $this->assertNull($this->cache->get('key')); + } + + + protected function tearDown() + { + @unlink(storage_path('settings.json')); + } + +} diff --git a/tests/SettingsTest.php b/tests/SettingsTest.php new file mode 100755 index 0000000..0f71ccf --- /dev/null +++ b/tests/SettingsTest.php @@ -0,0 +1,123 @@ +db = $this->initDb(); + + $this->config = [ + 'db_table' => 'settings', + 'cache_file' => storage_path('settings.json'), + ]; + $this->settings = new Settings($this->db, new Cache($this->config['cache_file']), $this->config); + } + + + public function testSet() + { + $this->settings->set('key', 'value'); + + $setting = $this->db->table($this->config['db_table'])->where('key', 'key')->first(['value']); + $this->assertEquals('value', unserialize($setting['value'])); + } + + public function testSetArray() + { + $set = ['valuekey' => 'value']; + $this->settings->set('key', $set); + + $setting = $this->db->table($this->config['db_table'])->where('key', 'key')->first(['value']); + + $this->assertEquals($set, unserialize($setting['value'])); + $this->assertEquals($set, $this->settings->get('key')); + } + + public function testGet() + { + $this->settings->set('key', 'value'); + $this->assertEquals('value', $this->settings->get('key')); + } + + public function testGetAll() + { + $this->settings->set('key', 'value'); + $this->settings->set('key2', 'value2'); + + $this->assertEquals('value', $this->settings->get('key')); + $this->assertEquals('value2', $this->settings->get('key2')); + + $this->assertEquals(['key' => 'value', 'key2' => 'value2'], $this->settings->getAll()); + } + + public function testFlush() + { + $this->settings->set('key', 'value'); + $this->settings->flush(); + $this->assertEquals([], $this->settings->getAll()); + } + + public function testHasKey() + { + $this->settings->set('key', 'value'); + $this->assertTrue($this->settings->hasKey('key')); + $this->assertFalse($this->settings->hasKey('key2')); + } + public function testHasKeyWithoutCache() + { + $this->settings->set('key', 'value'); + $this->assertTrue($this->settings->hasKey('key')); + $this->assertFalse($this->settings->hasKey('key2')); + + @unlink(storage_path('settings.json')); + $this->assertTrue($this->settings->hasKey('key')); + $this->assertFalse($this->settings->hasKey('key2')); + + } + + public function testForget() + { + $this->settings->set('key', 'value'); + $this->settings->forget('key'); + $this->assertNull($this->settings->get('key')); + } + + protected function tearDown() + { + Capsule::schema()->drop('settings'); + @unlink(storage_path('settings.json')); + } + + + private function initDb() + { + $capsule = new Capsule; + + $capsule->addConnection([ + 'driver' => 'sqlite', + 'host' => 'localhost', + 'database' => ':memory:', + 'prefix' => '', + ]); + $capsule->setEventDispatcher(new Dispatcher(new Container)); + $capsule->setAsGlobal(); + $capsule->bootEloquent(); + + Capsule::schema()->create('settings', function ($table) { + $table->string('key', 100)->index()->unique('key'); + $table->text('value', 65535)->nullable(); + }); + + return $capsule->getDatabaseManager(); + } + +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100755 index 0000000..3fe4186 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,7 @@ +