1<?php
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19**/
20
21
22/**
23 * Class for override widget field used in Graph widget configuration overrides tab.
24 */
25class CWidgetFieldGraphOverride extends CWidgetField {
26
27	/**
28	 * Create widget field for Graph Override selection.
29	 *
30	 * @param string $name   Field name in form.
31	 * @param string $label  Label for the field in form.
32	 */
33	public function __construct($name, $label) {
34		parent::__construct($name, $label);
35
36		$this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR);
37		$this->setValidationRules(['type' => API_OBJECTS, 'fields' => [
38			'hosts'				=> ['type' => API_STRINGS_UTF8, 'flags' => API_REQUIRED],
39			'items'				=> ['type' => API_STRINGS_UTF8, 'flags' => API_REQUIRED],
40			'color'				=> ['type' => API_COLOR],
41			'type'				=> ['type' => API_INT32, 'in' => implode(',', [SVG_GRAPH_TYPE_LINE, SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_STAIRCASE])],
42			'width'				=> ['type' => API_INT32, 'in' => implode(',', range(0, 10))],
43			'pointsize'			=> ['type' => API_INT32, 'in' => implode(',', range(1, 10))],
44			'transparency'		=> ['type' => API_INT32, 'in' => implode(',', range(0, 10))],
45			'fill'				=> ['type' => API_INT32, 'in' => implode(',', range(0, 10))],
46			'missingdatafunc'	=> ['type' => API_INT32, 'in' => implode(',', [SVG_GRAPH_MISSING_DATA_NONE, SVG_GRAPH_MISSING_DATA_CONNECTED, SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO])],
47			'axisy'				=> ['type' => API_INT32, 'in' => implode(',', [GRAPH_YAXIS_SIDE_LEFT, GRAPH_YAXIS_SIDE_RIGHT])],
48			'timeshift'			=> ['type' => API_TIME_UNIT, 'in' => implode(':', [ZBX_MIN_TIMESHIFT, ZBX_MAX_TIMESHIFT])]
49		]]);
50		$this->setDefault([]);
51	}
52
53	/**
54	 * Set additional flags, which can be used in configuration form.
55	 *
56	 * @param int $flags
57	 *
58	 * @return $this
59	 */
60	public function setFlags($flags) {
61		parent::setFlags($flags);
62
63		if ($flags & self::FLAG_NOT_EMPTY) {
64			$strict_validation_rules = $this->getValidationRules();
65			self::setValidationRuleFlag($strict_validation_rules['fields']['hosts'], API_NOT_EMPTY);
66			self::setValidationRuleFlag($strict_validation_rules['fields']['items'], API_NOT_EMPTY);
67			self::setValidationRuleFlag($strict_validation_rules['fields']['color'], API_NOT_EMPTY);
68			self::setValidationRuleFlag($strict_validation_rules['fields']['timeshift'], API_NOT_EMPTY);
69			$this->setStrictValidationRules($strict_validation_rules);
70		}
71		else {
72			$this->setStrictValidationRules(null);
73		}
74
75		return $this;
76	}
77
78	public function setValue($value) {
79		foreach ($value as &$val) {
80			// Values received from frontend are strings. Values received from database comes as arrays.
81			// TODO: remove hack with modifying of unvalidated data.
82			if (array_key_exists('hosts', $val)) {
83				$val['hosts'] = CWidgetHelper::splitPatternIntoParts($val['hosts']);
84			}
85			if (array_key_exists('items', $val)) {
86				$val['items'] = CWidgetHelper::splitPatternIntoParts($val['items']);
87			}
88		}
89		unset($val);
90
91		$this->value = $value;
92
93		return $this;
94	}
95
96	/**
97	 * Default values filled in newly created data set or used as unspecified values.
98	 *
99	 * @return array
100	 */
101	public static function getDefaults() {
102		return [
103			'hosts' => [],
104			'items' => []
105		];
106	}
107
108	/**
109	 * Returns array of supported override options.
110	 *
111	 * @return array
112	 */
113	public static function getOverrideOptions() {
114		return ['color', 'width', 'type', 'transparency', 'fill', 'pointsize', 'missingdatafunc', 'axisy', 'timeshift'];
115	}
116
117	/**
118	 * Function makes field specific validation for values set using self::setValue().
119	 *
120	 * @param  bool $strict    Either to make a strict validation.
121	 *
122	 * @return array $errors   List of errors found during validation.
123	 */
124	public function validate($strict = false) {
125		$errors = parent::validate($strict);
126		$value = $this->getValue();
127		$label = ($this->label === null) ? $this->name : $this->label;
128
129		// Validate options.
130		if (!$errors && $strict) {
131			foreach ($value as $index => $overrides) {
132				if (!array_intersect(self::getOverrideOptions(), array_keys($overrides))) {
133					$errors[] = _s('Invalid parameter "%1$s": %2$s.', $label.'/'.($index + 1),
134						_('at least one override option must be specified')
135					);
136					break;
137				}
138			}
139		}
140
141		return $errors;
142	}
143
144	/**
145	 * Prepares array entry for widget field, ready to be passed to CDashboard API functions.
146	 * Reference is needed here to avoid array merging in CWidgetForm::fieldsToApi method. With large number of widget
147	 * fields it causes significant performance decrease.
148	 *
149	 * @param array $widget_fields   reference to Array of widget fields.
150	 */
151	public function toApi(array &$widget_fields = []) {
152		$value = $this->getValue();
153
154		foreach ($value as $index => $val) {
155			// Hosts and items fields are stored as arrays to bypass length limit.
156			foreach ($val['hosts'] as $num => $pattern_item) {
157				$widget_fields[] = [
158					'type' => ZBX_WIDGET_FIELD_TYPE_STR,
159					'name' => $this->name.'.hosts.'.$index.'.'.$num,
160					'value' => $pattern_item
161				];
162			}
163			foreach ($val['items'] as $num => $pattern_item) {
164				$widget_fields[] = [
165					'type' => ZBX_WIDGET_FIELD_TYPE_STR,
166					'name' => $this->name.'.items.'.$index.'.'.$num,
167					'value' => $pattern_item
168				];
169			}
170
171			foreach (self::getOverrideOptions() as $opt) {
172				if (array_key_exists($opt, $val)) {
173					$widget_fields[] = [
174						'type' => ($opt === 'color' || $opt === 'timeshift')
175							? ZBX_WIDGET_FIELD_TYPE_STR
176							: ZBX_WIDGET_FIELD_TYPE_INT32,
177						'name' => $this->name.'.'.$opt.'.'.$index,
178						'value' => $val[$opt]
179					];
180				}
181			}
182		}
183	}
184}
185