vendor and env first commit
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
||||
; This file is for unifying the coding style for different editors and IDEs.
|
||||
; More information at https://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
@@ -0,0 +1,25 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text eol=lf
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.c text
|
||||
*.h text
|
||||
|
||||
# Declare files that will always have CRLF line endings on checkout.
|
||||
*.sln text eol=crlf
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.otf binary
|
||||
*.eot binary
|
||||
*.svg binary
|
||||
*.ttf binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
|
||||
*.css linguist-vendored
|
||||
*.scss linguist-vendored
|
||||
*.js linguist-vendored
|
||||
CHANGELOG.md export-ignore
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
|
||||
name: PHP ${{ matrix.php }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php: ['7.3', '7.4', '8.0', '8.1']
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Cache composer
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.composer/cache/files
|
||||
key: php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extension-csv: bcmath, ctype, dom, fileinfo, intl, gd, json, mbstring, pdo, pdo_sqlite, openssl, sqlite, xml, zip
|
||||
coverage: none
|
||||
|
||||
- name: Install composer
|
||||
run: composer install --no-interaction --no-scripts --no-suggest --prefer-source
|
||||
|
||||
- name: Execute tests
|
||||
run: vendor/bin/phpunit
|
||||
@@ -0,0 +1,9 @@
|
||||
/.idea
|
||||
/.history
|
||||
/.vscode
|
||||
/tests/databases
|
||||
/vendor
|
||||
.DS_Store
|
||||
.phpunit.result.cache
|
||||
composer.phar
|
||||
composer.lock
|
||||
@@ -0,0 +1,4 @@
|
||||
preset: psr2
|
||||
|
||||
enabled:
|
||||
- concat_with_spaces
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Andreas Lutro
|
||||
|
||||
Copyright (c) 2017 Akaunting
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
# Persistent settings package for Laravel
|
||||
|
||||
[](https://github.com/akaunting/laravel-setting)
|
||||
[](https://styleci.io/repos/101231817)
|
||||
[](LICENSE.md)
|
||||
|
||||
This package allows you to save settings in a more persistent way. You can use the database and/or json file to save your settings. You can also override the Laravel config.
|
||||
|
||||
* Driver support
|
||||
* Helper function
|
||||
* Blade directive
|
||||
* Override config values
|
||||
* Encryption
|
||||
* Custom file, table and columns
|
||||
* Auto save
|
||||
* Extra columns
|
||||
* Cache support
|
||||
|
||||
## Getting Started
|
||||
|
||||
### 1. Install
|
||||
|
||||
Run the following command:
|
||||
|
||||
```bash
|
||||
composer require akaunting/laravel-setting
|
||||
```
|
||||
|
||||
### 2. Register (for Laravel < 5.5)
|
||||
|
||||
Register the service provider in `config/app.php`
|
||||
|
||||
```php
|
||||
Akaunting\Setting\Provider::class,
|
||||
```
|
||||
|
||||
Add alias if you want to use the facade.
|
||||
|
||||
```php
|
||||
'Setting' => Akaunting\Setting\Facade::class,
|
||||
```
|
||||
|
||||
### 3. Publish
|
||||
|
||||
Publish config file.
|
||||
|
||||
```bash
|
||||
php artisan vendor:publish --tag=setting
|
||||
```
|
||||
|
||||
### 4. Database
|
||||
|
||||
Create table for database driver
|
||||
|
||||
```bash
|
||||
php artisan migrate
|
||||
```
|
||||
|
||||
### 5. Configure
|
||||
|
||||
You can change the options of your app from `config/setting.php` file
|
||||
|
||||
## Usage
|
||||
|
||||
You can either use the helper method like `setting('foo')` or the facade `Setting::get('foo')`
|
||||
|
||||
### Facade
|
||||
|
||||
```php
|
||||
Setting::get('foo', 'default');
|
||||
Setting::get('nested.element');
|
||||
Setting::set('foo', 'bar');
|
||||
Setting::forget('foo');
|
||||
$settings = Setting::all();
|
||||
```
|
||||
|
||||
### Helper
|
||||
|
||||
```php
|
||||
setting('foo', 'default');
|
||||
setting('nested.element');
|
||||
setting(['foo' => 'bar']);
|
||||
setting()->forget('foo');
|
||||
$settings = setting()->all();
|
||||
```
|
||||
|
||||
You can call the `save()` method to save the changes.
|
||||
|
||||
### Auto Save
|
||||
|
||||
If you enable the `auto_save` option in the config file, settings will be saved automatically every time the application shuts down if anything has been changed.
|
||||
|
||||
### Blade Directive
|
||||
|
||||
You can get the settings directly in your blade templates using the helper method or the blade directive like `@setting('foo')`
|
||||
|
||||
### Override Config Values
|
||||
|
||||
You can easily override default config values by adding them to the `override` option in `config/setting.php`, thereby eliminating the need to modify the default config files and also allowing you to change said values during production. Ex:
|
||||
|
||||
```php
|
||||
'override' => [
|
||||
"app.name" => "app_name",
|
||||
"app.env" => "app_env",
|
||||
"mail.driver" => "app_mail_driver",
|
||||
"mail.host" => "app_mail_host",
|
||||
],
|
||||
```
|
||||
|
||||
The values on the left corresponds to the respective config value (Ex: config('app.name')) and the value on the right is the name of the `key` in your settings table/json file.
|
||||
|
||||
### Encryption
|
||||
|
||||
If you like to encrypt the values for a given key, you can pass the key to the `encrypted_keys` option in `config/setting.php` and the rest is automatically handled by using Laravel's built-in encryption facilities. Ex:
|
||||
|
||||
```php
|
||||
'encrypted_keys' => [
|
||||
"payment.key",
|
||||
],
|
||||
```
|
||||
|
||||
### JSON Storage
|
||||
|
||||
You can modify the path used on run-time using `setting()->setPath($path)`.
|
||||
|
||||
### Database Storage
|
||||
|
||||
If you want to use the database as settings storage then you should run the `php artisan migrate`. You can modify the table fields from the `create_settings_table` file in the migrations directory.
|
||||
|
||||
#### Extra Columns
|
||||
|
||||
If you want to store settings for multiple users/clients in the same database you can do so by specifying extra columns:
|
||||
|
||||
```php
|
||||
setting()->setExtraColumns(['user_id' => Auth::user()->id]);
|
||||
```
|
||||
|
||||
where `user_id = x` will now be added to the database query when settings are retrieved, and when new settings are saved, the `user_id` will be populated.
|
||||
|
||||
If you need more fine-tuned control over which data gets queried, you can use the `setConstraint` method which takes a closure with two arguments:
|
||||
|
||||
- `$query` is the query builder instance
|
||||
- `$insert` is a boolean telling you whether the query is an insert or not. If it is an insert, you usually don't need to do anything to `$query`.
|
||||
|
||||
```php
|
||||
setting()->setConstraint(function($query, $insert) {
|
||||
if ($insert) return;
|
||||
$query->where(/* ... */);
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Drivers
|
||||
|
||||
This package uses the Laravel `Manager` class under the hood, so it's easy to add your own storage driver. All you need to do is extend the abstract `Driver` class, implement the abstract methods and call `setting()->extend`.
|
||||
|
||||
```php
|
||||
class MyDriver extends Akaunting\Setting\Contracts\Driver
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
app('setting.manager')->extend('mydriver', function($app) {
|
||||
return $app->make('MyDriver');
|
||||
});
|
||||
```
|
||||
|
||||
## Changelog
|
||||
|
||||
Please see [Releases](../../releases) for more information what has changed recently.
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests are more than welcome. You must follow the PSR coding standards.
|
||||
|
||||
## Security
|
||||
|
||||
If you discover any security related issues, please email security@akaunting.com instead of using the issue tracker.
|
||||
|
||||
## Credits
|
||||
|
||||
- [Denis Duliçi](https://github.com/denisdulici)
|
||||
- [All Contributors](../../contributors)
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information.
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "akaunting/laravel-setting",
|
||||
"description": "Persistent settings package for Laravel",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"persistent",
|
||||
"settings",
|
||||
"config"
|
||||
],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Denis Duliçi",
|
||||
"email": "info@akaunting.com",
|
||||
"homepage": "https://akaunting.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"laravel/framework": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=4.8",
|
||||
"mockery/mockery": "0.9.*",
|
||||
"laravel/framework": ">=5.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Akaunting\\Setting\\": "./src"
|
||||
},
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Akaunting\\Setting\\Provider"
|
||||
],
|
||||
"aliases": {
|
||||
"Setting": "Akaunting\\Setting\\Facade"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Package Test Suite">
|
||||
<directory suffix=".php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enable / Disable auto save
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Auto-save every time the application shuts down
|
||||
|
|
||||
*/
|
||||
'auto_save' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Options for caching. Set whether to enable cache, its key, time to live
|
||||
| in seconds and whether to auto clear after save.
|
||||
|
|
||||
*/
|
||||
'cache' => [
|
||||
'enabled' => false,
|
||||
'key' => 'setting',
|
||||
'ttl' => 3600,
|
||||
'auto_clear' => true,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Setting driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Select where to store the settings.
|
||||
|
|
||||
| Supported: "database", "json", "memory"
|
||||
|
|
||||
*/
|
||||
'driver' => 'database',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Database driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Options for database driver. Enter which connection to use, null means
|
||||
| the default connection. Set the table and column names.
|
||||
|
|
||||
*/
|
||||
'database' => [
|
||||
'connection' => null,
|
||||
'table' => 'settings',
|
||||
'key' => 'key',
|
||||
'value' => 'value',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JSON driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Options for json driver. Enter the full path to the .json file.
|
||||
|
|
||||
*/
|
||||
'json' => [
|
||||
'path' => storage_path() . '/settings.json',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Override application config values
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If defined, settings package will override these config values.
|
||||
|
|
||||
| Sample:
|
||||
| "app.locale" => "settings.locale",
|
||||
|
|
||||
*/
|
||||
'override' => [
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fallback
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Define fallback settings to be used in case the default is null
|
||||
|
|
||||
| Sample:
|
||||
| "currency" => "USD",
|
||||
|
|
||||
*/
|
||||
'fallback' => [
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Required Extra Columns
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The list of columns required to be set up
|
||||
|
|
||||
| Sample:
|
||||
| "user_id",
|
||||
| "tenant_id",
|
||||
|
|
||||
*/
|
||||
'required_extra_columns' => [
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Define the keys which should be crypt automatically.
|
||||
|
|
||||
| Sample:
|
||||
| "payment.key"
|
||||
|
|
||||
*/
|
||||
'encrypted_keys' => [
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting\Contracts;
|
||||
|
||||
use Akaunting\Setting\Support\Arr;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
abstract class Driver
|
||||
{
|
||||
/**
|
||||
* The settings data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* Whether the store has changed since it was last loaded.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $unsaved = false;
|
||||
|
||||
/**
|
||||
* Whether the settings data are loaded.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $loaded = false;
|
||||
|
||||
/**
|
||||
* Include and merge with fallbacks
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $with_fallback = true;
|
||||
|
||||
/**
|
||||
* Excludes fallback data
|
||||
*/
|
||||
public function withoutFallback()
|
||||
{
|
||||
$this->with_fallback = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific key from the settings data.
|
||||
*
|
||||
* @param string|array $key
|
||||
* @param mixed $default Optional default value.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
if (!$this->checkExtraColumns()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->load();
|
||||
|
||||
return Arr::get($this->data, $key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fallback value if default is null.
|
||||
*
|
||||
* @param string|array $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFallback($key, $default = null)
|
||||
{
|
||||
if (($default !== null) || is_array($key)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return Arr::get((array) config('setting.fallback'), $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given value is same as fallback.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEqualToFallback($key, $value)
|
||||
{
|
||||
return (string) $this->getFallback($key) == (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a key exists in the settings data.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($key)
|
||||
{
|
||||
if (!$this->checkExtraColumns()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->load();
|
||||
|
||||
return Arr::has($this->data, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific key to a value in the settings data.
|
||||
*
|
||||
* @param string|array $key Key string or associative array of key => value
|
||||
* @param mixed $value Optional only if the first argument is an array
|
||||
*/
|
||||
public function set($key, $value = null)
|
||||
{
|
||||
if (!$this->checkExtraColumns()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->load();
|
||||
$this->unsaved = true;
|
||||
|
||||
if (is_array($key)) {
|
||||
foreach ($key as $k => $v) {
|
||||
Arr::set($this->data, $k, $v);
|
||||
}
|
||||
} else {
|
||||
Arr::set($this->data, $key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset a key in the settings data.
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
public function forget($key)
|
||||
{
|
||||
if (!$this->checkExtraColumns()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->unsaved = true;
|
||||
|
||||
if ($this->has($key)) {
|
||||
Arr::forget($this->data, $key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset all keys in the settings data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function forgetAll()
|
||||
{
|
||||
if (!$this->checkExtraColumns()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config('setting.cache.enabled')) {
|
||||
Cache::forget($this->getCacheKey());
|
||||
}
|
||||
|
||||
$this->unsaved = true;
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all settings data.
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
if (!$this->checkExtraColumns()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$this->load();
|
||||
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save any changes done to the settings data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if (!$this->checkExtraColumns()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->unsaved) {
|
||||
// either nothing has been changed, or data has not been loaded, so
|
||||
// do nothing by returning early
|
||||
return;
|
||||
}
|
||||
|
||||
if (config('setting.cache.enabled') && config('setting.cache.auto_clear')) {
|
||||
Cache::forget($this->getCacheKey());
|
||||
}
|
||||
|
||||
$this->write($this->data);
|
||||
$this->unsaved = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure data is loaded.
|
||||
*
|
||||
* @param $force Force a reload of data. Default false.
|
||||
*/
|
||||
public function load($force = false)
|
||||
{
|
||||
if (!$this->checkExtraColumns()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->loaded && !$force) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fallback_data = $this->with_fallback ? config('setting.fallback') : [];
|
||||
$driver_data = $this->readData();
|
||||
|
||||
$this->data = Arr::merge((array) $fallback_data, (array) $driver_data);
|
||||
$this->loaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from driver or cache
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function readData()
|
||||
{
|
||||
if (config('setting.cache.enabled')) {
|
||||
return $this->readDataFromCache();
|
||||
}
|
||||
|
||||
return $this->read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from cache
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function readDataFromCache()
|
||||
{
|
||||
return Cache::remember($this->getCacheKey(), config('setting.cache.ttl'), function () {
|
||||
return $this->read();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if extra columns are set up.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function checkExtraColumns()
|
||||
{
|
||||
if (!$required_extra_columns = config('setting.required_extra_columns')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (array_keys_exists($required_extra_columns, $this->getExtraColumns())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key based on extra columns.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCacheKey()
|
||||
{
|
||||
$key = config('setting.cache.key');
|
||||
|
||||
foreach ($this->getExtraColumns() as $name => $value) {
|
||||
$key .= '_' . $name . '_' . $value;
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extra columns added to the rows.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getExtraColumns();
|
||||
|
||||
/**
|
||||
* Read data from driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function read();
|
||||
|
||||
/**
|
||||
* Write data to driver.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function write(array $data);
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting\Drivers;
|
||||
|
||||
use Akaunting\Setting\Contracts\Driver;
|
||||
use Akaunting\Setting\Support\Arr;
|
||||
use Closure;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Support\Arr as LaravelArr;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class Database extends Driver
|
||||
{
|
||||
/**
|
||||
* The database connection instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The table to query from.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* The key column name to query from.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $key;
|
||||
|
||||
/**
|
||||
* The value column name to query from.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Keys which should be encrypt automatically.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $encrypted_keys;
|
||||
|
||||
/**
|
||||
* Any query constraints that should be applied.
|
||||
*
|
||||
* @var Closure|null
|
||||
*/
|
||||
protected $query_constraint;
|
||||
|
||||
/**
|
||||
* Any extra columns that should be added to the rows.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $extra_columns = [];
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
* @param string $table
|
||||
*/
|
||||
public function __construct(Connection $connection, $table = null, $key = null, $value = null, array $encrypted_keys = [])
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->table = $table ?: 'settings';
|
||||
$this->key = $key ?: 'key';
|
||||
$this->value = $value ?: 'value';
|
||||
$this->encrypted_keys = $encrypted_keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table to query from.
|
||||
*
|
||||
* @param string $table
|
||||
*/
|
||||
public function setTable($table)
|
||||
{
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the key column name to query from.
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
public function setKey($key)
|
||||
{
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value column name to query from.
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query constraint.
|
||||
*
|
||||
* @param Closure $callback
|
||||
*/
|
||||
public function setConstraint(Closure $callback)
|
||||
{
|
||||
$this->data = [];
|
||||
$this->loaded = false;
|
||||
$this->query_constraint = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set extra columns to be added to the rows.
|
||||
*
|
||||
* @param array $columns
|
||||
*/
|
||||
public function setExtraColumns(array $columns)
|
||||
{
|
||||
$this->extra_columns = $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extra columns added to the rows.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExtraColumns()
|
||||
{
|
||||
return $this->extra_columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function forget($key)
|
||||
{
|
||||
parent::forget($key);
|
||||
|
||||
// because the database driver cannot store empty arrays, remove empty
|
||||
// arrays to keep data consistent before and after saving
|
||||
$segments = explode('.', $key);
|
||||
array_pop($segments);
|
||||
|
||||
while ($segments) {
|
||||
$segment = implode('.', $segments);
|
||||
|
||||
// non-empty array - exit out of the loop
|
||||
if ($this->get($segment)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// remove the empty array and move on to the next segment
|
||||
$this->forget($segment);
|
||||
array_pop($segments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $data)
|
||||
{
|
||||
// Get current data
|
||||
$db_data = $this->newQuery()->get([$this->key, $this->value])->toArray();
|
||||
|
||||
$insert_data = LaravelArr::dot($data);
|
||||
$update_data = [];
|
||||
$delete_keys = [];
|
||||
|
||||
foreach ($db_data as $db_row) {
|
||||
$key = $db_row->{$this->key};
|
||||
$value = $db_row->{$this->value};
|
||||
|
||||
$is_in_insert = $is_different_in_db = $is_same_as_fallback = false;
|
||||
|
||||
if (isset($insert_data[$key])) {
|
||||
$is_in_insert = true;
|
||||
$is_different_in_db = (string) $insert_data[$key] != (string) $value;
|
||||
$is_same_as_fallback = $this->isEqualToFallback($key, $insert_data[$key]);
|
||||
}
|
||||
|
||||
if ($is_in_insert) {
|
||||
if ($is_same_as_fallback) {
|
||||
// Delete if new data is same as fallback
|
||||
$delete_keys[] = $key;
|
||||
} elseif ($is_different_in_db) {
|
||||
// Update if new data is different from db
|
||||
$update_data[$key] = $insert_data[$key];
|
||||
}
|
||||
} else {
|
||||
// Delete if current db not available in new data
|
||||
$delete_keys[] = $key;
|
||||
}
|
||||
|
||||
unset($insert_data[$key]);
|
||||
}
|
||||
|
||||
foreach ($update_data as $key => $value) {
|
||||
$value = $this->prepareValue($key, $value);
|
||||
|
||||
$this->newQuery()
|
||||
->where($this->key, '=', $key)
|
||||
->update([$this->value => $value]);
|
||||
}
|
||||
|
||||
if ($insert_data) {
|
||||
$this->newQuery(true)
|
||||
->insert($this->prepareInsertData($insert_data));
|
||||
}
|
||||
|
||||
if ($delete_keys) {
|
||||
$this->newQuery()
|
||||
->whereIn($this->key, $delete_keys)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms settings data into an array ready to be insterted into the
|
||||
* database. Call array_dot on a multidimensional array before passing it
|
||||
* into this method!
|
||||
*
|
||||
* @param array $data Call array_dot on a multidimensional array before passing it into this method!
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareInsertData(array $data)
|
||||
{
|
||||
$db_data = [];
|
||||
|
||||
if ($this->getExtraColumns()) {
|
||||
foreach ($data as $key => $value) {
|
||||
$value = $this->prepareValue($key, $value);
|
||||
|
||||
// Don't insert if same as fallback
|
||||
if ($this->isEqualToFallback($key, $value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$db_data[] = array_merge(
|
||||
$this->getExtraColumns(),
|
||||
[$this->key => $key, $this->value => $value]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
foreach ($data as $key => $value) {
|
||||
$value = $this->prepareValue($key, $value);
|
||||
|
||||
// Don't insert if same as fallback
|
||||
if ($this->isEqualToFallback($key, $value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$db_data[] = [$this->key => $key, $this->value => $value];
|
||||
}
|
||||
}
|
||||
|
||||
return $db_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided key should be encrypted or not.
|
||||
* Also type casts the given value to a string so errors with booleans or integers are handeled.
|
||||
* Otherwise it returns the original value.
|
||||
*
|
||||
* @param string $key Key to check if it's inside the encryptedValues variable.
|
||||
* @param mixed $value Info: Encryption only supports strings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareValue(string $key, $value)
|
||||
{
|
||||
// Check if key should be encrypted
|
||||
if (in_array($key, $this->encrypted_keys)) {
|
||||
// Cast to string to avoid error when a user passes a boolean value
|
||||
return Crypt::encryptString((string) $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided key should be decrypted or not.
|
||||
* Otherwise it returns the original value.
|
||||
*
|
||||
* @param string $key Key to check if it's inside the encryptedValues variable.
|
||||
* @param mixed $value Info: Encryption only supports strings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function unpackValue(string $key, $value)
|
||||
{
|
||||
// Check if key should be encrypted
|
||||
if (in_array($key, $this->encrypted_keys)) {
|
||||
// Cast to string to avoid error when a user passes a boolean value
|
||||
return Crypt::decryptString((string) $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function read()
|
||||
{
|
||||
return $this->parseReadData($this->newQuery()->get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse data coming from the database.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parseReadData($data)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($data as $row) {
|
||||
if (is_array($row)) {
|
||||
$key = $row[$this->key];
|
||||
$value = $row[$this->value];
|
||||
} elseif (is_object($row)) {
|
||||
$key = $row->{$this->key};
|
||||
$value = $row->{$this->value};
|
||||
} else {
|
||||
$msg = 'Expected array or object, got ' . gettype($row);
|
||||
throw new \UnexpectedValueException($msg);
|
||||
}
|
||||
|
||||
// Encryption
|
||||
$value = $this->unpackValue($key, $value);
|
||||
|
||||
Arr::set($results, $key, $value);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new query builder instance.
|
||||
*
|
||||
* @param bool $insert
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder
|
||||
*/
|
||||
protected function newQuery($insert = false)
|
||||
{
|
||||
$query = $this->connection->table($this->table);
|
||||
|
||||
if (!$insert) {
|
||||
foreach ($this->getExtraColumns() as $key => $value) {
|
||||
$query->where($key, '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->query_constraint !== null) {
|
||||
$callback = $this->query_constraint;
|
||||
$callback($query, $insert);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting\Drivers;
|
||||
|
||||
use Akaunting\Setting\Contracts\Driver;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
||||
class Json extends Driver
|
||||
{
|
||||
/**
|
||||
* @param \Illuminate\Filesystem\Filesystem $files
|
||||
* @param string $path
|
||||
*/
|
||||
public function __construct(Filesystem $files, $path = null)
|
||||
{
|
||||
$this->files = $files;
|
||||
|
||||
$this->setPath($path ?: storage_path() . '/settings.json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path for the JSON file.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
// If the file does not already exist, we will attempt to create it.
|
||||
if (!$this->files->exists($path)) {
|
||||
$result = $this->files->put($path, '{}');
|
||||
if ($result === false) {
|
||||
throw new \InvalidArgumentException("Could not write to $path.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->files->isWritable($path)) {
|
||||
throw new \InvalidArgumentException("$path is not writable.");
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtraColumns()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function read()
|
||||
{
|
||||
$contents = $this->files->get($this->path);
|
||||
|
||||
$data = json_decode($contents, true);
|
||||
|
||||
if ($data === null) {
|
||||
throw new \RuntimeException("Invalid JSON in {$this->path}");
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $data)
|
||||
{
|
||||
if ($data) {
|
||||
$contents = json_encode($data);
|
||||
} else {
|
||||
$contents = '{}';
|
||||
}
|
||||
|
||||
$this->files->put($this->path, $contents);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting\Drivers;
|
||||
|
||||
use Akaunting\Setting\Contracts\Driver;
|
||||
|
||||
class Memory extends Driver
|
||||
{
|
||||
/**
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(array $data = null)
|
||||
{
|
||||
if ($data) {
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExtraColumns()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function read()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $data)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting;
|
||||
|
||||
use Illuminate\Support\Facades\Facade as BaseFacade;
|
||||
|
||||
class Facade extends BaseFacade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*/
|
||||
public static function getFacadeAccessor()
|
||||
{
|
||||
return 'setting';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting;
|
||||
|
||||
use Akaunting\Setting\Drivers\Database;
|
||||
use Akaunting\Setting\Drivers\Json;
|
||||
use Akaunting\Setting\Drivers\Memory;
|
||||
use Illuminate\Support\Manager as BaseManager;
|
||||
|
||||
class Manager extends BaseManager
|
||||
{
|
||||
/**
|
||||
* The container instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Container\Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* The application instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
*/
|
||||
public function __construct($app = null)
|
||||
{
|
||||
$this->container = $app ?? app();
|
||||
|
||||
parent::__construct($this->container);
|
||||
}
|
||||
|
||||
public function getDefaultDriver()
|
||||
{
|
||||
return config('setting.driver');
|
||||
}
|
||||
|
||||
public function createJsonDriver()
|
||||
{
|
||||
$path = config('setting.json.path');
|
||||
|
||||
return new Json($this->container['files'], $path);
|
||||
}
|
||||
|
||||
public function createDatabaseDriver()
|
||||
{
|
||||
$connection = $this->container['db']->connection(config('setting.database.connection'));
|
||||
$table = config('setting.database.table');
|
||||
$key = config('setting.database.key');
|
||||
$value = config('setting.database.value');
|
||||
$encryptedKeys = config('setting.encrypted_keys');
|
||||
|
||||
return new Database($connection, $table, $key, $value, $encryptedKeys);
|
||||
}
|
||||
|
||||
public function createMemoryDriver()
|
||||
{
|
||||
return new Memory();
|
||||
}
|
||||
|
||||
public function createArrayDriver()
|
||||
{
|
||||
return $this->createMemoryDriver();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class AutoSaveSetting
|
||||
{
|
||||
/**
|
||||
* Create a new save settings middleware.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setting = app('setting');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$response = $next($request);
|
||||
|
||||
$this->setting->save();
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateSettingsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Set up the options.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->table = config('setting.database.table');
|
||||
$this->key = config('setting.database.key');
|
||||
$this->value = config('setting.database.value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create($this->table, function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string($this->key)->index();
|
||||
$table->text($this->value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop($this->table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting;
|
||||
|
||||
use Akaunting\Setting\Middleware\AutoSaveSetting;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\View\Compilers\BladeCompiler;
|
||||
|
||||
class Provider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->publishes([
|
||||
__DIR__ . '/Config/setting.php' => config_path('setting.php'),
|
||||
__DIR__ . '/Migrations/2017_08_24_000000_create_settings_table.php' => database_path('migrations/2017_08_24_000000_create_settings_table.php'),
|
||||
], 'setting');
|
||||
|
||||
// Auto save setting
|
||||
if (config('setting.auto_save')) {
|
||||
$kernel = $this->app['Illuminate\Contracts\Http\Kernel'];
|
||||
$kernel->pushMiddleware(AutoSaveSetting::class);
|
||||
}
|
||||
|
||||
$this->override();
|
||||
|
||||
// Register blade directive
|
||||
$this->callAfterResolving('blade.compiler', function (BladeCompiler $compiler) {
|
||||
$compiler->directive('setting', function ($expression) {
|
||||
return "<?php echo setting($expression); ?>";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->singleton('setting.manager', function ($app) {
|
||||
return new Manager($app);
|
||||
});
|
||||
|
||||
$this->app->singleton('setting', function ($app) {
|
||||
return $app['setting.manager']->driver();
|
||||
});
|
||||
|
||||
$this->mergeConfigFrom(__DIR__ . '/Config/setting.php', 'setting');
|
||||
}
|
||||
|
||||
private function override()
|
||||
{
|
||||
$override = config('setting.override', []);
|
||||
|
||||
foreach (Arr::dot($override) as $config_key => $setting_key) {
|
||||
$config_key = is_string($config_key) ? $config_key : $setting_key;
|
||||
|
||||
try {
|
||||
if (! is_null($value = setting($setting_key))) {
|
||||
config([$config_key => $value]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
namespace Akaunting\Setting\Support;
|
||||
|
||||
class Arr
|
||||
{
|
||||
/**
|
||||
* This class is a static class and should not be instantiated.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element from an array.
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $key Specify a nested element by separating keys with full stops.
|
||||
* @param mixed $default If the element is not found, return this.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get(array $data, $key, $default = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (is_array($key)) {
|
||||
return static::getArray($data, $key, $default);
|
||||
}
|
||||
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($data)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if (!array_key_exists($segment, $data)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$data = $data[$segment];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected static function getArray(array $input, $keys, $default = null)
|
||||
{
|
||||
$output = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
static::set($output, $key, static::get($input, $key, $default));
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an array has a given key.
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function has(array $data, $key)
|
||||
{
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array_key_exists($segment, $data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = $data[$segment];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an element of an array.
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $key Specify a nested element by separating keys with full stops.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function set(array &$data, $key, $value)
|
||||
{
|
||||
$segments = explode('.', $key);
|
||||
|
||||
$key = array_pop($segments);
|
||||
|
||||
// iterate through all of $segments except the last one
|
||||
foreach ($segments as $segment) {
|
||||
if (!array_key_exists($segment, $data)) {
|
||||
$data[$segment] = array();
|
||||
} elseif (!is_array($data[$segment])) {
|
||||
throw new \UnexpectedValueException('Non-array segment encountered');
|
||||
}
|
||||
|
||||
$data = &$data[$segment];
|
||||
}
|
||||
|
||||
$data[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset an element from an array.
|
||||
*
|
||||
* @param array &$data
|
||||
* @param string $key Specify a nested element by separating keys with full stops.
|
||||
*/
|
||||
public static function forget(array &$data, $key)
|
||||
{
|
||||
$segments = explode('.', $key);
|
||||
|
||||
$key = array_pop($segments);
|
||||
|
||||
// iterate through all of $segments except the last one
|
||||
foreach ($segments as $segment) {
|
||||
if (!array_key_exists($segment, $data)) {
|
||||
return;
|
||||
} elseif (!is_array($data[$segment])) {
|
||||
throw new \UnexpectedValueException('Non-array segment encountered');
|
||||
}
|
||||
|
||||
$data = &$data[$segment];
|
||||
}
|
||||
|
||||
unset($data[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two multidimensional arrays recursive
|
||||
*
|
||||
* @param array $array_1
|
||||
* @param array $array_2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function merge(array $array_1, array $array_2)
|
||||
{
|
||||
$merged = $array_1;
|
||||
|
||||
foreach ($array_2 as $key => $value) {
|
||||
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
|
||||
$merged[$key] = static::merge($merged[$key], $value);
|
||||
} elseif (is_numeric($key)) {
|
||||
if (!in_array($value, $merged)) {
|
||||
$merged[] = $value;
|
||||
}
|
||||
} else {
|
||||
$merged[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $merged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
if (!function_exists('array_keys_exists')) {
|
||||
/**
|
||||
* Easily check if multiple array keys exist.
|
||||
*
|
||||
* @param array $keys
|
||||
* @param array $arr
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function array_keys_exists(array $keys, array $arr)
|
||||
{
|
||||
return !array_diff_key(array_flip($keys), $arr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('setting')) {
|
||||
/**
|
||||
* Get / set the specified setting value.
|
||||
*
|
||||
* If an array is passed as the key, we will assume you want to set an array of values.
|
||||
*
|
||||
* @param array|string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function setting($key = null, $default = null)
|
||||
{
|
||||
$setting = app('setting');
|
||||
|
||||
if (is_null($key)) {
|
||||
return $setting;
|
||||
}
|
||||
|
||||
if (is_array($key)) {
|
||||
$setting->set($key);
|
||||
|
||||
return $setting;
|
||||
}
|
||||
|
||||
return $setting->get($key, $default);
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
use Akaunting\Setting\Drivers\Database;
|
||||
|
||||
abstract class AbstractFunctionalTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
abstract protected function createStore(array $data = []);
|
||||
|
||||
protected function assertStoreEquals($store, $expected, $message = null)
|
||||
{
|
||||
$this->assertEquals($expected, $store->all(), $message);
|
||||
$store->save();
|
||||
$store = $this->createStore();
|
||||
$this->assertEquals($expected, $store->all(), $message);
|
||||
}
|
||||
|
||||
protected function assertStoreKeyEquals($store, $key, $expected, $message = null)
|
||||
{
|
||||
$this->assertEquals($expected, $store->get($key), $message);
|
||||
$store->save();
|
||||
$store = $this->createStore();
|
||||
$this->assertEquals($expected, $store->get($key), $message);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function store_is_initially_empty()
|
||||
{
|
||||
$store = $this->createStore();
|
||||
$this->assertEquals([], $store->all());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function written_changes_are_saved()
|
||||
{
|
||||
$store = $this->createStore();
|
||||
$store->set('foo', 'bar');
|
||||
$this->assertStoreKeyEquals($store, 'foo', 'bar');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function nested_keys_are_nested()
|
||||
{
|
||||
$store = $this->createStore();
|
||||
$store->set('foo.bar', 'baz');
|
||||
$this->assertStoreEquals($store, ['foo' => ['bar' => 'baz']]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function cannot_set_nested_key_on_non_array_member()
|
||||
{
|
||||
$store = $this->createStore();
|
||||
$store->set('foo', 'bar');
|
||||
$this->setExpectedException('UnexpectedValueException', 'Non-array segment encountered');
|
||||
$store->set('foo.bar', 'baz');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function can_forget_key()
|
||||
{
|
||||
$store = $this->createStore();
|
||||
$store->set('foo', 'bar');
|
||||
$store->set('bar', 'baz');
|
||||
$this->assertStoreEquals($store, ['foo' => 'bar', 'bar' => 'baz']);
|
||||
|
||||
$store->forget('foo');
|
||||
$this->assertStoreEquals($store, ['bar' => 'baz']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function can_forget_nested_key()
|
||||
{
|
||||
$store = $this->createStore();
|
||||
$store->set('foo.bar', 'baz');
|
||||
$store->set('foo.baz', 'bar');
|
||||
$store->set('bar.foo', 'baz');
|
||||
$this->assertStoreEquals($store, [
|
||||
'foo' => [
|
||||
'bar' => 'baz',
|
||||
'baz' => 'bar',
|
||||
],
|
||||
'bar' => [
|
||||
'foo' => 'baz',
|
||||
],
|
||||
]);
|
||||
|
||||
$store->forget('foo.bar');
|
||||
$this->assertStoreEquals($store, [
|
||||
'foo' => [
|
||||
'baz' => 'bar',
|
||||
],
|
||||
'bar' => [
|
||||
'foo' => 'baz',
|
||||
],
|
||||
]);
|
||||
|
||||
$store->forget('bar.foo');
|
||||
$expected = [
|
||||
'foo' => [
|
||||
'baz' => 'bar',
|
||||
],
|
||||
'bar' => [
|
||||
],
|
||||
];
|
||||
if ($store instanceof Database) {
|
||||
unset($expected['bar']);
|
||||
}
|
||||
$this->assertStoreEquals($store, $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function can_forget_all()
|
||||
{
|
||||
$store = $this->createStore(['foo' => 'bar']);
|
||||
$this->assertStoreEquals($store, ['foo' => 'bar']);
|
||||
$store->forgetAll();
|
||||
$this->assertStoreEquals($store, []);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
class DatabaseTest extends AbstractFunctionalTest
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->container = new \Illuminate\Container\Container();
|
||||
$this->capsule = new \Illuminate\Database\Capsule\Manager($this->container);
|
||||
$this->capsule->setAsGlobal();
|
||||
$this->container['db'] = $this->capsule;
|
||||
$this->capsule->addConnection([
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
'prefix' => '',
|
||||
]);
|
||||
|
||||
$this->capsule->schema()->create('settings', function ($t) {
|
||||
$t->string('key', 64)->unique();
|
||||
$t->string('value', 4096);
|
||||
});
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->capsule->schema()->drop('settings');
|
||||
unset($this->capsule);
|
||||
unset($this->container);
|
||||
}
|
||||
|
||||
protected function createStore(array $data = [])
|
||||
{
|
||||
if ($data) {
|
||||
$store = $this->createStore();
|
||||
$store->set($data);
|
||||
$store->save();
|
||||
unset($store);
|
||||
}
|
||||
|
||||
return new \Akaunting\Setting\Drivers\Database(
|
||||
$this->capsule->getConnection()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
class JsonTest extends AbstractFunctionalTest
|
||||
{
|
||||
protected function createStore(array $data = null)
|
||||
{
|
||||
$path = dirname(__DIR__) . '/tmp/store.json';
|
||||
|
||||
if ($data !== null) {
|
||||
if ($data) {
|
||||
$json = json_encode($data);
|
||||
} else {
|
||||
$json = '{}';
|
||||
}
|
||||
|
||||
file_put_contents($path, $json);
|
||||
}
|
||||
|
||||
return new \Akaunting\Setting\Drivers\Json(
|
||||
new \Illuminate\Filesystem\Filesystem(),
|
||||
$path
|
||||
);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$path = dirname(__DIR__) . '/tmp/store.json';
|
||||
unlink($path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
class MemoryTest extends AbstractFunctionalTest
|
||||
{
|
||||
protected function assertStoreEquals($store, $expected, $message = null)
|
||||
{
|
||||
$this->assertEquals($expected, $store->all(), $message);
|
||||
// removed persistance test assertions
|
||||
}
|
||||
|
||||
protected function assertStoreKeyEquals($store, $key, $expected, $message = null)
|
||||
{
|
||||
$this->assertEquals($expected, $store->get($key), $message);
|
||||
// removed persistance test assertions
|
||||
}
|
||||
|
||||
protected function createStore(array $data = null)
|
||||
{
|
||||
return new \Akaunting\Setting\Drivers\Memory($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
use Akaunting\Setting\Support\Arr;
|
||||
|
||||
class ArrayUtilityTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider getGetData
|
||||
*/
|
||||
public function getReturnsCorrectValue(array $data, $key, $expected)
|
||||
{
|
||||
$this->assertEquals($expected, Arr::get($data, $key));
|
||||
}
|
||||
|
||||
public function getGetData()
|
||||
{
|
||||
return [
|
||||
[[], 'foo', null],
|
||||
[['foo' => 'bar'], 'foo', 'bar'],
|
||||
[['foo' => 'bar'], 'bar', null],
|
||||
[['foo' => 'bar'], 'foo.bar', null],
|
||||
[['foo' => ['bar' => 'baz']], 'foo.bar', 'baz'],
|
||||
[['foo' => ['bar' => 'baz']], 'foo.baz', null],
|
||||
[['foo' => ['bar' => 'baz']], 'foo', ['bar' => 'baz']],
|
||||
[
|
||||
['foo' => 'bar', 'bar' => 'baz'],
|
||||
['foo', 'bar'],
|
||||
['foo' => 'bar', 'bar' => 'baz'],
|
||||
],
|
||||
[
|
||||
['foo' => ['bar' => 'baz'], 'bar' => 'baz'],
|
||||
['foo.bar', 'bar'],
|
||||
['foo' => ['bar' => 'baz'], 'bar' => 'baz'],
|
||||
],
|
||||
[
|
||||
['foo' => ['bar' => 'baz'], 'bar' => 'baz'],
|
||||
['foo.bar'],
|
||||
['foo' => ['bar' => 'baz']],
|
||||
],
|
||||
[
|
||||
['foo' => ['bar' => 'baz'], 'bar' => 'baz'],
|
||||
['foo.bar', 'baz'],
|
||||
['foo' => ['bar' => 'baz'], 'baz' => null],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider getSetData
|
||||
*/
|
||||
public function setSetsCorrectKeyToValue(array $input, $key, $value, array $expected)
|
||||
{
|
||||
Arr::set($input, $key, $value);
|
||||
$this->assertEquals($expected, $input);
|
||||
}
|
||||
|
||||
public function getSetData()
|
||||
{
|
||||
return [
|
||||
[
|
||||
['foo' => 'bar'],
|
||||
'foo',
|
||||
'baz',
|
||||
['foo' => 'baz'],
|
||||
],
|
||||
[
|
||||
[],
|
||||
'foo',
|
||||
'bar',
|
||||
['foo' => 'bar'],
|
||||
],
|
||||
[
|
||||
[],
|
||||
'foo.bar',
|
||||
'baz',
|
||||
['foo' => ['bar' => 'baz']],
|
||||
],
|
||||
[
|
||||
['foo' => ['bar' => 'baz']],
|
||||
'foo.baz',
|
||||
'foo',
|
||||
['foo' => ['bar' => 'baz', 'baz' => 'foo']],
|
||||
],
|
||||
[
|
||||
['foo' => ['bar' => 'baz']],
|
||||
'foo.baz.bar',
|
||||
'baz',
|
||||
['foo' => ['bar' => 'baz', 'baz' => ['bar' => 'baz']]],
|
||||
],
|
||||
[
|
||||
[],
|
||||
'foo.bar.baz',
|
||||
'foo',
|
||||
['foo' => ['bar' => ['baz' => 'foo']]],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function setThrowsExceptionOnNonArraySegment()
|
||||
{
|
||||
$data = ['foo' => 'bar'];
|
||||
$this->setExpectedException('UnexpectedValueException', 'Non-array segment encountered');
|
||||
Arr::set($data, 'foo.bar', 'baz');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider getHasData
|
||||
*/
|
||||
public function hasReturnsCorrectly(array $input, $key, $expected)
|
||||
{
|
||||
$this->assertEquals($expected, Arr::has($input, $key));
|
||||
}
|
||||
|
||||
public function getHasData()
|
||||
{
|
||||
return [
|
||||
[[], 'foo', false],
|
||||
[['foo' => 'bar'], 'foo', true],
|
||||
[['foo' => 'bar'], 'bar', false],
|
||||
[['foo' => 'bar'], 'foo.bar', false],
|
||||
[['foo' => ['bar' => 'baz']], 'foo.bar', true],
|
||||
[['foo' => ['bar' => 'baz']], 'foo.baz', false],
|
||||
[['foo' => ['bar' => 'baz']], 'foo', true],
|
||||
[['foo' => null], 'foo', true],
|
||||
[['foo' => ['bar' => null]], 'foo.bar', true],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
use Mockery as m;
|
||||
|
||||
class DatabaseDriverTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function tearDown()
|
||||
{
|
||||
m::close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function correct_data_is_inserted_and_updated()
|
||||
{
|
||||
$connection = $this->mockConnection();
|
||||
$query = $this->mockQuery($connection);
|
||||
|
||||
$query->shouldReceive('get')->once()->andReturn([
|
||||
['key' => 'nest.one', 'value' => 'old'],
|
||||
]);
|
||||
$query->shouldReceive('lists')->atMost(1)->andReturn(['nest.one']);
|
||||
$query->shouldReceive('pluck')->atMost(1)->andReturn(['nest.one']);
|
||||
$dbData = $this->getDbData();
|
||||
unset($dbData[1]); // remove the nest.one array member
|
||||
$query->shouldReceive('where')->with('key', '=', 'nest.one')->andReturn(m::self())->getMock()
|
||||
->shouldReceive('update')->with(['value' => 'nestone']);
|
||||
$self = $this; // 5.3 compatibility
|
||||
$query->shouldReceive('insert')->once()->andReturnUsing(function ($arg) use ($dbData, $self) {
|
||||
$self->assertEquals(count($dbData), count($arg));
|
||||
foreach ($dbData as $key => $value) {
|
||||
$self->assertContains($value, $arg);
|
||||
}
|
||||
});
|
||||
|
||||
$store = $this->makeStore($connection);
|
||||
$store->set('foo', 'bar');
|
||||
$store->set('nest.one', 'nestone');
|
||||
$store->set('nest.two', 'nesttwo');
|
||||
$store->set('array', ['one', 'two']);
|
||||
$store->save();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function extra_columns_are_queried()
|
||||
{
|
||||
$connection = $this->mockConnection();
|
||||
$query = $this->mockQuery($connection);
|
||||
$query->shouldReceive('where')->once()->with('foo', '=', 'bar')
|
||||
->andReturn(m::self())->getMock()
|
||||
->shouldReceive('get')->once()->andReturn([
|
||||
['key' => 'foo', 'value' => 'bar'],
|
||||
]);
|
||||
|
||||
$store = $this->makeStore($connection);
|
||||
$store->setExtraColumns(['foo' => 'bar']);
|
||||
$this->assertEquals('bar', $store->get('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function extra_columns_are_inserted()
|
||||
{
|
||||
$connection = $this->mockConnection();
|
||||
$query = $this->mockQuery($connection);
|
||||
$query->shouldReceive('where')->times(2)->with('extracol', '=', 'extradata')
|
||||
->andReturn(m::self());
|
||||
$query->shouldReceive('get')->once()->andReturn([]);
|
||||
$query->shouldReceive('lists')->atMost(1)->andReturn([]);
|
||||
$query->shouldReceive('pluck')->atMost(1)->andReturn([]);
|
||||
$query->shouldReceive('insert')->once()->with([
|
||||
['key' => 'foo', 'value' => 'bar', 'extracol' => 'extradata'],
|
||||
]);
|
||||
|
||||
$store = $this->makeStore($connection);
|
||||
$store->setExtraColumns(['extracol' => 'extradata']);
|
||||
$store->set('foo', 'bar');
|
||||
$store->save();
|
||||
}
|
||||
|
||||
protected function getDbData()
|
||||
{
|
||||
return [
|
||||
['key' => 'foo', 'value' => 'bar'],
|
||||
['key' => 'nest.one', 'value' => 'nestone'],
|
||||
['key' => 'nest.two', 'value' => 'nesttwo'],
|
||||
['key' => 'array.0', 'value' => 'one'],
|
||||
['key' => 'array.1', 'value' => 'two'],
|
||||
];
|
||||
}
|
||||
|
||||
protected function mockConnection()
|
||||
{
|
||||
return m::mock('Illuminate\Database\Connection');
|
||||
}
|
||||
|
||||
protected function mockQuery($connection)
|
||||
{
|
||||
$query = m::mock('Illuminate\Database\Query\Builder');
|
||||
$connection->shouldReceive('table')->andReturn($query);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function makeStore($connection)
|
||||
{
|
||||
return new Akaunting\Setting\Drivers\Database($connection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Mockery as m;
|
||||
|
||||
class HelperTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public static $functions;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
self::$functions = m::mock();
|
||||
|
||||
Container::setInstance(new Container());
|
||||
|
||||
$store = m::mock('Akaunting\Setting\Contracts\Driver');
|
||||
|
||||
app()->bind('setting', function () use ($store) {
|
||||
return $store;
|
||||
});
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function helper_without_parameters_returns_store()
|
||||
{
|
||||
$this->assertInstanceOf('Akaunting\Setting\Contracts\Driver', setting());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function single_parameter_get_a_key_from_store()
|
||||
{
|
||||
app('setting')->shouldReceive('get')->with('foo', null)->once();
|
||||
|
||||
setting('foo');
|
||||
}
|
||||
|
||||
public function two_parameters_return_a_default_value()
|
||||
{
|
||||
app('setting')->shouldReceive('get')->with('foo', 'bar')->once();
|
||||
|
||||
setting('foo', 'bar');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function array_parameter_call_set_method_into_store()
|
||||
{
|
||||
app('setting')->shouldReceive('set')->with(['foo', 'bar'])->once();
|
||||
|
||||
setting(['foo', 'bar']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
use Mockery as m;
|
||||
|
||||
class JsonDriverTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function tearDown()
|
||||
{
|
||||
m::close();
|
||||
}
|
||||
|
||||
protected function mockFilesystem()
|
||||
{
|
||||
return m::mock('Illuminate\Filesystem\Filesystem');
|
||||
}
|
||||
|
||||
protected function makeStore($files, $path = 'fakepath')
|
||||
{
|
||||
return new Akaunting\Setting\Drivers\Json($files, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function throws_exception_when_file_not_writeable()
|
||||
{
|
||||
$files = $this->mockFilesystem();
|
||||
$files->shouldReceive('exists')->once()->with('fakepath')->andReturn(true);
|
||||
$files->shouldReceive('isWritable')->once()->with('fakepath')->andReturn(false);
|
||||
$store = $this->makeStore($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function throws_exception_when_files_put_fails()
|
||||
{
|
||||
$files = $this->mockFilesystem();
|
||||
$files->shouldReceive('exists')->once()->with('fakepath')->andReturn(false);
|
||||
$files->shouldReceive('put')->once()->with('fakepath', '{}')->andReturn(false);
|
||||
$store = $this->makeStore($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @expectedException RuntimeException
|
||||
*/
|
||||
public function throws_exception_when_file_contains_invalid_json()
|
||||
{
|
||||
$files = $this->mockFilesystem();
|
||||
$files->shouldReceive('exists')->once()->with('fakepath')->andReturn(true);
|
||||
$files->shouldReceive('isWritable')->once()->with('fakepath')->andReturn(true);
|
||||
$files->shouldReceive('get')->once()->with('fakepath')->andReturn('[[!1!11]');
|
||||
|
||||
$store = $this->makeStore($files);
|
||||
$store->get('foo');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user