Provides database storage and retrieval of application settings, with a fallback to the config classes.

Related tags

Frameworks settings
Overview

CodeIgniter 4 Settings

Provides database storage and retrieval of application settings, with a fallback to the config classes.

Coverage Status

Quick Start

  1. Install with Composer: > composer require codeigniter4/settings
  2. Create a new migration and copy the provided class from below into it.

Settings provides a simple interface that you can use in place of calling config() to allow you to read and store config values in the database. If the value has not been updated and saved in the database then the original value from the config file will be used.

This allows you to save your application's default state as values in config files, all stored in version control, and still allows your users to override those settings once the site is live.

Installation

Install easily via Composer to take advantage of CodeIgniter 4's autoloading capabilities and always be up-to-date:

  • > composer require codeigniter4/settings

Or, install manually by downloading the source files and adding the directory to app/Config/Autoload.php.

Setup

In order to store the settings in the database, you can run the provided migration:

> php spark migrate --all

This will also migrate all other packages. If you don't want to do that you can copy the file from vendor/codeigniter4/settings/src/Database/Migrations/2021-07-04-041948_CreateSettingsTable.php into app/Database/Migrations, and migrate without the --all flag.

dot Notation

This library uses what we call "dot notation" to specify the class name and the property name to use. These are joined by a dot, hence the name.

If you have a class named App, and the property you are wanting to use is siteName, then the key would be App.siteName.

Usage

To retrieve a config value use the settings service.

// The same as config('App')->siteName;
$siteName = service('settings')->get('App.siteName');

In this case we used the short class name, App, which the config() method automatically locates within the app/Config directory. If it was from a module, it would be found there. Either way, the fully qualified name is automatically detected by the Settings class to keep values separated from config files that may share the same name but different namespaces. If no config file match is found, the short name will be used, so it can be used to store settings without config files.

To save a value, call the set() method on the settings class, providing the class name, the key, and the value. Note that boolean true/false will be converted to strings :true and :false when stored in the database, but will be converted back into a boolean when retrieved. Arrays and objects are serialized when saved, and unserialized when retrieved.

service('setting')->set('App.siteName', 'My Great Site');

You can delete a value from the persistent storage with the forget() method. Since it is removed from the storage, it effectively resets itself back to the default value in config file, if any.

service('setting')->forget('App.siteName')

Contextual Settings

In addition to the default behavior describe above, Settings can can be used to define "contextual settings". A context may be anything you want, but common examples are a runtime environment or an authenticated user. In order to use a context you pass it as an additional parameter to the get()/set()/forget() methods; if a context setting is requested and does not exist then the general value will be used.

Contexts may be any unique string you choose, but a recommended format for supplying some consistency is to give them a category and identifier, like environment:production or group:42.

An example... Say your App config includes the name of a theme to use to enhance your display. By default your config file specifies App.theme = 'default'. When a user changes their theme, you do not want this to change the theme for all visitors to the site, so you need to provide the user as the context for the change:

$context = 'user:' . user_id();
service('setting')->set('App.theme', 'dark', $context);

Now when your filter is determining which theme to apply it can check for the current user as the context:

$context = 'user:' . user_id();
$theme = service('setting')->get('App.theme', $context);

// or using the helper
setting()->get('App.theme', $context);

Contexts are a cascading check, so if a context does not match a value it will fall back on general, i.e. service('setting')->get('App.theme'). Return value priority is as follows: "Setting with a context > Setting without context > Config value > null".

Using the Helper

The helper provides a shortcut to the using the service. It must first be loaded using the helper() method or telling your BaseController to always load it.

helper('setting');

$name = setting('App.siteName');
// Store a value
setting('App.siteName', 'My Great Site');

// Using the service through the helper
$name = setting()->get('App.siteName');
setting()->set('App.siteName', 'My Great Site');

// Forgetting a value
setting()->forget('App.siteName');

Note: Due to the shorthand nature of the helper function it cannot access contextual settings.

Known Limitations

The following are known limitations of the library:

  1. You can currently only store a single setting at a time. While the DatabaseHandler uses a local cache to keep performance as high as possible for reads, writes must be done one at a time.
  2. You can only access the first level within a property directly. In most config classes this is a non-issue, since the properties are simple values. Some config files, like the database file, contain properties that are arrays.
Comments
  • Composer install did not work

    Composer install did not work

    Hi, Nice Extension to CI 4. Unfortunately, when i installed with composer, the composer ran but nothing got installed. I checked the Migration folder and nothing was there.

    Did i do something wrong or do i have to do somethings manually?

    opened by murugappanrm 5
  • Feature: Multiple Write Handlers

    Feature: Multiple Write Handlers

    Every time I think about adding new handlers I run into the same logical issue: how to deal with multiple handlers that need to write a state. I would like to hear a bit more of the logic behind the single-handler approach, in case I am missing something; then maybe consider expanding it to support any registered handler.

    opened by MGatner 4
  • Contexts

    Contexts

    This PR expands the core function to add a new feature: contexts. A "contextual setting" is a way of defining a setting for a specific subset of circumstances, left to the developer to define (see https://github.com/codeigniter4/settings/pull/15#issuecomment-968101752). Contextual settings fall back on their "global" version (i.e. the current behavior), providing one more layer of customizability. An example of a contextual setting might be environment-specific URLs:

    service('Settings')->set('App.homepage', '/welcome', 'environment:production');
    service('Settings')->set('App.homepage', '/debug', 'environment:development');
    

    In order to facilitate detection of "hits" versus "misses" this PR also adds the has() method to handlers to determine whether a value is present or not. This expands on null value support, since we can now differentiate between "nonexistent" and "present but null".

    Note: Because this feature modifies an abstract method definition it will require a major release.

    opened by MGatner 4
  • Config Injection

    Config Injection

    A nod towards DI and to ease extending the actual class, this PR adds a parameter for the Config file to be used to make handler definition easier. I think ideally this parameter would be required and the service would handle the config fallback, but that BC will have to wait for version 2.

    opened by MGatner 4
  • Feature: Handler priority

    Feature: Handler priority

    There should be some meaningful way to specify handler priority, aside from "whichever comes first in Settings Config". Probably the way to do this is add a priority field to the handler arrays - this way if a module uses a Registrar to tack on a handler it can make it the "preferred" version.

    Addendum: it might be good to allow some way of specifying a handler(s) to use for a single call.

    opened by MGatner 4
  • Null Handling

    Null Handling

    Your latest commit points out a problem in the current flow: settings with null values. I think this will be a frequent enough need with Config handling that it will merit handling explicitly (maybe types will help?). Handlers should be able to:

    • Handle a set() request to store an overriding null value
    • Differentiate "no handler value" that should percolate from an actual null value response from get() requests that should stop

    The service and helper will need updating to accommodate these parameters.

    opened by MGatner 4
  • Bug: Context Update Spillover

    Bug: Context Update Spillover

    Hello, I'm trying to implement new settings library into my project. Everything is going fine, but I would like to have an option for the user to change his theme of app based on the logged in user ID. I am using myth-auth so is no problem to get actually logged in user. I tried to use user_id() as a $context so if is logged in user with ID for example 1 than he can go to settings and change via the form theme of the app.

    Here is the form-select:

    <div class="mb-3">
        <label class="form-label" for="theme"><?= lang('Settings.theme') ?></label>
        <div class="col">
            <select name="theme" class="form-select <?php if (session('errors.theme')) : ?>is-invalid<?php endif ?>">
                <?php
                foreach ([1 => lang('Settings.themes.light'), 2 => lang('Settings.themes.dark')] as $k => $v) {
                    if ($k === set_value('theme', (int) setting()->get('App.theme', user_id()))){
                        echo '<option value="'.$k.'" selected>'.$v.'</option>';
                    } else {
                        echo '<option value="'.$k.'">'.$v.'</option>';
                    }
                }
                ?>
            </select>
        </div>
    </div>
    

    This show to user by default theme-light what is ok. Now he want to change theme to theme-dark so he will choose theme-dark and submit the form. Form is going to the controller method:

        public function attemptUpdate()
        {
            // Validate basics first since some password rules rely on these fields
            $rules = [
                'theme' => 'required',
            ];
    
            if (! $this->validate($rules)) {
                return redirect()
                    ->back()
                    ->with('errors', $this->validator->getErrors());
            }
    
            // Update settings of the user logged in
            setting()->set('App.theme', $this->request->getPost('theme'), user_id());
    
            // Success!
            return redirect()
                ->route('settings')
                ->with('message', lang('Settings.updateSuccess'));
        }
    

    and create settings row in the table settings like:

    1	Config\App	theme	2	string	1	2021-11-20 08:07:47	2021-11-20 08:07:47
    

    as far so good. When another user log in and try to change his settings of theme another row will be created what is ok:

    2	Config\App	theme	2	string	5	2021-11-20 08:07:47	2021-11-20 08:07:47
    

    but for example he want to change his settings back to ligh-theme and all rows in the table are changed like:

    1	Config\App	theme	1	string	5	2021-11-20 08:07:26	2021-11-20 08:09:32
    2	Config\App	theme	1	string	5	2021-11-20 08:07:47	2021-11-20 08:09:32
    

    and setttings of the user with ID 1 are lost.

    opened by jozefrebjak 3
  • Type Casting

    Type Casting

    Note that boolean true/false will be converted to strings :true and :false when stored in the database, but will be converted back into a boolean when retrieved. Arrays and objects are serialized when saved, and unserialized when retrieved.

    One of the most recent additions to Tatter\Settings was type casting - storing the actual setting type in the database so the Library can cast it upon retrieval. I would love to see something like that added here, even if it was "optional" (or auto-detect during set()).

    opened by MGatner 3
  • Multi-Language support

    Multi-Language support

    Is there multi-language support? For example, it would be better to add an extra new column and have multi-language support for example "local".

    opened by mbnl 2
  • Overriding values in Config/App.php

    Overriding values in Config/App.php

    Could you please give me a hint how to use Settings to store values from Config/App.php? For example we have $defaultLocale = 'en' defined in the file, but in the database I have settings(id, class, key, value, created_at, updated_at) VALUES ('1', 'Config/App', 'defaultLocale', 'en', '2022-04-15 08:39:25', '2022-04-15 06:42:47'.

    Should the values from the database automatically override the value from Config/App.php? Do I need to somehow manipulate the framework to use the values from the database for $dafaultLocale?

    I ask because overriding the value from the database does not change the language in the framework (manually changing it in Config/App.php obviously works fine).

    opened by clsmedia 2
  • Why is the namespace starting with

    Why is the namespace starting with "Sparks"?

    First off, thanks for this! Currently using it in my project :)

    As I wanted to migrate the settings table programmatically, I had to input this package's namespace. So, it came as a surprise that CodeIgniter/Settings didn't work. I had to go through the package files to find out that the Sparks/Settings was to be used instead.

    What is the reason for naming it Sparks/Settings? Shouldn't the namespace be CodeIgniter/Settings?

    opened by yassinedoghri 2
  • Return array - multiple result

    Return array - multiple result

    It is possible to get multiple values or an array as result? e.g. - see code Get all the settings from a specific key (App.theme) : setting()->get('App.theme','') Get all the settings form a specific context : setting()->get('','user1') Get all the settings from a specific class : setting()->get('Log')

            $br='<br/>';
    
            service('settings')->set('App.theme', 'dark', 'user1');
            service('settings')->set('App.theme', 'white', 'user2');
            service('settings')->set('App.theme', 'red', 'user3');
            echo setting()->get('App.theme', 'user1').$br;
            echo setting()->get('App.theme', 'user2').$br;
            echo setting()->get('App.theme', 'user3').$br;
            print_r(setting()->get('App.theme','*')).$br;
            print_r(setting()->get('*','user1')).$br;
    
            service('settings')->set('Log.location', 'site/log');
            service('settings')->set('Log.date', '20220102');
            service('settings')->set('Log.name', 'service');
            echo setting()->get('Log.location').$br;
            echo setting()->get('Log.date').$br;
            echo setting()->get('Log.name').$br;
            print_r (setting()->get('Log')).$br;
    

    Sample database

    -- Dumping structure for table ca70_assets.da_settings
    CREATE TABLE IF NOT EXISTS `da_settings` (
      `class` varchar(255) COLLATE armscii8_bin DEFAULT NULL,
      `key` varchar(255) COLLATE armscii8_bin DEFAULT NULL,
      `type` varchar(31) COLLATE armscii8_bin DEFAULT NULL,
      `context` varchar(255) COLLATE armscii8_bin DEFAULT NULL,
      `value` text COLLATE armscii8_bin DEFAULT NULL,
      `created_at` datetime NOT NULL,
      `updated_at` datetime NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=armscii8 COLLATE=armscii8_bin;
    
    -- Dumping data for table ca70_assets.da_settings: ~11 rows (approximately)
    INSERT INTO `da_settings` (`class`, `key`, `type`, `context`, `value`, `created_at`, `updated_at`) VALUES
    	('Config\\App', 'theme', 'string', 'user1', 'dark', '2023-01-02 16:10:06', '2023-01-02 16:14:10'),
    	('Config\\App', 'theme', 'string', 'user2', 'white', '2023-01-02 16:10:06', '2023-01-02 16:14:10'),
    	('Config\\App', 'theme', 'string', 'user3', 'red', '2023-01-02 16:10:06', '2023-01-02 16:14:10'),
    	('Log', 'location', 'string', NULL, 'site/log', '2023-01-02 16:13:08', '2023-01-02 16:14:10'),
    	('Log', 'date', 'string', NULL, '20220102', '2023-01-02 16:13:08', '2023-01-02 16:14:10'),
    	('Log', 'name', 'string', NULL, 'service', '2023-01-02 16:13:08', '2023-01-02 16:14:10');
    
    opened by bgougent 0
  • Feature: Bulk handling

    Feature: Bulk handling

    Performance-wise it would be a good idea to implement some bulk handling, so multiple settings can be retrieved with e.g. a single database call. For storage this might mean deferred writes, which shouldn't be too hard since we already use a local store.

    opened by MGatner 1
Releases(v2.1.0)
  • v2.1.0(Nov 22, 2021)

    New Features

    • A new bundled handler ArrayHandler makes for faster and easier testing as well as enabling memory storage for extended classes.
    • Now supports writing to any writeable handlers instead of just the first.

    Change Log

    • DatabaseHandler: Enforce Context Updates by @MGatner in https://github.com/codeigniter4/settings/pull/21
    • Array Handler by @MGatner in https://github.com/codeigniter4/settings/pull/23
    • Multiple Write Handlers by @MGatner in https://github.com/codeigniter4/settings/pull/22

    Full Changelog: https://github.com/codeigniter4/settings/compare/v2.0.0...v2.1.0

    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(Nov 16, 2021)

    This release switches the namespace from Sparks\Settings to CodeIgniter\Settings, and introduces $contexts that allow you to store more customized settings.

    What's Changed

    • Update Toolkit by @MGatner in https://github.com/codeigniter4/settings/pull/12
    • Apply coding standard by @MGatner in https://github.com/codeigniter4/settings/pull/13
    • Helper Nulls by @MGatner in https://github.com/codeigniter4/settings/pull/14
    • Config Injection by @MGatner in https://github.com/codeigniter4/settings/pull/15
    • Contexts by @MGatner in https://github.com/codeigniter4/settings/pull/16
    • Service Configuration by @MGatner in https://github.com/codeigniter4/settings/pull/17
    • Namespace by @MGatner in https://github.com/codeigniter4/settings/pull/18

    Full Changelog: https://github.com/codeigniter4/settings/compare/v1.0.0...v2.0.0

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Nov 9, 2021)

Owner
CodeIgniter 4 web framework
CodeIgniter 4 web framework
Parses YAML files and adds them to Slim's config application instance method.

Slim Config - YAML Parses YAML files and adds them into Slim's config singleton. Uses Symfony's YAML Component to parse files (http://github.com/symfo

Bill Rex 4 Mar 10, 2022
Domain Driven Design PHP helper classes

carlosbuenosvinos/ddd This library will help you with typical DDD scenarios, for now: Application Services Interface Transactional Application Service

Domain-Driven Design in PHP 642 Dec 28, 2022
PHPneeds library (classes) package.

PHPneeds is a lightweight non-MVC PHP library for quickly start a project. About PHPneeds library (classes) package. Please use with PHPneeds base pro

PHPneeds 2 Oct 21, 2021
PSR Log - This repository holds all interfaces/classes/traits related to PSR-3.

PSR Log This repository holds all interfaces/classes/traits related to PSR-3. Note that this is not a logger of its own. It is merely an interface tha

PHP-FIG 10.1k Jan 3, 2023
This repository contains custom View classes for the template frameworks

Slim Views This repository contains custom View classes for the template frameworks listed below. You can use any of these custom View classes by eith

Slim Framework 308 Nov 7, 2022
This package provides some basic methods to implement a self updating functionality for your Laravel application. Already bundled are some methods to provide a self-update mechanism via Github or some private repository via http.

This package provides some basic methods to implement a self updating functionality for your Laravel 5 application. Already bundled are some methods to provide a self-update mechanism via Github.

Holger Lösken 311 Dec 31, 2022
This package provides a high performance HTTP server to speed up your Laravel/Lumen application based on Swoole.

This package provides a high performance HTTP server to speed up your Laravel/Lumen application based on Swoole.

Swoole Taiwan 3.9k Jan 8, 2023
A easy way to install your basic yii projetc, we have encrypt database password in phpfile, my class with alot funtions to help you encrypt and decrypt and our swoole server install just run ./yii swoole/start and be happy!

Yii 2 Basic Project Template with swoole and Modules Yii 2 Basic Project Template is a skeleton Yii 2 application best for rapidly creating small proj

null 3 Apr 11, 2022
Provides TemplateView and TwoStepView using PHP as the templating language, with support for partials, sections, and helpers.

Aura View This package provides an implementation of the TemplateView and TwoStepView patterns using PHP itself as the templating language. It support

Aura for PHP 83 Jan 3, 2023
QPM, the process management framework in PHP, the efficient toolkit for CLI development. QPM provides basic daemon functions and supervision mechanisms to simplify multi-process app dev.

QPM QPM全名是 Quick(or Q's) Process Management Framework for PHP. PHP 是强大的web开发语言,以至于大家常常忘记PHP 可以用来开发健壮的命令行(CLI)程序以至于daemon程序。 而编写daemon程序免不了与各种进程管理打交道。Q

Comos 75 Dec 21, 2021
The package provides definition syntax. Definition is describing a way to create and configure a service or an object.

Yii Definitions The package ... Requirements PHP 7.4 or higher. Installation The package could be installed with composer: composer require yiisoft/de

Yii Software 6 Jul 15, 2022
🎲 This project provides an integration for the Doctrine ORM and the Hyperf framework

Hyperf ?? Doctrine This project provides an integration for the Doctrine ORM and the Hyperf framework. Install composer require leocavalcante/hyperf-d

Leo Cavalcante 49 Dec 3, 2022
Bootcamp project based on PHP-MVC using MySQL database.

Up-Stream This is the implementation of a full website based on PHP MVC. Using MySql database to create a website. And Bootstrap4 for front-end. Start

AmirH.Najafizadeh 4 Jul 31, 2022
REST APIs using Slim framework. Implemented all CRUD operations on the MySql database

PHP REST API using slim framework and CRUD operations ?? Hi there, this is a simple REST API built using the Slim framework. And this is for the folks

Hanoak 2 Jun 1, 2022
The Slim PHP micro framework paired with Laravel's Illuminate Database toolkit.

Slim & Eloquent The Slim PHP micro framework paired with Laravel's Illuminate Database toolkit. Getting started # Download composer curl -s https://ge

Kyle Ladd 111 Jul 23, 2022
This extension provides a view renderer for Pug templates for Yii framework 2.0 applications.

This extension provides a view renderer for Pug templates for Yii framework 2.0 applications.

Revin Roman 9 Jun 17, 2022
This extension provides Flysystem integration for the Yii framework

This extension provides Flysystem integration for the Yii framework. Flysystem is a filesystem abstraction which allows you to easily swap out a local filesystem for a remote one.

Alexander Kochetov 276 Dec 9, 2022
A simple class that provides access to country & state list.

GeoData A simple class that provides access to country & state list. Installation composer require ahmard/geodata Usage Fetch country list <?php use

Ahmad Mustapha 4 Jun 20, 2022