Skip to content

Commit

Permalink
Store config data serialized (#10651)
Browse files Browse the repository at this point in the history
* Store config data serialized
This way we can store null, booleans, and more reliably.

* Use model to get the mutated output.

* fix whitespace and unused function

* use json_encode/decode and casts
migration to transfer

* json_encode JSON_UNESCAPED_SLASHES

* Use JSON_UNESCAPED_SLASHES.  That is only relevant if you are printing into an HTML page.

* pre-encode the seed...

* filter other fields besides config_value
  • Loading branch information
murrant committed Oct 6, 2019
1 parent a2c69cd commit be04388
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 192 deletions.
115 changes: 29 additions & 86 deletions LibreNMS/Config.php
Expand Up @@ -44,7 +44,7 @@ public static function &load()
self::loadFiles();

// Make sure the database is connected
if (Eloquent::isConnected() || (function_exists('dbIsConnected') && dbIsConnected())) {
if (Eloquent::isConnected()) {
// pull in the database config settings
self::mergeDb();

Expand Down Expand Up @@ -244,39 +244,23 @@ public static function set($key, $value, $persist = false, $default = null, $des
global $config;

if ($persist) {
if (Eloquent::isConnected()) {
try {
$config_array = collect([
'config_name' => $key,
'config_value' => $value,
'config_default' => $default,
'config_descr' => $descr,
'config_group' => $group,
'config_sub_group' => $sub_group,
])->filter(function ($value) {
return !is_null($value);
})->toArray();

\App\Models\Config::updateOrCreate(['config_name' => $key], $config_array);
} catch (QueryException $e) {
// possibly table config doesn't exist yet
global $debug;
if ($debug) {
echo $e;
}
try {
\App\Models\Config::updateOrCreate(['config_name' => $key], collect([
'config_name' => $key,
'config_default' => $default,
'config_descr' => $descr,
'config_group' => $group,
'config_sub_group' => $sub_group,
])->filter(function ($value, $field) {
return !is_null($value);
})->put('config_value', $value)->toArray());
} catch (QueryException $e) {
if (class_exists(\Log::class)) {
\Log::error($e);
}
} else {
$res = dbUpdate(array('config_value' => $value), 'config', '`config_name`=?', array($key));
if (!$res && !dbFetchCell('SELECT 1 FROM `config` WHERE `config_name`=?', array($key))) {
$insert = array(
'config_name' => $key,
'config_value' => $value,
'config_default' => $default,
'config_descr' => $descr,
'config_group' => $group,
'config_sub_group' => $sub_group,
);
dbInsert($insert, 'config');
global $debug;
if ($debug) {
echo $e;
}
}
}
Expand Down Expand Up @@ -356,68 +340,27 @@ private static function mergeDb()

$db_config = [];

if (Eloquent::isConnected()) {
try {
\App\Models\Config::get(['config_name', 'config_value'])
->each(function ($item) use (&$db_config) {
array_set($db_config, $item->config_name, $item->config_value);
});
} catch (QueryException $e) {
// possibly table config doesn't exist yet
}

} else {
foreach (dbFetchRows('SELECT `config_name`,`config_value` FROM `config`') as $obj) {
self::assignArrayByPath($db_config, $obj['config_name'], $obj['config_value']);
}
try {
\App\Models\Config::get(['config_name', 'config_value'])
->each(function ($item) use (&$db_config) {
Arr::set($db_config, $item->config_name, $item->config_value);
});
} catch (QueryException $e) {
// possibly table config doesn't exist yet
}

$config = array_replace_recursive($db_config, $config);
}

/**
* Assign a value into the passed array by a path
* 'snmp.version' = 'v1' becomes $arr['snmp']['version'] = 'v1'
*
* @param array $arr the array to insert the value into, will be modified in place
* @param string $path the path to insert the value at
* @param mixed $value the value to insert, will be type cast
* @param string $separator path separator
*/
private static function assignArrayByPath(&$arr, $path, $value, $separator = '.')
{
// type cast value. Is this needed here?
if (filter_var($value, FILTER_VALIDATE_INT)) {
$value = (int)$value;
} elseif (filter_var($value, FILTER_VALIDATE_FLOAT)) {
$value = (float)$value;
} elseif (filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) !== null) {
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
}

$keys = explode($separator, $path);

// walk the array creating keys if they don't exist
foreach ($keys as $key) {
$arr = &$arr[$key];
}
// assign the variable
$arr = $value;
}

private static function loadGraphsFromDb()
{
global $config;

if (Eloquent::isConnected()) {
try {
$graph_types = GraphType::all()->toArray();
} catch (QueryException $e) {
// possibly table config doesn't exist yet
$graph_types = [];
}
} else {
$graph_types = dbFetchRows('SELECT * FROM graph_types');
try {
$graph_types = GraphType::all()->toArray();
} catch (QueryException $e) {
// possibly table config doesn't exist yet
$graph_types = [];
}

// load graph types from the database
Expand Down
25 changes: 5 additions & 20 deletions app/Models/Config.php
Expand Up @@ -45,32 +45,17 @@ class Config extends BaseModel
'config_group' => '',
'config_sub_group' => '',
];
protected $casts = [
'config_default' => 'array'
];

/**
* Get the config_value (type cast)
*
* @param string $value
* @return mixed
*/
public function getConfigValueAttribute($value)
{
if (filter_var($value, FILTER_VALIDATE_INT)) {
return (int)$value;
} elseif (filter_var($value, FILTER_VALIDATE_FLOAT)) {
return (float)$value;
} elseif (filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) !== null) {
return filter_var($value, FILTER_VALIDATE_BOOLEAN);
}

return $value;
return json_decode($value);
}

public function setConfigValueAttribute($value)
{
if (is_bool($value)) {
$this->attributes['config_value'] = $value ? 'true' : 'false';
} else {
$this->attributes['config_value'] = $value;
}
$this->attributes['config_value'] = json_encode($value, JSON_UNESCAPED_SLASHES);
}
}
49 changes: 49 additions & 0 deletions database/migrations/2019_10_03_211702_serialize_config.php
@@ -0,0 +1,49 @@
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class SerializeConfig extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::table('config')->get()->each(function ($config) {
$value = $config->config_value;

if (filter_var($value, FILTER_VALIDATE_INT)) {
$value = (int)$value;
} elseif (filter_var($value, FILTER_VALIDATE_FLOAT)) {
$value = (float)$value;
} elseif (filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) !== null) {
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
}

DB::table('config')
->where('config_id', $config->config_id)
->update(['config_value' => json_encode($value)]);
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
DB::table('config')->get()->each(function ($config) {
$value = json_decode($config->config_value);
$value = is_bool($value) ? var_export($value, true) : (string)$value;

DB::table('config')
->where('config_id', $config->config_id)
->update(['config_value' => $value]);
});
}
}

0 comments on commit be04388

Please sign in to comment.