Completed
Pull Request — develop (#57)
by Tony
06:32
created

Settings::set()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 22
rs 8.9197
cc 4
eloc 13
nc 6
nop 2
1
<?php
2
/*
3
 * Copyright (C) 2016 Tony Murray <[email protected]>
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17
/**
18
 * Settings.php
19
 *
20
 * @package    LibreNMS
21
 * @author     Tony Murray <[email protected]>
22
 * @copyright  2016 Tony Murray
23
 * @license    @license http://opensource.org/licenses/GPL-3.0 GNU Public License v3 or later
24
 */
25
namespace App;
26
27
28
use App\Models\DbConfig;
29
use Cache;
30
use Config;
31
use Illuminate\Contracts\Config\Repository as ConfigContract;  // adds the possibility to replace the default Config facade
32
33
class Settings implements ConfigContract
34
{
35
    /**
36
     * @var
37
     */
38
    private $cache_time;
39
40
    /**
41
     * Settings constructor.
42
     */
43
    public function __construct()
44
    {
45
        $this->cache_time = env('CACHE_LIFETIME', 60);
46
    }
47
48
    /**
49
     * Set a key value pair into the Settings store.
50
     * 
51
     * @param string $key A . separated path to this setting
52
     * @param array|null $value A value or an array. If value is an array it will be converted to a . separate path(s) concatinated onto the given key
53
     */
54
    public function set($key, $value = null)
55
    {
56
        // Clear caches that may contain this value
57
        $path = [];
58
        foreach (explode('.', $key) as $item) {
59
            $path[] = $item;
60
            Cache::forget(join('.', $path));
61
        }
62
63
        if (is_array($value)) {
64
            $value = self::arrayToPath($value, $key);
65
            foreach ($value as $k => $v) {
66
                DbConfig::updateOrCreate(['config_name' => $k], ['config_value' => $v]);
1 ignored issue
show
Bug introduced by
The method updateOrCreate() does not exist on App\Models\DbConfig. Did you maybe mean create()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
67
                Cache::put($k, $v, $this->cache_time);
68
            }
69
        }
70
        else {
71
            DbConfig::updateOrCreate(['config_name' => $key], ['config_value' => $value]);
1 ignored issue
show
Bug introduced by
The method updateOrCreate() does not exist on App\Models\DbConfig. Did you maybe mean create()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
72
            Cache::put($key, $value, $this->cache_time);
73
        }
74
75
    }
76
77
78
    /**
79
     * Get a value from the Settings store.
80
     * 
81
     * @param string $key A full or partial . separated key.
82
     * @param null $default If the key isn't found, return this value. By default undefined keys return null.
83
     * @return mixed If the $key is a full path, a bare value will be returned.  If it is a partial path, a nested array will be retuned.
84
     */
85
    public function get($key, $default = null)
86
    {
87
        // return value from cache or fetch it and return it
88
        return Cache::remember($key, $this->cache_time, function () use ($key, $default) {
89
            $db_data = DbConfig::key($key)->get(['config_name', 'config_value']);
90
91
            if (count($db_data) == 1 && $db_data->first()->config_name == $key) {
92
                // return a bare value if we are getting one item
93
                return $db_data->first()->config_value;
94
            }
95
            elseif (count($db_data) >= 1) {
96
                // convert collection to an array and merge with the config fallback
97
                $result = self::collectionToArray($db_data, $key);
98
                $config = Config::get('config.' . $key, $default);
99
                if (!is_null($config) && is_array($config)) {
100
                    $result = array_replace_recursive($config, $result);
101
                }
102
                return $result;
103
            }
104
            else {
105
                // fallback to the config or return the default value
106
                return Config::get('config.' . $key, $default);
107
            }
108
109
        });
110
    }
111
112
113
    /**
114
     * Check if the key is defined in the Settings store.
115
     * 
116
     * @param string $key Only full paths will return true.
117
     * @return bool 
118
     */
119
    public function has($key)
120
    {
121
        return (Cache::has($key) || Config::has($key) || DbConfig::exactKey($key)->exists());
0 ignored issues
show
Bug introduced by
The method exactKey() does not exist on App\Models\DbConfig. Did you maybe mean scopeExactKey()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
122
    }
123
124
    /**
125
     * Forget a key.  Gets to forgotten keys will return null instead of the default.
126
     * @param $key string Only works for full paths.
127
     */
128
    public function forget($key)
129
    {
130
        // set to null to prevent falling back to Config
131
        DbConfig::key($key)->update(['config_value' => null]);
132
        Cache::forget($key);
133
    }
134
135
    /**
136
     * Get all settings defined in the Settings store.
137
     * 
138
     * @return array A nested array of all settings.
139
     */
140
    public function all()
141
    {
142
        // no caching :(
143
        $config_settings = Config::all()['config'];
144
        $db_settings = self::collectionToArray(DbConfig::all());
145
        return array_replace_recursive($config_settings, $db_settings);
146
    }
147
148
    /**
149
     * Prepend a value onto an array configuration value.
150
     *
151
     * @param  string $key
152
     * @param  mixed $value
153
     * @return void
154
     */
155
    public function prepend($key, $value)
156
    {
157
        // TODO: Implement prepend() method.
158
    }
159
160
    /**
161
     * Push a value onto an array configuration value.
162
     *
163
     * @param  string $key
164
     * @param  mixed $value
165
     * @return void
166
     */
167
    public function push($key, $value)
168
    {
169
        // TODO: Implement push() method.
170
    }
171
172
    // ---- Local Utility functions ----
173
174
    /**
175
     * Convert an Eloquent Collection into a nested array
176
     *
177
     * @param $data \Illuminate\Database\Eloquent\Collection The Collection.
178
     * @param string $prefix Path to prepend. Do not include trailing .
179
     * @return array The resulting nested array.
180
     */
181
    private static function collectionToArray($data, $prefix = "")
182
    {
183
        $tree = array();
184
        foreach ($data as $item) {
185
            $key = $item->config_name;
186
            if (substr($key, 0, strlen($prefix)) == $prefix) {
187
                $key = substr($key, strlen($prefix));
188
            }
189
            $parts = explode('.', trim($key, '.'));
190
191
            $temp = &$tree;
192
            foreach ($parts as $part) {
193
                $temp = &$temp[$part];
194
            }
195
            $temp = $item->config_value;
196
            unset($temp);
197
        }
198
        return $tree;
199
    }
200
201
    /**
202
     * Convert a nested array of values to an array of . separated paths and values.
203
     *
204
     * @param $array array Nested array.
205
     * @param string $prefix Path to prepend to all keys.
206
     * @return array An array of path/value pairs.
207
     */
208
    private static function arrayToPath($array, $prefix = "")
209
    {
210
        return self::recursive_keys($array, $prefix);
211
    }
212
    private static function recursive_keys(array $array, $prefix = "", array $path = array())
213
    {
214
        if ($prefix != "") {
215
            $prefix = trim($prefix, '.') . '.';
216
        }
217
        $result = array();
218
        foreach ($array as $key => $val) {
219
            $currentPath = array_merge($path, array($key));
220
            if (is_array($val)) {
221
                $result = array_merge($result, self::recursive_keys($val, $prefix, $currentPath));
222
            }
223
            else {
224
                $result[$prefix . join('.', $currentPath)] = $val;
225
            }
226
        }
227
        return $result;
228
    }
229
}
230