├── .gitignore ├── CHANGELOG.md ├── CONFIGURATION.md ├── LICENSE ├── README.md ├── composer.json ├── config └── _setting.php ├── database └── migrations │ ├── 2023_11_03_030451_create_settings_table.php │ └── 2023_12_08_042350_create_settings_mongodb_collection.php ├── src ├── Cache │ ├── Cache.php │ └── Drivers │ │ ├── File.php │ │ └── Redis.php ├── Concerns │ ├── DeleteCallbacksTrait.php │ ├── GetCallbacksTrait.php │ ├── ProcessTrait.php │ └── SetCallbacksTrait.php ├── Console │ ├── ClearCacheCommand.php │ ├── InstallCommand.php │ ├── PublishCommand.php │ └── PublishMongoDBCommand.php ├── Contracts │ ├── CacheDriverInterface.php │ ├── DatabaseDriverInterface.php │ └── StoreDriverInterface.php ├── Drivers │ ├── Database.php │ ├── Database │ │ ├── MongoDB.php │ │ └── Mysql.php │ └── File.php ├── Events │ ├── DeleteSettingEvent.php │ └── UpdateSettingEvent.php ├── Exceptions │ ├── DatabaseConnectionException.php │ ├── SettingKeyNotFoundException.php │ ├── SettingNotFoundException.php │ └── SettingNotSelectedException.php ├── Jobs │ ├── DeleteSettingJob.php │ └── UpdateSettingJob.php ├── LaravelSettingPro.php ├── Providers │ └── LaravelSettingProServiceProvider.php ├── Services │ └── SettingStore.php └── Support │ ├── Setting.php │ └── helpers.php └── tests └── setting └── test.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /vendor/ 3 | composer.lock -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [2.0.2] - 2024-04-23 9 | 10 | ### Added 11 | 12 | - No addition. 13 | 14 | ### Changed 15 | 16 | - Change composer dependencies and is now support on laravel 11. 17 | 18 | ### Fixed 19 | 20 | - No Fix. 21 | 22 | ## [2.0.1] - 2023-12-29 23 | 24 | ### Added 25 | 26 | - No addition. 27 | 28 | ### Changed 29 | 30 | - No Change. 31 | 32 | ### Fixed 33 | 34 | - Fixed issue when `set` with two params. setting('setting_name')->set('key','value') 35 | 36 | ## [2.0.0] - 2023-12-28 37 | 38 | ### Added 39 | 40 | - Add `mysql` driver for setting store. 41 | - Add `mongodb` driver for setting store. 42 | - Add `file` driver for cache setting. 43 | - Add `redis` driver for cache setting. 44 | - Add `setting:clear-cache` artisan command. 45 | - Add exception for database connection. 46 | 47 | ### Changed 48 | 49 | - Big update and remove all dependent classes in laravel before bootstrapping to use setting on anywhere files. 50 | 51 | ### Fixed 52 | 53 | - Fixed issue with Laravel bootstrapping. [Issue Link](https://github.com/laravel/framework/issues/49346) 54 | 55 | ## [1.0.1] - 2023-12-12 56 | 57 | ### Added 58 | 59 | - Added `has` method. 60 | - Added Concern files and clean `LaravelSettingPro` class 61 | 62 | ### Changed 63 | 64 | - Update & optimize and Refactor. 65 | - Rename test directory to tests. 66 | 67 | ### Fixed 68 | 69 | - No Fixed. 70 | 71 | ## [1.0.0] - 2023-12-09 72 | 73 | ### Added 74 | 75 | - Initial release. 76 | 77 | -------------------------------------------------------------------------------- /CONFIGURATION.md: -------------------------------------------------------------------------------- 1 | ## Laravel Setting Pro Configuration 2 | Explore and customize the Laravel Setting Pro package with the following configuration options tailored to your needs. 3 | 4 | Here is the configuration file for Laravel Setting Pro `_setting.php`: 5 | 6 | ```php 7 | return [ 8 | 'store' => [ 9 | //Default setting store driver 10 | 'default' => 'file', 11 | 12 | //If any requested setting is not found in the default driver, 13 | //this driver is used and if available, it is imported into 14 | //the default driver. you can set empty to disable this feature. 15 | 'import_from' => '', 16 | 17 | //Include drivers and configures for setting store 18 | 'drivers' => [ 19 | 'file' => [ 20 | 'path' => base_path('setting'), 21 | 'class' => \Sajadsdi\LaravelSettingPro\Drivers\File::class, 22 | ], 23 | 'database' => [ 24 | //Default database connection if default store is 'database' 25 | 'connection' => 'mysql', 26 | 'class' => \Sajadsdi\LaravelSettingPro\Drivers\Database::class, 27 | 'connections' => [ 28 | 'mysql' => [ 29 | 'class' => \Sajadsdi\LaravelSettingPro\Drivers\Database\Mysql::class, 30 | 'driver' => "mysql", 31 | 'host' => env('DB_HOST', '127.0.0.1'), 32 | 'port' => env('DB_PORT', '3306'), 33 | 'database' => env('DB_DATABASE', 'forge'), 34 | 'username' => env('DB_USERNAME', 'forge'), 35 | 'password' => env('DB_PASSWORD', ''), 36 | 'charset' => 'utf8mb4', 37 | 'prefix' => '', 38 | ], 39 | 'mongodb' => [ 40 | 'class' => \Sajadsdi\LaravelSettingPro\Drivers\Database\MongoDB::class, 41 | 'host' => env('MONGO_DB_HOST', '127.0.0.1'), 42 | 'port' => env('MONGO_DB_PORT', 27017), 43 | 'database' => env('MONGO_DB_DATABASE', 'forge'), 44 | 'username' => env('MONGO_DB_USERNAME', ''), 45 | 'password' => env('MONGO_DB_PASSWORD', ''), 46 | 'options' => [ 47 | 48 | ], 49 | ] 50 | ] 51 | ], 52 | ], 53 | ], 54 | 'cache' => [ 55 | //flag for enable or disable cache. 56 | 'enabled' => false, 57 | 58 | //Default setting cache driver 59 | 'default' => 'file', 60 | 'class' => \Sajadsdi\LaravelSettingPro\Cache\Cache::class, 61 | 62 | //Include drivers and configures for setting cache 63 | 'drivers' => [ 64 | 'file' => [ 65 | 'class' => \Sajadsdi\LaravelSettingPro\Cache\Drivers\File::class, 66 | 'path' => storage_path('framework/cache/settings'), 67 | ], 68 | 'redis' => [ 69 | 'class' => \Sajadsdi\LaravelSettingPro\Cache\Drivers\Redis::class, 70 | 'connection' => [ 71 | 'scheme' => 'tcp', 72 | 'host' => env('REDIS_HOST', '127.0.0.1'), 73 | 'username' => env('REDIS_USERNAME'), 74 | 'password' => env('REDIS_PASSWORD'), 75 | 'port' => env('REDIS_PORT', '6379'), 76 | 'database' => env('REDIS_CACHE_DB', '1'), 77 | ], 78 | 'options' => [ 79 | 'cluster' => env('REDIS_CLUSTER', 'redis'), 80 | 'prefix' => 'setting_caches_', 81 | ], 82 | ] 83 | ] 84 | ], 85 | 86 | //If true ,update and delete Settings handled on background. 87 | 'process_to_queue' => false, 88 | 'queue' => 'settings', 89 | 90 | //If true ,trigger events after update and delete settings. you can create listener for: 91 | //Sajadsdi\LaravelSettingPro\Events\UpdateSettingEvent 92 | //Sajadsdi\LaravelSettingPro\Events\DeleteSettingEvent 93 | 'trigger_events' => false 94 | ]; 95 | 96 | ``` 97 | 98 | 99 | Now, let's break down the purpose of each key in this configuration: 100 | 101 | 1. **`store` Section:** 102 | 103 | - **`default`**: Sets the default storage for settings. It is currently configured for `file`. 104 | - **`import_from`**: Defines the initial storage for loading settings (If any requested setting is not found in the default driver), currently is not set. 105 | - **`drivers`**: Configures different drivers for storing settings. 106 | 107 | - **`file`**: Configures file storage settings, including the file path (`path`) and the driver class. 108 | - **`database`**: Configures database storage settings, including the database `connection` for default, `class`, and `Connections` for configure each database . You can choose `mysql` or `mongodb` or any defined connection driver. 109 | - if you need use mongodb ,you must install `mongodb/mongodb` 110 | package and set connection config for mongodb, and run artisan command `php artisan setting:publish-mongodb` and `php artisan migrate` 111 | 112 | 2. **`cache` Section:** 113 | 114 | - **`enabled`**: Toggles caching for settings. Currently, caching is disabled. 115 | - **`default`**: Set the default cache driver. 116 | - **`class`**: Specifies the class related to settings caching. 117 | - **`drivers`**: Include drivers and configures for setting cache. You can add new cache driver if needed. 118 | 119 | - **`file`**: Configures file cache settings, including the directory path (path) and the driver class. 120 | - **`redis`**: Configures redis cache settings, including driver class and connection configs. 121 | - if you need use `redis` for cache driver, you must install `predis/predis` package and setup connection. 122 | 123 | 3. **`process_to_queue` Section:** 124 | 125 | - **`process_to_queue`**: Determines whether a queue should process settings update and delete. Currently, this feature is disabled.If users want to grant expensive update and delete operations, it's advised to use a separate queue name and single separate worker only for setting. 126 | 127 | 4. **`queue` Section:** 128 | 129 | - **`queue`**: Specifies the queue name for processing settings if `process_to_queue` is enabled. 130 | 131 | 5. **`trigger_events` Section:** 132 | 133 | - **`trigger_events`**: Indicates whether an update or delete events should be triggered when a setting is updated or deleted. Currently, this feature is disabled. 134 | 135 | This configuration provides flexibility and control over various aspects of Laravel Setting Pro, allowing you to tailor it to your specific requirements. 136 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SajaD SaeeDi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Laravel Setting Pro](https://sajadsdi.github.io/images/laravel-setting-pro.jpg) 2 | 3 | # Laravel Setting Pro 4 | 5 | Effortless Management of Laravel Application Settings. 6 | 7 | ## Description 8 | 9 | A Laravel package that provides a simple and effective way to handle application settings with support for persistent 10 | storage using both file-based and database drivers. 11 | 12 | ## Features 13 | 14 | The Laravel Setting Pro package simplifies application settings management in Laravel and provides these key features: 15 | 16 | - **Flexible Storage**: Choose between file-based or database storage to suit your application's needs. 17 | 18 | - **Flexible Database**: Choose between `mysql` or `mongodb` or create own db connection for settings. 19 | 20 | - **Caching**: Improve performance with automatic caching of settings. You can choose between `file` or `redis` or create own cache driver. 21 | 22 | - **Queue Support**: Handle setting updates and deletes in the background, ensuring smooth user experiences. 23 | 24 | - **Event Triggers**: Respond to setting changes in real-time by leveraging Laravel events. 25 | 26 | - **Global Helper Function & Facade**: Access and manipulate settings anywhere in your laravel app with a simple `setting` function or `Setting` facade (even in the config files). 27 | 28 | - **Artisan Commands for Ease of Use**: Publish configuration and migrations effortlessly with the `setting:publish` 29 | artisan command; complete installations, migrations, and initial tests using the `setting:install` command. 30 | 31 | - **Easy get & set and delete settings with dot notation**: `get` & `set` & `delete` and `has` operations on nested settings keys. 32 | 33 | - **Easy import settings** : Import settings from a driver to default store driver. 34 | 35 | - **Auto create setting** : you can use default value for get operation or set operation on any new setting name. 36 | 37 | This package is designed for developers looking for an efficient and intuitive way to handle application settings. It 38 | offers the necessary tools while keeping the process simple and maintainable. 39 | 40 | ## Requirements 41 | 42 | - PHP ^8.1 43 | - Laravel ^9.0|^10.0 44 | 45 | ## Installation 46 | 47 | Use Composer to install the package: 48 | 49 | ```bash 50 | composer require sajadsdi/laravel-setting-pro 51 | ``` 52 | 53 | ## Setup 54 | 55 | After the package installation, use the provided Artisan commands to publish configuration and migration files, and 56 | complete the installation process: 57 | 58 | First, publish the configuration and migration files using: 59 | 60 | ```bash 61 | php artisan setting:publish 62 | ```` 63 | 64 | This will publish `_setting.php` to your `config` folder and migration file. 65 | 66 | Then, use the installation command to perform migrations and any necessary setup operations: 67 | 68 | ```bash 69 | php artisan setting:install 70 | ``` 71 | 72 | These commands will set up your settings table in the database and ensure that the package is ready to use. 73 | 74 | ## Usage 75 | 76 | Two ways to use Laravel Setting Pro: 77 | 78 | 1. Using the `setting` function: 79 | 80 | ```php 81 | // Get a setting value 82 | $value = setting('my_setting')->get('key', 'default value'); 83 | //or 84 | $value = setting('my_setting','key', 'default value'); 85 | //or 86 | $value = setting()->select('my_setting')->get('key', 'default value'); 87 | 88 | 89 | // Set a setting value 90 | setting('my_setting')->set(['key' => 'value']); 91 | //or 92 | setting()->select('my_setting')->set(['key' => 'value']); 93 | 94 | 95 | //delete a key from setting 96 | setting('my_setting')->delete('key'); 97 | //or 98 | setting()->select('my_setting')->delete('key'); 99 | 100 | ``` 101 | 102 | 2. Using the `Setting` facade: 103 | 104 | ```php 105 | get('key', 'default value'); 110 | //or 111 | $value = Setting::my_setting()->get('key', 'default value'); 112 | //or 113 | $value = Setting::my_setting('key', 'default value'); 114 | 115 | // Set a setting value 116 | Setting::select('my_setting')->set('key', 'value'); 117 | //or 118 | Setting::my_setting()->set('key', 'value'); 119 | 120 | //delete key from setting 121 | Setting::select('my_setting')->delete('key'); 122 | //or 123 | Setting::my_setting()->delete('key'); 124 | 125 | //checking exists by has method 126 | if(Setting::select('my_setting')->has('key')){ 127 | echo "key exists!"; 128 | }else{ 129 | echo "key not exists!"; 130 | } 131 | 132 | ``` 133 | 134 | ## Advanced Usage 135 | you can use `set` and `get` operation in any way as stated above, with dot notation and multiple keys and defaults like this: 136 | 137 | ```php 138 | //get operation 139 | 140 | $value = Setting::my_setting(['users.3.profile.pic','users.3.profile.name'], ["default.png","No name"]); 141 | //or multi keys and single defaults 142 | $value = setting('my_setting')->get(['users.3.profile.pic','users.3.profile.name'], ["no data"]); 143 | 144 | 145 | //set operation 146 | setting::select('my_setting')->set(['users.3.profile.pic' => "profile.png",'users.3.profile.name' => "john"]) 147 | 148 | //delete multiple keys 149 | setting::select('my_setting')->delete(['users.3.profile.pic','users.3.profile.name']); 150 | 151 | //multiple keys checking exists by has method 152 | if(Setting::select('my_setting')->has(['users.3.profile.pic','users.3.profile.name'])){ 153 | echo "The keys are exists!"; 154 | }else{ 155 | echo "The keys do not exist!"; 156 | } 157 | 158 | 159 | // it's very Easy 160 | ``` 161 | This package use `Dot Notation Array` package to getting keys and setting operations you can see [Documentation](https://github.com/sajadsdi/array-dot-notation) to better use for Laravel Setting Pro 162 | 163 | ## Caching 164 | 165 | You can set config to enable setting cache, and you can choose cache driver for optimal performance. 166 | To clear the settings cache, use: 167 | 168 | ```bash 169 | php artisan setting:clear-cache 170 | ``` 171 | 172 | ## Configuration 173 | You can change `_setting` config on laravel config path. 174 | 175 | For more details about Configuration Laravel Setting Pro , [click here](CONFIGURATION.md) 176 | 177 | ### Contributing 178 | 179 | We welcome contributions from the community to improve and extend this library. If you'd like to contribute, please follow these steps: 180 | 181 | 1. Fork the repository on GitHub. 182 | 2. Clone your fork locally. 183 | 3. Create a new branch for your feature or bug fix. 184 | 4. Make your changes and commit them with clear, concise commit messages. 185 | 5. Push your changes to your fork on GitHub. 186 | 6. Submit a pull request to the main repository. 187 | 188 | ### Reporting Bugs and Security Issues 189 | 190 | If you discover any security vulnerabilities or bugs in this project, please let us know through the following channels: 191 | 192 | - **GitHub Issues**: You can [open an issue](https://github.com/sajadsdi/laravel-setting-pro/issues) on our GitHub repository to report bugs or security concerns. Please provide as much detail as possible, including steps to reproduce the issue. 193 | 194 | - **Contact**: For sensitive security-related issues, you can contact us directly through the following contact channels 195 | 196 | ### Contact 197 | 198 | If you have any questions, suggestions, financial, or if you'd like to contribute to this project, please feel free to contact the maintainer: 199 | 200 | - Email: thunder11like@gmail.com 201 | 202 | We appreciate your feedback, support, and any financial contributions that help us maintain and improve this project. 203 | 204 | ## License 205 | 206 | This package is open-sourced software licensed under the [MIT license](LICENSE). 207 | 208 | --- 209 | 210 | Made with ❤️ by [SajaD SaeeDi](mailto:thunder11like@gmail.com). 211 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sajadsdi/laravel-setting-pro", 3 | "description": "Easy settings management for laravel framework", 4 | "type": "laravel-package", 5 | "keywords": [ 6 | "laravel", 7 | "package", 8 | "settings", 9 | "configs" 10 | ], 11 | "license": "MIT", 12 | "autoload": { 13 | "files": [ 14 | "src/Support/helpers.php" 15 | ], 16 | "psr-4": { 17 | "Sajadsdi\\LaravelSettingPro\\": "src/" 18 | } 19 | }, 20 | "authors": [ 21 | { 22 | "name": "SajaD SaeeDi", 23 | "email": "thunder11like@gmail.com" 24 | } 25 | ], 26 | "require": { 27 | "php": "^8.1", 28 | "ext-pdo": "*", 29 | "illuminate/console": "^9.0|^10.0|^11.0", 30 | "illuminate/support": "^9.0|^10.0|^11.0", 31 | "sajadsdi/array-dot-notation": "^1.0" 32 | }, 33 | "extra": { 34 | "laravel": { 35 | "providers": [ 36 | "Sajadsdi\\LaravelSettingPro\\Providers\\LaravelSettingProServiceProvider" 37 | ] 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /config/_setting.php: -------------------------------------------------------------------------------- 1 | [ 5 | //Default setting store driver 6 | 'default' => 'file', 7 | 8 | //If any requested setting is not found in the default driver, 9 | //this driver is used and if available, it is imported into 10 | //the default driver. you can set empty to disable this feature. 11 | 'import_from' => '', 12 | 13 | //Include drivers and configures for setting store 14 | 'drivers' => [ 15 | 'file' => [ 16 | 'path' => base_path('setting'), 17 | 'class' => \Sajadsdi\LaravelSettingPro\Drivers\File::class, 18 | ], 19 | 'database' => [ 20 | //Default database connection if default store is 'database' 21 | 'connection' => 'mysql', 22 | 'class' => \Sajadsdi\LaravelSettingPro\Drivers\Database::class, 23 | 'connections' => [ 24 | 'mysql' => [ 25 | 'class' => \Sajadsdi\LaravelSettingPro\Drivers\Database\Mysql::class, 26 | 'driver' => "mysql", 27 | 'host' => env('DB_HOST', '127.0.0.1'), 28 | 'port' => env('DB_PORT', '3306'), 29 | 'database' => env('DB_DATABASE', 'forge'), 30 | 'username' => env('DB_USERNAME', 'forge'), 31 | 'password' => env('DB_PASSWORD', ''), 32 | 'charset' => 'utf8mb4', 33 | 'prefix' => '', 34 | ], 35 | 'mongodb' => [ 36 | 'class' => \Sajadsdi\LaravelSettingPro\Drivers\Database\MongoDB::class, 37 | 'host' => env('MONGO_DB_HOST', '127.0.0.1'), 38 | 'port' => env('MONGO_DB_PORT', 27017), 39 | 'database' => env('MONGO_DB_DATABASE', 'forge'), 40 | 'username' => env('MONGO_DB_USERNAME', ''), 41 | 'password' => env('MONGO_DB_PASSWORD', ''), 42 | 'options' => [ 43 | 44 | ], 45 | ] 46 | ] 47 | ], 48 | ], 49 | ], 50 | 'cache' => [ 51 | //flag for enable or disable cache. 52 | 'enabled' => false, 53 | 54 | //Default setting cache driver 55 | 'default' => 'file', 56 | 'class' => \Sajadsdi\LaravelSettingPro\Cache\Cache::class, 57 | 58 | //Include drivers and configures for setting cache 59 | 'drivers' => [ 60 | 'file' => [ 61 | 'class' => \Sajadsdi\LaravelSettingPro\Cache\Drivers\File::class, 62 | 'path' => storage_path('framework/cache/settings'), 63 | ], 64 | 'redis' => [ 65 | 'class' => \Sajadsdi\LaravelSettingPro\Cache\Drivers\Redis::class, 66 | 'connection' => [ 67 | 'scheme' => 'tcp', 68 | 'host' => env('REDIS_HOST', '127.0.0.1'), 69 | 'username' => env('REDIS_USERNAME'), 70 | 'password' => env('REDIS_PASSWORD'), 71 | 'port' => env('REDIS_PORT', '6379'), 72 | 'database' => env('REDIS_CACHE_DB', '1'), 73 | ], 74 | 'options' => [ 75 | 'cluster' => env('REDIS_CLUSTER', 'redis'), 76 | 'prefix' => 'setting_caches_', 77 | ], 78 | ] 79 | ] 80 | ], 81 | 82 | //If true ,update and delete Settings handled on background. 83 | 'process_to_queue' => false, 84 | 'queue' => 'settings', 85 | 86 | //If true ,trigger events after update and delete settings. you can create listener for: 87 | //Sajadsdi\LaravelSettingPro\Events\UpdateSettingEvent 88 | //Sajadsdi\LaravelSettingPro\Events\DeleteSettingEvent 89 | 'trigger_events' => false 90 | ]; 91 | -------------------------------------------------------------------------------- /database/migrations/2023_11_03_030451_create_settings_table.php: -------------------------------------------------------------------------------- 1 | create('settings', function (Blueprint $table) { 15 | $table->string('setting')->primary(); 16 | $table->longText('data'); 17 | $table->timestamps(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | */ 24 | public function down(): void 25 | { 26 | Schema::connection('mysql')->dropIfExists('settings'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /database/migrations/2023_12_08_042350_create_settings_mongodb_collection.php: -------------------------------------------------------------------------------- 1 | create('settings',function ($collection){ 15 | $collection->unique('setting'); 16 | }); 17 | } 18 | 19 | /** 20 | * Reverse the migrations. 21 | */ 22 | public function down(): void 23 | { 24 | Schema::connection('mongodb')->dropIfExists('settings'); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/Cache/Cache.php: -------------------------------------------------------------------------------- 1 | driver = new $config['drivers'][$config['default']]['class']($config['drivers'][$config['default']]); 17 | } 18 | 19 | /** 20 | * Get cache from driver with key. 21 | * @param $key 22 | * @return mixed 23 | */ 24 | public function get($key): mixed 25 | { 26 | return $this->driver->get($key); 27 | } 28 | 29 | /** 30 | * Set cache on driver with key and data. 31 | * @param string $key 32 | * @param mixed $data 33 | * @return void 34 | */ 35 | public function set(string $key, mixed $data): void 36 | { 37 | $this->driver->set($key, $data); 38 | } 39 | 40 | /** 41 | * Clear cache from driver with key. 42 | * @param $key 43 | * @return void 44 | */ 45 | public function clear($key): void 46 | { 47 | $this->driver->clear($key); 48 | } 49 | 50 | /** 51 | * Clear all caches from driver. 52 | * @return void 53 | */ 54 | public function clearAll(): void 55 | { 56 | $this->driver->clearAll(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Cache/Drivers/File.php: -------------------------------------------------------------------------------- 1 | path = realpath($config['path']); 17 | 18 | if(!is_dir($this->path)){ 19 | mkdir($this->path,0777,true); 20 | } 21 | } 22 | 23 | /** 24 | * Get cache file with key. 25 | * @param string $key 26 | * @return mixed 27 | */ 28 | public function get(string $key): mixed 29 | { 30 | if (file_exists($file = $this->getFile($key))) { 31 | return unserialize(file_get_contents($file)); 32 | } 33 | 34 | return null; 35 | } 36 | 37 | /** 38 | * Set cache file with key and data. 39 | * @param string $key 40 | * @param mixed $data 41 | * @return void 42 | */ 43 | public function set(string $key, mixed $data): void 44 | { 45 | file_put_contents($this->getFile($key), serialize($data)); 46 | } 47 | 48 | /** 49 | * Delete a cache file with key. 50 | * @param $key 51 | * @return void 52 | */ 53 | public function clear($key): void 54 | { 55 | if (file_exists($file = $this->getFile($key))) { 56 | unlink($file); 57 | } 58 | } 59 | 60 | /** 61 | * Get cache file path. 62 | * @param string $key 63 | * @return string 64 | */ 65 | private function getFile(string $key): string 66 | { 67 | return $this->path . DIRECTORY_SEPARATOR . md5($key); 68 | } 69 | 70 | /** 71 | * Delete setting cache directory and create again. 72 | * @return void 73 | */ 74 | public function clearAll(): void 75 | { 76 | $files = scandir($this->path); 77 | 78 | foreach ($files as $file) { 79 | if($file != '.' && $file != '..') { 80 | unlink($this->path . DIRECTORY_SEPARATOR . $file); 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Cache/Drivers/Redis.php: -------------------------------------------------------------------------------- 1 | client = new RedisClient($config['connection'],$config['options']); 18 | } 19 | 20 | /** 21 | * Get cache from redis database with key. 22 | * @param string $key 23 | * @return mixed 24 | */ 25 | public function get(string $key): mixed 26 | { 27 | $value = $this->client->get($key); 28 | 29 | return $value ? unserialize($value) : null; 30 | } 31 | 32 | /** 33 | * Set Cache on redis database with key and data. 34 | * @param string $key 35 | * @param mixed $data 36 | * @return void 37 | */ 38 | public function set(string $key, mixed $data): void 39 | { 40 | $this->client->set($key, serialize($data)); 41 | } 42 | 43 | /** 44 | * Delete a cache with key. 45 | * @param string $key 46 | * @return void 47 | */ 48 | public function clear(string $key): void 49 | { 50 | $this->client->del([$key]); 51 | } 52 | 53 | /** 54 | * Delete all keys from selected redis database. 55 | * @return void 56 | */ 57 | public function clearAll(): void 58 | { 59 | $this->client->flushdb(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Concerns/DeleteCallbacksTrait.php: -------------------------------------------------------------------------------- 1 | addToDelete($setting, [$key]); 19 | 20 | unset($class->sets[$setting][$key]); 21 | 22 | if (isset($class->sets[$setting]) && !$class->sets[$setting]) { 23 | $this->removeFromSet($setting); 24 | } 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Concerns/GetCallbacksTrait.php: -------------------------------------------------------------------------------- 1 | set($setting, [$key => $default]); 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Concerns/ProcessTrait.php: -------------------------------------------------------------------------------- 1 | sets[$setting] = array_merge($this->sets[$setting] ?? [], $keyValue); 24 | } 25 | 26 | /** 27 | * remove pairs to the set of changes to be saved. 28 | * 29 | * @param string $settingName 30 | * @return void 31 | */ 32 | private function removeFromSet(string $settingName): void 33 | { 34 | unset($this->sets[$settingName]); 35 | } 36 | 37 | /** 38 | * Add keys pairs to the delete operations. 39 | * 40 | * @param string $setting Name of the setting to add the key pairs to. 41 | * @param array $keys Keys pairs to add to the deletes. 42 | * @return void 43 | */ 44 | private function addToDelete(string $setting, array $keys): void 45 | { 46 | $this->deletes[$setting] = array_merge($this->deletes[$setting] ?? [], $keys); 47 | } 48 | 49 | /** 50 | * Destructor for LaravelSettingPro class. Save changes to settings. 51 | * 52 | * @return void 53 | */ 54 | public function __destruct() 55 | { 56 | $this->deleteProcess(); 57 | $this->settingProcess(); 58 | } 59 | 60 | /** 61 | * Process changes to settings and save them. 62 | * 63 | * @return void 64 | */ 65 | private function settingProcess(): void 66 | { 67 | foreach ($this->sets as $setting => $keyValue) { 68 | $updateParams = [ 69 | $setting, 70 | $keyValue, 71 | $this->config['cache']['enabled'], 72 | $this->config['trigger_events'], 73 | $this->config['queue'], 74 | ]; 75 | 76 | if ($this->config['process_to_queue']) { 77 | UpdateSettingJob::dispatch(...$updateParams); 78 | } else { 79 | UpdateSettingJob::dispatchSync(...$updateParams); 80 | } 81 | } 82 | } 83 | 84 | /** 85 | * Process delete on settings and save them. 86 | * 87 | * @return void 88 | */ 89 | private function deleteProcess(): void 90 | { 91 | foreach ($this->deletes as $setting => $keys) { 92 | $deleteParams = [ 93 | $setting, 94 | $keys, 95 | $this->config['cache']['enabled'], 96 | $this->config['trigger_events'], 97 | $this->config['queue'], 98 | ]; 99 | 100 | if ($this->config['process_to_queue']) { 101 | DeleteSettingJob::dispatch(...$deleteParams); 102 | } else { 103 | DeleteSettingJob::dispatchSync(...$deleteParams); 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Concerns/SetCallbacksTrait.php: -------------------------------------------------------------------------------- 1 | addToSet($setting, [$key => $value]); 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Console/ClearCacheCommand.php: -------------------------------------------------------------------------------- 1 | info('Clearing Setting Caches ...'); 33 | if(config('_setting.cache.enabled')) { 34 | $store->cache()->clearAll(); 35 | $this->info('Caches Cleared !'); 36 | }else{ 37 | $this->info('Setting cache not enabled. Clear skipped !'); 38 | } 39 | return null; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/Console/InstallCommand.php: -------------------------------------------------------------------------------- 1 | info('Installing Laravel Setting Pro ...'); 32 | $this->installMigrations(); 33 | $config = config('_setting'); 34 | $this->installSettingDirectory($config); 35 | $this->info('Installation completed !'); 36 | $this->installTestSetting($config); 37 | $this->testSetting(); 38 | return null; 39 | } 40 | 41 | private function installSettingDirectory($config) 42 | { 43 | $this->comment('Creating setting directory ...'); 44 | 45 | if (is_dir($config['store']['drivers']['file']['path'])) { 46 | $this->warn('setting directory is exists ............ SKIPPED'); 47 | } else { 48 | mkdir($config['store']['drivers']['file']['path'], 0775); 49 | $this->info($config['store']['drivers']['file']['path'] . ' directory created ...... DONE'); 50 | } 51 | } 52 | 53 | private function installTestSetting($config) 54 | { 55 | $this->comment('Creating test setting ...'); 56 | if (file_exists($config['store']['drivers']['file']['path'] . DIRECTORY_SEPARATOR . 'test.php')) { 57 | $this->warn('test.php is exists in setting directory ............ SKIPPED'); 58 | } else { 59 | file_put_contents($config['store']['drivers']['file']['path'] . DIRECTORY_SEPARATOR . 'test.php', 60 | file_get_contents(__DIR__ . "/../../tests/setting/test.php") 61 | ); 62 | $this->info($config['store']['drivers']['file']['path'] . DIRECTORY_SEPARATOR . 'test.php created ....... DONE'); 63 | } 64 | } 65 | 66 | private function installMigrations() 67 | { 68 | $this->comment('Migrating ...'); 69 | $this->call('migrate', ['--path' => "database/migrations/2023_11_03_030451_create_settings_table.php"]); 70 | } 71 | 72 | private function testSetting() 73 | { 74 | $this->comment("testing ..."); 75 | 76 | $this->alert(setting('test', 'welcome') . " Ver:" . setting('test', 'version')); 77 | 78 | $this->comment("nested key testing for 'users.5.profile.address' from test setting ..."); 79 | 80 | $this->alert('address is: ' . setting('test', 'users.5.profile.address')); 81 | 82 | $this->comment("removing 'users.5.profile.address' key from test setting ..."); 83 | 84 | setting('test')->delete('users.5.profile.address'); 85 | 86 | $has = setting('test')->has('users.5.profile.address'); 87 | 88 | $this->comment("testing has for deleted key (users.5.profile.address) ..."); 89 | 90 | $this->alert($has ? "not deleted !" : "deleted successfully !"); 91 | 92 | $this->comment("set deleted key again. setting 'test value set!' value on 'users.5.profile.address' key ..."); 93 | 94 | setting('test')->set(['users.5.profile.address' => 'test value set!']); 95 | 96 | $this->alert('new address is: ' . setting('test', 'users.5.profile.address')); 97 | 98 | $this->comment("testing finished !"); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/Console/PublishCommand.php: -------------------------------------------------------------------------------- 1 | info('Publishing Laravel Setting Pro ...'); 32 | $this->publish(); 33 | return null; 34 | } 35 | 36 | private function publish() 37 | { 38 | $this->comment('Publishing configure ...'); 39 | $this->call('vendor:publish', ['--tag' => "laravel-setting-pro-configure"]); 40 | 41 | $this->comment('Publishing migration ...'); 42 | $this->call('vendor:publish', ['--tag' => "laravel-setting-pro-migration"]); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Console/PublishMongoDBCommand.php: -------------------------------------------------------------------------------- 1 | info('Publishing Laravel Setting Pro ...'); 32 | $this->publish(); 33 | return null; 34 | } 35 | 36 | private function publish() 37 | { 38 | $this->comment('Publishing migration for mongoDB...'); 39 | $this->call('vendor:publish', ['--tag' => "laravel-setting-pro--mongodb-migration"]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Contracts/CacheDriverInterface.php: -------------------------------------------------------------------------------- 1 | driver = new $config['connections'][$config['connection']]['class']($config['connections'][$config['connection']]); 18 | } 19 | 20 | /** 21 | * Get database setting with key. 22 | * @param string $key 23 | * @return mixed 24 | */ 25 | public function get(string $key): mixed 26 | { 27 | return $this->driver->getSetting($key); 28 | } 29 | 30 | /** 31 | * Update database setting with key and data. 32 | * @param string $key 33 | * @param mixed $data 34 | * @return void 35 | */ 36 | public function set(string $key, mixed $data): void 37 | { 38 | $this->driver->setSetting($key, $data); 39 | } 40 | 41 | /** 42 | * Delete setting row with key. 43 | * @param string $key 44 | * @return void 45 | */ 46 | public function delete(string $key): void 47 | { 48 | $this->driver->deleteSetting($key); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Drivers/Database/MongoDB.php: -------------------------------------------------------------------------------- 1 | get($key); 25 | 26 | return $setting ? $setting['data'] : null; 27 | } 28 | 29 | /** 30 | * Update the value of a setting based on the provided key. 31 | * 32 | * @param string $key The key of the setting. 33 | * @param mixed $data The value to be set for the setting. 34 | * @return void 35 | */ 36 | public function setSetting(string $key, mixed $data): void 37 | { 38 | $setting = $this->get($key); 39 | 40 | if ($setting) { 41 | $this->set($key, $data); 42 | } else { 43 | $this->insert($key, $data); 44 | } 45 | } 46 | 47 | /** 48 | * Delete a setting document with key. 49 | * @param string $key 50 | * @return void 51 | */ 52 | public function deleteSetting(string $key): void 53 | { 54 | $this->connection->deleteOne(['setting' => $key]); 55 | } 56 | 57 | /** 58 | * @throws DatabaseConnectionException 59 | */ 60 | public function __construct(array $config) 61 | { 62 | $this->setConnection($config); 63 | } 64 | 65 | /** 66 | * Create connection to MongoDB database. 67 | * @param $config 68 | * @return void 69 | * @throws DatabaseConnectionException 70 | */ 71 | private function setConnection($config): void 72 | { 73 | try { 74 | $uri = "mongodb://{$config['host']}:{$config['port']}"; 75 | 76 | if ($config['username'] && $config['password']) { 77 | $uri = "mongodb://{$config['username']}:{$config['password']}@{$config['host']}:{$config['port']}/{$config['database']}"; 78 | } 79 | 80 | $client = new Client($uri, $config['options']); 81 | 82 | // The selectDatabase method is lazy and won't immediately cause a connection 83 | $database = $client->selectDatabase($config['database']); 84 | $collection = $database->selectCollection($this->collection); 85 | 86 | // The following line triggers an actual connection and will throw a ConnectionException if it fails 87 | $database->listCollections(); 88 | 89 | $this->connection = $collection; 90 | 91 | } catch (\Exception $e) { 92 | throw new DatabaseConnectionException('MongoDB', $e->getMessage()); 93 | } 94 | } 95 | 96 | /** 97 | * get setting document with key. 98 | * @param string $key 99 | * @return array|object|null 100 | */ 101 | private function get(string $key): array|null|object 102 | { 103 | return $this->connection->findOne(['setting', $key]); 104 | } 105 | 106 | /** 107 | * Update a setting document with key and data. 108 | * @param string $key 109 | * @param mixed $data 110 | * @return void 111 | */ 112 | private function set(string $key, mixed $data): void 113 | { 114 | $date = new UTCDateTime((new \DateTime())->getTimestamp() * 1000); 115 | 116 | $document = ['data' => $data, 'updated_at' => $date]; 117 | 118 | $this->connection->updateOne( 119 | ['setting' => $key], 120 | ['$set' => $document], 121 | ['upsert' => true] 122 | ); 123 | } 124 | 125 | /** 126 | * Insert a document with key and data. 127 | * @param string $key 128 | * @param mixed $data 129 | * @return void 130 | */ 131 | private function insert(string $key, mixed $data): void 132 | { 133 | $date = new UTCDateTime((new \DateTime())->getTimestamp() * 1000); 134 | 135 | $document = [ 136 | 'setting' => $key, 137 | 'data' => $data, 138 | 'created_at' => $date, 139 | 'updated_at' => $date 140 | ]; 141 | 142 | $this->connection->insertOne($document); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/Drivers/Database/Mysql.php: -------------------------------------------------------------------------------- 1 | get($key); 25 | 26 | return $setting ? json_decode($setting['data'], true) : null; 27 | } 28 | 29 | /** 30 | * Sets the value of a setting based on the provided key. 31 | * 32 | * @param string $key The key of the setting. 33 | * @param mixed $data The value to be set for the setting. 34 | * @return void 35 | */ 36 | public function setSetting(string $key, mixed $data): void 37 | { 38 | $setting = $this->get($key); 39 | 40 | if ($setting) { 41 | $this->set($key, $data); 42 | } else { 43 | $this->insert($key, $data); 44 | } 45 | } 46 | 47 | /** 48 | * Delete a setting row with key. 49 | * @param string $key 50 | * @return void 51 | */ 52 | public function deleteSetting(string $key): void 53 | { 54 | $query = $this->connection->prepare("DELETE FROM {$this->table()} WHERE setting = ?"); 55 | 56 | $query->execute([$key]); 57 | } 58 | 59 | /** 60 | * @throws DatabaseConnectionException 61 | */ 62 | public function __construct(array $config) 63 | { 64 | $this->prefix = $config['prefix']; 65 | $this->setConnection($config); 66 | } 67 | 68 | /** 69 | * This method return a full name of setting table. 70 | * @return string 71 | */ 72 | private function table(): string 73 | { 74 | return $this->prefix ? $this->prefix . '_' . $this->table : $this->table; 75 | } 76 | 77 | /** 78 | * Create a PDO connection. 79 | * @param $config 80 | * @return void 81 | * @throws DatabaseConnectionException 82 | */ 83 | private function setConnection($config): void 84 | { 85 | try { 86 | $dsn = $config['driver'] . ":host=" . $config['host'] . ";port=" . $config['port'] . ";dbname=" . $config['database'] . ";charset=".$config['charset']; 87 | 88 | $this->connection = new PDO($dsn, $config['username'], $config['password']); 89 | 90 | $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 91 | 92 | } catch (PDOException $e) { 93 | throw new DatabaseConnectionException('MySQL', $e->getMessage()); 94 | } 95 | } 96 | 97 | /** 98 | * Get query to retrieve a setting row with key. 99 | * @param string $key 100 | * @return mixed 101 | */ 102 | private function get(string $key): mixed 103 | { 104 | $query = $this->connection->prepare("SELECT * FROM {$this->table()} WHERE setting = ?"); 105 | $query->execute([$key]); 106 | 107 | return $query->fetch(PDO::FETCH_ASSOC); 108 | } 109 | 110 | /** 111 | * Update query for set a setting with key and data. 112 | * @param string $key 113 | * @param mixed $data 114 | * @return void 115 | */ 116 | private function set(string $key, mixed $data): void 117 | { 118 | $query = $this->connection->prepare("UPDATE {$this->table()} SET updated_at = ? , data = ? WHERE setting = ?"); 119 | 120 | $query->execute([date('Y-m-d H:i:s'), json_encode($data, JSON_NUMERIC_CHECK | JSON_PRESERVE_ZERO_FRACTION | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), $key]); 121 | } 122 | 123 | /** 124 | * Insert a row in setting table with key and data. 125 | * @param string $key 126 | * @param mixed $data 127 | * @return void 128 | */ 129 | private function insert(string $key, mixed $data): void 130 | { 131 | $query = $this->connection->prepare("INSERT INTO {$this->table()} (setting,data,created_at,updated_at) VALUES (?,?,?,?)"); 132 | 133 | $date = date('Y-m-d H:i:s'); 134 | 135 | $query->execute([$key, json_encode($data, JSON_NUMERIC_CHECK | JSON_PRESERVE_ZERO_FRACTION | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), $date, $date]); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/Drivers/File.php: -------------------------------------------------------------------------------- 1 | config = $config; 18 | $this->config['path'] = realpath(str_replace(['/', '\\'], self::DS, $this->config['path'])); 19 | } 20 | 21 | /** 22 | * Get setting file with key name. 23 | * @param string $key 24 | * @return mixed 25 | */ 26 | public function get(string $key): mixed 27 | { 28 | $data = null; 29 | $file = $this->config['path'] . self::DS . $key . '.php'; 30 | if (file_exists($file)) { 31 | $data = require $file; 32 | } 33 | return $data; 34 | } 35 | 36 | /** 37 | * Update setting file with key name and data. 38 | * @param string $key 39 | * @param mixed $data 40 | * @return void 41 | */ 42 | public function set(string $key, mixed $data): void 43 | { 44 | file_put_contents($this->config['path'] . self::DS . $key . '.php', str_replace([": ", " {", " }", "\n}"], [" => ", " [", " ]", "\n]"], "config['path'] . self::DS . $key . '.php'; 55 | if (file_exists($file)) { 56 | unlink($file); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Events/DeleteSettingEvent.php: -------------------------------------------------------------------------------- 1 | key}' key" . ($this->keysPath ? " in '{$this->keysPath}*' path" : "") . " from '{$this->settingName}' setting ."); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Exceptions/SettingNotFoundException.php: -------------------------------------------------------------------------------- 1 | onQueue($queue); 25 | } 26 | 27 | /** 28 | * Execute the job. 29 | * @throws ArrayKeyNotFoundException 30 | */ 31 | public function handle(SettingStore $store): void 32 | { 33 | $oldData = $store->getSetting($this->settingName) ?? []; 34 | $data = $oldData; 35 | 36 | if (!$this->keys) { 37 | $store->delete($this->settingName); 38 | } else { 39 | $store->set($this->settingName, $this->deleteByDotMulti($data, $this->keys)); 40 | } 41 | 42 | if ($this->cacheEnabled) { 43 | $store->cache()->clear($this->settingName); 44 | } 45 | 46 | if ($this->triggerEvent) { 47 | DeleteSettingEvent::dispatch($this->settingName, $this->keys, $oldData); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Jobs/UpdateSettingJob.php: -------------------------------------------------------------------------------- 1 | onQueue($queue); 24 | } 25 | 26 | /** 27 | * Execute the job. 28 | */ 29 | public function handle(SettingStore $store): void 30 | { 31 | $oldData = $store->getSetting($this->settingName) ?? []; 32 | $data = $oldData; 33 | 34 | $store->set($this->settingName, $this->setByDotMulti($data, $this->keyValue)); 35 | 36 | if ($this->cacheEnabled) { 37 | $store->cache()->clear($this->settingName); 38 | } 39 | 40 | if ($this->triggerEvent) { 41 | UpdateSettingEvent::dispatch($this->settingName, $this->keyValue, $oldData); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/LaravelSettingPro.php: -------------------------------------------------------------------------------- 1 | config = $config; 38 | $this->store = $store; 39 | } 40 | 41 | /** 42 | * Get the value of a setting using array dot notation. 43 | * 44 | * @param string $settingName Name of the setting to get. 45 | * @param mixed $Keys Keys to access nested values in the setting. 46 | * @param mixed|null $default Default value to return if the setting or key is not found. 47 | * @param bool $throw flag to disable 'NotFound' exceptions 48 | * @return mixed Value of the setting. 49 | * 50 | * @throws SettingKeyNotFoundException If the specified key is not found in the setting. 51 | * @throws SettingNotFoundException If the specified setting is not found. 52 | * @throws SettingNotSelectedException If no setting is selected. 53 | */ 54 | public function get(string $settingName, mixed $Keys = [], mixed $default = null, bool $throw = true): mixed 55 | { 56 | $this->load($settingName, 'get'); 57 | 58 | try { 59 | 60 | return $this->getByDotMulti( 61 | $this->getSetting($settingName), 62 | $this->getArrayKeys($Keys), $default, 63 | $this->getCallbackDefaultValueOperation($settingName) 64 | ); 65 | 66 | } catch (ArrayKeyNotFoundException $exception) { 67 | 68 | if ($throw) { 69 | if ($this->settings[$settingName]) { 70 | throw new SettingKeyNotFoundException($exception->key, $exception->keysPath, $settingName); 71 | } else { 72 | throw new SettingNotFoundException($settingName); 73 | } 74 | } 75 | 76 | } 77 | 78 | return null; 79 | } 80 | 81 | /** 82 | * Set the value of a setting using array dot notation. 83 | * 84 | * @param string $settingName Name of the setting to set. 85 | * @param array $keyValue Associative array of keys and values to set in the setting. 86 | * @return void 87 | * 88 | * @throws SettingNotSelectedException If no setting is selected. 89 | */ 90 | public function set(string $settingName, array $keyValue): void 91 | { 92 | $this->load($settingName, 'set'); 93 | 94 | $this->setByDotMulti($this->settings[$settingName], $keyValue, $this->getCallbackSetOperation($settingName)); 95 | } 96 | 97 | /** 98 | * Delete the keys of a setting using array dot notation. 99 | * 100 | * @param string $settingName Name of the setting to delete. 101 | * @param array|string|int $keys keys to delete in the setting. 102 | * @return void 103 | * 104 | * @throws ArrayKeyNotFoundException 105 | * @throws SettingNotSelectedException If no setting is selected. 106 | */ 107 | public function delete(string $settingName, mixed $keys = []): void 108 | { 109 | $this->load($settingName, 'delete'); 110 | 111 | $aKeys = $this->getArrayKeys($keys); 112 | 113 | if (!$aKeys) { 114 | $this->setSetting($settingName, []); 115 | $this->addToDelete($settingName, $aKeys); 116 | $this->removeFromSet($settingName); 117 | } else { 118 | $this->deleteByDotMulti($this->settings[$settingName], $aKeys, false, $this->getCallbackDeleteOperation($settingName)); 119 | } 120 | } 121 | 122 | /** 123 | * Has key(S) on selected setting. 124 | * 125 | * @param string $settingName Name of the setting. 126 | * @param mixed $keys to check has exists on setting. 127 | * @return bool 128 | * 129 | * @throws SettingNotSelectedException 130 | */ 131 | public function has(string $settingName, mixed $keys = []): bool 132 | { 133 | $this->load($settingName, 'has'); 134 | 135 | return $this->issetAll($this->getSetting($settingName), $this->getArrayKeys($keys)); 136 | } 137 | 138 | /** 139 | * Load a setting and validate that it exists. 140 | * 141 | * @param string $setting Name of the setting to load. 142 | * @param string $operation Name of the operation being performed (get or set or delete). 143 | * @return void 144 | * 145 | * @throws SettingNotSelectedException If no setting is selected. 146 | */ 147 | private function load(string $setting, string $operation): void 148 | { 149 | if (!$setting) { 150 | throw new SettingNotSelectedException($operation); 151 | } 152 | 153 | if ($this->isSetSetting($setting)) { 154 | $this->setSetting($setting, $this->store->get($setting) ?? []); 155 | } 156 | } 157 | 158 | /** 159 | * Set the value of a setting. 160 | * 161 | * @param string $name Name of the setting to set. 162 | * @param mixed $data Value to set in the setting. 163 | * @return void 164 | */ 165 | private function setSetting(string $name, mixed $data): void 166 | { 167 | $this->settings[$name] = $data; 168 | } 169 | 170 | /** 171 | * Get the value of a setting. 172 | * 173 | * @param string $name Name of the setting to get. 174 | * @return mixed Value of the setting. 175 | */ 176 | private function getSetting(string $name): mixed 177 | { 178 | return $this->settings[$name] ?? $this->settings[$name] = []; 179 | } 180 | 181 | /** 182 | * check Setting name is seated. 183 | * @param string $setting 184 | * @return bool 185 | */ 186 | private function isSetSetting(string $setting): bool 187 | { 188 | return !isset($this->settings[$setting]); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/Providers/LaravelSettingProServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton(SettingStore::class,function () { 17 | return new SettingStore(config('_setting')); 18 | }); 19 | 20 | //singleton pattern implemented in setting class for work in any laravel files before bootstrap! 21 | 22 | //$this->app->singleton(LaravelSettingPro::class); 23 | 24 | //$this->app->singleton(Setting::class); 25 | } 26 | 27 | public function boot(): void 28 | { 29 | if ($this->app->runningInConsole()) { 30 | $this->configurePublishing(); 31 | $this->migrationPublishing(); 32 | $this->registerCommands(); 33 | } 34 | } 35 | 36 | private function configurePublishing() 37 | { 38 | $this->publishes([__DIR__ . '/../../config/_setting.php' => config_path('_setting.php')], 'laravel-setting-pro-configure'); 39 | } 40 | 41 | private function migrationPublishing() 42 | { 43 | $this->publishes([__DIR__ . '/../../database/migrations/2023_11_03_030451_create_settings_table.php' => database_path('migrations/2023_11_03_030451_create_settings_table.php')], 'laravel-setting-pro-migration'); 44 | $this->publishes([__DIR__ . '/../../database/migrations/2023_12_08_042350_create_settings_mongodb_collection.php' => database_path('migrations/2023_12_08_042350_create_settings_mongodb_collection.php')], 'laravel-setting-pro--mongodb-migration'); 45 | } 46 | 47 | private function registerCommands() 48 | { 49 | $this->commands([ 50 | PublishCommand::class, 51 | InstallCommand::class, 52 | PublishMongoDBCommand::class, 53 | ClearCacheCommand::class 54 | ]); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/Services/SettingStore.php: -------------------------------------------------------------------------------- 1 | config = $config; 20 | 21 | if ($this->cacheEnabled()) { 22 | $this->setCache(new $this->config['cache']['class']($this->config['cache'])); 23 | } 24 | } 25 | 26 | /** 27 | * Get the value of a setting. 28 | * 29 | * @param string $name 30 | * @return mixed 31 | */ 32 | public function get(string $name): mixed 33 | { 34 | $data = null; 35 | if ($this->cacheEnabled()) { 36 | $data = $this->cache->get($name); 37 | } 38 | if ($data === null) { 39 | $data = $this->getSetting($name); 40 | if ($this->cacheEnabled() && $data !== null) { 41 | $this->cache->set($name, $data); 42 | } 43 | } 44 | return $data; 45 | } 46 | 47 | /** 48 | * Get the value of a setting from the appropriate driver. 49 | * 50 | * @param string $name 51 | * @return mixed 52 | */ 53 | public function getSetting(string $name): mixed 54 | { 55 | $data = $this->getDriver($this->config['store']['default'])->get($name); 56 | 57 | if ($data === null) { 58 | if ($this->config['store']['import_from']) { 59 | $data = $this->getDriver($this->config['store']['import_from'])->get($name); 60 | if ($data) { 61 | $this->getDriver($this->config['store']['default'])->set($name, $data); 62 | } 63 | } 64 | } 65 | return $data; 66 | } 67 | 68 | /** 69 | * Set the value of a setting. 70 | * 71 | * @param string $name 72 | * @param mixed $data 73 | * @return void 74 | */ 75 | public function set(string $name, mixed $data): void 76 | { 77 | $this->getDriver($this->config['store']['default'])->set($name, $data); 78 | } 79 | 80 | /** 81 | * delete a setting. 82 | * 83 | * @param string $name 84 | * @return void 85 | */ 86 | public function delete(string $name): void 87 | { 88 | $this->getDriver($this->config['store']['default'])->delete($name); 89 | } 90 | 91 | /** 92 | * Check if caching is enabled. 93 | * 94 | * @return bool 95 | */ 96 | private function cacheEnabled(): bool 97 | { 98 | return $this->config['cache']['enabled']; 99 | } 100 | 101 | /** 102 | * Get the driver instance for the given name. 103 | * 104 | * @param string $name 105 | * @return StoreDriverInterface 106 | */ 107 | private function getDriver(string $name): StoreDriverInterface 108 | { 109 | if (!isset($this->drivers[$name])) { 110 | $this->setDriver($name, new $this->config['store']['drivers'][$name]['class']($this->config['store']['drivers'][$name])); 111 | } 112 | return $this->drivers[$name]; 113 | } 114 | 115 | /** 116 | * Set the driver instance for the given name. 117 | * 118 | * @param string $name 119 | * @param StoreDriverInterface $class 120 | * @return void 121 | */ 122 | private function setDriver(string $name, StoreDriverInterface $class) 123 | { 124 | $this->drivers[$name] = $class; 125 | } 126 | 127 | /** 128 | * Set the cache instance. 129 | * 130 | * @param CacheDriverInterface $cacheDriver 131 | * @return void 132 | */ 133 | private function setCache(CacheDriverInterface $cacheDriver): void 134 | { 135 | $this->cache = $cacheDriver; 136 | } 137 | 138 | /** 139 | * Get the cache instance. 140 | * 141 | * @return CacheDriverInterface 142 | */ 143 | public function cache(): CacheDriverInterface 144 | { 145 | return $this->cache; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/Support/Setting.php: -------------------------------------------------------------------------------- 1 | setting = $setting; 29 | self::$obj = $this; 30 | } 31 | 32 | /** 33 | * Handle dynamic static method calls. 34 | * 35 | * @param string $name 36 | * @param array $arguments 37 | * @return mixed 38 | * @throws SettingKeyNotFoundException 39 | * @throws SettingNotFoundException 40 | * @throws SettingNotSelectedException 41 | */ 42 | public static function __callStatic(string $name, array $arguments) 43 | { 44 | if (strtolower($name) == 'select') { 45 | return self::Obj()->selectSetting(...$arguments); 46 | } elseif ($arguments) { 47 | return self::Obj()->setting->get($name, ...$arguments); 48 | } else { 49 | return self::Obj()->selectSetting($name); 50 | } 51 | } 52 | 53 | /** 54 | * Handle dynamic method calls. 55 | * 56 | * @param string $name 57 | * @param array $arguments 58 | * @return mixed 59 | * 60 | * @throws SettingKeyNotFoundException 61 | * @throws SettingNotFoundException 62 | * @throws SettingNotSelectedException 63 | */ 64 | public function __call(string $name, array $arguments) 65 | { 66 | if (strtolower($name) == 'select') { 67 | return $this->selectSetting(...$arguments); 68 | } elseif ($arguments) { 69 | return $this->setting->get($name, ...$arguments); 70 | } else { 71 | return $this->selectSetting($name); 72 | } 73 | } 74 | 75 | /** 76 | * Get values of keys on selected setting. 77 | * 78 | * @param mixed $keys Keys to access values in the setting. 79 | * @param mixed|null $default Default value to return if the setting or key is not found. 80 | * @param bool $throw flag to disable 'NotFound' exceptions 81 | * @return mixed 82 | * 83 | * @throws SettingKeyNotFoundException 84 | * @throws SettingNotFoundException 85 | * @throws SettingNotSelectedException 86 | */ 87 | public function get(mixed $keys = [], mixed $default = null, bool $throw = true): mixed 88 | { 89 | return $this->setting->get($this->getSelect(), $keys, $default, $throw); 90 | } 91 | 92 | /** 93 | * Set values of keys on selected setting. 94 | * 95 | * @param mixed $key 96 | * @param mixed $value 97 | * @return void 98 | * @throws SettingNotSelectedException 99 | */ 100 | public function set(mixed $key, mixed $value = []): void 101 | { 102 | if ($key) { 103 | if (is_string($key) && $value) { 104 | $this->setting->set($this->getSelect(), [$key => $value]); 105 | } elseif (is_array($key)) { 106 | $this->setting->set($this->getSelect(), $key); 107 | } 108 | } 109 | } 110 | 111 | /** 112 | * delete keys of the selected setting. 113 | * 114 | * @param mixed $keys 115 | * @return void 116 | * @throws SettingNotSelectedException 117 | * @throws ArrayKeyNotFoundException 118 | */ 119 | public function delete(mixed $keys = []): void 120 | { 121 | $this->setting->delete($this->getSelect(), $keys); 122 | } 123 | 124 | /** 125 | * @param mixed $keys 126 | * @return bool 127 | * 128 | * @throws SettingNotSelectedException 129 | */ 130 | public function has(mixed $keys = []): bool 131 | { 132 | return $this->setting->has($this->getSelect(), $keys); 133 | } 134 | 135 | /** 136 | * Select a setting to work with. 137 | * 138 | * @param string $setting 139 | * @return Setting 140 | */ 141 | private function selectSetting(string $setting = ''): Setting 142 | { 143 | $this->select = $setting; 144 | return $this; 145 | } 146 | 147 | /** 148 | * Get the currently selected setting. 149 | * 150 | * @return string 151 | */ 152 | private function getSelect(): string 153 | { 154 | $select = $this->select; 155 | $this->selectSetting(); 156 | return $select; 157 | } 158 | 159 | /** 160 | * Get the instance of the Setting class. 161 | * 162 | * @return Setting 163 | */ 164 | public static function Obj(): Setting 165 | { 166 | if (!isset(self::$obj)) { 167 | //this added for resolve conflict with laravel bootstrap configuration 168 | $config = require base_path('config') . DIRECTORY_SEPARATOR . "_setting.php"; 169 | 170 | new Setting(new LaravelSettingPro($config, new SettingStore($config))); 171 | } 172 | 173 | return self::$obj; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/Support/helpers.php: -------------------------------------------------------------------------------- 1 | select($settingName)->get($key, $default); 23 | } 24 | 25 | return Setting::Obj()->select($settingName); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/setting/test.php: -------------------------------------------------------------------------------- 1 | 'welcome to Laravel Setting Pro', 5 | 'version' => '2.0.0', 6 | 'users' => [ 7 | '1' => [ 8 | 'name' => 'test user 1', 9 | 'profile' => [ 10 | 'address' => 'address test 1', 11 | 'pic' => 'test1.png' 12 | ] 13 | ], 14 | '2' => [ 15 | 'name' => 'test user 2', 16 | 'profile' => [ 17 | 'address' => 'address test 2', 18 | 'pic' => 'test2.png' 19 | ] 20 | ], 21 | '3' => [ 22 | 'name' => 'test user 3', 23 | 'profile' => [ 24 | 'address' => 'address test 3', 25 | 'pic' => 'test3.png' 26 | ] 27 | ], 28 | '4' => [ 29 | 'name' => 'test user 4', 30 | 'profile' => [ 31 | 'address' => 'address test 4', 32 | 'pic' => 'test4.png' 33 | ] 34 | ], 35 | '5' => [ 36 | 'name' => 'test user 5', 37 | 'profile' => [ 38 | 'address' => 'address test 5', 39 | 'pic' => 'test5.png' 40 | ] 41 | ] 42 | ] 43 | ]; 44 | --------------------------------------------------------------------------------