Add settings to any Laravel model.

Overview

Laravel Property Bag

Latest Stable Version License Build Status Quality Score StyleCI Total Downloads

Simple settings for Laravel apps.
  • Easily give multiple resources settings
  • Simple to add additional settings as your app grows
  • Set default settings and limit setting values for security
  • Fully configurable

Contents

Upgrade Information

From 1.3.* to 1.4.0

1.4.0 drops support for PHP 7.1 and adds support for Laravel 6.

From 1.2.* to 1.3.0

1.3.0 drops support for PHP 7.0.

From 1.1.* to 1.2.0

1.2.0 drops support for PHP 5.6. It will likely still work in older PHP versions, but bugs or issues that focus specifically on 5.6 or lower will no longer be dealt with. Support for PHP 7.2 added.

From 1.0.* to 1.1.0

1.1.0 adds Lumen support and support for Laravel 5.4 (thanks tzurbaev). There should be no breaking changes. If using Laravel 5.3, please use Version 1.0.5:

composer require zachleigh/laravel-property-bag:1.0.*
From 0.9.* to 1.0.0

Version 1.0.0 brings major changes to the package that make it incompatible with previous versions. The package was essentially rewritten making upgrade from 0.9.7 to 1.0.0 difficult at best.

About

Laravel Property Bag gives your application resources savable, secure settings by using a single database property bag table. The benefit of using this kind of settings table, as opposed to say a json blob column on the resource table, is that if in the future you decide to change a setting value, a simple database query can easily take care of it.

Install

1. Install through composer
composer require zachleigh/laravel-property-bag

Laravel Installation

a. Register the service provider

In Laravel's config/app.php file, add the service provider to the array with the 'providers' key.

LaravelPropertyBag\ServiceProvider::class
b. Publish the migration
php artisan vendor:publish --provider="LaravelPropertyBag\ServiceProvider"

Lumen Installation

a. Enable Eloquent

If you haven't already done so, find and uncomment $app->withEloquent() in app/boostrap.php.

b. Register the service provider

In Lumen's app/bootstrap.php file, add the service provider:

$app->register(LaravelPropertyBag\ServiceProvider::class);
c. Copy migration file

Since Lumen doesn't offer the php artisan vendor:publish command, you have to copy the migration file manually from the vendor/zachleigh/laravel-property-bag/src/Migrations directory to the database/migrations directory.

2. Run the migration
php artisan migrate
3. Create a new settings config file for your resource.
php artisan pbag:make {resource}

{resource} should be the name of the model you wish to add settings to. For example:

php artisan pbag:make User

This will create a Settings directory containing a UserSettings class where you can configure your settings for the User class.

Usage

1. Use the trait in the model.
...
use LaravelPropertyBag\Settings\HasSettings;

class User extends Model
{
    use HasSettings;

    ...
}
2. Register your settings plus their allowed values and defaults

After publishing the UserSettings file (hopefully you did this above), register settings in the UserSettings class.

protected $registeredSettings = [
    'example_setting' => [
        'allowed' => [true, false],
        'default' => false
    ]
];

Each setting must contain an array of allowed values and a default value. It is also possible to use validation rules instead of hardcoding allowed values.

3. Set the setting from the user model
$user->settings(['example_setting' => false]);
// or
$user->settings()->set(['example_setting' => false]);
// or
$user->setSettings(['example_setting' => false]);

Set multiple values at a time

$user->settings([
    'example_setting' => false,
    'another_setting' => 'grey'
]);
4. Get the set value from the user model
$value = $user->settings('example_setting');
// or
$value = $user->settings()->get('example_setting');

If the value has not been set, the registered default value will be returned. Note that default values are not stored in the database in order to limit database size.

Methods

get($key)

Get value for given key.

$value = $model->settings()->get($key);
set($array)

Set array keys to associated values. Values may be of any type. Returns Settings. When a default value is passed to set(), it will not be stored in the database. Don't be alarmed if your default values aren't showing up in the table. If a value is not registered in the allowed values array, a LaravelPropertyBag\Exceptions\InvalidSettingsValue exception will be thrown. You can use the $e->getFailedKey() method to retrieve the failed setting name.

$model->settings()->set([
  'key1' => 'value1',
  'key2' => 'value2'
]);

// or

$model->setSettings([
  'key1' => 'value1',
  'key2' => 'value2'
]);
getDefault($key)

Get default value for given key.

$default = $model->settings()->getDefault($key);

// or

$default = $model->defaultSetting($key);
allDefaults()

Get all the default values for registered settings. Returns collection.

$defaults = $model->settings()->allDefaults();

// or

$defaults = $model->defaultSetting();
getAllowed($key)

Get allowed values for given key. Returns collection.

$allowed = $model->settings()->getAllowed($key);

// or

$allowed = $model->allowedSetting($key);
allAllowed()

Get all allowed values for registered settings. Returns collection.

$allowed = $model->settings()->allAllowed();

// or

$allowed = $model->allowedSetting();
isDefault($key, $value)

Return true if given value is the default value for given key.

$boolean = $model->settings()->isDefault($key, $value);
isValid($key, $value)

Return true if given value is allowed for given key.

$boolean = $model->settings()->isValid($key, $value);
all()

Return all setting value's for model. Returns collection.

$allSettings = $model->settings()->all();

// or

$allSettings = $model->allSettings();
keyIs($key, $value)

Return true if setting for given key equals given value.

$boolean = $model->settings()->keyIs($key, $value);
reset($key)

Reset key to default value.

$default = $model->settings()->reset($key);
withSetting($key, $value = null)

Get an array with all stored rows with a given setting and/or value.

$collection = $model::withSetting($key);
// or
$collection = $model::withSetting($key, $value);

Validation Rules

Rather than hardcoding values in an array, it is also possible to define rules that determine whether a setting value is valid. Rules are always strings and must contain a colon at both the beginning and ending of the string.

'integer' => [
    'allowed' => ':int:',
    'default' => 7
]

In this case, the setting value saved for the 'integer' key must be an integer.

Some rules require parameters. Parameters can be passed in the rule definition by using an equal sign and a comma separated list.

'range' => [
    'allowed' => ':range=1,5:',
    'default' => 1
]

Available Rules

':any:'

Any value will be accepted.

':alpha:'

Alphabetic values will be accepted.

':alphanum:'

Alphanumeric values will be accepted.

':bool:'

Boolean values will be accepted.

':int:'

Integer values will be accepted.

':num:'

Numeric values will be accepted.

':range=low,high:'

Numeric values falling between or inluding the given low and high parameters will be accpeted. Example:

'range' => [
    'allowed' => ':range=1,10:',
    'default' => 5
]

The numbers 1 to 10 will be allowed.

':string:'

Strings will be accepted.

User Defined Rules

To make user defined rules, first publish the Rules file to Settings/Resources/Rules.php:

php artisan pbag:rules

Rule validation methods should be named by prepending 'rule' to the rule name. For example, if our rule is 'example', we would define it in the settings config file like this:

'setting_name' => [
    'allowed' => ':example:',
    'default' => 'default'
]

And then our method would be called 'ruleExample':

public static function ruleExample($value)
{
    // do stuff
    //
    // return boolean;
}

All rule methods should be static and thus should not care about object or application state. If your rule requires parameters, accept them as arguments to the method.

'setting_name' => [
    'allowed' => ':example=arg1,arg2:',
    'default' => 'default'
]
public static function ruleExample($value, $arg1, $arg2)
{
    // do stuff
    //
    // return boolean;
}

Another option would be to validate input with Laravel's built in validation, which is much more complete than what this package offers, and then set all your setting allowed values to ':any:'.

Advanced Configuration

Laravel Property Bag gives you several ways to configure the package to fit your needs and wants.

I don't want to register settings as an array

Cool. I get it. Especially if you have dozens of settings, dealing with an array can be annoying. In the model settings config file, add the registeredSettings method.

/**
 * Return a collection of registered settings.
 *
 * @return Collection
 */
public function registeredSettings()
{
    // Your code

    return $collection;
}

In this method, do whatever you want and return a collection of items that has the same structure as the registeredSettings array.

'example_setting' => [
    'allowed' => [true, false],
    'default' => true
]
I want to use dynamic allowed and default values.

No problem. Like in the above section, create your own registeredSettings method in the settings config file and return a collection of registered settings.

/**
 * Return a collection of registered settings.
 *
 * @return Collection
 */
public function registeredSettings()
{
    $allGroups = Auth::user()->allGroupNames();

    return collect([
        'default_group' => [
            'allowed' => $allGroups,
            'default' => $allGroups[0]
        ]
    ]);
}

The allGroupNames function simply returns an array of group names:

/**
 * Get array of all group names.
 *
 * @return array
 */
public function allgroupNames()
{
    return $this->groups->pluck('name')->all();
}

You can also access the model the settings are attached to with the getResource() method.

/**
 * Return a collection of registered settings.
 *
 * @return Collection
 */
public function registeredSettings()
{
    $allGroups = getResource()->allGroupNames();

    return collect([
        'default_group' => [
            'allowed' => $allGroups,
            'default' => $allGroups[0]
        ]
    ]);
}

Contributing

Contributions are more than welcome. Fork, improve and make a pull request. For bugs, ideas for improvement or other, please create an issue.

Comments
  • migrate --provider option doesn't exist

    migrate --provider option doesn't exist

    php artisan migrate --provider="LaravelPropertyBag\ServiceProvider"

    That --provider option doesn't exist in 5.3. I assume it can be changed to php artisan migrate?

    opened by a3020 5
  • Add Lumen support

    Add Lumen support

    Since this package is already compatible with Lumen Framework, the only change is to use qualified name for the File facade & replace app_path() calls to base_path() with app/ prefix.

    opened by tzurbaev 4
  • Pass resource to ResourceConfig instance

    Pass resource to ResourceConfig instance

    This patch allows ResourceConfig to access original model while building registered settings.

    This might be helpful while working with models that should have different settings (depending on instance's attribute value, as example).

    opened by tzurbaev 4
  • Set not creating

    Set not creating

    Edit nvm. Took me a while to understand set() doesn't create if it is the default value.

    Although the json_encode is ugly if we're not using json in our db

    opened by racashmoney 4
  • error :  Specified key was too long; max key length is 1000 bytes

    error : Specified key was too long; max key length is 1000 bytes

    i'm getting this error after running php artisan migrate

    full error :

    Illuminate\Database\QueryException  : SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes (SQL: alter table 'property_bag' add unique 'property_bag_resource_type_resource_id_key_unique'('resource_type', 'resource_id', 'key'))
    
      at /vendor/laravel/framework/src/Illuminate/Database/Connection.php:664
        660|         // If an exception occurs when attempting to run a query, we'll format the error
        661|         // message to include the bindings with SQL, which will make this exception a
        662|         // lot more helpful to the developer instead of just the database's errors.
        663|         catch (Exception $e) {
      > 664|             throw new QueryException(
        665|                 $query, $this->prepareBindings($bindings), $e
        666|             );
        667|         }
        668|
    
      Exception trace:
    
      1   Doctrine\DBAL\Driver\PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes")
         /vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:119
    
      2   PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes")
          /vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:117
    
    opened by AMAFsoft 2
  • Support uncommon primary keys for models

    Support uncommon primary keys for models

    If you have a Model with an uncommon primary key, you won't be able to use this package because it directly depends on id. Instead of that, I replaced it with resource->getKey() which gets the value of whichever primary key the Model has defined.

    opened by darkostanimirovic 2
  • Reduce SQL queries by utilizing eagerly loaded propertyBag relation

    Reduce SQL queries by utilizing eagerly loaded propertyBag relation

    Sometimes we need to read settings of multiple models at once - Eloquent's eager loading feature is life saver in those situations. Unfortunately at this time property-bag does not support it. Furthermore, it loads data from DB twice: at first - from Settings::sync method and at second - from Settings::getAllSettings method.

    Since instantiating Settings class performs initial synchronization, we have +2 queries for each model we're working with - even if we explicitly loaded propertyBag relation via Eloquent's with method.

    This PR removes $this->resource->load('propertyBag'); line from Settings::sync method and adds check for loaded propertyBag relation in Settings::getAllSettings method.

    Besides, when user updates settings of resource that have eagerly loaded propertyBag relation, Setting::set method will reload propertyBag relation to make sure that we're wokring only with actual settings.

    I've added new tests to be sure that user is able to read updated setting's value when working with & without eagerly loaded relation.

    opened by tzurbaev 2
  • Given value is not a registered allowed value for 0

    Given value is not a registered allowed value for 0

    hello,

    this is my code : App\Settings\UserSettings.php

        protected $registeredSettings = [
    
            'payment_method' => [
                'allowed' => ['bank', 'paypal','payoneer'],
                'default' => 'bank'
            ],
    
        ];
    
    

    My controller

            $user = auth()->user();
            $request->validate([
                'payment_method' => 'in:bank,paypal,payoneer'
            ]);
            if($request->filled('payment_method')){
                if(!$user->settings()->keyIs('payment_method', $request->payment_method)){
                    $user->settings(['payment_method',$request->payment_method]); //Problem is here
                }
            }
    

    GET request URL : /settings/payments?payment_method=payoneer

    And it works only with : paypal as a value /settings/payments?payment_method=paypal

    i have no idea whats going on

    Update

    1- "paypal" works because of the condition before saving the settings 2- i forgot to mention that i'm using laravel 5.7

    opened by AMAFsoft 1
  • Feature related to #21

    Feature related to #21

    This pull request has a simple implementation for a feature related to #21. Some examples below: YourModel::withSetting('music_notifications'); // returns a collection of YourModel with a specific setting or YourModel::withSetting('music_notifications', true); // returns a collection of YourModel with a specific setting and value YourModel must have the HasSettings trait, so you could use it like this: $userCollection = User::withSetting('music_notifications');

    opened by luizvid 1
  • Get users with a particular setting?

    Get users with a particular setting?

    Hello,

    This is a really awesome. Thanks for sharing. I'm wondering, is it possible to retrieve all users with a particular setting through the user Model? I figure the via setting model below could also work but maybe you have a way more efficient way?

    PropertyBag::where('key', 'music_notifications')->where('value', true)->pluck('owner_id');

    enhancement 
    opened by haleyngonadi 1
  • Have more control to choose when the properties should persist

    Have more control to choose when the properties should persist

    Is there a way to add property bags as a new model is created ? Currently it looks like the model must be existing first

    $user = new User($data);
    $user->save();
    //Then add settings
    $user->settings(['valid_date_or_birth',false]);
    
    

    There is no way to add those settings prior to saving ?

    $user = new User();
    $user->settings(['valid_date_or_birth',false]);  
    //The problem is that this will trigger a SQL query
    //I am sure a workaround could be to set the settings first before adding any other data
    // $user->save(); here then filling the data later on
    $user->fill($data); // include operations that will be affected by the settings
    $user->save();
    

    One of the issues I have been running into is that I have settings in my model that affect some attributes and mutators. For example. If this valid_date_or_birth setting affect how a date format should change in either an accessor or a mutator. Because the user would not have an ID at the time this setting is stored, It will fail. The problem is that as soon as the settings is set, it triggers a SQL query. However I would like to set those settings so that I can do extra computations (especially for models not currently saved) and save those settings when its time to do so

    class User extends Model{
        public function getDateAttribute(){
            //Perform operation based on the user settings
        }
        public function setDateAttribute(){
            //Perform operation based on the user settings
        }
    }
    
    opened by swinyx 1
Releases(v1.4.1)
Owner
Zach Leigh
Zach Leigh
Model Settings for your Laravel app

Model Settings for your Laravel app 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

Lorand Gombos 611 Dec 15, 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
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 that adds a simple image functionality to any Laravel model

Laraimage A Laravel package that adds a simple image functionality to any Laravel model Introduction Laraimage served four use cases when using images

Hussein Feras 52 Jul 17, 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
Easily create a revision history for any laravel model

Wouldn't it be nice to have a revision history for any model in your project, without having to do any work for it. By simply adding the RevisionableT

Venture Craft 2.4k Jan 6, 2023
Laravel 2-Step Verification is a package to add 2-Step user authentication to any Laravel project easily.

Laravel 2-Step verification is a package to add 2-Step user authentication to any Laravel project easily. It is configurable and customizable. It uses notifications to send the user an email with a 4-digit verification code. Laravel 2-Step Authentication Verification for Laravel. Can be used in out the box with Laravel's authentication scaffolding or integrated into other projects.

Jeremy Kenedy 204 Dec 23, 2022
Add eloquent model events fired after a transaction is committed or rolled back

Laravel Transactional Model Events Add transactional events to your eloquent models. Will automatically detect changes in your models within a transac

Mark van Duijker 62 Dec 22, 2022
This package helps you to add user based follow system to your model.

Laravel Follow User follow unfollow system for Laravel. Related projects: Like: overtrue/laravel-like Favorite: overtrue/laravel-favorite Subscribe: o

安正超 1k Dec 31, 2022
Turn any Eloquent model into a list!

Listify Turn any Eloquent model into a list! Description Listify provides the capabilities for sorting and reordering a number of objects in a list. T

Travis Vignon 138 Nov 28, 2022
This package provides a trait that will generate a unique uuid when saving any Eloquent model.

Generate slugs when saving Eloquent models This package provides a trait that will generate a unique uuid when saving any Eloquent model. $model = new

Abdul Kudus 2 Oct 14, 2021
cybercog 996 Dec 28, 2022
A Laravel 8 Project Implement with GraphQL With Sanctum APIs Authentications Which utilized in Any Frontend or Any Mobile Application Programs.

A Laravel 8 Project Implement with GraphQL With Sanctum APIs Authentications Which utilized in Any Frontend or Any Mobile Application Programs.

Vikas Ukani 3 Jan 6, 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
⚙️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