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 containing methods for operations with map elements. 24 * 25 * @return mixed 26 */ 27abstract class CMapElement extends CApiService { 28 29 protected function checkSelementInput(&$selements, $method) { 30 $create = ($method === 'createSelements'); 31 $update = ($method === 'updateSelements'); 32 33 $element_types = [SYSMAP_ELEMENT_TYPE_HOST, SYSMAP_ELEMENT_TYPE_MAP, SYSMAP_ELEMENT_TYPE_TRIGGER, 34 SYSMAP_ELEMENT_TYPE_HOST_GROUP, SYSMAP_ELEMENT_TYPE_IMAGE 35 ]; 36 37 $elementtype_validator = new CLimitedSetValidator(['values' => $element_types]); 38 39 if ($update) { 40 $db_selements = $this->fetchSelementsByIds(zbx_objectValues($selements, 'selementid')); 41 $selements = $this->extendFromObjects(zbx_toHash($selements, 'selementid'), $db_selements, ['elementtype', 'elements']); 42 } 43 44 foreach ($selements as &$selement) { 45 if (!is_array($selement)) { 46 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); 47 } 48 49 if ($create) { 50 // Check required parameters. 51 $missing_keys = array_diff(['sysmapid', 'elementtype', 'iconid_off'], array_keys($selement)); 52 53 if ($missing_keys) { 54 self::exception(ZBX_API_ERROR_PARAMETERS, 55 _s('Map element is missing parameters: %1$s', implode(', ', $missing_keys)) 56 ); 57 } 58 } 59 60 if (array_key_exists('urls', $selement)) { 61 $url_validate_options = ['allow_user_macro' => false]; 62 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST) { 63 $url_validate_options['allow_inventory_macro'] = INVENTORY_URL_MACRO_HOST; 64 } 65 elseif ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 66 $url_validate_options['allow_inventory_macro'] = INVENTORY_URL_MACRO_TRIGGER; 67 } 68 else { 69 $url_validate_options['allow_inventory_macro'] = INVENTORY_URL_MACRO_NONE; 70 } 71 72 foreach ($selement['urls'] as $url_data) { 73 if (!CHtmlUrlValidator::validate($url_data['url'], $url_validate_options)) { 74 self::exception(ZBX_API_ERROR_PARAMETERS, _('Wrong value for url field.')); 75 } 76 } 77 } 78 79 if ($update && array_key_exists('selementid', $selement) 80 && array_key_exists($selement['selementid'], $db_selements)) { 81 $db_selement = $db_selements[$selement['selementid']]; 82 } 83 84 if (!$elementtype_validator->validate($selement['elementtype'])) { 85 self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect value for field "%1$s": %2$s.', 86 'elementtype', _s('value must be one of %1$s', implode(', ', $element_types)) 87 )); 88 } 89 90 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_IMAGE) { 91 unset($selement['elements']); 92 } 93 else { 94 if (!array_key_exists('elements', $selement)) { 95 self::exception(ZBX_API_ERROR_PARAMETERS, 96 _s('Map element is missing parameters: %1$s', 'elements') 97 ); 98 } 99 100 if (!is_array($selement['elements'])) { 101 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); 102 } 103 104 if (!$selement['elements']) { 105 self::exception(ZBX_API_ERROR_PARAMETERS, 106 _s('Incorrect value for field "%1$s": %2$s.', 'elements', _('cannot be empty')) 107 ); 108 } 109 } 110 111 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 112 foreach ($selement['elements'] as $element) { 113 if (!array_key_exists('triggerid', $element)) { 114 self::exception(ZBX_API_ERROR_PARAMETERS, 115 _s('Map element is missing parameters: %1$s', 'triggerid') 116 ); 117 } 118 119 if (is_array($element['triggerid'])) { 120 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); 121 } 122 elseif ($element['triggerid'] === '' || $element['triggerid'] === null 123 || $element['triggerid'] === false) { 124 self::exception(ZBX_API_ERROR_PARAMETERS, 125 _s('Incorrect value for field "%1$s": %2$s.', 'triggerid', _('cannot be empty')) 126 ); 127 } 128 } 129 } 130 else { 131 if (array_key_exists('elements', $selement)) { 132 switch ($selement['elementtype']) { 133 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 134 $field = 'groupid'; 135 break; 136 137 case SYSMAP_ELEMENT_TYPE_HOST: 138 $field = 'hostid'; 139 break; 140 141 case SYSMAP_ELEMENT_TYPE_MAP: 142 $field = 'sysmapid'; 143 break; 144 } 145 146 $elements = reset($selement['elements']); 147 148 if (!is_array($elements)) { 149 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); 150 } 151 152 if (!array_key_exists($field, $elements)) { 153 self::exception(ZBX_API_ERROR_PARAMETERS, 154 _s('Map element is missing parameters: %1$s', $field) 155 ); 156 } 157 158 if (is_array($elements[$field])) { 159 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); 160 } 161 elseif ($elements[$field] === '' || $elements[$field] === null || $elements[$field] === false) { 162 self::exception(ZBX_API_ERROR_PARAMETERS, 163 _s('Incorrect value for field "%1$s": %2$s.', $field, _('cannot be empty')) 164 ); 165 } 166 167 if (count($selement['elements']) > 1) { 168 self::exception(ZBX_API_ERROR_PARAMETERS, 169 _s('Incorrect value for field "%1$s": %2$s.', 'elements', _('incorrect element count')) 170 ); 171 } 172 } 173 } 174 175 if (isset($selement['iconid_off']) && $selement['iconid_off'] == 0) { 176 self::exception(ZBX_API_ERROR_PARAMETERS, _s('No icon for map element ""%1$s".', 177 array_key_exists('label', $selement) ? $selement['label'] : '' 178 )); 179 } 180 181 if ($create) { 182 $selement['urls'] = array_key_exists('urls', $selement) ? $selement['urls'] : []; 183 } 184 } 185 unset($selement); 186 187 // check permissions to used objects 188 if (!CMapHelper::checkSelementPermissions($selements)) { 189 self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); 190 } 191 192 return $update ? $db_selements : true; 193 } 194 195 /** 196 * Checks that shape color attributes are valid. 197 * 198 * @throws APIException if input is invalid. 199 * 200 * @param array $shapes An array of shapes. 201 */ 202 protected function checkShapeInput($shapes) { 203 $color_validator = new CColorValidator(); 204 $fields = ['border_color', 'background_color', 'font_color']; 205 206 foreach ($shapes as $shape) { 207 foreach ($fields as $field) { 208 if (array_key_exists($field, $shape) && $shape[$field] !== '' 209 && !$color_validator->validate($shape[$field])) { 210 self::exception(ZBX_API_ERROR_PARAMETERS, $color_validator->getError()); 211 } 212 } 213 } 214 } 215 216 /** 217 * Returns a hash of map elements with the given IDs. The result also includes URL assigned to the elements. 218 * 219 * @param array $selementIds 220 * 221 * @return array 222 */ 223 protected function fetchSelementsByIds(array $selementIds) { 224 $selements = API::getApiService()->select('sysmaps_elements', [ 225 'output' => API_OUTPUT_EXTEND, 226 'filter' => ['selementid' => $selementIds], 227 'preservekeys' => true 228 ]); 229 230 if ($selements) { 231 foreach ($selements as &$selement) { 232 $selement['urls'] = []; 233 $selement['elements'] = []; 234 } 235 unset($selement); 236 237 $selementUrls = API::getApiService()->select('sysmap_element_url', [ 238 'output' => API_OUTPUT_EXTEND, 239 'filter' => ['selementid' => $selementIds] 240 ]); 241 foreach ($selementUrls as $selementUrl) { 242 $selements[$selementUrl['selementid']]['urls'][] = $selementUrl; 243 } 244 245 $selement_triggers = API::getApiService()->select('sysmap_element_trigger', [ 246 'output' => ['selement_triggerid', 'selementid', 'triggerid'], 247 'filter' => ['selementid' => $selementIds] 248 ]); 249 250 foreach ($selement_triggers as $selement_trigger) { 251 $selements[$selement_trigger['selementid']]['elements'][] = [ 252 'selement_triggerid' => $selement_trigger['selement_triggerid'], 253 'triggerid' => $selement_trigger['triggerid'] 254 ]; 255 } 256 257 $single_element_types = [SYSMAP_ELEMENT_TYPE_HOST, SYSMAP_ELEMENT_TYPE_MAP, SYSMAP_ELEMENT_TYPE_HOST_GROUP]; 258 foreach ($selements as &$selement) { 259 if (in_array($selement['elementtype'], $single_element_types)) { 260 switch ($selement['elementtype']) { 261 case SYSMAP_ELEMENT_TYPE_HOST_GROUP: 262 $field = 'groupid'; 263 break; 264 265 case SYSMAP_ELEMENT_TYPE_HOST: 266 $field = 'hostid'; 267 break; 268 269 case SYSMAP_ELEMENT_TYPE_MAP: 270 $field = 'sysmapid'; 271 break; 272 } 273 $selement['elements'][] = [$field => $selement['elementid']]; 274 } 275 276 unset($selement['elementid']); 277 } 278 unset($selement); 279 } 280 281 return $selements; 282 } 283 284 protected function checkLinkInput($links, $method) { 285 $update = ($method == 'updateLink'); 286 $delete = ($method == 'deleteLink'); 287 288 // permissions 289 if ($update || $delete) { 290 $linkDbFields = ['linkid' => null]; 291 292 $dbLinks = API::getApiService()->select('sysmap_element_url', [ 293 'filter' => ['selementid' => zbx_objectValues($links, 'linkid')], 294 'output' => ['linkid'], 295 'preservekeys' => true 296 ]); 297 } 298 else { 299 $linkDbFields = [ 300 'sysmapid' => null, 301 'selementid1' => null, 302 'selementid2' => null 303 ]; 304 } 305 306 $colorValidator = new CColorValidator(); 307 308 foreach ($links as $link) { 309 if (!check_db_fields($linkDbFields, $link)) { 310 self::exception(ZBX_API_ERROR_PARAMETERS, _('Wrong fields for map link.')); 311 } 312 313 if (isset($link['color']) && !$colorValidator->validate($link['color'])) { 314 self::exception(ZBX_API_ERROR_PARAMETERS, $colorValidator->getError()); 315 } 316 317 if ($update || $delete) { 318 if (!isset($dbLinks[$link['linkid']])) { 319 self::exception(ZBX_API_ERROR_PARAMETERS, _('No permissions to referred object or it does not exist!')); 320 } 321 } 322 } 323 324 return true; 325 } 326 327 /** 328 * Add element to sysmap. 329 * 330 * @param array $elements[0,...]['sysmapid'] 331 * @param array $elements[0,...]['elementid'] 332 * @param array $elements[0,...]['elementtype'] 333 * @param array $elements[0,...]['label'] 334 * @param array $elements[0,...]['x'] 335 * @param array $elements[0,...]['y'] 336 * @param array $elements[0,...]['iconid_off'] 337 * @param array $elements[0,...]['iconid_on'] 338 * @param array $elements[0,...]['iconid_disabled'] 339 * @param array $elements[0,...]['urls'][0,...] 340 * @param array $elements[0,...]['label_location'] 341 * 342 * @return array 343 */ 344 protected function createSelements(array $selements) { 345 $selements = zbx_toArray($selements); 346 347 $this->checkSelementInput($selements, __FUNCTION__); 348 349 $single_element_types = [SYSMAP_ELEMENT_TYPE_HOST, SYSMAP_ELEMENT_TYPE_MAP, SYSMAP_ELEMENT_TYPE_HOST_GROUP]; 350 foreach ($selements as &$selement) { 351 if (in_array($selement['elementtype'], $single_element_types)) { 352 $selement['elementid'] = reset($selement['elements'][0]); 353 } 354 elseif ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 355 unset($selement['elementid']); 356 } 357 } 358 unset($selement); 359 360 $selementids = DB::insert('sysmaps_elements', $selements); 361 362 $triggerids = []; 363 364 foreach ($selementids as $key => $selementid) { 365 if ($selements[$key]['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 366 foreach ($selements[$key]['elements'] as $element) { 367 $triggerids[$element['triggerid']] = true; 368 } 369 } 370 } 371 372 $db_triggers = API::Trigger()->get([ 373 'output' => ['triggerid', 'priority'], 374 'triggerids' => array_keys($triggerids), 375 'preservekeys' => true 376 ]); 377 378 $triggers = []; 379 380 foreach ($selementids as $key => $selementid) { 381 if ($selements[$key]['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 382 foreach ($selements[$key]['elements'] as $element) { 383 $priority = $db_triggers[$element['triggerid']]['priority']; 384 $triggers[$selementid][$priority][] = [ 385 'selementid' => $selementid, 386 'triggerid' => $element['triggerid'] 387 ]; 388 } 389 krsort($triggers[$selementid]); 390 } 391 } 392 393 $triggers_to_add = []; 394 395 foreach ($triggers as $selement_triggers) { 396 foreach ($selement_triggers as $selement_trigger_priorities) { 397 foreach ($selement_trigger_priorities as $selement_trigger_priority) { 398 $triggers_to_add[] = $selement_trigger_priority; 399 } 400 } 401 } 402 403 DB::insert('sysmap_element_trigger', $triggers_to_add); 404 405 $insertUrls = []; 406 407 foreach ($selementids as $key => $selementid) { 408 foreach ($selements[$key]['urls'] as $url) { 409 $url['selementid'] = $selementid; 410 411 $insertUrls[] = $url; 412 } 413 } 414 415 DB::insert('sysmap_element_url', $insertUrls); 416 417 $this->createSelementsTags($selements, $selementids); 418 419 return ['selementids' => $selementids]; 420 } 421 422 /** 423 * Update element to sysmap. 424 * 425 * @param array $elements[0,...]['selementid'] 426 * @param array $elements[0,...]['sysmapid'] 427 * @param array $elements[0,...]['elementid'] 428 * @param array $elements[0,...]['elementtype'] 429 * @param array $elements[0,...]['label'] 430 * @param array $elements[0,...]['x'] 431 * @param array $elements[0,...]['y'] 432 * @param array $elements[0,...]['iconid_off'] 433 * @param array $elements[0,...]['iconid_on'] 434 * @param array $elements[0,...]['iconid_disabled'] 435 * @param array $elements[0,...]['url'] 436 * @param array $elements[0,...]['label_location'] 437 */ 438 protected function updateSelements(array $selements) { 439 $selements = zbx_toArray($selements); 440 $selementIds = []; 441 442 $db_selements = $this->checkSelementInput($selements, __FUNCTION__); 443 444 $update = []; 445 $urlsToDelete = []; 446 $urlsToUpdate = []; 447 $urlsToAdd = []; 448 $triggers_to_add = []; 449 $triggers_to_delete = []; 450 $triggerids = []; 451 452 foreach ($selements as &$selement) { 453 $db_selement = $db_selements[$selement['selementid']]; 454 455 // Change type from something to trigger. 456 if ($selement['elementtype'] != $db_selement['elementtype'] 457 && $selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 458 $selement['elementid'] = 0; 459 460 foreach ($selement['elements'] as $element) { 461 $triggerids[$element['triggerid']] = true; 462 } 463 } 464 465 // Change type from trigger to something. 466 if ($selement['elementtype'] != $db_selement['elementtype'] 467 && $db_selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 468 foreach ($db_selement['elements'] as $db_element) { 469 $triggers_to_delete[] = $db_element['selement_triggerid']; 470 } 471 } 472 473 if ($selement['elementtype'] != SYSMAP_ELEMENT_TYPE_IMAGE 474 && $selement['elementtype'] != SYSMAP_ELEMENT_TYPE_TRIGGER) { 475 $selement['elementid'] = reset($selement['elements'][0]); 476 } 477 478 $db_elements = $db_selement['elements']; 479 480 foreach ($db_selement['elements'] as &$element) { 481 unset($element['selement_triggerid']); 482 } 483 unset($element); 484 485 if ($selement['elementtype'] == $db_selement['elementtype'] 486 && $selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 487 foreach ($db_elements as $element) { 488 $triggers_to_delete[] = $element['selement_triggerid']; 489 } 490 491 foreach ($selement['elements'] as $element) { 492 $triggerids[$element['triggerid']] = true; 493 } 494 } 495 496 $update[] = [ 497 'values' => $selement, 498 'where' => ['selementid' => $selement['selementid']] 499 ]; 500 $selementIds[] = $selement['selementid']; 501 502 if (!isset($selement['urls'])) { 503 continue; 504 } 505 506 $diffUrls = zbx_array_diff($selement['urls'], $db_selement['urls'], 'name'); 507 508 // add 509 foreach ($diffUrls['first'] as $newUrl) { 510 $newUrl['selementid'] = $selement['selementid']; 511 $urlsToAdd[] = $newUrl; 512 } 513 514 // update url 515 foreach ($diffUrls['both'] as $updUrl) { 516 $urlsToUpdate[] = [ 517 'values' => $updUrl, 518 'where' => [ 519 'selementid' => $selement['selementid'], 520 'name' => $updUrl['name'] 521 ] 522 ]; 523 } 524 525 // delete url 526 $urlsToDelete = array_merge($urlsToDelete, zbx_objectValues($diffUrls['second'], 'sysmapelementurlid')); 527 } 528 unset($selement); 529 530 $this->updateElementsTags($selements); 531 532 $db_triggers = API::Trigger()->get([ 533 'output' => ['triggerid', 'priority'], 534 'triggerids' => array_keys($triggerids), 535 'preservekeys' => true 536 ]); 537 538 $triggers = []; 539 540 foreach ($selements as $key => $selement) { 541 if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) { 542 $selementid = $selement['selementid']; 543 544 foreach ($selement['elements'] as $element) { 545 $priority = $db_triggers[$element['triggerid']]['priority']; 546 $triggers[$selementid][$priority][] = [ 547 'selementid' => $selementid, 548 'triggerid' => $element['triggerid'] 549 ]; 550 } 551 krsort($triggers[$selementid]); 552 } 553 } 554 555 $triggers_to_add = []; 556 557 foreach ($triggers as $selement_triggers) { 558 foreach ($selement_triggers as $selement_trigger_priorities) { 559 foreach ($selement_trigger_priorities as $selement_trigger_priority) { 560 $triggers_to_add[] = $selement_trigger_priority; 561 } 562 } 563 } 564 565 DB::update('sysmaps_elements', $update); 566 567 if (!empty($urlsToDelete)) { 568 DB::delete('sysmap_element_url', ['sysmapelementurlid' => $urlsToDelete]); 569 } 570 571 if (!empty($urlsToUpdate)) { 572 DB::update('sysmap_element_url', $urlsToUpdate); 573 } 574 575 if (!empty($urlsToAdd)) { 576 DB::insert('sysmap_element_url', $urlsToAdd); 577 } 578 579 if ($triggers_to_delete) { 580 DB::delete('sysmap_element_trigger', ['selement_triggerid' => $triggers_to_delete]); 581 } 582 583 if ($triggers_to_add) { 584 DB::insert('sysmap_element_trigger', $triggers_to_add); 585 } 586 587 return ['selementids' => $selementIds]; 588 } 589 590 /** 591 * Delete element from map. 592 * 593 * @param array $selements multidimensional array with selement objects 594 * @param array $selements[0, ...]['selementid'] selementid to delete 595 */ 596 protected function deleteSelements(array $selements) { 597 $selements = zbx_toArray($selements); 598 $selementIds = zbx_objectValues($selements, 'selementid'); 599 600 DB::delete('sysmaps_elements', ['selementid' => $selementIds]); 601 602 return $selementIds; 603 } 604 605 /** 606 * Add shape to sysmap. 607 * 608 * @param array $shapes Multidimensional array with shape properties. 609 */ 610 protected function createShapes(array $shapes) { 611 $shapes = zbx_toArray($shapes); 612 613 $this->checkShapeInput($shapes); 614 615 DB::insert('sysmap_shape', $shapes); 616 } 617 618 /** 619 * Update shapes to sysmap. 620 * 621 * @param array $shapes Multidimensional array with shape properties. 622 */ 623 protected function updateShapes(array $shapes) { 624 $shapes = zbx_toArray($shapes); 625 626 $this->checkShapeInput($shapes); 627 628 $update = []; 629 foreach ($shapes as $shape) { 630 $shapeid = $shape['sysmap_shapeid']; 631 unset($shape['sysmap_shapeid']); 632 633 if ($shape) { 634 $update[] = [ 635 'values' => $shape, 636 'where' => ['sysmap_shapeid' => $shapeid] 637 ]; 638 } 639 } 640 641 DB::update('sysmap_shape', $update); 642 } 643 644 /** 645 * Delete shapes from map. 646 * 647 * @param array $shapes Multidimensional array with shape properties. 648 */ 649 protected function deleteShapes(array $shapes) { 650 $shapes = zbx_toArray($shapes); 651 $shapeids = zbx_objectValues($shapes, 'sysmap_shapeid'); 652 653 DB::delete('sysmap_shape', ['sysmap_shapeid' => $shapeids]); 654 } 655 656 /** 657 * Create link. 658 * 659 * @param array $links 660 * @param array $links[0,...]['sysmapid'] 661 * @param array $links[0,...]['selementid1'] 662 * @param array $links[0,...]['selementid2'] 663 * @param array $links[0,...]['drawtype'] 664 * @param array $links[0,...]['color'] 665 * 666 * @return array 667 */ 668 protected function createLinks(array $links) { 669 $links = zbx_toArray($links); 670 671 $this->checkLinkInput($links, __FUNCTION__); 672 673 $linkIds = DB::insert('sysmaps_links', $links); 674 675 return ['linkids' => $linkIds]; 676 } 677 678 protected function updateLinks($links) { 679 $links = zbx_toArray($links); 680 681 $this->checkLinkInput($links, __FUNCTION__); 682 683 $udpateLinks = []; 684 foreach ($links as $link) { 685 $udpateLinks[] = ['values' => $link, 'where' => ['linkid' => $link['linkid']]]; 686 } 687 688 DB::update('sysmaps_links', $udpateLinks); 689 690 return ['linkids' => zbx_objectValues($links, 'linkid')]; 691 } 692 693 /** 694 * Delete Link from map. 695 * 696 * @param array $links multidimensional array with link objects 697 * @param array $links[0, ...]['linkid'] link ID to delete 698 * 699 * @return array 700 */ 701 protected function deleteLinks($links) { 702 zbx_value2array($links); 703 $linkIds = zbx_objectValues($links, 'linkid'); 704 705 $this->checkLinkInput($links, __FUNCTION__); 706 707 DB::delete('sysmaps_links', ['linkid' => $linkIds]); 708 709 return ['linkids' => $linkIds]; 710 } 711 712 /** 713 * Add link trigger to link (sysmap). 714 * 715 * @param array $links[0,...]['linkid'] 716 * @param array $links[0,...]['triggerid'] 717 * @param array $links[0,...]['drawtype'] 718 * @param array $links[0,...]['color'] 719 */ 720 protected function createLinkTriggers($linkTriggers) { 721 $linkTriggers = zbx_toArray($linkTriggers); 722 723 $this->validateCreateLinkTriggers($linkTriggers); 724 725 $linkTriggerIds = DB::insert('sysmaps_link_triggers', $linkTriggers); 726 727 return ['linktriggerids' => $linkTriggerIds]; 728 } 729 730 protected function validateCreateLinkTriggers(array $linkTriggers) { 731 $linkTriggerDbFields = [ 732 'linkid' => null, 733 'triggerid' => null 734 ]; 735 736 $colorValidator = new CColorValidator(); 737 738 foreach ($linkTriggers as $linkTrigger) { 739 if (!check_db_fields($linkTriggerDbFields, $linkTrigger)) { 740 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); 741 } 742 743 if (isset($linkTrigger['color']) && !$colorValidator->validate($linkTrigger['color'])) { 744 self::exception(ZBX_API_ERROR_PARAMETERS, $colorValidator->getError()); 745 } 746 } 747 } 748 749 protected function updateLinkTriggers($linkTriggers) { 750 $linkTriggers = zbx_toArray($linkTriggers); 751 $this->validateUpdateLinkTriggers($linkTriggers); 752 753 $linkTriggerIds = zbx_objectValues($linkTriggers, 'linktriggerid'); 754 755 $updateLinkTriggers = []; 756 foreach ($linkTriggers as $linkTrigger) { 757 $updateLinkTriggers[] = [ 758 'values' => $linkTrigger, 759 'where' => ['linktriggerid' => $linkTrigger['linktriggerid']] 760 ]; 761 } 762 763 DB::update('sysmaps_link_triggers', $updateLinkTriggers); 764 765 return ['linktriggerids' => $linkTriggerIds]; 766 } 767 768 protected function validateUpdateLinkTriggers(array $linkTriggers) { 769 $linkTriggerDbFields = ['linktriggerid' => null]; 770 771 $colorValidator = new CColorValidator(); 772 773 foreach ($linkTriggers as $linkTrigger) { 774 if (!check_db_fields($linkTriggerDbFields, $linkTrigger)) { 775 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); 776 } 777 778 if (isset($linkTrigger['color']) && !$colorValidator->validate($linkTrigger['color'])) { 779 self::exception(ZBX_API_ERROR_PARAMETERS, $colorValidator->getError()); 780 } 781 } 782 } 783 784 protected function deleteLinkTriggers($linkTriggers) { 785 $linkTriggers = zbx_toArray($linkTriggers); 786 $this->validateDeleteLinkTriggers($linkTriggers); 787 788 $linkTriggerIds = zbx_objectValues($linkTriggers, 'linktriggerid'); 789 790 DB::delete('sysmaps_link_triggers', ['linktriggerid' => $linkTriggerIds]); 791 792 return ['linktriggerids' => $linkTriggerIds]; 793 } 794 795 protected function validateDeleteLinkTriggers(array $linkTriggers) { 796 $linktriggerDbFields = ['linktriggerid' => null]; 797 798 foreach ($linkTriggers as $linkTrigger) { 799 if (!check_db_fields($linktriggerDbFields, $linkTrigger)) { 800 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect arguments passed to function.')); 801 } 802 } 803 } 804 805 /** 806 * Create map element tags. 807 * 808 * @param array $selements 809 * @param int $selements[]['elementtype'] 810 * @param array $selements[]['tags'] 811 * @param string $selements[]['tags'][]['tag'] 812 * @param string $selements[]['tags'][]['value'] 813 * @param string $selements[]['tags'][]['operator'] 814 * @param array $selementids 815 */ 816 protected function createSelementsTags(array $selements, array $selementids): void { 817 $new_tags = []; 818 foreach ($selements as $index => $selement) { 819 if (!array_key_exists('tags', $selement) 820 || ($selement['elementtype'] != SYSMAP_ELEMENT_TYPE_HOST 821 && $selement['elementtype'] != SYSMAP_ELEMENT_TYPE_HOST_GROUP)) { 822 continue; 823 } 824 825 foreach ($selement['tags'] as $tag_add) { 826 $new_tags[] = ['selementid' => $selementids[$index]] + $tag_add; 827 } 828 } 829 830 if ($new_tags) { 831 DB::insert('sysmaps_element_tag', $new_tags); 832 } 833 } 834 835 /** 836 * Update map element tags. 837 * 838 * @param array $selements 839 * @param string $selements[]['selementid'] 840 * @param int $selements[]['elementtype'] 841 * @param array $selements[]['tags'] 842 * @param string $selements[]['tags'][]['tag'] 843 * @param string $selements[]['tags'][]['value'] 844 * @param string $selements[]['tags'][]['operator'] 845 */ 846 protected function updateElementsTags(array $selements): void { 847 // Select tags from database. 848 $db_tags = DBselect( 849 'SELECT selementtagid, selementid, tag, value, operator'. 850 ' FROM sysmaps_element_tag'. 851 ' WHERE '.dbConditionInt('selementid', array_column($selements, 'selementid')) 852 ); 853 854 array_walk($selements, function (&$selement) { 855 $selement['db_tags'] = []; 856 }); 857 858 while ($db_tag = DBfetch($db_tags)) { 859 $selements[$db_tag['selementid']]['db_tags'][] = $db_tag; 860 } 861 862 // Find which tags must be added/deleted. 863 $new_tags = []; 864 $del_tagids = []; 865 foreach ($selements as $selement) { 866 if ($selement['elementtype'] != SYSMAP_ELEMENT_TYPE_HOST 867 && $selement['elementtype'] != SYSMAP_ELEMENT_TYPE_HOST_GROUP) { 868 $del_tagids = array_merge($del_tagids, array_column($selement['db_tags'], 'selementtagid')); 869 continue; 870 } 871 872 foreach ($selement['db_tags'] as $del_tag_key => $tag_delete) { 873 foreach ($selement['tags'] as $new_tag_key => $tag_add) { 874 if ($tag_delete['tag'] === $tag_add['tag'] && $tag_delete['value'] === $tag_add['value'] 875 && $tag_delete['operator'] === $tag_add['operator']) { 876 unset($selement['db_tags'][$del_tag_key], $selement['tags'][$new_tag_key]); 877 continue 2; 878 } 879 } 880 } 881 882 $del_tagids = array_merge($del_tagids, array_column($selement['db_tags'], 'selementtagid')); 883 884 foreach ($selement['tags'] as $tag_add) { 885 $tag_add['selementid'] = $selement['selementid']; 886 $new_tags[] = $tag_add; 887 } 888 } 889 890 if ($del_tagids) { 891 DB::delete('sysmaps_element_tag', ['selementtagid' => $del_tagids]); 892 } 893 if ($new_tags) { 894 DB::insert('sysmaps_element_tag', $new_tags); 895 } 896 } 897} 898