Visual Console Refactor: finished the color cloud model
Former-commit-id: a8a98ba44a459044e9f262d6dc062bde64743406
This commit is contained in:
parent
adc0f3c21b
commit
1f8d115130
|
@ -35,82 +35,242 @@ final class ColorCloud extends Item
|
|||
*
|
||||
* @return array Data structure representing the model.
|
||||
*
|
||||
* @overrides Item::decode.
|
||||
* @overrides Item->decode.
|
||||
*/
|
||||
protected function decode(array $data): array
|
||||
{
|
||||
$colorCloudData = parent::decode($data);
|
||||
$colorCloudData['type'] = COLOR_CLOUD;
|
||||
$colorCloudData['color'] = $this->extractColor($data);
|
||||
$colorCloudData['colorRanges'] = '';
|
||||
$decodedData = parent::decode($data);
|
||||
$decodedData['type'] = COLOR_CLOUD;
|
||||
$decodedData['label'] = null;
|
||||
$decodedData['defaultColor'] = static::extractDefaultColor($data);
|
||||
$decodedData['colorRanges'] = static::extractColorRanges($data);
|
||||
$decodedData['color'] = static::notEmptyStringOr($data['color'], null);
|
||||
|
||||
return $colorCloudData;
|
||||
return $decodedData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract a color value.
|
||||
* Extract the default color value.
|
||||
*
|
||||
* @param array $data Unknown input data structure.
|
||||
*
|
||||
* @return string
|
||||
* @return string Default color.
|
||||
* @throws \InvalidArgumentException If the default color cannot be
|
||||
* extracted.
|
||||
*/
|
||||
private function extractColor(array $data): string
|
||||
private static function extractDefaultColor(array $data): string
|
||||
{
|
||||
$color = static::notEmptyStringOr(
|
||||
static::issetInArray($data, ['color']),
|
||||
null
|
||||
);
|
||||
|
||||
if (empty($color) === true) {
|
||||
$color = static::notEmptyStringOr(
|
||||
static::issetInArray($data, ['label']),
|
||||
if (isset($data['defaultColor'])) {
|
||||
$defaultColor = static::notEmptyStringOr(
|
||||
$data['defaultColor'],
|
||||
null
|
||||
);
|
||||
|
||||
$color_decode = \json_decode($color);
|
||||
if (empty($color) === true || empty($color_decode->default_color) === true) {
|
||||
if ($defaultColor === null) {
|
||||
throw new \InvalidArgumentException(
|
||||
'the color property is required and should be string'
|
||||
'the default color property is required and should be a not empty string'
|
||||
);
|
||||
} else {
|
||||
return $color_decode->default_color;
|
||||
}
|
||||
|
||||
return $defaultColor;
|
||||
} else {
|
||||
return $color;
|
||||
$dynamicData = static::extractDynamicData($data);
|
||||
return $dynamicData['defaultColor'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract a color ranges value.
|
||||
* Extract a list of color ranges.
|
||||
*
|
||||
* @param array $data Unknown input data structure.
|
||||
*
|
||||
* @return string
|
||||
* @return array Color ranges list.
|
||||
* @throws \InvalidArgumentException If any of the color ranges is invalid.
|
||||
*/
|
||||
private function extractColorRanges(array $data): array
|
||||
private static function extractColorRanges(array $data): array
|
||||
{
|
||||
if (isset($data['colorRanges']) && \is_array($data['colorRanges'])) {
|
||||
foreach ($data['colorRanges'] as $key => $value) {
|
||||
if ((!isset($data['colorRanges'][$key]['fromValue']) || !\is_float($data['colorRanges'][$key]['fromValue']))
|
||||
|| (!isset($data['colorRanges'][$key]['toValue']) || !\is_float($data['colorRanges'][$key]['toValue']))
|
||||
|| (!isset($data['colorRanges'][$key]['color']) | !\is_string($data['colorRanges'][$key]['color']) || strlen($data['colorRanges'][$key]['color']) == 0)
|
||||
// Validate the color ranges.
|
||||
foreach ($data['colorRanges'] as $colorRange) {
|
||||
if (\is_numeric($colorRange['fromValue']) === false
|
||||
|| \is_numeric($colorRange['toValue']) === false
|
||||
|| static::notEmptyStringOr($colorRange['color'], null) === null
|
||||
) {
|
||||
throw new \InvalidArgumentException(
|
||||
'the color property is required and should be string'
|
||||
);
|
||||
throw new \InvalidArgumentException('invalid color range');
|
||||
}
|
||||
}
|
||||
|
||||
return $data['colorRanges'];
|
||||
} else if (isset($data['label']) === true) {
|
||||
$colorRanges_decode = \json_decode($data['label']);
|
||||
return $colorRanges_decode->color_ranges;
|
||||
$dynamicData = static::extractDynamicData($data);
|
||||
return $dynamicData['colorRanges'];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract a dynamic data structure from the 'label' field.
|
||||
*
|
||||
* @param array $data Unknown input data structure.
|
||||
*
|
||||
* @return array Dynamic data structure.
|
||||
* @throws \InvalidArgumentException If the structure cannot be built.
|
||||
*
|
||||
* @example [
|
||||
* 'defaultColor' => '#FFF',
|
||||
* 'colorRanges' => [
|
||||
* [
|
||||
* 'fromValue' => 50.0,
|
||||
* 'toValue' => 150.5,
|
||||
* 'color' => '#000',
|
||||
* ],
|
||||
* [
|
||||
* 'fromValue' => 200.0,
|
||||
* 'toValue' => 300.5,
|
||||
* 'color' => '#F0F0F0',
|
||||
* ],
|
||||
* ]
|
||||
* ]
|
||||
*/
|
||||
private static function extractDynamicData(array $data): array
|
||||
{
|
||||
$dynamicDataEncoded = static::notEmptyStringOr($data['label'], null);
|
||||
|
||||
if ($dynamicDataEncoded === null) {
|
||||
throw new \InvalidArgumentException('dynamic data not found');
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
try {
|
||||
$dynamicData = \json_decode(
|
||||
\base64_decode($dynamicDataEncoded),
|
||||
true
|
||||
);
|
||||
|
||||
$result['defaultColor'] = $dynamicData['default_color'];
|
||||
$result['colorRanges'] = [];
|
||||
|
||||
if (\is_array($dynamicData['color_ranges']) === true) {
|
||||
foreach ($dynamicData['color_ranges'] as $colorRange) {
|
||||
if (\is_numeric($colorRange['from_value']) === true
|
||||
&& \is_numeric($colorRange['to_value']) === true
|
||||
&& static::notEmptyStringOr(
|
||||
$colorRange['color'],
|
||||
null
|
||||
) !== null
|
||||
) {
|
||||
$result['colorRanges'][] = [
|
||||
'color' => $colorRange['color'],
|
||||
'fromValue' => (float) $colorRange['from_value'],
|
||||
'toValue' => (float) $colorRange['to_value'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new \InvalidArgumentException('invalid dynamic data');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch a vc item data structure from the database using a filter.
|
||||
*
|
||||
* @param array $filter Filter of the Visual Console Item.
|
||||
*
|
||||
* @return array The Visual Console Item data structure stored into the DB.
|
||||
* @throws \InvalidArgumentException When an agent Id cannot be found.
|
||||
*
|
||||
* @override Item::fetchDataFromDB.
|
||||
*/
|
||||
protected static function fetchDataFromDB(array $filter): array
|
||||
{
|
||||
// Due to this DB call, this function cannot be unit tested without
|
||||
// a proper mock.
|
||||
$data = parent::fetchDataFromDB($filter);
|
||||
|
||||
/*
|
||||
* Retrieve extra data.
|
||||
*/
|
||||
|
||||
// Load side libraries.
|
||||
global $config;
|
||||
include_once $config['homedir'].'/include/functions_graph.php';
|
||||
include_once $config['homedir'].'/include/functions_modules.php';
|
||||
|
||||
// Get the linked module Id.
|
||||
$linkedModule = static::extractLinkedModule($data);
|
||||
$moduleId = static::parseIntOr($linkedModule['moduleId'], null);
|
||||
$metaconsoleId = static::parseIntOr(
|
||||
$linkedModule['metaconsoleId'],
|
||||
null
|
||||
);
|
||||
|
||||
if ($moduleId === null) {
|
||||
throw new \InvalidArgumentException('missing module Id');
|
||||
}
|
||||
|
||||
$dynamicData = static::extractDynamicData($data);
|
||||
// Set the initial color.
|
||||
$data['color'] = $dynamicData['defaultColor'];
|
||||
|
||||
// Search for a matching color range.
|
||||
if (empty($dynamicData['colorRanges']) === false) {
|
||||
// Connect to node.
|
||||
$nodeConnected = false;
|
||||
if (is_metaconsole() === true && $metaconsoleId !== null) {
|
||||
$nodeConnected = metaconsole_connect(
|
||||
null,
|
||||
$metaconsoleId
|
||||
) === NOERR;
|
||||
}
|
||||
|
||||
// Fetch module value.
|
||||
$value = false;
|
||||
if ($metaconsoleId === null
|
||||
|| ($metaconsoleId !== null && $nodeConnected)
|
||||
) {
|
||||
$value = modules_get_last_value($moduleId);
|
||||
}
|
||||
|
||||
// Restore connection.
|
||||
if ($nodeConnected === true) {
|
||||
metaconsole_restore_db();
|
||||
}
|
||||
|
||||
// Value found.
|
||||
if ($value !== false) {
|
||||
/*
|
||||
* TODO: It would be ok to give support to string values in the
|
||||
* future?
|
||||
*
|
||||
* It can be done by matching the range value with the value
|
||||
* if it is a string. I think the function to retrieve the value
|
||||
* only supports numeric values.
|
||||
*/
|
||||
|
||||
$value = (float) $value;
|
||||
foreach ($dynamicData['colorRanges'] as $colorRange) {
|
||||
if ($colorRange['fromValue'] <= $value
|
||||
&& $colorRange['toValue'] >= $value
|
||||
) {
|
||||
// Range matched. Use the range color.
|
||||
$data['color'] = $colorRange['color'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Models\VisualConsole\Items\ColorCloud;
|
||||
|
||||
/**
|
||||
* Test for the Visual Console color cloud item model.
|
||||
*/
|
||||
class ColorCloudTest extends TestCase
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Test if the instance is created using a valid data structure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCanBeCreatedFromValidUserStructure(): void
|
||||
{
|
||||
$this->assertInstanceOf(
|
||||
ColorCloud::class,
|
||||
ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 345,
|
||||
'type' => COLOR_CLOUD,
|
||||
'label' => null,
|
||||
'isLinkEnabled' => true,
|
||||
'isOnTop' => false,
|
||||
'parentId' => null,
|
||||
'width' => '0',
|
||||
'height' => '0',
|
||||
'x' => -666,
|
||||
'y' => 76,
|
||||
'defaultColor' => '#FFF',
|
||||
'colorRanges' => [],
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
ColorCloud::class,
|
||||
ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 1000,
|
||||
'type' => COLOR_CLOUD,
|
||||
'width' => 100,
|
||||
'height' => 900,
|
||||
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
|
||||
'colorRanges' => [
|
||||
[
|
||||
'color' => '#000',
|
||||
'fromValue' => 10.05,
|
||||
'toValue' => 100.0,
|
||||
],
|
||||
],
|
||||
'color' => '#000',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
ColorCloud::class,
|
||||
ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 1000,
|
||||
'type' => COLOR_CLOUD,
|
||||
'width' => 100,
|
||||
'height' => 900,
|
||||
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if the model has a valid JSON representation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testContainerIsRepresentedAsJson(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
|
||||
(string) ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 7,
|
||||
'type' => COLOR_CLOUD,
|
||||
'label' => null,
|
||||
'labelPosition' => 'up',
|
||||
'isLinkEnabled' => true,
|
||||
'isOnTop' => false,
|
||||
'parentId' => null,
|
||||
'width' => '0',
|
||||
'height' => '0',
|
||||
'x' => -666,
|
||||
'y' => 76,
|
||||
'defaultColor' => '#FFF',
|
||||
'colorRanges' => [
|
||||
[
|
||||
'color' => '#000',
|
||||
'fromValue' => 10.05,
|
||||
'toValue' => 100.0,
|
||||
],
|
||||
],
|
||||
'color' => '#000',
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"colorRanges":[],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
|
||||
(string) ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 7,
|
||||
'type' => COLOR_CLOUD,
|
||||
'label' => null,
|
||||
'labelPosition' => 'up',
|
||||
'isLinkEnabled' => true,
|
||||
'isOnTop' => false,
|
||||
'parentId' => null,
|
||||
'width' => '0',
|
||||
'height' => '0',
|
||||
'x' => -666,
|
||||
'y' => 76,
|
||||
'defaultColor' => '#FFF',
|
||||
'colorRanges' => [],
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
|
||||
(string) ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 7,
|
||||
'type' => COLOR_CLOUD,
|
||||
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
|
||||
'labelPosition' => 'up',
|
||||
'isLinkEnabled' => true,
|
||||
'isOnTop' => false,
|
||||
'parentId' => null,
|
||||
'width' => '0',
|
||||
'height' => '0',
|
||||
'x' => -666,
|
||||
'y' => 76,
|
||||
'color' => '#000',
|
||||
'id_metaconsole' => 5,
|
||||
'linked_layout_node_id' => 3,
|
||||
'linkedLayoutId' => 2,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
|
||||
(string) ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 7,
|
||||
'type' => COLOR_CLOUD,
|
||||
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
|
||||
'labelPosition' => 'up',
|
||||
'isLinkEnabled' => true,
|
||||
'isOnTop' => false,
|
||||
'parentId' => null,
|
||||
'width' => '0',
|
||||
'height' => '0',
|
||||
'x' => -666,
|
||||
'y' => 76,
|
||||
'defaultColor' => '#FFF',
|
||||
'color' => '#000',
|
||||
'id_layout_linked' => 1,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
|
||||
(string) ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 7,
|
||||
'type' => COLOR_CLOUD,
|
||||
'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
|
||||
'labelPosition' => 'up',
|
||||
'isLinkEnabled' => true,
|
||||
'isOnTop' => false,
|
||||
'parentId' => null,
|
||||
'width' => '0',
|
||||
'height' => '0',
|
||||
'x' => -666,
|
||||
'y' => 76,
|
||||
'colorRanges' => [
|
||||
[
|
||||
'color' => '#000',
|
||||
'fromValue' => 10.05,
|
||||
'toValue' => 100.0,
|
||||
],
|
||||
],
|
||||
'color' => '#000',
|
||||
'linkedLayoutId' => 2,
|
||||
'linked_layout_status_type' => 'service',
|
||||
'linkedLayoutStatusTypeWarningThreshold' => 50,
|
||||
'linked_layout_status_as_service_critical' => 80,
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if the instance is not created when using a invalid dynamic data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCannotBeCreatedWithInvalidDynamicData(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
// Invalid dynamic data.
|
||||
ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 3,
|
||||
'type' => COLOR_CLOUD,
|
||||
'label' => null,
|
||||
'isLinkEnabled' => true,
|
||||
'isOnTop' => false,
|
||||
'parentId' => null,
|
||||
'width' => '330',
|
||||
'height' => '0',
|
||||
'x' => 511,
|
||||
'y' => 76,
|
||||
]
|
||||
);
|
||||
// Missing dynamic data.
|
||||
ColorCloud::fromArray(
|
||||
[
|
||||
'id' => 3,
|
||||
'type' => COLOR_CLOUD,
|
||||
'label' => null,
|
||||
'isLinkEnabled' => true,
|
||||
'isOnTop' => false,
|
||||
'parentId' => null,
|
||||
'width' => '330',
|
||||
'height' => '0',
|
||||
'x' => 511,
|
||||
'y' => 76,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue