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 that handles associations for zabbix elements unique fields and their database ids.
24 * The purpose is to gather all elements that need ids from database and resolve them with one query.
25 */
26class CImportReferencer {
27
28	/**
29	 * @var array with references to interfaceid (hostid -> reference_name -> interfaceid)
30	 */
31	public $interfaces_cache = [];
32
33	protected $groups = [];
34	protected $templates = [];
35	protected $hosts = [];
36	protected $items = [];
37	protected $valuemaps = [];
38	protected $triggers = [];
39	protected $graphs = [];
40	protected $iconmaps = [];
41	protected $images = [];
42	protected $maps = [];
43	protected $template_dashboards = [];
44	protected $template_macros = [];
45	protected $host_macros = [];
46	protected $host_prototype_macros = [];
47	protected $proxies = [];
48	protected $host_prototypes = [];
49	protected $httptests = [];
50	protected $httpsteps = [];
51
52	protected $db_groups;
53	protected $db_templates;
54	protected $db_hosts;
55	protected $db_items;
56	protected $db_valuemaps;
57	protected $db_triggers;
58	protected $db_graphs;
59	protected $db_iconmaps;
60	protected $db_images;
61	protected $db_maps;
62	protected $db_template_dashboards;
63	protected $db_template_macros;
64	protected $db_host_macros;
65	protected $db_host_prototype_macros;
66	protected $db_proxies;
67	protected $db_host_prototypes;
68	protected $db_httptests;
69	protected $db_httpsteps;
70
71	/**
72	 * Get group ID by group UUID.
73	 *
74	 * @param string $uuid
75	 *
76	 * @return string|null
77	 */
78	public function findGroupidByUuid(string $uuid): ?string {
79		if ($this->db_groups === null) {
80			$this->selectGroups();
81		}
82
83		foreach ($this->db_groups as $groupid => $group) {
84			if ($group['uuid'] === $uuid) {
85				return $groupid;
86			}
87		}
88
89		return null;
90	}
91
92	/**
93	 * Get group ID by group name.
94	 *
95	 * @param string $name
96	 *
97	 * @return string|null
98	 */
99	public function findGroupidByName(string $name): ?string {
100		if ($this->db_groups === null) {
101			$this->selectGroups();
102		}
103
104		foreach ($this->db_groups as $groupid => $group) {
105			if ($group['name'] === $name) {
106				return $groupid;
107			}
108		}
109
110		return null;
111	}
112
113	/**
114	 * Get template ID by group UUID.
115	 *
116	 * @param string $uuid
117	 *
118	 * @return string|null
119	 */
120	public function findTemplateidByUuid(string $uuid): ?string {
121		if ($this->db_templates === null) {
122			$this->selectTemplates();
123		}
124
125		foreach ($this->db_templates as $templateid => $template) {
126			if ($template['uuid'] === $uuid) {
127				return $templateid;
128			}
129		}
130
131		return null;
132	}
133
134	/**
135	 * Get template ID by template host.
136	 *
137	 * @param string $host
138	 *
139	 * @return string|null
140	 */
141	public function findTemplateidByHost(string $host): ?string {
142		if ($this->db_templates === null) {
143			$this->selectTemplates();
144		}
145
146		foreach ($this->db_templates as $templateid => $template) {
147			if ($template['host'] === $host) {
148				return $templateid;
149			}
150		}
151
152		return null;
153	}
154
155	/**
156	 * Get host ID by host.
157	 *
158	 * @param string $name
159	 *
160	 * @return string|bool
161	 */
162	public function findHostidByHost(string $name): ?string {
163		if ($this->db_hosts === null) {
164			$this->selectHosts();
165		}
166
167		foreach ($this->db_hosts as $hostid => $host) {
168			if ($host['host'] === $name) {
169				return $hostid;
170			}
171		}
172
173		return null;
174	}
175
176	/**
177	 * Get host ID or template ID by host.
178	 *
179	 * @param string $host
180	 *
181	 * @return string|null
182	 */
183	public function findTemplateidOrHostidByHost(string $host): ?string {
184		$templateid = $this->findTemplateidByHost($host);
185
186		if ($templateid !== null) {
187			return $templateid;
188		}
189
190		return $this->findHostidByHost($host);
191	}
192
193	/**
194	 * Get interface ID by host ID and interface reference.
195	 *
196	 * @param string $hostid
197	 * @param string $interface_ref
198	 *
199	 * @return string|null
200	 */
201	public function findInterfaceidByRef(string $hostid, string $interface_ref): ?string {
202		if (array_key_exists($hostid, $this->interfaces_cache)
203				&& array_key_exists($interface_ref, $this->interfaces_cache[$hostid])) {
204			return $this->interfaces_cache[$hostid][$interface_ref];
205		}
206
207		return null;
208	}
209
210	/**
211	 * Initializes references for items.
212	 */
213	public function initItemsReferences(): void {
214		if ($this->db_items === null) {
215			$this->selectItems();
216		}
217	}
218
219	/**
220	 * Get item ID by uuid.
221	 *
222	 * @param string $uuid
223	 *
224	 * @return string|null
225	 */
226	public function findItemidByUuid(string $uuid): ?string {
227		if ($this->db_items === null) {
228			$this->selectItems();
229		}
230
231		foreach ($this->db_items as $itemid => $item) {
232			if ($item['uuid'] === $uuid) {
233				return $itemid;
234			}
235		}
236
237		return null;
238	}
239
240	/**
241	 * Get item ID by host ID and item key_.
242	 *
243	 * @param string $hostid
244	 * @param string $key
245	 *
246	 * @return string|null
247	 */
248	public function findItemidByKey(string $hostid, string $key): ?string {
249		if ($this->db_items === null) {
250			$this->selectItems();
251		}
252
253		foreach ($this->db_items as $itemid => $item) {
254			if ($item['hostid'] === $hostid && $item['key_'] === $key) {
255				return $itemid;
256			}
257		}
258
259		return null;
260	}
261
262	/**
263	 * Get valuemap ID by valuemap name.
264	 *
265	 * @param string $hostid
266	 * @param string $name
267	 *
268	 * @return string|null
269	 */
270	public function findValuemapidByName(string $hostid, string $name): ?string {
271		if ($this->db_valuemaps === null) {
272			$this->selectValuemaps();
273		}
274
275		foreach ($this->db_valuemaps as $valuemapid => $valuemap) {
276			if ($valuemap['hostid'] === $hostid && $valuemap['name'] === $name) {
277				return $valuemapid;
278			}
279		}
280
281		return null;
282	}
283
284	/**
285	 * Get image ID by image name.
286	 *
287	 * @param string $name
288	 *
289	 * @return string|null
290	 */
291	public function findImageidByName(string $name): ?string {
292		if ($this->db_images === null) {
293			$this->selectImages();
294		}
295
296		foreach ($this->db_images as $imageid => $image) {
297			if ($image['name'] === $name) {
298				return $imageid;
299			}
300		}
301
302		return null;
303	}
304
305	/**
306	 * Get trigger by trigger ID.
307	 *
308	 * @param string $triggerid
309	 *
310	 * @return array|null
311	 */
312	public function findTriggerById(string $triggerid): ?array {
313		if ($this->db_triggers === null) {
314			$this->selectTriggers();
315		}
316
317		if (array_key_exists($triggerid, $this->db_triggers)) {
318			return $this->db_triggers[$triggerid];
319		}
320
321		return null;
322	}
323
324	/**
325	 * Get trigger ID by trigger UUID.
326	 *
327	 * @param string $uuid
328	 *
329	 * @return string|null
330	 */
331	public function findTriggeridByUuid(string $uuid): ?string {
332		if ($this->db_triggers === null) {
333			$this->selectTriggers();
334		}
335
336		foreach ($this->db_triggers as $triggerid => $trigger) {
337			if ($trigger['uuid'] === $uuid) {
338				return $triggerid;
339			}
340		}
341
342		return null;
343	}
344
345	/**
346	 * Get trigger ID by trigger name and expressions.
347	 *
348	 * @param string $name
349	 * @param string $expression
350	 * @param string $recovery_expression
351	 *
352	 * @return string|null
353	 */
354	public function findTriggeridByName(string $name, string $expression, string $recovery_expression): ?string {
355		if ($this->db_triggers === null) {
356			$this->selectTriggers();
357		}
358
359		foreach ($this->db_triggers as $triggerid => $trigger) {
360			if ($trigger['description'] === $name
361					&& $trigger['expression'] === $expression
362					&& $trigger['recovery_expression'] === $recovery_expression) {
363				return $triggerid;
364			}
365		}
366
367		return null;
368	}
369
370	/**
371	 * Get graph ID by UUID.
372	 *
373	 * @param string $uuid
374	 *
375	 * @return string|null
376	 */
377	public function findGraphidByUuid(string $uuid): ?string {
378		if ($this->db_graphs === null) {
379			$this->selectGraphs();
380		}
381
382		foreach ($this->db_graphs as $graphid => $graph) {
383			if ($graph['uuid'] === $uuid) {
384				return $graphid;
385			}
386		}
387
388		return null;
389	}
390
391	/**
392	 * Get graph ID by host ID and graph name.
393	 *
394	 * @param string $hostid
395	 * @param string $name
396	 *
397	 * @return string|null
398	 */
399	public function findGraphidByName(string $hostid, string $name): ?string {
400		if ($this->db_graphs === null) {
401			$this->selectGraphs();
402		}
403
404		foreach ($this->db_graphs as $graphid => $graph) {
405			if ($graph['name'] === $name && in_array($hostid, $graph['hosts'])) {
406				return $graphid;
407			}
408		}
409
410		return null;
411	}
412
413	/**
414	 * Get iconmap ID by name.
415	 *
416	 * @param string $name
417	 *
418	 * @return string|null
419	 */
420	public function findIconmapidByName(string $name): ?string {
421		if ($this->db_iconmaps === null) {
422			$this->selectIconmaps();
423		}
424
425		foreach ($this->db_iconmaps as $iconmapid => $iconmap) {
426			if ($iconmap['name'] === $name) {
427				return $iconmapid;
428			}
429		}
430
431		return null;
432	}
433
434	/**
435	 * Get map ID by name.
436	 *
437	 * @param string $name
438	 *
439	 * @return string|null
440	 */
441	public function findMapidByName(string $name): ?string {
442		if ($this->db_maps === null) {
443			$this->selectMaps();
444		}
445
446		foreach ($this->db_maps as $mapid => $map) {
447			if ($map['name'] === $name) {
448				return $mapid;
449			}
450		}
451
452		return null;
453	}
454
455	/**
456	 * Get template dashboard ID by dashboard UUID.
457	 *
458	 * @param string $uuid
459	 *
460	 * @return string|null
461	 *
462	 * @throws APIException
463	 */
464	public function findTemplateDashboardidByUuid(string $uuid): ?string {
465		if ($this->db_template_dashboards === null) {
466			$this->selectTemplateDashboards();
467		}
468
469		foreach ($this->db_template_dashboards as $dashboardid => $dashboard) {
470			if ($dashboard['uuid'] === $uuid) {
471				return $dashboardid;
472			}
473		}
474
475		return null;
476	}
477
478	/**
479	 * Get macro ID by template ID and macro name.
480	 *
481	 * @param string $templateid
482	 * @param string $macro
483	 *
484	 * @return string|null
485	 */
486	public function findTemplateMacroid(string $templateid, string $macro): ?string {
487		if ($this->db_template_macros === null) {
488			$this->selectTemplateMacros();
489		}
490
491		return (array_key_exists($templateid, $this->db_template_macros)
492				&& array_key_exists($macro, $this->db_template_macros[$templateid]))
493			? $this->db_template_macros[$templateid][$macro]
494			: null;
495	}
496
497	/**
498	 * Get macro ID by host ID and macro name.
499	 *
500	 * @param string $hostid
501	 * @param string $macro
502	 *
503	 * @return string|null
504	 */
505	public function findHostMacroid(string $hostid, string $macro): ?string {
506		if ($this->db_host_macros === null) {
507			$this->selectHostMacros();
508		}
509
510		return (array_key_exists($hostid, $this->db_host_macros)
511				&& array_key_exists($macro, $this->db_host_macros[$hostid]))
512			? $this->db_host_macros[$hostid][$macro]
513			: null;
514	}
515
516	/**
517	 * Get macro ID by host prototype ID and macro name.
518	 *
519	 * @param string $hostid
520	 * @param string $macro
521	 *
522	 * @return string|null
523	 */
524	public function findHostPrototypeMacroid(string $hostid, string $macro): ?string {
525		if ($this->db_host_prototype_macros === null) {
526			$this->selectHostPrototypeMacros();
527		}
528
529		return (array_key_exists($hostid, $this->db_host_prototype_macros)
530				&& array_key_exists($macro, $this->db_host_prototype_macros[$hostid]))
531			? $this->db_host_prototype_macros[$hostid][$macro]
532			: null;
533	}
534
535	/**
536	 * Get proxy ID by name.
537	 *
538	 * @param string $host
539	 *
540	 * @return string|null
541	 */
542	public function findProxyidByHost(string $host): ?string {
543		if ($this->db_proxies === null) {
544			$this->selectProxies();
545		}
546
547		foreach ($this->db_proxies as $proxyid => $proxy) {
548			if ($proxy['host'] === $host) {
549				return $proxyid;
550			}
551		}
552
553		return null;
554	}
555
556	/**
557	 * Get host prototype ID by UUID.
558	 *
559	 * @param string $uuid
560	 *
561	 * @return string|null
562	 */
563	public function findHostPrototypeidByUuid(string $uuid): ?string {
564		if ($this->db_host_prototypes === null) {
565			$this->selectHostPrototypes();
566		}
567
568		foreach ($this->db_host_prototypes as $host_prototypeid => $host_prototype) {
569			if ($host_prototype['uuid'] === $uuid) {
570				return $host_prototypeid;
571			}
572		}
573
574		return null;
575	}
576
577	/**
578	 * Get host prototype ID by host.
579	 *
580	 * @param string $parent_hostid
581	 * @param string $discovery_ruleid
582	 * @param string $host
583	 *
584	 * @return string|null
585	 */
586	public function findHostPrototypeidByHost(string $parent_hostid, string $discovery_ruleid, string $host): ?string {
587		if ($this->db_host_prototypes === null) {
588			$this->selectHostPrototypes();
589		}
590
591		foreach ($this->db_host_prototypes as $host_prototypeid => $host_prototype) {
592			if ($host_prototype['parent_hostid'] === $parent_hostid
593					&& $host_prototype['discovery_ruleid'] === $discovery_ruleid
594					&& $host_prototype['host'] === $host) {
595				return $host_prototypeid;
596			}
597		}
598
599		return null;
600	}
601
602	/**
603	 * Get httptest ID by web scenario UUID.
604	 *
605	 * @param string $uuid
606	 *
607	 * @return string|null
608	 */
609	public function findHttpTestidByUuid(string $uuid): ?string {
610		if ($this->db_httptests === null) {
611			$this->selectHttpTests();
612		}
613
614		foreach ($this->db_httptests as $httptestid => $httptest) {
615			if ($httptest['uuid'] === $uuid) {
616				return $httptestid;
617			}
618		}
619
620		return null;
621	}
622
623	/**
624	 * Get httptest ID by hostid and web scenario name.
625	 *
626	 * @param string $hostid
627	 * @param string $name
628	 *
629	 * @return string|bool
630	 */
631	public function findHttpTestidByName(string $hostid, string $name): ?string {
632		if ($this->db_httptests === null) {
633			$this->selectHttpTests();
634		}
635
636		foreach ($this->db_httptests as $httptestid => $httptest) {
637			if ($httptest['hostid'] === $hostid && $httptest['name'] === $name) {
638				return $httptestid;
639			}
640		}
641
642		return null;
643	}
644
645	/**
646	 * Get httpstep ID by hostid, httptestid and web scenario step name.
647	 *
648	 * @param string $hostid
649	 * @param string $httptestid
650	 * @param string $name
651	 *
652	 * @return string|null
653	 */
654	public function findHttpStepidByName(string $hostid, string $httptestid, string $name): ?string {
655		if ($this->db_httpsteps === null) {
656			$this->selectHttpSteps();
657		}
658
659		foreach ($this->db_httpsteps as $httpstepid => $httpstep) {
660			if ($httpstep['hostid'] === $hostid && $httpstep['name'] === $name
661					&& $httpstep['httptestid'] === $httptestid) {
662				return $httpstepid;
663			}
664		}
665
666		return null;
667	}
668
669	/**
670	 * Add group names that need association with a database group ID.
671	 *
672	 * @param array $groups
673	 */
674	public function addGroups(array $groups): void {
675		$this->groups = $groups;
676	}
677
678	/**
679	 * Add group name association with group ID.
680	 *
681	 * @param string $groupid
682	 * @param array  $group
683	 */
684	public function setDbGroup(string $groupid, array $group): void {
685		$this->db_groups[$groupid] = [
686			'uuid' => $group['uuid'],
687			'name' => $group['name']
688		];
689	}
690
691	/**
692	 * Add templates names that need association with a database template ID.
693	 *
694	 * @param array $templates
695	 */
696	public function addTemplates(array $templates): void {
697		$this->templates = $templates;
698	}
699
700	/**
701	 * Add template name association with template ID.
702	 *
703	 * @param string $templateid
704	 * @param array  $template
705	 */
706	public function setDbTemplate(string $templateid, array $template): void {
707		$this->db_templates[$templateid] = [
708			'uuid' => $template['uuid'],
709			'host' => $template['host']
710		];
711	}
712
713	/**
714	 * Add hosts names that need association with a database host ID.
715	 *
716	 * @param array $hosts
717	 */
718	public function addHosts(array $hosts): void {
719		$this->hosts = $hosts;
720	}
721
722	/**
723	 * Add host name association with host ID.
724	 *
725	 * @param string $hostid
726	 * @param array  $host
727	 */
728	public function setDbHost(string $hostid, array $host): void {
729		$this->db_hosts[$hostid] = [
730			'host' => $host['host']
731		];
732	}
733
734	/**
735	 * Add item keys that need association with a database item ID.
736	 *
737	 * @param array $items
738	 */
739	public function addItems(array $items): void {
740		$this->items = $items;
741	}
742
743	/**
744	 * Add item key association with item ID.
745	 *
746	 * @param string $itemid
747	 * @param array  $item
748	 */
749	public function setDbItem(string $itemid, array $item): void {
750		$this->db_items[$itemid] = [
751			'hostid' => $item['hostid'],
752			'uuid' => array_key_exists('uuid', $item) ? $item['uuid'] : '',
753			'key_' => $item['key_']
754		];
755	}
756
757	/**
758	 * Add value map names that need association with a database value map ID.
759	 *
760	 * @param array $valuemaps
761	 */
762	public function addValuemaps(array $valuemaps): void {
763		$this->valuemaps = $valuemaps;
764	}
765
766	/**
767	 * Add trigger description/expression/recovery_expression that need association with a database trigger ID.
768	 *
769	 * @param array $triggers
770	 */
771	public function addTriggers(array $triggers): void {
772		$this->triggers = $triggers;
773	}
774
775	/**
776	 * Add graph names that need association with a database graph ID.
777	 *
778	 * @param array $graphs
779	 */
780	public function addGraphs(array $graphs): void {
781		$this->graphs = $graphs;
782	}
783
784	/**
785	 * Add trigger name/expression association with trigger ID.
786	 *
787	 * @param string $triggerid
788	 * @param array  $trigger
789	 */
790	public function setDbTrigger(string $triggerid, array $trigger): void {
791		$this->db_triggers[$triggerid] = [
792			'uuid' => array_key_exists('uuid', $trigger) ? $trigger['uuid'] : '',
793			'description' => $trigger['description'],
794			'expression' => $trigger['expression'],
795			'recovery_expression' => $trigger['recovery_expression']
796		];
797	}
798
799	/**
800	 * Add icon map names that need association with a database icon map ID.
801	 *
802	 * @param array $iconmaps
803	 */
804	public function addIconmaps(array $iconmaps): void {
805		$this->iconmaps = $iconmaps;
806	}
807
808	/**
809	 * Add icon map names that need association with a database icon map ID.
810	 *
811	 * @param array $images
812	 */
813	public function addImages(array $images): void {
814		$this->images = $images;
815	}
816
817	/**
818	 * Add image name association with image ID.
819	 *
820	 * @param string $imageid
821	 * @param array  $image
822	 */
823	public function setDbImage(string $imageid, array $image): void {
824		$this->db_images[$imageid] = [
825			'name' => $image['name']
826		];
827	}
828
829	/**
830	 * Add map names that need association with a database map ID.
831	 *
832	 * @param array $maps
833	 */
834	public function addMaps(array $maps) {
835//		$this->maps = array_unique(array_merge($this->maps, $maps));
836		$this->maps = $maps;
837	}
838
839	/**
840	 * Add map name association with map ID.
841	 *
842	 * @param string $mapid
843	 * @param array  $map
844	 */
845	public function setDbMap(string $mapid, array $map): void {
846		$this->db_maps[$mapid] =[
847			'name' => $map['name']
848		];
849	}
850
851	/**
852	 * Add templated dashboard names that need association with a database dashboard ID.
853	 *
854	 * @param array $dashboards
855	 */
856	public function addTemplateDashboards(array $dashboards): void {
857		$this->template_dashboards = $dashboards;
858	}
859
860	/**
861	 * Add user macro names that need association with a database macro ID.
862	 *
863	 * @param array $macros[<template uuid>]  An array of macros by template UUID.
864	 */
865	public function addTemplateMacros(array $macros): void {
866		$this->template_macros = $macros;
867	}
868
869	/**
870	 * Add user macro names that need association with a database macro ID.
871	 *
872	 * @param array $macros[<host name>]  An array of macros by host technical name.
873	 */
874	public function addHostMacros(array $macros): void {
875		$this->host_macros = $macros;
876	}
877
878	/**
879	 * Add user macro names that need association with a database macro ID.
880	 *
881	 * @param array $macros[<host name>]  An array of macros by host technical name.
882	 */
883	public function addHostPrototypeMacros(array $macros): void {
884		$this->host_prototype_macros = $macros;
885	}
886
887	/**
888	 * Add proxy names that need association with a database proxy ID.
889	 *
890	 * @param array $proxies
891	 */
892	public function addProxies(array $proxies): void {
893		$this->proxies = $proxies;
894	}
895
896	/**
897	 * Add host prototypes that need association with a database host prototype ID.
898	 *
899	 * @param array $hostPrototypes
900	 */
901	public function addHostPrototypes(array $hostPrototypes): void {
902		$this->host_prototypes = $hostPrototypes;
903	}
904
905	/**
906	 * Add web scenario names that need association with a database httptest ID.
907	 *
908	 * @param array  $httptests
909	 */
910	public function addHttpTests(array $httptests): void {
911		$this->httptests = $httptests;
912	}
913
914	/**
915	 * Add web scenario step names that need association with a database httpstep ID.
916	 *
917	 * @param array  $httpsteps
918	 */
919	public function addHttpSteps(array $httpsteps): void {
920		$this->httpsteps = $httpsteps;
921	}
922
923	/**
924	 * Select group ids for previously added group names.
925	 */
926	protected function selectGroups(): void {
927		$this->db_groups = [];
928
929		if (!$this->groups) {
930			return;
931		}
932
933		$this->db_groups = API::HostGroup()->get([
934			'output' => ['name', 'uuid'],
935			'filter' => [
936				'uuid' => array_column($this->groups, 'uuid'),
937				'name' => array_keys($this->groups)
938			],
939			'searchByAny' => true,
940			'preservekeys' => true
941		]);
942
943		$this->groups = [];
944	}
945
946	/**
947	 * Select template ids for previously added template names.
948	 */
949	protected function selectTemplates(): void {
950		$this->db_templates = [];
951
952		if (!$this->templates) {
953			return;
954		}
955
956		$this->db_templates = API::Template()->get([
957			'output' => ['host', 'uuid'],
958			'filter' => [
959				'uuid' => array_column($this->templates, 'uuid'),
960				'host' => array_keys($this->templates)
961			],
962			'searchByAny' => true,
963			'editable' => true,
964			'preservekeys' => true
965		]);
966
967		$this->templates = [];
968	}
969
970	/**
971	 * Select host ids for previously added host names.
972	 */
973	protected function selectHosts(): void {
974		$this->db_hosts = [];
975
976		if (!$this->hosts) {
977			return;
978		}
979
980		// Fetch only normal hosts, discovered hosts must not be imported.
981		$this->db_hosts = API::Host()->get([
982			'output' => ['host'],
983			'filter' => ['host' => array_keys($this->hosts)],
984			'templated_hosts' => true,
985			'preservekeys' => true
986		]);
987
988		$this->hosts = [];
989	}
990
991	/**
992	 * Select item ids for previously added item keys.
993	 */
994	protected function selectItems(): void {
995		$this->db_items = [];
996
997		if (!$this->items) {
998			return;
999		}
1000
1001		$sql_where = [];
1002
1003		foreach ($this->items as $host => $items) {
1004			$hostid = $this->findTemplateidOrHostidByHost($host);
1005
1006			if ($hostid !== null) {
1007				$sql_where[] = '(i.hostid='.zbx_dbstr($hostid)
1008					.' AND ('
1009						.dbConditionString('i.key_', array_keys($items))
1010						.' OR '.dbConditionString('i.uuid', array_column($items, 'uuid'))
1011					.'))';
1012			}
1013		}
1014
1015		if ($sql_where) {
1016			$db_items = DBselect(
1017				'SELECT i.itemid,i.hostid,i.key_,i.uuid FROM items i WHERE '.implode(' OR ', $sql_where)
1018			);
1019
1020			while ($db_item = DBfetch($db_items)) {
1021				$this->db_items[$db_item['itemid']] = [
1022					'uuid' => $db_item['uuid'],
1023					'key_' => $db_item['key_'],
1024					'hostid' => $db_item['hostid']
1025				];
1026			}
1027		}
1028	}
1029
1030	/**
1031	 * Unset item refs to make referencer select them from db again.
1032	 */
1033	public function refreshItems(): void {
1034		$this->db_items = null;
1035	}
1036
1037	/**
1038	 * Select value map IDs for previously added value map names.
1039	 */
1040	protected function selectValuemaps(): void {
1041		$this->db_valuemaps = [];
1042
1043		if (!$this->valuemaps) {
1044			return;
1045		}
1046
1047		$sql_where = [];
1048
1049		foreach ($this->valuemaps as $host => $valuemap_names) {
1050			$hostid = $this->findTemplateidOrHostidByHost($host);
1051
1052			if ($hostid !== null) {
1053				$sql_where[] = '(vm.hostid='.zbx_dbstr($hostid).' AND '.
1054					dbConditionString('vm.name', array_keys($valuemap_names)).')';
1055			}
1056		}
1057
1058		if ($sql_where) {
1059			$db_valuemaps = DBselect(
1060				'SELECT vm.valuemapid,vm.hostid,vm.name'.
1061				' FROM valuemap vm'.
1062				' WHERE '.implode(' OR ', $sql_where)
1063			);
1064
1065			while ($valuemap = DBfetch($db_valuemaps)) {
1066				$this->db_valuemaps[$valuemap['valuemapid']] = [
1067					'name' => $valuemap['name'],
1068					'hostid' => $valuemap['hostid']
1069				];
1070			}
1071		}
1072
1073		$this->valuemaps = [];
1074	}
1075
1076	/**
1077	 * Select trigger ids for previously added trigger names/expressions.
1078	 */
1079	protected function selectTriggers(): void {
1080		$this->db_triggers = [];
1081
1082		if (!$this->triggers) {
1083			return;
1084		}
1085
1086		$uuids = [];
1087
1088		foreach ($this->triggers as $trigger) {
1089			foreach ($trigger as $expression) {
1090				$uuids += array_flip(array_column($expression, 'uuid'));
1091			}
1092		}
1093
1094		$db_triggers = API::Trigger()->get([
1095			'output' => ['uuid', 'description', 'expression', 'recovery_expression'],
1096			'filter' => [
1097				'uuid' => array_keys($uuids),
1098				'flags' => [
1099					ZBX_FLAG_DISCOVERY_NORMAL,
1100					ZBX_FLAG_DISCOVERY_PROTOTYPE,
1101					ZBX_FLAG_DISCOVERY_CREATED
1102				]
1103			],
1104			'preservekeys' => true
1105		]);
1106
1107		$db_triggers += API::Trigger()->get([
1108			'output' => ['uuid', 'description', 'expression', 'recovery_expression'],
1109			'filter' => [
1110				'description' => array_keys($this->triggers),
1111				'flags' => [
1112					ZBX_FLAG_DISCOVERY_NORMAL,
1113					ZBX_FLAG_DISCOVERY_PROTOTYPE,
1114					ZBX_FLAG_DISCOVERY_CREATED
1115				]
1116			],
1117			'preservekeys' => true
1118		]);
1119
1120		if (!$db_triggers) {
1121			return;
1122		}
1123
1124		$db_triggers = CMacrosResolverHelper::resolveTriggerExpressions($db_triggers,
1125			['sources' => ['expression', 'recovery_expression']]
1126		);
1127
1128		foreach ($db_triggers as $db_trigger) {
1129			$uuid = $db_trigger['uuid'];
1130			$description = $db_trigger['description'];
1131			$expression = $db_trigger['expression'];
1132			$recovery_expression = $db_trigger['recovery_expression'];
1133
1134			if (array_key_exists($uuid, $uuids)
1135				|| (array_key_exists($description, $this->triggers)
1136					&& array_key_exists($expression, $this->triggers[$description])
1137					&& array_key_exists($recovery_expression, $this->triggers[$description][$expression]))) {
1138				$this->db_triggers[$db_trigger['triggerid']] = $db_trigger;
1139			}
1140		}
1141	}
1142
1143	/**
1144	 * Unset trigger refs to make referencer select them from db again.
1145	 */
1146	public function refreshTriggers(): void {
1147		$this->db_triggers = null;
1148	}
1149
1150	/**
1151	 * Select graph IDs for previously added graph names.
1152	 */
1153	protected function selectGraphs(): void {
1154		$this->db_graphs = [];
1155
1156		if (!$this->graphs) {
1157			return;
1158		}
1159
1160		$graph_uuids = [];
1161		$graph_names = [];
1162
1163		foreach ($this->graphs as $graph) {
1164			$graph_uuids += array_flip(array_column($graph, 'uuid'));
1165			$graph_names += array_flip(array_keys($graph));
1166		}
1167
1168		$db_graphs =  API::Graph()->get([
1169			'output' => ['uuid', 'name'],
1170			'selectHosts' => ['hostid'],
1171			'filter' => [
1172				'uuid' => array_keys($graph_uuids),
1173				'flags' => null
1174			],
1175			'preservekeys' => true
1176		]);
1177
1178		$db_graphs += API::Graph()->get([
1179			'output' => ['uuid', 'name'],
1180			'selectHosts' => ['hostid'],
1181			'filter' => [
1182				'name' => array_keys($graph_names),
1183				'flags' => null
1184			],
1185			'preservekeys' => true
1186		]);
1187
1188		foreach ($db_graphs as $graph) {
1189			$graph['hosts'] = array_column($graph['hosts'], 'hostid');
1190			$this->db_graphs[$graph['graphid']] = $graph;
1191		}
1192	}
1193
1194	/**
1195	 * Unset graph refs to make referencer select them from DB again.
1196	 */
1197	public function refreshGraphs(): void {
1198		$this->db_graphs = null;
1199	}
1200
1201	/**
1202	 * Select icon map ids for previously added icon maps names.
1203	 */
1204	protected function selectIconmaps(): void {
1205		$this->db_iconmaps = [];
1206
1207		if (!$this->iconmaps) {
1208			return;
1209		}
1210
1211		$db_iconmaps = API::IconMap()->get([
1212			'filter' => ['name' => array_keys($this->iconmaps)],
1213			'output' => ['name'],
1214			'preservekeys' => true
1215		]);
1216
1217		foreach ($db_iconmaps as $iconmapid => $iconmap) {
1218			$this->db_iconmaps[$iconmapid] = $iconmap;
1219		}
1220
1221		$this->iconmaps = [];
1222	}
1223
1224	/**
1225	 * Select icon map ids for previously added icon maps names.
1226	 */
1227	protected function selectImages(): void {
1228		$this->db_images = [];
1229
1230		if (!$this->images) {
1231			return;
1232		}
1233
1234		$db_images = API::Image()->get([
1235			'output' => ['name'],
1236			'filter' => ['name' => array_keys($this->images)],
1237			'preservekeys' => true
1238		]);
1239
1240		foreach ($db_images as $imageid => $image) {
1241			$this->db_images[$imageid] = $image;
1242		}
1243
1244		$this->images = [];
1245	}
1246
1247	/**
1248	 * Select map ids for previously added maps names.
1249	 */
1250	protected function selectMaps(): void {
1251		$this->db_maps = [];
1252
1253		if (!$this->maps) {
1254			return;
1255		}
1256
1257		$db_maps = API::Map()->get([
1258			'output' => ['name'],
1259			'filter' => ['name' => array_keys($this->maps)],
1260			'preservekeys' => true
1261		]);
1262
1263		foreach ($db_maps as $mapid => $map) {
1264			$this->db_maps[$mapid] = $map;
1265		}
1266
1267		$this->maps = [];
1268	}
1269
1270	/**
1271	 * Select template dashboard IDs for previously added dashboard names and template IDs.
1272	 *
1273	 * @throws APIException
1274	 */
1275	protected function selectTemplateDashboards(): void {
1276		$this->db_template_dashboards = [];
1277
1278		if (!$this->template_dashboards) {
1279			return;
1280		}
1281
1282		$db_template_dashboards = API::TemplateDashboard()->get([
1283			'output' => ['uuid'],
1284			'filter' => ['uuid' => array_keys($this->template_dashboards)],
1285			'preservekeys' => true
1286		]);
1287
1288		foreach ($db_template_dashboards as $dashboardid => $dashboard) {
1289			$this->db_template_dashboards[$dashboardid] = [
1290				'uuid' => $dashboard['uuid']
1291			];
1292		}
1293
1294		$this->template_dashboards = [];
1295	}
1296
1297	/**
1298	 * Select user macro ids for previously added macro names.
1299	 */
1300	protected function selectTemplateMacros(): void {
1301		$this->db_template_macros = [];
1302
1303		$sql_where = [];
1304
1305		foreach ($this->template_macros as $uuid => $macros) {
1306			$sql_where[] = '(h.uuid='.zbx_dbstr($uuid).' AND '.dbConditionString('hm.macro', $macros).')';
1307		}
1308
1309		if ($sql_where) {
1310			$db_macros = DBselect(
1311				'SELECT hm.hostmacroid,hm.hostid,hm.macro'.
1312				' FROM hostmacro hm'.
1313					' JOIN hosts h on hm.hostid=h.hostid'.
1314				' WHERE '.implode(' OR ', $sql_where)
1315			);
1316
1317			while ($db_macro = DBfetch($db_macros)) {
1318				$this->db_template_macros[$db_macro['hostid']][$db_macro['macro']] = $db_macro['hostmacroid'];
1319			}
1320		}
1321
1322		$this->template_macros = [];
1323	}
1324
1325	/**
1326	 * Select user macro ids for previously added macro names.
1327	 */
1328	protected function selectHostMacros(): void {
1329		$this->db_host_macros = [];
1330
1331		$sql_where = [];
1332
1333		foreach ($this->host_macros as $host => $macros) {
1334			$sql_where[] = '(h.host='.zbx_dbstr($host).' AND '.dbConditionString('hm.macro', $macros).')';
1335		}
1336
1337		if ($sql_where) {
1338			$db_macros = DBselect(
1339				'SELECT hm.hostmacroid,hm.hostid,hm.macro'.
1340				' FROM hostmacro hm'.
1341					' JOIN hosts h on hm.hostid=h.hostid'.
1342				' WHERE '.implode(' OR ', $sql_where)
1343			);
1344
1345			while ($db_macro = DBfetch($db_macros)) {
1346				$this->db_host_macros[$db_macro['hostid']][$db_macro['macro']] = $db_macro['hostmacroid'];
1347			}
1348		}
1349
1350		$this->host_macros = [];
1351	}
1352
1353	/**
1354	 * Select user macro ids for previously added macro names.
1355	 */
1356	protected function selectHostPrototypeMacros(): void {
1357		$this->db_host_prototype_macros = [];
1358
1359		$sql_where = [];
1360
1361		foreach ($this->host_prototype_macros as $type => $hosts) {
1362			foreach ($hosts as $host => $discovery_rules) {
1363				foreach ($discovery_rules as $discovery_rule_key => $host_prototypes) {
1364					foreach ($host_prototypes as $host_prototype_id => $macros) {
1365						$sql_where[] = '('.
1366							'h.host='.zbx_dbstr($host).
1367							' AND dr.key_='.zbx_dbstr($discovery_rule_key).
1368							' AND hp.'.($type === 'uuid' ? 'uuid' : 'host').'='.zbx_dbstr($host_prototype_id).
1369							' AND '.dbConditionString('hm.macro', $macros).
1370						')';
1371					}
1372				}
1373			}
1374		}
1375
1376		if ($sql_where) {
1377			$db_macros = DBselect(
1378				'SELECT hm.hostmacroid,hm.hostid,hm.macro'.
1379				' FROM hostmacro hm'.
1380					' JOIN hosts hp on hm.hostid=hp.hostid'.
1381					' JOIN host_discovery hd on hp.hostid=hd.hostid'.
1382					' JOIN items dr on hd.parent_itemid=dr.itemid'.
1383					' JOIN hosts h on dr.hostid=h.hostid'.
1384				' WHERE '.implode(' OR ', $sql_where)
1385			);
1386
1387			while ($db_macro = DBfetch($db_macros)) {
1388				$this->db_host_prototype_macros[$db_macro['hostid']][$db_macro['macro']] = $db_macro['hostmacroid'];
1389			}
1390		}
1391
1392		$this->host_prototype_macros = [];
1393	}
1394
1395	/**
1396	 * Select proxy ids for previously added proxy names.
1397	 */
1398	protected function selectProxies(): void {
1399		$this->db_proxies = [];
1400
1401		if (!$this->proxies) {
1402			return;
1403		}
1404
1405		$this->db_proxies = API::Proxy()->get([
1406			'output' => ['host'],
1407			'filter' => ['host' => array_keys($this->proxies)],
1408			'preservekeys' => true
1409		]);
1410
1411		$this->proxies = [];
1412	}
1413
1414	/**
1415	 * Select host prototype ids for previously added host prototypes names.
1416	 */
1417	protected function selectHostPrototypes(): void {
1418		$this->db_host_prototypes = [];
1419
1420		$sql_where = [];
1421
1422		foreach ($this->host_prototypes as $type => $hosts) {
1423			foreach ($hosts as $host => $discovery_rules) {
1424				foreach ($discovery_rules as $discovery_rule_id => $host_prototype_ids) {
1425					$sql_where[] = '('.
1426						'h.host='.zbx_dbstr($host).
1427						' AND dr.'.($type === 'uuid' ? 'uuid' : 'key_').'='.zbx_dbstr($discovery_rule_id).
1428						' AND '.dbConditionString('hp.'.($type === 'uuid' ? 'uuid' : 'host'), $host_prototype_ids).
1429					')';
1430				}
1431			}
1432		}
1433
1434		if ($sql_where) {
1435			$db_host_prototypes = DBselect(
1436				'SELECT hp.host,hp.uuid,hp.hostid,hd.parent_itemid,dr.hostid AS parent_hostid'.
1437				' FROM hosts hp'.
1438					' JOIN host_discovery hd ON hp.hostid=hd.hostid'.
1439					' JOIN items dr ON hd.parent_itemid=dr.itemid'.
1440					' JOIN hosts h on dr.hostid=h.hostid'.
1441				' WHERE '.implode(' OR ', $sql_where)
1442			);
1443			while ($db_host_prototype = DBfetch($db_host_prototypes)) {
1444				$this->db_host_prototypes[$db_host_prototype['hostid']] = [
1445					'uuid' => $db_host_prototype['uuid'],
1446					'host' => $db_host_prototype['host'],
1447					'parent_hostid' => $db_host_prototype['parent_hostid'],
1448					'discovery_ruleid' => $db_host_prototype['parent_itemid']
1449				];
1450			}
1451		}
1452
1453		$this->host_prototypes = [];
1454	}
1455
1456	/**
1457	 * Select httptestids for previously added web scenario names.
1458	 */
1459	protected function selectHttpTests(): void {
1460		$this->db_httptests = [];
1461
1462		if (!$this->httptests) {
1463			return;
1464		}
1465
1466		$sql_where = [];
1467
1468		foreach ($this->httptests as $host => $httptests) {
1469			$hostid = $this->findTemplateidOrHostidByHost($host);
1470
1471			if ($hostid !== false) {
1472				$sql_where[] = '(ht.hostid='.zbx_dbstr($hostid)
1473					.' AND ('
1474						.dbConditionString('ht.name', array_keys($httptests))
1475						.' OR '.dbConditionString('ht.uuid', array_column($httptests, 'uuid'))
1476					.'))';
1477			}
1478		}
1479
1480		if ($sql_where) {
1481			$db_httptests = DBselect(
1482				'SELECT ht.hostid,ht.name,ht.httptestid,ht.uuid FROM httptest ht WHERE '.implode(' OR ', $sql_where)
1483			);
1484
1485			while ($db_httptest = DBfetch($db_httptests)) {
1486				$this->db_httptests[$db_httptest['httptestid']] = [
1487					'uuid' => $db_httptest['uuid'],
1488					'name' => $db_httptest['name'],
1489					'hostid' => $db_httptest['hostid']
1490				];
1491			}
1492		}
1493	}
1494
1495	/**
1496	 * Unset web scenario refs to make referencer select them from db again.
1497	 */
1498	public function refreshHttpTests(): void {
1499		$this->db_httptests = null;
1500	}
1501
1502	/**
1503	 * Select httpstepids for previously added web scenario step names.
1504	 */
1505	protected function selectHttpSteps(): void {
1506		$this->db_httpsteps = [];
1507
1508		if (!$this->httpsteps) {
1509			return;
1510		}
1511
1512		$sql_where = [];
1513
1514		foreach ($this->httpsteps as $host => $httptests) {
1515			$hostid = $this->findTemplateidOrHostidByHost($host);
1516
1517			if ($hostid !== null) {
1518				foreach ($httptests as $httpstep_names) {
1519					$sql_where[] = dbConditionString('hs.name', array_keys($httpstep_names));
1520				}
1521			}
1522		}
1523
1524		if ($sql_where) {
1525			$db_httpsteps = DBselect(
1526				'SELECT ht.hostid,hs.httptestid,hs.name,hs.httpstepid'.
1527				' FROM httptest ht,httpstep hs'.
1528				' WHERE ht.httptestid=hs.httptestid'.
1529					' AND ('.implode(' OR ', $sql_where).')'
1530			);
1531
1532			while ($db_httpstep = DBfetch($db_httpsteps)) {
1533				$this->db_httpsteps[$db_httpstep['httpstepid']] = [
1534					'name' => $db_httpstep['name'],
1535					'hostid' => $db_httpstep['hostid'],
1536					'httptestid' => $db_httpstep['httptestid']
1537				];
1538			}
1539		}
1540	}
1541}
1542