Completed
Pull Request — develop (#57)
by Tony
07:24
created

Settings::prepend()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 4
rs 10
cc 1
eloc 1
nc 1
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;
32
33
// adds the possibility to replace the default Config facade
34
35
class Settings implements ConfigContract
36
{
37
    /**
38
     * The tag for the cache.
39
     *
40
     * @var string
41
     */
42
    public static $cache_tag = "Settings";
43
    /**
44
     * The amount of time in minutes to store values in cache
45
     * @var int
46
     */
47
    private $cache_time;
48
49
    /**
50
     * Settings constructor.
51
     */
52
    public function __construct()
53
    {
54
        $this->cache_time = env('CACHE_LIFETIME', 60);
55
    }
56
57
    /**
58
     * Set a key value pair into the Settings store.
59
     * 
60
     * @param string $key A . separated path to this setting
61
     * @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
62
     */
63
    public function set($key, $value = null)
64
    {
65
        // Clear cache that may contain this value
66
        $path = [];
67
        foreach (explode('.', $key) as $item) {
68
            $path[] = $item;
69
            Cache::tags(self::$cache_tag)->forget(join('.', $path));
70
        }
71
72
        // save the value to the database
73
        if (is_array($value)) {
74
            foreach ($value as $k => $v) {
75
                if(!empty($key)) {
76
                    $temp = $key.'.'.$k;
77
                } else {
78
                    $temp = $k;
79
                }
80
                // repeat until value contains no arrays
81
                $this->set($temp, $v);
82
            }
83
        }
84
        else {
85
            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...
86
            Cache::tags(self::$cache_tag)->put($key, $value, $this->cache_time);
87
        }
88
89
    }
90
91
    /**
92
     * Convert a nested array of values to an array of . separated paths and values.
93
     *
94
     * @param $array array Nested array.
95
     * @param string $prefix Path to prepend to all keys.
96
     * @return array An array of path/value pairs.
97
     */
98
    private static function arrayToPath($array, $prefix = "")
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
99
    {
100
        return self::recursive_keys($array, $prefix);
101
    }
102
103
    private static function recursive_keys(array $array, $prefix = "", array $path = array())
104
    {
105
        if ($prefix != "") {
106
            $prefix = trim($prefix, '.') . '.';
107
        }
108
        $result = array();
109
        foreach ($array as $key => $val) {
110
            $currentPath = array_merge($path, array($key));
111
            if (is_array($val)) {
112
                $result = array_merge($result, self::recursive_keys($val, $prefix, $currentPath));
113
            }
114
            else {
115
                $result[$prefix . join('.', $currentPath)] = $val;
116
            }
117
        }
118
        return $result;
119
    }
120
121
    /**
122
     * Get a value from the Settings store.
123
     * 
124
     * @param string $key A full or partial . separated key.
125
     * @param null $default If the key isn't found, return this value. By default undefined keys return null.
126
     * @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.
127
     */
128
    public function get($key, $default = null)
129
    {
130
        // return value from cache or fetch it and return it
131
        return Cache::tags(self::$cache_tag)->remember($key, $this->cache_time, function () use ($key, $default) {
132
            $db_data = DbConfig::key($key)->get(['config_name', 'config_value']);
133
134
            if (count($db_data) == 1 && $db_data->first()->config_name == $key) {
135
                // return a bare value if we are getting one item
136
                return $db_data->first()->config_value;
137
            }
138
            elseif (count($db_data) >= 1) {
139
                // convert collection to an array and merge with the config fallback
140
                $result = self::collectionToArray($db_data, $key);
141
                $config = Config::get('config.' . $key, $default);
142
                if (!is_null($config) && is_array($config)) {
143
                    $result = array_replace_recursive($config, $result);
144
                }
145
                return $result;
146
            }
147
            else {
148
                // fallback to the config or return the default value
149
                return Config::get('config.' . $key, $default);
150
            }
151
152
        });
153
    }
154
155
    /**
156
     * Convert an Eloquent Collection into a nested array
157
     *
158
     * @param $data \Illuminate\Database\Eloquent\Collection The Collection.
159
     * @param string $prefix Path to prepend. Do not include trailing .
160
     * @return array The resulting nested array.
161
     */
162
    private static function collectionToArray($data, $prefix = "")
163
    {
164
        $tree = array();
165
        foreach ($data as $item) {
166
            $key = $item->config_name;
167
            if (substr($key, 0, strlen($prefix)) == $prefix) {
168
                $key = substr($key, strlen($prefix));
169
            }
170
            $parts = explode('.', trim($key, '.'));
171
172
            $temp = &$tree;
173
            foreach ($parts as $part) {
174
                $temp = &$temp[$part];
175
            }
176
            $temp = $item->config_value;
177
            unset($temp);
178
        }
179
        return $tree;
180
    }
181
182
    /**
183
     * Check if the key is defined in the Settings store.
184
     * 
185
     * @param string $key Only full paths will return true.
186
     * @return bool 
187
     */
188
    public function has($key)
189
    {
190
        return (Cache::tags(self::$cache_tag)->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...
191
    }
192
193
    /**
194
     * Forget a key.  Gets to forgotten keys will return null instead of the default.
195
     * @param $key string Only works for full paths.
196
     */
197
    public function forget($key)
198
    {
199
        // set to null to prevent falling back to Config
200
        DbConfig::key($key)->update(['config_value' => null]);
201
        Cache::tags(self::$cache_tag)->forget($key);
202
    }
203
204
    /**
205
     * Get all settings defined in the Settings store.
206
     * 
207
     * @return array A nested array of all settings.
208
     */
209
    public function all()
210
    {
211
        // no caching :(
212
        $config_settings = Config::all()['config'];
213
        $db_settings = self::collectionToArray(DbConfig::all());
214
        return array_replace_recursive($config_settings, $db_settings);
215
    }
216
217
    // ---- Local Utility functions ----
218
219
    /**
220
     * Clear the settings cache.
221
     * This should not be called normally, please consider filing a bug if you need this.
222
     */
223
    public function flush()
224
    {
225
        Cache::tags(self::$cache_tag)->flush();
226
    }
227
228
    /**
229
     * Prepend a value onto an array configuration value.
230
     *
231
     * @param  string $key
232
     * @param  mixed $value
233
     * @return void
234
     */
235
    public function prepend($key, $value)
236
    {
237
        // TODO: Implement prepend() method.
238
    }
239
240
    /**
241
     * Push a value onto an array configuration value.
242
     *
243
     * @param  string $key
244
     * @param  mixed $value
245
     * @return void
246
     */
247
    public function push($key, $value)
248
    {
249
        // TODO: Implement push() method.
250
    }
251
}
252