Model Settings for your Laravel app

Overview

laravel

Model Settings for your Laravel app

Total Downloads
Latest Stable Version 'Github Actions Build Status Software License maintainability
StyleCI Scrutinizer Code Quality Scrutinizer Code Coverage
PHP Version

The package requires PHP 7.3+ and follows the FIG standards PSR-1, PSR-2, PSR-4 and PSR-12 to ensure a high level of interoperability between shared PHP.

Bug reports, feature requests, and pull requests can be submitted by following our Contribution Guide.

Table of contents

Installation

$ composer require glorand/laravel-model-settings
{
    "require": {
        "glorand/laravel-model-settings": "^4.0"
    }
}

Env (config) variables (.env file)

Default name for the settings field - when you use the HasSettingsField

MODEL_SETTINGS_FIELD_NAME=settings

Default name for the settings table - when you use the HasSettingsTable

MODEL_SETTINGS_TABLE_NAME=model_settings

Updating your Eloquent Models

Your models should use the HasSettingsField or HasSettingsTable trait.

Option 1 - HasSettingsField trait

Run the php artisan model-settings:model-settings-field in order to create a migration file for a table.
This command will create a json field (default name settings, from config) for the mentioned table.

You can choose another than default, in this case you have to specify it in you model.

public $settingsFieldName = 'user_settings';

Complete example:

use Glorand\Model\Settings\Traits\HasSettingsField;

class User extends Model
{
    use HasSettingsField;

    //define only if you select a different name from the default
    public $settingsFieldName = 'user_settings';

    //define only if the model overrides the default connection
    protected $connection = 'mysql';

}

Option 2 - HasSettingsTable trait

Run before the command php artisan model-settings:model-settings-table.
The command will copy for you the migration class to create the table where the setting values will be stored.
The default name of the table is model_settings; change the config or env value MODEL_SETTINGS_TABLE_NAME if you want to rewrite the default name (before you run the command!)

use Glorand\Model\Settings\Traits\HasSettingsTable;

class User extends Model
{
    use HasSettingsTable;
}

Option 3 - HasSettingsRedis trait

use Glorand\Model\Settings\Traits\HasSettingsRedis;

class User extends Model
{
    use HasSettingsRedis;
}

Default settings

You can set default configs for a table in model_settings.php config file

return [
    // start other config options

    // end other config options

    // defaultConfigs
    'defaultSettings' => [
        'users' => [
            'key_1' => 'val_1',
        ]
    ]
];

Or in your model itself:

use Glorand\Model\Settings\Traits\HasSettingsTable;

class User extends Model
{
    public $defaultSettings = [
        'key_1' => 'val_1',
    ];
}

Please note that if you define settings in the model, the settings from configs will have no effect, they will just be ignored.

Usage

$user = App\User::first();

Check id the settings for the entity is empty

$user->settings()->empty();

Check settings (exist)

$user->settings()->exist();

Get all model's settings

$user->settings()->all();
$user->settings()->get();

Get a specific setting

$user->settings()->get('some.setting');
$user->settings()->get('some.setting', 'default value');
//multiple
$user->settings()->getMultiple(
	[
		'some.setting_1',
		'some.setting_2',
	],
	'default value'
);

Add / Update setting

$user->settings()->apply((array)$settings);
$user->settings()->set('some.setting', 'new value');
$user->settings()->update('some.setting', 'new value');
//multiple
$user->settings()->setMultiple([
	'some.setting_1' => 'new value 1',
	'some.setting_2' => 'new value 2',
]);

Check if the model has a specific setting

$user->settings()->has('some.setting');

Remove a setting from a model

$user->settings()->delete('some.setting');
//multiple
$user->settings()->deleteMultiple([
	'some.setting_1',
	'some.setting_2',
]);
//all
$user->settings()->clear();

Persistence for settings field

In case of field settings the auto-save is configurable.

The default value is true

  • Use an attribute on model
protected $persistSettings = true; //boolean
  • Environment (.env) variable
MODEL_SETTINGS_PERSISTENT=true
  • Config value - model settings config file
'settings_persistent' => env('MODEL_SETTINGS_PERSISTENT', true),

If the persistence is false you have to save the model after the operation.

Using another method name other than settings()

If you prefer to use another name other than settings , you can do so by defining a $invokeSettingsBy property. This forward calls (such as configurations()) to the settings() method.

Validation system for settings data <a name="validation>

When you're using the set() or apply()|update() methods thrown an exception when you break a rule. You can define rules on model using $settingsRules public property, and the rules array definition is identical with the Laravel default validation rules. (see Laravel rules)

class User extends Model
{
    use HasSettingsTable;

    public array $defaultSettings = [
        'user' => [
            'name' => 'Test User',
            'email' => '[email protected]'
            'age' => 27,
        ],
        'language' => 'en',
        'max_size' => 12,
    ];

    // settings rules
    public array $settingsRules = [
        'user' => 'array',
        'user.email' => [
            'string',
            'email',
        ],
        'user.age' => 'integer',
        'language' => 'string|in:en,es,it|max:2',
        'max_size' => 'int|min:5|max:15',
    ];
}

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

License

The MIT License (MIT). Please see LICENSE for more information.

Related Stuff

Comments
  • [Bug] Merging default settings does not work

    [Bug] Merging default settings does not work

    Settings are merged with default settings in the AbstractSettingsManager.

    /**
         * @return array
         */
        public function all(): array
        {
            $array = [];
            foreach (array_merge($this->model->getDefaultSettings(), $this->model->getSettingsValue()) as $key => $value) {
                Arr::set($array, $key, $value);
            }
            return $array;
        }
    

    The issue with this logic is that we are merging two completely different kinds of arrays. The default settings are (or should be) a flat array with dot notation whereas the getSettingsValue may return a deeply nested array from json_decode. Merging both will result in overwriting nested defaults with the current empty value (especially a problem when adding new nested settings).

    There are two simple approaches to solve this issue.

    1. Use nested arrays on both sides and use array_merge_recursive
    2. (Favorite) Flatten the settings value with dot notation before merging. Keep in mind that you cannot use Arr:dot for this purpose since it would also flatten non-associative arrays like ['array.0' => value] which results in poor merging.

    You can use this instead:

    /**
         * Check if array is associative and not sequential
         * @param array $arr
         * @return bool
         */
        static function isAssoc(array $arr)
        {
            if (array() === $arr) return false;
            return array_keys($arr) !== range(0, count($arr) - 1);
        }
    
        /**
         * Flatten array with dots for settings package
         * @param $array
         * @param string $prepend
         * @return array
         */
        static function dotFlatten($array, $prepend = '') {
            $results = [];
            foreach ($array as $key => $value) {
                // only re-run if nested array is associative (key-based)
                if (is_array($value) && static::isAssoc($value) && !empty($value)) {
                    $results = array_merge($results, static::dotFlatten($value, $prepend.$key.'.'));
                } else {
                    $results[$prepend.$key] = $value;
                }
            }
            return $results;
        }
    

    Thanks in advance!

    opened by lucianholt97 13
  • Unknown field (settings)

    Unknown field (settings)

    Hi,

    I'm having this issue "Unknown field (settings) on table members". The field settings exist on the table members.

    if I remove this code in Glorand\Model\Settings\Traits\HasSettingsField

    if (!$this->hasSettingsField()) {
    throw new ModelSettingsException("Unknown field ($settingsFieldName) on table {$this->getTable()}");
     }
    

    it will work fine. I am using laravel 6.9.0 and this package version 3.5.4.

    Anyone has this issue?

    opened by SDCCardsDeveloper 11
  • [Proposal] Settings validations

    [Proposal] Settings validations

    Is your feature request related to a problem? Please describe. This is a proposal to a new feature that could be implemented in this project.

    Describe the solution you'd like Add a validation system when you're using the set() or update() methods to throw an exception when you break a rule.

    Describe alternatives you've considered You could check the value before set or update a setting but, in my opinion, is long and boring...

    Additional context This is an example of how it could be implemented:

    class Chat extends Model
    {
        use HasSettingsTable;
    
        public array $defaultSettings = [
            'news' => true,
            'language' => 'en',
            'max_size' => 12,
        ];
    
        // settings rules
        public array $settingsRules = [
            'news' => 'bool',
            'language' => 'string|in:en,es,it|max:2',
            'max_size' => 'int|min:5|max:15',
        ];
    }
    
    // set or update setting
    Chat::find(1)->settings()->set('language','it'); // OK!
    Chat::find(1)->settings()->set('news',123456); // throws an exception! - it must be a boolean
    
    
    Type: Enhancement Status: Accepted 
    opened by Lukasss93 5
  • Incompatible declaration of Traits\HasSettingsField::settings() error on PHP 8

    Incompatible declaration of Traits\HasSettingsField::settings() error on PHP 8

    Hi. After updating to PHP 8.0, I get this exception:

    Declaration of Glorand\Model\Settings\Traits\HasSettingsField::settings(): Glorand\Model\Settings\Contracts\SettingsManagerContract must be compatible with Glorand\Model\Settings\Traits\HasSettings::settings(): Glorand\Model\Settings\Managers\AbstractSettingsManager at ...vendor\glorand\laravel-model-settings\src\Traits\HasSettingsField.php:37

    Priority: Low Status: Accepted 
    opened by alin78hai 5
  • [Help] How to eager load settings for all users?

    [Help] How to eager load settings for all users?

    I recently came across a scenario where I needed settings for all the users in the collection. I tried to eager load it but unfortunately it doesn't work. I am using HasSettingsTable trait.

    $users = User::with('settings')->get();

    This returns an error: Call to undefined method Glorand\Model\Settings\Managers\TableSettingsManager::addEagerConstraints()

    So I was wondering if there is any way to get this relation eager load? I have version 3.6.5 installed.

    opened by 77media-creations 4
  • FIX: HasSettingsField now adheres to $connection override on model (#62)

    FIX: HasSettingsField now adheres to $connection override on model (#62)

    Modified the HasSettingsField.php to allow for reading the model's connection value (default or otherwise) as proposed on issue #62 Updated readme.md to document change

    opened by bickle66 4
  • Can't search for settings via a model.

    Can't search for settings via a model.

    I'm using the table based setup, and I have a User model that has a setting named nickname.

    Searching via a setting field blows up.

    $user->with([
        'settings' => function($builder) use ($nickname) {
            $builder->where('nickname', $nickname);
        }
    ]);
    

    Throws a Call to undefined method Glorand\Model\Settings\Managers\TableSettingsManager::addEagerConstraints() exception.

    Good First Issue Type: Question 
    opened by kevinruscoe 4
  • [Proposal] Have Trait read from model's $connection settings

    [Proposal] Have Trait read from model's $connection settings

    In the case of a multi-tenant application (or any model that uses a different connection to the default) it doesn't seem to adhere to the Model's $connection setting.

    In the HasSettingField.php a method:

        /**
         * @return string
         */
        public function getConnectionName(): string
        {
            return $this->connection ?? config('database.default');
        }
    

    And modify the hasSettingField to:

        /**
         * @return mixed
         */
        private function hasSettingsField()
        {
            return Cache::remember(
                config('model_settings.settings_table_cache_prefix') . '::has_field',
                now()->addDays(1),
                function () {
                    return Schema::connection($this->getConnectionName())->hasColumn($this->getTable(), $this->getSettingsFieldName());
                }
            );
        }
    
    Status: Completed Help wanted Priority: High 
    opened by bickle66 3
  • JSON DataType not supported with MariaDB ?

    JSON DataType not supported with MariaDB ?

    [Illuminate\Database\QueryException] SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error i n your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'json not null,descriptionjso n null,detailsjson null,featuresjson nul' at line 1 (SQL: create ta bleproducts(idint unsigned not null auto_increment primary key,nam ejson not null,descriptionjson null,detailsjson null,featuresjson null,priceint not null,category_idint not null,extrasjson null,created_attimestamp null,updated_attimestamp null) default cha racter set utf8 collate utf8_unicode_ci)

    Unfortunately MariaDB doesn't support column type of json :/. I changed to longText to make it work. But is that in all cases safe to do ?

    opened by AntonLugtenburg 3
  • UPDATE: Reuse validated settings

    UPDATE: Reuse validated settings

    Currently validated settings are discarded, and that's mostly OK, but sometimes it's not.

    My case comes from using Excluding Unvalidated Array Keys.

    It's possible to call validation for settings before they are set - but that kinda defeats the purpose of using a package :smile:

    opened by vkislichenko 2
  • No support to custom validation rules

    No support to custom validation rules

    Describe the bug There is no support to add custom validation rules Reference: https://github.com/glorand/laravel-model-settings/issues/87#issuecomment-964529183

    To Reproduce Add a custom validation rule. You'll get "expression is not allowed as field default value".

    Expected behavior Convert the "settingsRules" property to a method like the "rules" method in Laravel FormRequest

    Screenshots 141001871-95d6659e-2495-4532-b6e3-34239146c17a

    opened by Lukasss93 2
  • How to get GetMultiple with different default values

    How to get GetMultiple with different default values

    As for getting multiple settings at once, currently what is supported is

    //multiple
    $user->settings()->getMultiple(
    	[
    		'some.setting_1',
    		'some.setting_2',
    	],
    	'default value'
    );
    

    However, in my case, seeting_1 is true and setting_2 is false. I have tried:

    //multiple
    $user->settings()->getMultiple(
    	[
    		'some.setting_1' => true,
    		'some.setting_2' => false,
    	],
    );
    

    But it doesn't work.

    Any workaround???

    opened by pathros 0
  • Set defaults in the database

    Set defaults in the database

    Is your feature request related to a problem? Please describe. Changing defaults currently requires code updates.

    Describe the solution you'd like It would be great to have the ability to create, edit, and even delete defaults for models directly in the database so they can be changed without performing code changes, releases, or deployments.

    I think just a default_settings table would probably keep things simple, with a model_type column that associates a model with a single row. The table schema structure would pretty much look the same as the model_settings table minus the model_id column.

    Thanks for the awesome package, I'm loving it so far. 🙏

    opened by joelmellon 0
Releases(5.0.0)
Owner
Lorand Gombos
Lorand Gombos
Add settings to any Laravel model.

Laravel Property Bag Simple settings for Laravel apps. Easily give multiple resources settings Simple to add additional settings as your app grows Set

Zach Leigh 80 Aug 8, 2022
⚙️Simple key/value typed settings for your Laravel app with synchronized json export

Simple key/value typed settings for your Laravel app Create, store and use key/value settings, typed from numbers over dates to array, cached for quic

elipZis 8 Jan 7, 2023
Laravel-model-mapper - Map your model attributes to class properties with ease.

Laravel Model-Property Mapper This package provides functionality to map your model attributes to local class properties with the same names. The pack

Michael Rubel 15 Oct 29, 2022
A laravel package to handle sanitize process of model data to create/update model records.

Laravel Model UUID A simple package to sanitize model data to create/update table records. Installation Require the package using composer: composer r

null 66 Sep 19, 2022
A laravel package to generate model hashid based on model id column.

Laravel Model Hashid A package to generate model hash id from the model auto increment id for laravel models Installation Require the package using co

Touhidur Rahman 13 Jan 20, 2022
A package to filter laravel model based on query params or retrieved model collection

Laravel Filterable A package to filter laravel model based on query params or retrived model collection. Installation Require/Install the package usin

Touhidur Rahman 17 Jan 20, 2022
Store your Laravel application settings in an on-disk JSON file

Store your Laravel application settings in an on-disk JSON file. This package provides a simple SettingsRepository class that can be used to store you

Ryan Chandler 24 Nov 16, 2022
Kalibrant - a package that provides a simple way to manage your models settings

Introduction For your laravel 9.x applications, Kalibrant is a package that provides a simple way to manage your models settings. It is a simple way t

Starfolk 3 Jun 18, 2022
Persistent settings in Laravel

Laravel Settings Persistent, application-wide settings for Laravel. Despite the package name, this package works with Laravel 4, 5, 6, 7 and 8! Common

Andreas Lutro 855 Dec 27, 2022
Per-user settings repository system for Laravel

Laraconfig Per-user settings repository system for Laravel. This package allows users to have settings that can be queried, changed and even updated,

Italo 170 Oct 26, 2022
Simple Arabic Laravel Dashboard , has basic settings and a nice layout . to make it easy for you to create fast dashboard

Simple Arabic Laravel Dashboard âś… Auto Seo âś… Optimized Notifications With Images âś… Smart Alerts âś… Auto Js Validations âś… Front End Alert âś… Nice Image V

Peter Tharwat 254 Dec 19, 2022
Strongly typed settings for Laravel, includes built-in encryption and friendly validation.

Strongly Typed Laravel Settings Install composer require bogdankharchenko/typed-laravel-settings Model Setup namespace App\Models\User; use Illuminat

Bogdan Kharchenko 10 Aug 31, 2022
An interface for the administrator to easily change application settings. Uses Laravel Backpack

Backpack\Settings An interface for the administrator to easily change application settings. Uses Laravel Backpack. Works on Laravel 5.2 to Laravel 8.

Backpack for Laravel 207 Dec 6, 2022
This Laravel Nova settings tool based on env, using nativ nova fields and resources

Nova Settings Description This Laravel Nova settings tool based on env, using nativ nova fields and resources Features Using native Nova resources Ful

Artem Stepanenko 21 Dec 28, 2022
Bootstrap Theme Generator inside of a Wordpress-Settings-Page. Includes live compilation of SCSS!

Bootstrap-Theme-Generator Bootstrap Theme Generator enables you to choose which components of Bootstrap you want to load. It also gives you the possib

null 3 Aug 15, 2022
Laravel comments - This package enables to easily associate comments to any Eloquent model in your Laravel application

Laravel comments - This package enables to easily associate comments to any Eloquent model in your Laravel application

Rubik 4 May 12, 2022
Update multiple Laravel Model records, each with it's own set of values, sending a single query to your database!

Laravel Mass Update Update multiple Laravel Model records, each with its own set of values, sending a single query to your database! Installation You

Jorge González 88 Dec 31, 2022
Make your own custom cast type for Laravel model attributes

Laravel Custom Casts Make your own cast type for Laravel model attributes Laravel custom casts works similarly to Eloquent attribute casting, but with

Vladimir Ković 220 Oct 28, 2022
Allow your model to record the creation, update and deletion of user fingerprints in laravel packages

This laravel package will allow your models to record the the created, updated and deleted by User FingerPrints

Managemize 4 Mar 11, 2022