phplaravel-5config

Store config in database in Laravel


I am currently using Laravel 5.2. I want to be able to store config properties (key-value pairs) in database, that I am willing to access from both my application on runtime and the console (either php artisan command or Tinker).

What is my best option?

The reason I am interested in database config, is because we often replace/delete files during deployment. Also it would be nice to store values encrypted. Also important feature here is to be able to easily get values via either php artisan or tinker


Solution

    1. Make a migration: php artisan make:migration CreateSettingsTable
    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    class CreateSettingsTable extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::create('settings', function (Blueprint $table) {
                $table->id();
                $table->string('key');
                $table->string('value');
                $table->timestamps();
    
                $table->unique([
                    'key', //I add a unique to prevent double keys
                ]);
            });
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::dropIfExists('settings');
        }
    }
    
    1. Make the model: php artisan make:model Setting
    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Setting extends Model
    {
        protected $fillable = [
            'key',
            'value'
        ];
    
        //I would normally do this in a repository,
        // but for simplicity sake, i've put it in here :)
        static public $settings = null;
    
        static function get($key, $default = null)
        {
            if (empty(self::$settings)) {
                self::$settings = self::all();
            }
            $model = self
                ::$settings
                ->where('key', $key)
                ->first();
            if (empty($model)) {
                if (empty($default)) {
                    //Throw an exception, you cannot resume without the setting.
                    throw new \Exception('Cannot find setting: '.$key);
                }
                else {
                    return $default;
                }
            }
            else {
                return $model->value;
            }
        }
    
        static function set(string $key, $value)
        {
            if (empty(self::$settings)) {
                self::$settings = self::all();
            }
            if (is_string($value) || is_int($value)) {
                $model = self
                    ::$settings
                    ->where('key', $key)
                    ->first();
    
                if (empty($model)) {
                    $model = self::create([
                        'key' => $key,
                        'value' => $value
                    ]);
                    self::$settings->push($model);
                }
                else {
                    $model->update(compact('value'));
                }
                return true;
            }
            else {
                return false;
            }
        }
    }
    
    

    Please note here, that I added the get and set functions, together with a static $settings variable directly to the model, to keep the example small. Usually I would opt to making a repository or service(not serviceprovider) to handle these functions. This way you only query db once(per request) for all the settings. You could stick this in cache, but that is not part of this answer of now.

    1. Run php artisan migrate to ge the table in the db.

    2. Run composer dump-autoload to make sure tinker can find the Setting class.

    3. Use someting like php artisan tinker(https://laravel.com/docs/7.x/artisan#tinker) to test it, in this case you can do:

    Setting::set('someKey', 'someValue'); //Set someKey to someValue
    Setting::get('someKey'); //Get someKey, throws exception if not found
    Setting::get('somekey2', 'someDefault'); //Shows someDefault because somekey2 is not set yet.
    

    I hope it helps! :)