* @copyright synetics GmbH * @license http://www.i-doit.com/en/resources/licensing-terms/ */ class isys_import_handler_cmdb extends isys_import_handler { /** * Data structure's element key for objects. * @var string Returns 'objects'. */ const C__OBJECTS = 'objects'; /** * Data structure's element key for category types. * @var string Returns 'category_types'. */ const C__CATEGORY_TYPES = 'category_types'; /** * Data structure's element key for categories. * @var string Returns 'categories'. */ const C__CATEGORIES = 'categories'; /** * Data structure's element key for all category data. * @var string Returns 'category_entities'. */ const C__CATEGORY_ENTITIES = 'category_entities'; /** * Data structure's element key for properties. * @var string Returns 'properties'. */ const C__PROPERTIES = 'properties'; /** * Data structure's element key for priorities. * @var string Returns 'priority'. */ const C__PRIORITY = 'priority'; /** * Data structure's element key to mark dummies. * @var string Returns 'dummy'. */ const C__DUMMY = 'dummy'; /** * Threshold for comparison. * @var integer Returns 4. */ const C__COMPARISON__THRESHOLD = 4; /** * Comparison result: failed. * @var integer Returns -1. */ const C__COMPARISON__FAILED = -1; /** * Comparison result: different. * @var integer Returns 0. */ const C__COMPARISON__DIFFERENT = 0; /** * Comparison result: same. * @var integer Returns 1. */ const C__COMPARISON__SAME = 1; /** * Comparison result: partly different. * @var integer Returns 2. */ const C__COMPARISON__PARTLY = 2; /** * Import mode: Append data to existing one. * @var integer Returns 1 */ const C__APPEND = 1; /** * Import mode: Merge data with existing one. * @var integer Returns 2 */ const C__MERGE = 2; /** * Import mode: Overwrite existing data. * @var integer Returns 4 */ const C__OVERWRITE = 4; /** * Import mode: Update existing data by identifiers. * @var integer Returns 8 */ const C__USE_IDS = 8; /** * Status to keep existing data. * @var integer Returns 0. */ const C__KEEP = 0; /** * Status to crete new data. * @var integer Return 1. */ const C__CREATE = 1; /** * Status to update existing data. * @var integer Returns 2. */ const C__UPDATE = 2; /** * Prepared data. * @var array */ protected $m_prepared; /** * Temporary variable with information about importing data. * @var array */ protected $m_info; /** * Object types. * @var array Array with object type identifiers as keys and their correspondant constants as values */ protected $m_object_types; /** * Object type identifiers * * @var array Array with exported object type identifiers as keys and their correspondant identifiers in database as values. */ protected $m_object_type_ids; /** * Object identifiers. * @var array Array with exported object identifiers as keys and their correspondant identifiers in database as values. */ protected $m_object_ids; /** * Category identifiers. * @var array Array with exported category identifiers as keys and their correspondant identifiers in database as values. */ protected $m_category_ids; /** * Category data identifiers. * @var array Array with exported category data identifiers as keys and their correspondant identifiers in database as values. */ protected $m_category_data_ids; /** * Property identifiers. * @var array Array with exported property identifiers as keys and their correspondant identifiers in database as values. */ protected $m_property_ids; /** * Log. * @var isys_import_log */ protected $m_log; /** * Date format. * @var string */ protected $m_date_format = 'Y-m-d H:i:s'; /** * Import mode. * @var integer */ protected $m_mode; /** * Variable which marks the "changed" status. * @var boolean * @todo Why is that used? */ public static $m_changed = false; /** * Method for setting the "changed" status. * @todo Why is that used? */ public static function change_reset() { isys_import_handler_cmdb::$m_changed = false; } // function /** * @todo Why is that used? */ public static function changed() { return isys_import_handler_cmdb::$m_changed; } // function /** * Constructor */ public function __construct() { // $this->m_log = isys_log_import::get_instance(); } #function /** * Gets import mode. * * @return int Returns null, if import mode has not been set yet. */ public function get_mode() { return $this->m_mode; } #function /** * Sets import mode. * * @param int $p_mode */ public function set_mode($p_mode) { assert('is_int($p_mode)'); switch($p_mode) { case self::C__APPEND: // $this->m_log->notice('Export data will be appended to existing data.'); break; case self::C__MERGE: // $this->m_log->notice('Export data will be merged with existing data.'); break; case self::C__OVERWRITE: // $this->m_log->notice('Export data will overwrite existing data.'); break; case self::C__USE_IDS: // $this->m_log->notice('Export data will update existing data by identifiers.'); break; default: throw new isys_exception_cmdb( 'Import mode is not supported.' ); break; } #switch modes $this->m_mode = $p_mode; } #function /** * Parses data from an i-doit CMDB export. * * @param string $p_xml_data XML data. Set it to null to use XML data that * is already set before. Defaults to null. * * @return bool Success? */ public function parse($p_xml_data = null) { // $this->m_log->info('Parsing the import file...'); $l_xml_data = $p_xml_data; if (empty($p_xml_data)) { $l_xml_data = $this->get_xml_object(); } else { $this->set_xml_object($l_xml_data); } // Export info: $this->m_scantime = strtotime((string) $l_xml_data->head->datetime); $this->m_mandator = array( C__CATEGORY_DATA__VALUE => (string) $l_xml_data->head->mandator, ); $l_mandator_attr = (array) $l_xml_data->head->mandator->attributes(); $this->m_mandator = array_merge($this->m_mandator, $l_mandator_attr['@attributes']); $this->m_type = $l_xml_data->head->type; $this->m_version = $l_xml_data->head->version; // Initialize: $l_object_id = 0; $l_title = null; $l_type = null; if (!isset($l_xml_data->objects->object) || count($l_xml_data->objects->object) <= 0) { throw new isys_exception_general('Import failed. File not readable or no objects inside!'); } $l_object_counter = count($l_xml_data->objects->object); if ($l_object_counter == 1) { // $this->m_log->info('There is 1 object waiting...'); } else { // $this->m_log->info('There are ' . $l_object_counter . ' objects waiting...'); } #if // $this->m_log->debug('Parsing objects...'); // Iterate through objects: foreach ($l_xml_data->objects->object as $l_object) { $l_object_id = (string) $l_object->id; if (empty($l_object_id)) { continue; } // Title: $l_title = (string) $l_object->title; // SYSID: $l_sysid = (string) $l_object->sysid; // Add type attributes: $l_type = array(); $l_type[C__CATEGORY_DATA__VALUE] = (string) $l_object->type; $l_type_attr = (array) $l_object->type->attributes(); foreach ($l_type_attr['@attributes'] as $l_key => $l_value) { $l_type[$l_key] = $l_value; } // Created: $l_created = strtotime((string) $l_object->created); $l_created_attr = (array) $l_object->created->attributes(); // Updated: $l_updated = strtotime((string) $l_object->updated); $l_updated_attr = (array) $l_object->updated->attributes(); // Add head information: $this->m_data[$l_object_id] = array( C__CATEGORY_DATA__TITLE => $l_title, 'id' => $l_object_id, 'sysid' => $l_sysid, 'type' => $l_type, 'created' => $l_created, 'created_by' => $l_created_attr['@attributes']['by'], 'updated' => $l_updated, 'updated_by' => $l_updated_attr['@attributes']['by'], 'status' => (int) $l_object->status, 'cmdb_status' => (int) $l_object->cmdb_status ); // Initialize categories: $this->m_data[$l_object_id][self::C__CATEGORY_TYPES] = array( C__CMDB__CATEGORY__TYPE_GLOBAL => array(), C__CMDB__CATEGORY__TYPE_SPECIFIC => array() ); // $this->m_log->debug( // sprintf( // 'Found object %s (%s) of type %s.', // $l_title, // $l_object_id, // $l_type['value'] // ) // ); // $this->m_log->debug('Parsing categories...'); // Extract categories: foreach ($l_object->data->category as $l_category) { // Get attributes: $l_attributes = $l_category->get_attributes(); unset($l_category['@attributes']); // Check for valid content: if (!isset($l_attributes['const'])) { continue; } $l_cat_const = $l_attributes['const']; $l_cat_type = $l_attributes['category_type']; //@TODO Check Custom Field Const if(is_numeric(strpos($l_cat_const, "C__CATG__CUSTOM_FIELDS"))){ $l_cat_id = substr($l_cat_const, strlen("C__CATG__CUSTOM_FIELDS_"), strlen($l_cat_const)); } else{ if (!defined($l_cat_const)) { $this->m_log->notice( printf( 'Category %s\'s constant has not been defined yet.', $l_cat_const ) ); } $l_cat_id = constant($l_cat_const); if ($l_cat_id <= 0) { continue; } } // Attach information about the category: $this->m_data[$l_object_id][self::C__CATEGORY_TYPES][$l_cat_type][$l_cat_id] = $l_attributes; // $this->m_log->debug('Parsing category data...'); // Extract categories data: foreach ($l_category->cat_data as $l_category_data) { // Extract category data information and properties: $l_new_category = array(); $l_category_data_array = (array) $l_category_data; foreach ($l_category_data_array as $l_category_data_key => $l_category_data_value) { if ($l_category_data_key === '@attributes') { $l_new_category = $l_category_data_value; continue; } else if ($l_category_data_key === 0) { // Skip empty category data: continue; } // Recursion: $l_property = $this->parse_properties($l_category_data, $l_category_data_key, $l_category_data_value); $l_new_category[self::C__PROPERTIES][$l_category_data_key] = $l_property; } $this->m_data[$l_object_id][self::C__CATEGORY_TYPES][$l_cat_type][$l_cat_id][self::C__CATEGORY_ENTITIES][$l_new_category['data_id']] = $l_new_category; } #foreach } #foreach } #foreach return true; } #function /** * Parses recursivly properties. Used for $this->parse(). * * @param mixed $p_data SimpleXML objects and/or arrays. * * @return array Parsed */ private function parse_properties($p_data, $p_key, $p_value) { // $this->m_log->debug('Parsing properties...'); $l_result = array(); $l_result[C__CATEGORY_DATA__TAG] = $p_key; switch (gettype($p_value)) { case 'object': assert('$p_value instanceof isys_library_xml'); $l_arr = (array) $p_value; if (isset($l_arr[0])) { $l_result[C__CATEGORY_DATA__VALUE] = $l_arr[0]; } else { foreach ($p_value as $l_sub_key => $l_sub_value) { // @deleteme WARNING! This is a bug fix, but it could break the whole import! // Original: // $l_result = array_merge($l_result, $p_value->$l_sub_key->get_attributes()); // $l_sub = $this->parse_properties($p_value, $l_sub_key, $l_sub_value); // $l_result[C__CATEGORY_DATA__VALUE][] = $l_sub; // Fix: $l_sub = $this->parse_properties($p_value, $l_sub_key, $l_sub_value); $l_sub = array_merge($p_value->$l_sub_key->get_attributes(), $l_sub); $l_result[C__CATEGORY_DATA__VALUE][] = $l_sub; } #foreach } #if // Warning: See below... $l_result = array_merge($l_result, $p_value->get_attributes()); break; case 'array': foreach ($p_value as $l_value) { $l_sub = $this->parse_properties($l_value, null, $l_value); $l_sub[C__CATEGORY_DATA__TAG] = $l_sub[C__CATEGORY_DATA__TITLE]; $l_result[C__CATEGORY_DATA__VALUE][] = $l_sub; } #foreach break; case 'string': $l_result[C__CATEGORY_DATA__VALUE] = $p_value; $l_result = array_merge($l_result, $p_data->$p_key->get_attributes()); break; default: $this->m_log->warning( sprintf( 'Unknown property type %s.', gettype($p_value) ) ); break; } #switch type // Warning: There is the possibility that an attribute // has the same name like a constant, e. g. 'value' // (C__CATEGORY_DATA__VALUE), so this array field will // be overwritten! But... that's okay, because when // this happens, attributes like this are more // important. Otherwise... just change the constant ;-) // $l_result = array_merge($l_result, $p_data->$p_key->get_attributes()); return $l_result; } #function /** * Prepares the import data, determines priorities and sorting the data. * * @return array */ public function prepare() { // $this->m_log->info('Preparing data...'); assert('isset($this->m_data) && is_array($this->m_data)'); // Iterate through objects: foreach ($this->m_data as $l_object_id => $l_object_values) { // 1. step is to prioritize objects: // Initialize object's priority: if (!isset($this->m_prepared[$l_object_id][self::C__PRIORITY])) { $this->m_prepared[$l_object_id][self::C__PRIORITY] = 0; } #if // Add object information: foreach ($l_object_values as $l_object_values_keys => $l_object_values_values) { if ($l_object_values_keys !== self::C__CATEGORY_TYPES) { $this->m_prepared[$l_object_id][$l_object_values_keys] = $l_object_values_values; } #if } #foreach // Iterate trough category types: foreach ($l_object_values[self::C__CATEGORY_TYPES] as $l_category_type_id => $l_categories) { // Iterate through categories: foreach ($l_categories as $l_category_id => $l_category_values) { // Sometimes the priority is even set without any other category values. Handle it: if (!isset($this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_category_type_id . '_' . $l_category_id][self::C__PRIORITY])) { // Append categories to the prepared data: $this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_category_type_id . '_' . $l_category_id] = $l_category_values; // Initialize category's priority: $this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_category_type_id . '_' . $l_category_id][self::C__PRIORITY] = 0; } else { // Append categories to the prepared data and merge it with existing priority: $this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_category_type_id . '_' . $l_category_id] = array_merge( $l_category_values, $this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_category_type_id . '_' . $l_category_id] ); } // Iterate through category instances: foreach ($l_category_values[self::C__CATEGORY_ENTITIES] as $l_category_data_id => $l_category_data_values) { if (!isset($l_category_data_values[self::C__PROPERTIES])) { // Skip empty category data: continue; } #if // Iterate through properties: foreach ($l_category_data_values[self::C__PROPERTIES] as $l_property_id => $l_property) { // Iterate recursivly through properties: $l_found_references = $this->find_references($l_object_id, $l_category_type_id, $l_category_id, $l_category_data_id, $l_property_id, $l_property); if(count($l_found_references) > 0){ foreach ($l_found_references as $l_ref) { if (isset($l_ref['id']) && isset($l_ref['type']) && isset($l_ref['sysid'])) { // We've found a property that's related to an object: // Look for this referenced object: $l_found_object = $this->fetch_object_reference( $l_object_id, $l_ref['id'], $l_ref['type'], $l_ref['sysid'], $l_ref[C__CATEGORY_DATA__VALUE] ); // If false, there are two possibilities: // 1. Object was not exported. // 2. Data is corrupted. // The import function has to handle it! if ($l_found_object === true) { // Increase found objects' priorities. // Use also this object's priority: $this->m_prepared[$l_property['id']][self::C__PRIORITY] += $this->m_prepared[$l_object_id][self::C__PRIORITY] + 1; $this->m_info[self::C__OBJECTS][$l_object_id][self::C__PRIORITY] = $this->m_prepared[$l_property['id']][self::C__PRIORITY]; } #if } else if (isset($l_ref['id']) && isset($l_ref['type'])) { // We've found a property that's related to a category data: // Look for this referenced category data: $l_found_category_datas = $this->fetch_category_reference( $l_object_id, $l_ref['id'], $l_ref['type'], $l_ref[C__CATEGORY_DATA__VALUE] ); // If false, there are two possibilities: // 1. Category was not exported. // 2. Data is corrupted. // The import function has to handle it! if ($l_found_category_datas !== false) { // Increase found categories' priorities: foreach($l_found_category_datas as $l_found_category_data) { if ($l_category_values['const'] === 'C__CMDB__SUBCAT__STORAGE__DEVICE' && $l_ref['type'] === 'C__CATG__CONTROLLER') { // @todo If category C__CMDB__SUBCAT__STORAGE__DEVICE has a reference to a RAID group // there may be a problem with priorities, because RAID groups may also contain references // to C__CMDB__SUBCAT__STORAGE__DEVICE. This double referencing causes problems with other // references in C__CMDB__SUBCAT__STORAGE__DEVICE, i. e. C__CATG__CONTROLLER. This is just // a workaround: $this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_found_category_data['category_type_id'] . '_' . $l_found_category_data['category_id']][self::C__PRIORITY] += $this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_category_type_id . '_' . $l_category_id][self::C__PRIORITY] + 10000; } else { // Use also this category's priority: $this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_found_category_data['category_type_id'] . '_' . $l_found_category_data['category_id']][self::C__PRIORITY] += $this->m_prepared[$l_object_id][self::C__CATEGORIES][$l_category_type_id . '_' . $l_category_id][self::C__PRIORITY] + 1; } } #foreach } #if } #if } #foreach found references } } #foreach properties } #foreach category instances } #foreach categories } #foreach category types // Sort categories by priority: $this->m_info['object_id'] = $l_object_id; if (isset($this->m_prepared[$l_object_id][self::C__CATEGORIES])) { // $this->m_log->info('Sorting categories by priority...'); uksort( $this->m_prepared[$l_object_id][self::C__CATEGORIES], array($this, 'sort_categories') ); } #if unset($this->m_info['object_id']); $this->m_info[self::C__OBJECTS][$l_object_id][self::C__DUMMY] = false; } #foreach objects // Sort objects by priority // $this->m_log->info('Sorting objects by priority...'); uksort($this->m_prepared, array($this, 'sort_objects')); // We don't need we raw import data anymore: unset($this->m_data); // $this->m_log->debug('Optimizing data is done.'); return true; } #function /** * Finds references in the raw data structure. Used by $this->prepare(). * * @param int $p_object_id Object identifier * @param int $p_category_type_id Category type identifier * @param int $p_category_id Category identifier * @param int $p_category_data_id Category data identifier * @param int $p_property_id Property identifier * @param array $p_data_arr (optional) Defaults to null. * * @return array Found references */ private function find_references( $p_object_id, $p_category_type_id, $p_category_id, $p_category_data_id, $p_property_id, $p_data_arr = null ) { $l_result = array(); // Handle the recursion: $l_property = $p_data_arr; $l_value = null; if ($l_property[C__CATEGORY_DATA__VALUE]) { $l_value = $l_property[C__CATEGORY_DATA__VALUE]; } else{ $l_value = $l_property[C__CATEGORY_DATA__TITLE]; } $l_title = $l_property[C__CATEGORY_DATA__TITLE]; switch (gettype($l_value)) { case 'string': $l_title = $l_value; break; case 'array': foreach ($l_value as $l_sub_property) { // Next step: $l_new_result = $this->find_references( $p_object_id, $p_category_type_id, $p_category_id, $p_category_data_id, $p_property_id, $l_sub_property ); $l_result = array_merge($l_result, $l_new_result); } #foreach break; } #switch $l_new_result = array(); if (!isset($l_property[C__CATEGORY_DATA__TITLE])) { // $this->m_log->warning( // sprintf( // 'Buggy property found! Tag: %s; object ID: %s; category type ID: %s; category ID: %s', // $p_property_id, // $p_object_id, // $p_category_type_id, // $p_category_id // ) // ); } else if (isset($l_property['id']) && isset($l_property['type']) && isset($l_property['sysid'])) { // Reference to object: $l_new_result['id'] = $l_property['id']; $l_new_result['type'] = $l_property['type']; $l_new_result['sysid'] = $l_property['sysid']; $l_new_result[C__CATEGORY_DATA__VALUE] = $l_title; $this->m_info[self::C__OBJECTS][$l_property['id']][self::C__PROPERTIES] = $l_property; // $this->m_log->debug( // sprintf( // 'Reference to object %s with SYSID %s found. Its identifier is %s and its type is %s.', // $l_property[C__CATEGORY_DATA__VALUE], // $l_property['sysid'], // $l_property['id'], // $l_property['type'] // ) // ); } else if (isset($l_property['id']) && isset($l_property['type'])) { // Reference to category: $l_new_result['id'] = $l_property['id']; $l_new_result['type'] = $l_property['type']; $l_new_result[C__CATEGORY_DATA__VALUE] = $l_title; // $this->m_log->debug( // sprintf( // 'Reference to category %s found. Its identifier is %s and its type is %s.', // $l_property[C__CATEGORY_DATA__VALUE], // $l_property['id'], // $l_property['type'] // ) // ); } else if (isset($l_property['id']) && isset($l_property['const'])) { // Reference to other property content: $l_new_result['id'] = $l_property['id']; $l_new_result['const'] = $l_property['const']; $l_new_result[C__CATEGORY_DATA__VALUE] = $l_title; // $this->m_log->debug( // sprintf( // 'Reference to another property content %s with const %s found. Its identifier is %s.', // $l_property[C__CATEGORY_DATA__VALUE], // $l_property['const'], // $l_property['id'] // ) // ); } #if if (count($l_new_result) > 0) { $l_result[] = $l_new_result; } #if return $l_result; } /** * Looks for a referenced object. * * @param int $p_current_object_id Current object identifier, so it will be * ignored if found. * @param int $p_object_id Object identifier * @param int $p_type Object type * @param string $p_sysid SYSID * @param string $p_value Object title * * @return bool Returns true if object is found, otherwise false. */ private function fetch_object_reference( $p_current_object_id, $p_object_id, $p_type, $p_sysid, $p_value ) { // $this->m_log->debug( // sprintf( // 'Look for object %s of type %s with sysid %s and title %s...', // $p_object_id, // $p_type, // $p_sysid, // $p_value, // $p_current_object_id // ) // ); // Iterate through objects: foreach ($this->m_data as $l_object_id => $l_object_values) { if ($l_object_id === $p_current_object_id) { continue; } #if // Okay, we really don't need so much information, but let's get through: if ($l_object_id == $p_object_id && $l_object_values['type']['const'] == $p_type && $l_object_values['sysid'] == $p_sysid && $l_object_values[C__CATEGORY_DATA__TITLE] == $p_value) { // $this->m_log->debug('Match found.'); // if (!isset($this->m_info[self::C__OBJECTS][$l_object_id][self::C__DUMMY])) { // $this->m_info[self::C__OBJECTS][$l_object_id][self::C__DUMMY] = false; // } #if return true; } #if } #foreach if (!isset($this->m_info[self::C__OBJECTS][$l_object_id][self::C__DUMMY])) { $this->m_info[self::C__OBJECTS][$l_object_id][self::C__DUMMY] = true; } #if return false; } #function private function fetch_category_reference( $p_object_id, $p_category_data_id, $p_property_constant, $p_property_value ) { // $this->m_log->debug( // sprintf( // 'Look for object %s\'s property type %s with id %s and value %s...', // $p_object_id, // $p_property_constant, // $p_category_data_id, // $p_property_value // ) // ); // Set constant to int if it is a string: if (!is_numeric($p_property_constant)) { $p_property_constant = constant($p_property_constant); } $l_result = false; // Iterate through objects: foreach ($this->m_data as $l_object_id => $l_object_values) { if ($l_object_id !== $p_object_id) { // Objects should ignore themselves: continue; } #if // Iterate trough category types: foreach ($l_object_values[self::C__CATEGORY_TYPES] as $l_category_type_id => $l_categories) { // Iterate through categories: foreach ($l_categories as $l_category_id => $l_category_values) { // Check wether correct category: if($l_category_id != $p_property_constant) { continue; } // Iterate through category data: foreach ($l_category_values[self::C__CATEGORY_ENTITIES] as $l_category_data_id => $l_category_data_values) { if ($l_category_data_id != $p_category_data_id) { continue; } #if // Skip empty category data: if (!is_array($l_category_data_values[self::C__PROPERTIES])) { continue; } #if $l_found_value = false; // Iterate through properties: foreach ($l_category_data_values[self::C__PROPERTIES] as $l_property) { // Recursion: //list($l_const, $l_value) = $this->fetch_categories_in_properties($l_property); $l_arr = $this->fetch_categories_in_properties($l_property); if ($l_arr['value'] == $p_property_value) { $l_found_value = true; break; } #if } #foreach property if ($l_found_value === true) { // $this->m_log->debug(sprintf('Match found: category %s in category type %s', $l_category_id, $l_category_type_id)); $l_result[] = array( 'category_type_id' => $l_category_type_id, 'category_id' => $l_category_id ); } #if } #foreach category data } #foreach category } #foreach category type } #foreach object return $l_result; } #function /** * Looks recursivly for referenced categories in a property. * * @param array $p_property Property * * @return array Returns array of strings or nulls with keys 'const' and * 'value'. */ private function fetch_categories_in_properties($p_property) { $l_result = array( 'value' => null ); switch (gettype($p_property[C__CATEGORY_DATA__VALUE])) { case 'string': $l_result['value'] = $p_property[C__CATEGORY_DATA__VALUE]; break; case 'array': foreach ($p_property[C__CATEGORY_DATA__VALUE] as $l_sub_property) { // Recursion: return $this->fetch_categories_in_properties($l_sub_property); } #foreach break; } #switch return $l_result; } #function /** * Sorts objects. Used for uksort(). * * @param int $p_a_key Array key * @param int $p_a_key Array key */ private function sort_objects($p_a_key, $p_b_key) { $l_a_prio = $this->m_prepared[$p_a_key][self::C__PRIORITY]; $l_b_prio = $this->m_prepared[$p_b_key][self::C__PRIORITY]; if ($l_a_prio == $l_b_prio) { return 0; } else { return ($l_a_prio < $l_b_prio) ? 1 : -1; } #if } #function /** * Sorts categories for each object. Used for uksort(). * * @param int $p_a_key Array key * @param int $p_a_key Array key */ private function sort_categories($p_a_key, $p_b_key) { $l_a_category_type_id = null; $l_a_category_id = null; $l_b_category_type_id = null; $l_b_category_id = null; list($l_a_category_type_id, $l_a_category_id) = explode('_', $p_a_key); list($l_b_category_type_id, $l_b_category_id) = explode('_', $p_b_key); $l_a_prio = $this->m_prepared[$this->m_info['object_id']][self::C__CATEGORIES][$l_a_category_type_id . '_' . $l_a_category_id][self::C__PRIORITY]; $l_b_prio = $this->m_prepared[$this->m_info['object_id']][self::C__CATEGORIES][$l_b_category_type_id . '_' . $l_b_category_id][self::C__PRIORITY]; if ($l_a_prio == $l_b_prio) { return 0; } else { return ($l_a_prio < $l_b_prio) ? 1 : -1; } #if } #function /** * Imports CMDB data. * * @todo Get rid of the parameters. * * @param int $p_object_id (UNUSED) Object identifier * @param string $p_object_title (UNUSED) Object title * @param int $p_status (UNUSED) ITIL status * * @return bool Succees? */ public function import($p_object_id = null, $p_object_title = null, $p_status = null) { // NOTICE: This code is a little bit 'heavy', so we tried to comment it // whereever it's necessary to understand, what happens here. If you // want to change ANYTHING, please be aware of a consistent data // structure that is used whenever something is imported/exported/ // templated/duplicated/whatever. assert('isset($this->m_prepared) && is_array($this->m_prepared)'); // $this->m_log->info('Importing data to database...'); global $g_comp_database; global $g_comp_template_language_manager; global $g_convert; global $g_mandator_info; global $g_comp_signals; // Check import mode: if (!isset($this->m_mode)) { // Try to set it automaticly: $this->m_log->notice('Import mode is not set.'); if ($this->m_mandator[C__CATEGORY_DATA__VALUE] == $g_mandator_info['isys_mandator__title'] && $this->m_mandator['id'] == $g_mandator_info['isys_mandator__id']) { $this->m_log->notice('The export source is the same like this system.'); $this->set_mode(self::C__USE_IDS); } else { $this->m_log->notice('The export source is another one then this system.'); $this->set_mode(self::C__MERGE); } #if } #if // Initialize database: $l_dao = new isys_cmdb_dao($g_comp_database); // Avoid encoding problems: $g_comp_database->query("SET NAMES 'utf8';"); $g_comp_database->query("SET CHARACTER SET 'utf8';"); // Initialize logbook: $l_log = isys_event_manager::getInstance(); // Print some main information: // $this->m_log->notice('Mandator: ' . $this->m_mandator[C__CATEGORY_DATA__VALUE]); // $this->m_log->notice('Version: ' . $this->m_version); // $this->m_log->notice('Exported at: ' . date($this->m_date_format, $this->m_scantime)); // $this->m_log->notice('Export-Type: ' . $this->m_type); // Initialize variables to cache some information: $l_object_counter = array( 'created' => 0, 'updated' => 0, 'skipped' => 0 ); $l_object_ids = array(); $l_object_type_ids = array(); $l_found_objects = array(); $this->m_object_ids =& $l_object_ids; $this->m_object_type_ids =& $l_object_type_ids; $l_object_states = array(); // We need all existing object types from database to verify import: $l_object_types_result = $l_dao->get_types(); $this->m_object_types = array(); while ($l_row = $l_object_types_result->get_row()) { $this->m_object_types[$l_row['isys_obj_type__id']] = $l_row['isys_obj_type__const']; } #while #------------------------------------------------------------------------------- // $this->m_log->info('First, create referenced objects without any exported data (dummies).'); // Iterate through objects: foreach ($this->m_info[self::C__OBJECTS] as $l_object_id => $l_object_info) { if ($l_object_info[self::C__DUMMY] === false) { // Handle only dummies: continue; } #if // $this->m_log->debug( // sprintf( // 'Handle dummy object %s: %s (%s)', // $l_object_id, // $l_object_info[self::C__PROPERTIES][C__CATEGORY_DATA__VALUE], // $l_object_info[self::C__PROPERTIES]['sysid'] // ) // ); // Preparation: $l_object_ids[$l_object_id] = $l_object_id; // Look for object by its identifier in database and compare // result with this object: $l_found_objects[$l_object_id] = $this->compare_objects( $l_dao->get_object($l_object_id), $l_object_info[self::C__PROPERTIES], $l_object_ids[$l_object_id] ); // First try: if ($l_found_objects[$l_object_id] === self::C__COMPARISON__DIFFERENT) { // $this->m_log->debug( // 'Looks like current object is unknown, but we also take a look at the SYSID.' // ); // Look for object by its sysid in database and compare result // with this object: $l_found_objects[$l_object_id] = $this->compare_objects( $l_dao->get_object( $l_dao->get_obj_id_by_sysid( $l_object_info[self::C__PROPERTIES]['sysid'] ) ), $l_object_info[self::C__PROPERTIES], $l_object_ids[$l_object_id] ); } #if // Second try: if ($l_found_objects[$l_object_id] === self::C__COMPARISON__DIFFERENT) { // $this->m_log->debug( // 'Looks like current object is unknown, but we also take a look at the Title and Type.' // ); // Look for object by its sysid in database and compare result // with this object: if(defined($l_object_info[self::C__PROPERTIES]['type'])){ $l_found_objects[$l_object_id] = $this->compare_objects( $l_dao->get_object( $l_dao->get_obj_id_by_title($l_object_info[self::C__PROPERTIES]['value'], constant($l_object_info[self::C__PROPERTIES]['type'])) ), $l_object_info[self::C__PROPERTIES], $l_object_ids[$l_object_id] ); } } #if // Next try: if ($l_found_objects[$l_object_id] === self::C__COMPARISON__SAME) { // $this->m_log->debug('Match found in database.'); $l_object_type_ids[$l_object_id] = $l_object_info[self::C__PROPERTIES]['type']; } else if ($l_found_objects[$l_object_id] === self::C__COMPARISON__PARTLY) { // $this->m_log->debug( // 'Match found in database, but it\'s not exactly the same. Updating.' // ); $l_update_title = $l_object_info[self::C__PROPERTIES][C__CATEGORY_DATA__TITLE]; if (!is_array($l_object_info[self::C__PROPERTIES][C__CATEGORY_DATA__VALUE])) { $l_update_title = $l_object_info[self::C__PROPERTIES][C__CATEGORY_DATA__VALUE]; } #if try { $l_status = $l_dao->update_object( $l_object_ids[$l_object_id], null, $l_update_title, null, $l_object_info[self::C__PROPERTIES]['sysid'] ); if ($l_status === false) { $this->m_log->error('Failed to update database. Aborting.'); return false; } #if } catch (isys_exception_cmdb $e) { throw $e; } #try/catch // Keep the object type in mind: $l_object_type_ids[$l_object_id] = $l_object_info[self::C__PROPERTIES]['type']; // Log: $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__OBJECT_CHANGED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], constant($l_object_type_ids[$l_object_id]), $l_update_title ); $l_object_counter['updated']++; } else if ($l_found_objects[$l_object_id] === self::C__COMPARISON__DIFFERENT) { $this->m_log->debug( 'No match found in database. Create new object in a moment.' ); // $this->m_log->debug( // sprintf( // 'Check wether object type %s exists.', // $l_object_info[self::C__PROPERTIES]['type'] // ) // ); if (in_array($l_object_info[self::C__PROPERTIES]['type'], $this->m_object_types)) { // $this->m_log->debug('Object type already exists.'); $l_object_type_ids[$l_object_id] = $l_object_info[self::C__PROPERTIES]['type']; } else { // $this->m_log->debug('Object type is unknown. A dummy will be now created.'); $l_object_type_ids[$l_object_id] = $l_dao->insert_new_objtype( null, null, $l_object_info[self::C__PROPERTIES]['type'] ); if (!is_numeric($l_object_type_ids[$l_object_id])) { throw new isys_exception_general( sprintf( 'Failed to create new object type %s.', $l_object_info[self::C__PROPERTIES]['type'] ) ); } // $this->m_log->debug( // sprintf( // 'New object type %s created as a dummy.', // $l_object_info[self::C__PROPERTIES]['type'] // ) // ); // Log: $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__OBJECTTYPE_CREATED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], constant($l_object_type_ids[$l_object_id]) ); } #if $this->m_log->debug('Now it\'s time to create new object.'); $l_object_ids[$l_object_id] = $l_dao->insert_new_obj( constant($l_object_type_ids[$l_object_id]), false, $l_object_info[self::C__PROPERTIES][C__CATEGORY_DATA__VALUE], $l_object_info[self::C__PROPERTIES]['sysid'], C__RECORD_STATUS__NORMAL, null, null, true, null, null, null, null, null, null, C__CMDB_STATUS__IN_OPERATION ); // Log: $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__OBJECT_CREATED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], constant($l_object_type_ids[$l_object_id]) ); $l_object_counter['created']++; } #if comparison } #foreach dummy object // We don't need $m_info any more: unset($this->m_info); // $this->m_log->debug('Dummy objects created if needed.'); #------------------------------------------------------------------------------- // $this->m_log->info( // 'Second, only objects without their categories are imported.' // ); // Iterate through objects: foreach ($this->m_prepared as $l_object_id => $l_object_values) { // $this->m_log->debug( // sprintf( // 'Handle object %s: %s (%s)', // $l_object_id, // $l_object_values[C__CATEGORY_DATA__TITLE], // $l_object_values['sysid'] // ) // ); // Preparation: $l_object_ids[$l_object_id] = $l_object_id; // Act based on import mode: if ($this->m_mode !== self::C__APPEND) { // Look for object by its identifier in database and compare result // with this object: $l_found_objects[$l_object_id] = $this->compare_objects( $l_dao->get_object($l_object_id), $l_object_values, $l_object_ids[$l_object_id] ); // First try: if ($l_found_objects[$l_object_id] === self::C__COMPARISON__DIFFERENT) { // $this->m_log->debug( // 'Looks like current object is unknown, but we also take a look at the SYSID.' // ); // Look for object by its sysid in database and compare result // with this object: $l_found_objects[$l_object_id] = $this->compare_objects( $l_dao->get_object( $l_dao->get_obj_id_by_sysid( $l_object_values['sysid'] ) ), $l_object_values, $l_object_ids[$l_object_id] ); } #if // Second try: if ($l_found_objects[$l_object_id] === self::C__COMPARISON__DIFFERENT) { // $this->m_log->debug( // 'Looks like current object is unknown, but we also take a look at the Object Title and Object Type.' // ); // Look for object by its sysid in database and compare result // with this object: if(defined($l_object_values['type']['const'])){ $l_found_objects[$l_object_id] = $this->compare_objects( $l_dao->get_object( $l_dao->get_obj_id_by_title($l_object_values['title'], constant($l_object_values['type']['const'])) ), $l_object_values, $l_object_ids[$l_object_id] ); } } #if // New try: if ($l_found_objects[$l_object_id] === self::C__COMPARISON__SAME) { // $this->m_log->debug('Match found in database.'); $l_object_type_ids[$l_object_id] = constant($l_object_values['type']['const']); $l_object_states[$l_object_ids[$l_object_id]] = self::C__KEEP; } else if ($l_found_objects[$l_object_id] === self::C__COMPARISON__PARTLY) { $this->m_log->debug( 'Match found in database, but it\'s not exactly the same. Updating.' ); try { $l_status = $l_dao->update_object( $l_object_ids[$l_object_id], null, $l_object_values[C__CATEGORY_DATA__TITLE], null, $l_object_values['sysid'], null, null, $this->m_scantime, $l_object_values['created'], $l_object_values['created_by'], $l_object_values['updated'], $l_object_values['updated_by'], $l_object_values['cmdb_status'] ); if ($l_status === false) { $this->m_log->error('Failed to update database. Aborting.'); return false; } #if } catch (isys_exception_cmdb $e) { throw $e; } #try/catch $l_object_type_ids[$l_object_id] = $l_object_values['type']['const']; // Log: $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__OBJECT_CHANGED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], constant($l_object_type_ids[$l_object_id]), $l_object_values['categories'][C__CMDB__CATEGORY__TYPE_GLOBAL."_".C__CATG__GLOBAL]['title'] ); $l_object_counter['updated']++; $l_object_states[$l_object_ids[$l_object_id]] = self::C__UPDATE; } else if ($l_found_objects[$l_object_id] === self::C__COMPARISON__DIFFERENT) { $this->m_log->debug( 'No match found in database. Create new object in a moment.' ); $this->m_log->debug( sprintf( 'Check wether object type %s exists.', $l_object_values['type']['const'] ) ); if (in_array($l_object_values['type']['const'], $this->m_object_types)) { $this->m_log->debug('Object type already exists.'); $l_object_type_ids[$l_object_id] = $l_object_values['type']['const']; } else { $this->m_log->debug( 'Object type is unknown. It will be now created.' ); $l_status = $l_dao->insert_new_objtype( $l_object_values['type']['group'], $l_object_values['type']['title_lang'], $l_object_values['type']['const'] ); if (!is_numeric($l_status)) { throw new isys_exception_general( sprintf( 'Failed to create new object type %s in group %s with language constant %s.', $l_object_values['type']['const'], $l_object_values['type']['group'], $l_object_values['type']['title_lang'] ) ); } $l_object_type_ids[$l_object_id] = $l_object_values['type']['const']; $this->m_log->debug( sprintf( 'New object type %s created in group %s with language constant %s.', $l_object_values['type']['const'], $l_object_values['type']['group'], $l_object_values['type']['title_lang'] ) ); // Log: $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__OBJECTTYPE_CREATED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], constant($l_object_type_ids[$l_object_id]) ); } #if $this->m_log->debug('Now it\'s time to create new object.'); $l_object_ids[$l_object_id] = $l_dao->insert_new_obj( constant($l_object_type_ids[$l_object_id]), false, $l_object_values[C__CATEGORY_DATA__TITLE], $l_object_values['sysid'], $l_object_values['status'], null, date($this->m_date_format, $this->m_scantime), true, date($this->m_date_format, $l_object_values['created']), $l_object_values['created_by'], date($this->m_date_format, $l_object_values['updated']), $l_object_values['updated_by'], null, null, $l_object_values['cmdb_status'] ); // Log: $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__OBJECT_CREATED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], constant($l_object_type_ids[$l_object_id]) ); $l_object_counter['created']++; $l_object_states[$l_object_ids[$l_object_id]] = self::C__CREATE; } #if comparison } else if ($this->m_mode === self::C__APPEND) { // $this->m_log->debug( // 'Create new object in a moment.' // ); // $this->m_log->debug( // sprintf( // 'Check wether object type %s exists.', // $l_object_values['type']['const'] // ) // ); if (in_array($l_object_values['type']['const'], $this->m_object_types)) { // $this->m_log->debug('Object type already exists.'); $l_object_type_ids[$l_object_id] = $l_object_values['type']['const']; } else { // $this->m_log->debug( // 'Object type is unknown. It will be now created.' // ); $l_status = $l_dao->insert_new_objtype( $l_object_values['type']['group'], $l_object_values['type']['title_lang'], $l_object_values['type']['const'] ); if (!is_numeric($l_status)) { throw new isys_exception_general( sprintf( 'Failed to create new object type %s in group %s with language constant %s.', $l_object_values['type']['const'], $l_object_values['type']['group'], $l_object_values['type']['title_lang'] ) ); } $l_object_type_ids[$l_object_id] = $l_object_values['type']['const']; // $this->m_log->debug( // sprintf( // 'New object type %s created in group %s with language constant %s.', // $l_object_values['type']['const'], // $l_object_values['type']['group'], // $l_object_values['type']['title_lang'] // ) // ); // Log: $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__OBJECTTYPE_CREATED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], constant($l_object_type_ids[$l_object_id]) ); } #if // $this->m_log->debug('Now it\'s time to create new object.'); $l_object_ids[$l_object_id] = $l_dao->insert_new_obj( constant($l_object_type_ids[$l_object_id]), false, $l_object_values[C__CATEGORY_DATA__TITLE], $l_object_values['sysid'], $l_object_values['status'], null, date($this->m_date_format, $this->m_scantime), true, date($this->m_date_format, $l_object_values['created']), $l_object_values['created_by'], date($this->m_date_format, $l_object_values['updated']), $l_object_values['updated_by'], null, null, $l_object_values['cmdb_status'] ); // Log: $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__OBJECT_CREATED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], constant($l_object_type_ids[$l_object_id]) ); $l_object_counter['created']++; $l_object_states[$l_object_ids[$l_object_id]] = self::C__CREATE; } } #foreach objects #------------------------------------------------------------------------------- // $this->m_log->info('Third, after importing only objects also import their categories.'); // Fetch all categories from database: $l_all_categories = $this->fetch_all_categories(); /*print_r($this->m_object_ids);*/ // Iterate through objects: foreach ($this->m_prepared as $l_object_id => $l_object_values) { // $this->m_log->debug( // sprintf( // 'Handle object %s: %s (%s)', // $l_object_ids[$l_object_id], // $l_object_values[C__CATEGORY_DATA__TITLE], // $l_object_values['sysid'] // ) // ); // Initialize some information about the categories: $l_changed_categories = false; $l_category_ids = array(); $l_category_data_ids = array(); $l_property_ids = array(); // Remember processed dao's for this object to not process them twice. (Like it's done with Person and Person-Masterdata) $l_daos_processed = array(); // Prepare id cache $this->m_category_ids[$l_object_id] =& $l_category_ids; $this->m_category_data_ids[$l_object_id] =& $l_category_data_ids; $this->m_property_ids[$l_object_id] =& $l_property_ids; // Iterate trough categories: foreach ($l_object_values[self::C__CATEGORIES] as $l_category_key => $l_category_values) { // Determine identifiers: $l_category_type_id = null; $l_category_id = null; list($l_category_type_id, $l_category_id) = explode('_', $l_category_key); // The custom category type needs a special handling: if ($l_category_type_id == C__CMDB__CATEGORY__TYPE_CUSTOM) { $l_category_id = C__CATG__CUSTOM_FIELDS; $l_category_type_id = C__CMDB__CATEGORY__TYPE_GLOBAL; } #if // Translate category name: $l_category_name = $g_comp_template_language_manager->get( $l_all_categories[$l_category_type_id][$l_category_id]['title'] ); // $this->m_log->debug( // sprintf( // 'Handle category %s (%s, type %s).', // $l_category_name, // $l_category_values['const'], // $l_category_type_id // ) // ); // Check category type id: if (!array_key_exists($l_category_type_id, $l_dao->get_category_types())) { // $this->m_log->debug( // sprintf( // 'Category type %s does not exist. Skipping.', // $l_category_type_id // ) // ); continue; } #if // Class name of category DAO: $l_cat_class = $l_all_categories[$l_category_type_id][$l_category_id]['class_name']; // If DAO was already processed, skip this iteration if (isset($l_daos_processed[$l_cat_class])) { // $this->m_log->debug( // sprintf( // 'Category %s [%s] was already processed by the import. Skipping.', // $l_cat_class, // $l_category_id // ) // ); continue; } if (!class_exists($l_cat_class)) { // $this->m_log->debug( // sprintf( // 'Category %s [%s] (taken from import) is not available on this i-doit system. Skipping.', // $l_cat_class, // $l_category_id // ) // ); continue; } #if // We need the category DAO: $l_cat_dao = new $l_cat_class($g_comp_database); // Remember wether dao has been processed before: $l_daos_processed[$l_cat_class] = true; // One more time using special handling for custom categories: if ($l_category_id == C__CATG__CUSTOM_FIELDS) { // $this->m_log->debug( // sprintf( // 'Handle custom category %s [%s].', // $l_category_values['title'], // $l_category_values['const'] // ) // ); // This identifier is needed to get category's data information: $l_catg_custom_id = key($l_category_values[self::C__CATEGORY_ENTITIES]); $l_cat_dao->set_catg_custom_id($l_catg_custom_id); // Check wether custom category already exists: $l_custom_module = new isys_module_dao_custom_fields($g_comp_database); // Create custom category configuration: $l_config = array(); foreach ($l_category_values[self::C__CATEGORY_ENTITIES] as $l_category_data_values) { foreach ($l_category_data_values['properties'] as $l_tag => $l_values) { if ($l_tag == 'description') { continue; } $l_key = substr(strrchr($l_tag, '_'), 1); $l_type = substr($l_tag, 0, strrpos($l_tag, '_')); $l_config[$l_key] = array( 'type' => $l_type, 'title' => $l_values['title'] ); if ($l_type == 'f_popup') { if (is_string($l_values['sysid'])) { $l_config[$l_key]['popup'] = 'browser_object'; } else { $l_config[$l_key]['popup'] = 'dialog_plus'; $l_config[$l_key]['identifier'] = $l_values[C__CATEGORY_DATA__VALUE]; } } } } $l_serialized_config = serialize($l_config); // Search by identifier, title and config: $l_found = false; $l_module_data = $l_custom_module->get_data(null, $l_category_values['title'])->__as_array(); if (count($l_module_data) > 0) { foreach ($l_module_data as $l_candidate) { if ($l_candidate['isysgui_catg_custom__id'] == $l_catg_custom_id) { $l_found = true; } else if ($l_candidate['isysgui_catg_custom__config'] == $l_serialized_config) { $l_found = true; } if ($l_found === true) { // Update identifier: $l_catg_custom_id = $l_candidate['isysgui_catg_custom__id']; $l_cat_dao->set_catg_custom_id($l_catg_custom_id); break; } } } if ($l_found === false) { $this->m_log->notice( sprintf( 'Custom category %s [%s] not found. Creating...', $l_category_values['title'], $l_category_values['const'] ) ); $l_catg_custom_id = $l_custom_module->create( $l_category_values['title'], $l_config, 0, 0 ); if ($l_catg_custom_id === false) { // $this->m_log->warning( // sprintf( // 'Failed to create custom category %s [%s]. Skipping.', // $l_category_values['title'], // $l_category_values['const'] // ) // ); continue; } #if $l_status = $l_custom_module->assign( $l_catg_custom_id, constant($l_object_type_ids[$l_object_id]) ); if ($l_status === false) { // $this->m_log->warning( // sprintf( // 'Failed to assign custom category %s [%s] to object type %s. Skipping.', // $l_category_values['title'], // $l_category_values['const'], // $l_object_type_ids[$l_object_id] // ) // ); continue; } #if // Update identifier: $l_cat_dao->set_catg_custom_id($l_catg_custom_id); } #if custom category is unknown unset($l_custom_module); } #if custom category // Get property information: $l_property_info = $l_cat_dao->get_data_information(); // Is it a single or a multi-value category $l_cat_multi = (bool) $l_all_categories[$l_category_type_id][$l_category_id]['list_multi_value']; // Fetch category data from database by object identifier: $l_object_category_dataset = array(); if ($this->m_mode === self::C__MERGE || $this->m_mode === self::C__USE_IDS) { $l_object_category_dataset = $l_cat_dao->get_data_by_object($l_object_ids[$l_object_id])->__as_array(); } #if // Save category identifier: $l_category_ids[$l_category_type_id][$l_category_id] = $l_cat_dao->get_category_id(); // We need the category's 'main' table: $l_table = null; if (isset($this->m_info['tables'][$l_category_type_id][$l_category_id])) { // Short way: $l_table = $this->m_info['tables'][$l_category_type_id][$l_category_id]; } else { $l_table = $l_all_categories[$l_category_type_id][$l_category_id]['source_table']; // @todo The table names are broken: $l_table = (!strpos($l_table, '_list') && !strpos($l_table, '_2_')) ? $l_table."_list" : $l_table; /** * @todo isys_netp_ifacel is not conform to the * i-doit developer's conventions. It should be * called isys_catg_interface_l. */ if ($l_category_values['const'] === 'C__CMDB__SUBCAT__NETWORK_INTERFACE_L') { $l_table = 'isys_netp_ifacel'; } #if $this->m_info['tables'][$l_category_type_id][$l_category_id] = $l_table; } #if // Protect already used datasets: $l_used_datasets = array(); // Don't delete new added category data: $l_already_overwritten = false; // Iterate through category instances: foreach ($l_category_values[self::C__CATEGORY_ENTITIES] as $l_category_data_id => $l_category_data_values) { // $this->m_log->debug( // sprintf( // 'Handle category data %s.', // $l_category_data_id // ) // ); // Skip empty categories: if (count($l_category_data_values[self::C__PROPERTIES]) == 0) { // You may ask, why there are even these empty // categories? Whenever an empty category is edited // in the GUI, an empty entity will be created in // the database. But if the edit mode is aborted, // the empty entity will still remain. continue; } #if // Initiate used properties. Only these will be used for // the import: $l_used_properties = array(); // Iterate through properties to be imported: foreach ($l_category_data_values['properties'] as $l_key => $l_value) { // Check wether property is enabled for syncing: $l_used_properties[$l_key] = false; foreach ($l_property_info as $l_info) { // Skip useless properties (how could this happen?!): if (!isset($l_info[C__CATEGORY_DATA__TAG]) || $l_info[C__CATEGORY_DATA__TAG] !== $l_key) { continue; } #if // Import for this property is disabled: if (isset($l_info[C__CATEGORY_DATA__IMPORT]) && $l_info[C__CATEGORY_DATA__IMPORT] === false) { continue 2; } #if // Import for this property is disabled (next try): if (!isset($l_info[C__CATEGORY_DATA__VALUE])) { continue 2; } #if // Found right property: if ($l_info[C__CATEGORY_DATA__TAG] == $l_key) { $l_used_properties[$l_key] = $l_info; break; } #if } #foreach property information // Cannot match property with given information. Skipping: if ($l_used_properties[$l_key] === false) { continue; } #if // Call helper if needed: if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]) && isset($l_used_properties[$l_key][C__CATEGORY_DATA__METHOD])) { if (!class_exists($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER])) { throw new isys_exception_cmdb( sprintf( 'Import failed. Helping class %s for importing data is not available.', $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] ) ); } #if $l_helper_method = $l_used_properties[$l_key][C__CATEGORY_DATA__METHOD] . '_import'; // @todo Refactor this code. if (!method_exists($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER], $l_helper_method)) { // $this->m_log->warning( // sprintf( // 'Helping method %s for importing data is not available. Method was expected in class %s. Skipping', // $l_helper_method, // $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] // ) // ); } else { // Initiate helper class: $l_helper = null; if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__PARAM])) { $l_helper = new $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]($l_used_properties[$l_key][C__CATEGORY_DATA__PARAM]); } else { $l_helper = new $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]; } #if if (method_exists($l_helper, 'set_database')) { $l_helper->set_database($g_comp_database); } #if if (method_exists($l_helper, 'set_object_ids')) { $l_helper->set_object_ids($l_object_ids); } #if if (method_exists($l_helper, 'set_property_info')) { $l_helper->set_property_info($l_property_info); } #if if (method_exists($l_helper, 'set_property_data')){ $l_helper->set_property_data($l_category_data_values[self::C__PROPERTIES]); } #if if (method_exists($l_helper, 'set_category_ids')){ $l_helper->set_category_ids($l_category_ids); } #if if (method_exists($l_helper, 'set_category_data_ids')){ $l_helper->set_category_data_ids($l_category_data_ids); } #if if (method_exists($l_helper, 'set_mode')){ $l_helper->set_mode($this->m_mode); } #if $l_transformed = null; // Transform only values which needs to be // converted: if ($l_helper_method == 'convert_import' || $l_helper_method == 'dialog_import' || $l_helper_method == 'dialog_plus_import') { if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__ARG])) { $l_transformed = $l_helper->$l_helper_method( $l_used_properties[$l_key][C__CATEGORY_DATA__ARG] ); } else { $l_transformed = $l_helper->$l_helper_method( $l_value ); } #if if ($l_transformed === false) { // $this->m_log->warning( // sprintf( // 'Transformation failed (method %s from class %s).', // $l_helper_method, // $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] // ) // ); } #if } else { // Convert value for the comparison: $l_transformed = $l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE]; } #if if ($l_helper_method == 'convert_import') { $l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE.'_converted'] = $l_transformed; } else { $l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE] = $l_transformed; } #if unset($l_helper); } #if method exists } #if helper is needed } #foreach property // Initiate change log: $l_category_changes = array(); // Initiate helper class: $l_helper = null; // Initiate status: $l_category_data_status = self::C__CREATE; // Act based on import mode: if ($this->m_mode === self::C__APPEND) { $l_category_data_status = self::C__CREATE; // $this->m_log->debug( // 'Ignore data from database.' // ); } else if ($this->m_mode === self::C__OVERWRITE) { $l_category_data_status = self::C__CREATE; if ($l_already_overwritten === false) { // $this->m_log->debug( // 'Deleting existing category data from database...' // ); $l_cleared = $l_dao->clear( $l_table, $l_object_ids[$l_object_id] ); if ($l_cleared === true) { // $this->m_log->info( // 'Category data deleted.' // ); } else { // $this->m_log->warning( // sprintf( // 'Could not delete category data for object %s from category %s.', // $l_object_values[C__CATEGORY_DATA__TITLE], // $l_category_name // ) // ); } #if status $l_already_overwritten = true; } #if overwrite } else if ($this->m_mode === self::C__MERGE || $this->m_mode === self::C__USE_IDS) { // There are one or more data sets fetched from // database: if (count($l_object_category_dataset) == 0 || $l_category_id == C__CATG__CUSTOM_FIELDS) { $l_category_data_status = self::C__CREATE; } else { // If the category is single-valued, the standard // action is to update an existing dataset, // otherwise create it: if ($l_cat_multi === true) { $l_category_data_status = self::C__CREATE; } else { $l_category_data_status = self::C__UPDATE; } #if // Initiate some information about the comparison: $l_badness = array(); $l_comparison = array(); // // Let's compare the data from database with the // current category data to be imported: // $this->m_log->debug( // 'Checking wether one of the datasets matches the properties...' // ); // Iterate through local data sets: foreach ($l_object_category_dataset as $l_dataset) { $l_dataset_id_changed = false; $l_dataset_id = $l_dataset[$l_table . '__id']; // $this->m_log->debug( // sprintf( // 'Handle dataset %s.', // $l_dataset_id // ) // ); // Test the category data identifier: if ($l_category_data_values['data_id'] !== $l_dataset_id) { // $this->m_log->debug('Category data identifier is different.'); $l_badness[$l_dataset_id]++; $l_dataset_id_changed = true; if ($this->m_mode === self::C__USE_IDS) { continue; } #if } #if // Test each property: foreach ($l_category_data_values['properties'] as $l_key => $l_value) { // Find the right tag: if ($l_key !== $l_used_properties[$l_key][C__CATEGORY_DATA__TAG]) { continue; } #if // Need to unconvert: if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]) && isset($l_used_properties[$l_key][C__CATEGORY_DATA__METHOD])) { if (!class_exists($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER])) { throw new isys_exception_cmdb( sprintf( 'Import failed. Helping class %s for importing data is not available.', $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] ) ); } #if $l_helper_method = $l_used_properties[$l_key][C__CATEGORY_DATA__METHOD] . '_import'; // @todo Refactor this code. if (!method_exists($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER], $l_helper_method)) { // $this->m_log->warning( // sprintf( // 'Helping method %s for importing data is not available. Method was expected in class %s. Skipping', // $l_helper_method, // $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] // ) // ); if (isset($l_category_data_values[self::C__PROPERTIES][$l_key]['sysid'])) { // Object reference: $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = $l_object_ids[$l_category_data_values[self::C__PROPERTIES][$l_key]['id']]; // $this->m_log->info( // 'It is an object reference.' // ); } else { // Category reference: $l_id_set = false; $l_type_set = false; if (is_array($l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE])) { foreach ($l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] as $l_key2 => $l_val) { if (is_array($l_val)) { foreach ($l_val as $l_key3 => $l_val2) { if ($l_key3 === 'id') { $l_id_set = $l_val2; } if ($l_key3 === 'type') { $l_type_set = $l_val2; } } } else { if ($l_key2 === 'id') { $l_id_set = $l_val; } if ($l_key2 === 'type') { $l_type_set = $l_val; } } if ($l_id_set && $l_type_set) { break; } } } else { foreach ($l_category_data_values[self::C__PROPERTIES][$l_key] AS $l_key2 => $l_val) { if($l_key2 === 'id') { $l_id_set = $l_val; } if ($l_key2 === 'type') { $l_type_set = $l_val; } if ($l_id_set && $l_type_set) { break; } } } #if if ($l_id_set && $l_type_set) { if (!is_numeric($l_type_set)) { $l_type_set = constant($l_type_set); } if (isset($l_category_data_ids[$l_category_type_id][$l_type_set][$l_id_set])) { $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = $l_category_data_ids[$l_category_type_id][$l_type_set][$l_id_set]; // $this->m_log->info( // 'It is a category reference.' // ); } else { $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = null; } } #if } #if type of reference } else { // Initiate helper class: $l_helper = null; if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__PARAM])) { $l_helper = new $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]($l_used_properties[$l_key][C__CATEGORY_DATA__PARAM]); } else { $l_helper = new $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]; } #if if (method_exists($l_helper, 'set_database')) { $l_helper->set_database($g_comp_database); } #if if (method_exists($l_helper, 'set_row')){ $l_helper->set_row($l_dataset); } #if if (method_exists($l_helper, 'set_object_ids')) { $l_helper->set_object_ids($l_object_ids); } #if if (method_exists($l_helper, 'set_property_info')) { $l_helper->set_property_info($l_property_info); } #if if (method_exists($l_helper, 'set_property_data')) { $l_helper->set_property_data($l_category_data_values[self::C__PROPERTIES]); } #if if (method_exists($l_helper, 'set_category_ids')) { $l_helper->set_category_ids($l_category_ids); } #if if (method_exists($l_helper, 'set_category_data_ids')){ $l_helper->set_category_data_ids($l_category_data_ids); } #if if (method_exists($l_helper, 'set_mode')){ $l_helper->set_mode($this->m_mode); } #if $l_local = $l_dataset[$l_used_properties[$l_key][C__CATEGORY_DATA__VALUE]]; $l_import = $l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE]; // Initiate variables to save original // unconcerted values: $l_import_unconverted = null; $l_local_unconverted = null; // If values has been converted, convert the local value to the right unit: if (isset($l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE.'_converted'])) { $l_helper->set_reversed_methods(false); $l_import_unconverted = $l_import; $l_helper->set_additional($l_used_properties[$l_key][C__CATEGORY_DATA__PARAM]); $l_local_unconverted = $l_helper->$l_helper_method( array( C__CATEGORY_DATA__VALUE => $l_local, C__CATEGORY_DATA__TAG => $l_key ) ); $l_import = $l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE.'_converted']; } else { if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]) && isset($l_used_properties[$l_key][C__CATEGORY_DATA__METHOD]) /*&& in_array($l_used_properties[$l_key][C__CATEGORY_DATA__METHOD],$this->m_helper_methods)*/) { if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__ARG])) { $l_import = $l_helper->$l_helper_method( $l_used_properties[$l_key][C__CATEGORY_DATA__ARG] ); } else { $l_import = $l_helper->$l_helper_method( $l_value ); } #if if ($l_import === false) { // $this->m_log->warning( // sprintf( // 'Transformation failed (method %s from class %s).', // $l_helper_method, // $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] // ) // ); } #if $l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE] = $l_import; } else { } #if type of method } #if converted if ($l_local != $l_import && gettype($l_import) != 'array') { if (isset($l_value['const']) && $l_value['title_lang']) { $l_import = $g_comp_template_language_manager->get($l_value['title_lang']); $l_local_arr = $l_helper->dialog_plus($l_dataset[$l_used_properties[$l_key][C__CATEGORY_DATA__VALUE]],$l_used_properties[$l_key][C__CATEGORY_DATA__PARAM]); $l_local = $g_comp_template_language_manager->get($l_local_arr['title_lang']); } #if // $this->m_log->debug( // sprintf( // 'Property %s is different.', // $l_used_properties[$l_key][C__CATEGORY_DATA__TAG] // ) // ); // Build change log: if ($l_import_unconverted != '' && $l_local_unconverted != '') { $l_category_changes[$l_used_properties[$l_key][C__CATEGORY_DATA__FORMTAG]] = array( 'from' => $l_local_unconverted, 'to' => $l_import_unconverted ); } else { $l_category_changes[$l_used_properties[$l_key][C__CATEGORY_DATA__FORMTAG]] = array( 'from' => $l_local, 'to' => $l_import ); } $l_badness[$l_dataset_id]++; } else if (gettype($l_import) == 'array') { // $this->m_log->debug( // sprintf( // 'Could not compare values. Import Property is an array.', // $l_used_properties[$l_key][C__CATEGORY_DATA__TAG] // ) // ); } unset( $l_helper, $l_import_unconverted, $l_local_unconverted ); } #if } #if helper } #foreach used property if ($l_badness[$l_dataset_id] > self::C__COMPARISON__THRESHOLD && $l_cat_multi) { // $this->m_log->debug( // 'Dataset differs completly from category data.' // ); $l_comparison[self::C__COMPARISON__DIFFERENT][] = $l_dataset_id; } else if ($l_badness[$l_dataset_id] == 0) { // $this->m_log->debug( // 'Dataset and category data are the same.' // ); $l_comparison[self::C__COMPARISON__SAME][] = $l_dataset_id; } else { // $this->m_log->debug( // 'Dataset differs partly from category data.' // ); $l_comparison[self::C__COMPARISON__PARTLY][] = $l_dataset_id; } #if } #foreach data set $l_candidate_found = null; if (isset($l_comparison[self::C__COMPARISON__SAME]) && count($l_comparison[self::C__COMPARISON__SAME]) > 0) { foreach ($l_comparison[self::C__COMPARISON__SAME] as $l_candidate) { if (!in_array($l_candidate, $l_used_datasets)) { $l_candidate_found = $l_candidate; $l_used_datasets[] = $l_candidate; $l_category_data_status = self::C__KEEP; $l_category_data_values['data_id'] = $l_candidate; // $this->m_log->debug( // sprintf( // 'Dataset %s will be kept.', // $l_candidate // ) // ); break; } #if } #foreach } #if if ($l_candidate_found === null && isset($l_comparison[self::C__COMPARISON__PARTLY]) && count($l_comparison[self::C__COMPARISON__PARTLY]) > 0) { foreach ($l_badness as $l_cat_id => $l_bad_value) { if (is_null($l_candidate_found)) { $l_candidate_found = $l_cat_id; } else if ($l_badness[$l_candidate_found] > $l_bad_value) { $l_candidate_found = $l_cat_id; } } foreach ($l_comparison[self::C__COMPARISON__PARTLY] as $l_candidate) { if (!in_array($l_candidate, $l_used_datasets)) { $l_candidate_found = $l_candidate; $l_used_datasets[] = $l_candidate; $l_category_data_status = self::C__UPDATE; $l_category_data_values['data_id'] = $l_candidate; // $this->m_log->debug( // sprintf( // 'Dataset %s will be updated.', // $l_candidate // ) // ); break; } #if } #foreach } #if } #if count dataset } #if import mode // Initiate 'new' category data identifier: $l_new_category_data_id = $l_category_data_values['data_id']; if ($l_category_data_status !== self::C__KEEP) { if ($l_category_data_status === self::C__CREATE) { // $this->m_log->debug('Dataset will be created.'); } #if create dataset if ($this->m_mode == self::C__MERGE && count($l_object_category_dataset) > 0 && $l_category_id != C__CATG__CUSTOM_FIELDS) { // Skip transformation, because it's already done. } else { foreach ($l_category_data_values['properties'] as $l_key => $l_value) { // Need to unconvonvert: if (!isset($l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE.'_converted']) && isset($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]) && isset($l_used_properties[$l_key][C__CATEGORY_DATA__METHOD])) { if (!class_exists($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER])) { // $this->m_log->warning( // sprintf( // 'Import failed. Helping class %s for importing data is not available. Skipping.', // $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] // ) // ); continue; } #if $l_method = $l_used_properties[$l_key][C__CATEGORY_DATA__METHOD] . "_import"; if (!method_exists($l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER], $l_method)) { // $this->m_log->warning( // sprintf( // 'Helping method %s for importing data is not available. Method was expected in class %s. Skipping', // $l_method, // $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] // ) // ); // if (isset($l_category_data_values[self::C__PROPERTIES][$l_key]['sysid'])) { // Object reference $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = $l_object_ids[$l_category_data_values[self::C__PROPERTIES][$l_key]['id']]; } else { // Category reference $l_id_set = false; $l_type_set = false; if (is_array($l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE])) { foreach ($l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] AS $l_key2 => $l_val) { if(is_array($l_val)){ foreach ($l_val as $l_key3 => $l_val2) { if ($l_key3 === 'id') { $l_id_set = $l_val2; } #if if ($l_key3 === 'type') { $l_type_set = $l_val2; } #if } #foreach } else { if ($l_key2 === 'id') { $l_id_set = $l_val; } if ($l_key2 === 'type') { $l_type_set = $l_val; } } #if if ($l_id_set && $l_type_set) { break; } #if } #foreach category data value // $this->m_log->info( // 'It is a category reference.' // ); } else { foreach ($l_category_data_values[self::C__PROPERTIES][$l_key] as $l_key2 => $l_val) { if ($l_key2 === 'id') { $l_id_set = $l_val; } #if if ($l_key2 === 'type') { $l_type_set = $l_val; } #if if ($l_id_set && $l_type_set) { break; } #if } #foreach property } #if if ($l_id_set && $l_type_set) { if (!is_numeric($l_type_set)) { $l_type_set = constant($l_type_set); } if (isset($l_category_data_ids[$l_category_type_id][$l_type_set][$l_id_set])) { $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = $l_category_data_ids[$l_category_type_id][$l_type_set][$l_id_set]; } else { $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = null; } #if } #if } #if type of reference continue; } #if method exists if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__PARAM])) { $l_helper = new $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER]($l_used_properties[$l_key][C__CATEGORY_DATA__PARAM]); } else { $l_helper = new $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER](); } #if if (method_exists($l_helper, 'set_database')) { $l_helper->set_database($g_comp_database); } #if if (method_exists($l_helper, 'set_object_ids')) { $l_helper->set_object_ids($l_object_ids); } #if if (method_exists($l_helper, 'set_property_info')) { $l_helper->set_property_info($l_property_info); } #if if (method_exists($l_helper, 'set_property_data')){ $l_helper->set_property_data($l_category_data_values[self::C__PROPERTIES]); } #if if (method_exists($l_helper, 'set_category_ids')){ $l_helper->set_category_ids($l_category_ids); } #if if (method_exists($l_helper, 'set_category_data_ids')){ $l_helper->set_category_data_ids($l_category_data_ids); } #if if (method_exists($l_helper, 'set_reversed_methods')) { $l_helper->set_reversed_methods(true); } #if if (method_exists($l_helper, 'set_mode')){ $l_helper->set_mode($this->m_mode); } #if $l_import = null; if (isset($l_used_properties[$l_key][C__CATEGORY_DATA__ARG])) { $l_import = $l_helper->$l_method($l_used_properties[$l_key][C__CATEGORY_DATA__ARG]); } else { $l_import = $l_helper->$l_method($l_value); } #if if ($l_import === false) { // $this->m_log->warning( // sprintf( // 'Transformation failed (method %s from class %s).', // $l_method, // $l_used_properties[$l_key][C__CATEGORY_DATA__IMPORT_HELPER] // ) // ); } #if $l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE] = $l_import; unset($l_helper); } else { if (isset($l_category_data_values[self::C__PROPERTIES][$l_key]['sysid'])) { // Object reference $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = $l_object_ids[$l_category_data_values[self::C__PROPERTIES][$l_key]['id']]; } else { // Category reference $l_id_set = false; $l_type_set = false; if (is_array($l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE])) { foreach ($l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] AS $l_key2 => $l_val) { if(is_array($l_val)){ foreach ($l_val AS $l_key3 => $l_val2) { if ($l_key3 === 'id') { $l_id_set = $l_val2; } #if if ($l_key3 === 'type') { $l_type_set = $l_val2; } #if } #foreach } else { if ($l_key2 === 'id') { $l_id_set = $l_val; } if ($l_key2 === 'type') { $l_type_set = $l_val; } } #if if ($l_id_set && $l_type_set) { break; } #if } #foreach category data value // $this->m_log->info( // 'It is a category reference.' // ); } else { foreach ($l_category_data_values[self::C__PROPERTIES][$l_key] AS $l_key2 => $l_val) { if($l_key2 === 'id'){ $l_id_set = $l_val; } #if if($l_key2 === 'type'){ $l_type_set = $l_val; } #if if($l_id_set && $l_type_set){ break; } #if } #foreach property } #if if ($l_id_set && $l_type_set) { if (!is_numeric($l_type_set)) { $l_type_set = constant($l_type_set); } if (isset($l_category_data_ids[$l_category_type_id][$l_type_set][$l_id_set])) { $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = $l_category_data_ids[$l_category_type_id][$l_type_set][$l_id_set]; } else { $l_category_data_values[self::C__PROPERTIES][$l_key][C__CATEGORY_DATA__VALUE] = NULL; } #if } #if } #if type of reference } #if type of method } #foreach property } #if transformation is needed // $this->m_log->debug('Syncing category...'); // Emitting signal: $g_comp_signals->emit( 'mod.cmdb.beforeCategorySync', $l_category_id, $l_category_data_values, $l_object_ids[$l_object_id], $l_category_data_status ); // Sync category: $l_new_category_data_id = $l_cat_dao->sync( $l_category_data_values, $l_object_ids[$l_object_id], $l_category_data_status ); // Emitting signal: $g_comp_signals->emit( 'mod.cmdb.afterCategorySync', $l_category_id, $l_category_data_values, $l_new_category_data_id, $l_object_ids[$l_object_id], $l_category_data_status ); if ($l_new_category_data_id === false) { // $this->m_log->warning( // sprintf( // 'Syncing category %s (%s, %s) failed.', // $l_category_name, // $l_category_values['const'], // $l_category_id // ) // ); continue; } #if } #if not keep // Initiate compressed change log: $l_category_changed_compressed = null; // Create new logbook entry: if ($l_category_data_status === self::C__CREATE) { // $this->m_log->debug('Dataset created.'); // Build change log: foreach ($l_category_data_values['properties'] as $l_key => $l_value) { // Find the right tag: if ($l_key !== $l_used_properties[$l_key][C__CATEGORY_DATA__TAG]) { continue; } #if $l_category_changes[$l_used_properties[$l_key][C__CATEGORY_DATA__FORMTAG]] = array( 'from' => 0, 'to' => $l_category_data_values['properties'][$l_key][C__CATEGORY_DATA__VALUE] ); break; } #foreach property if (count($l_category_changes) > 0) { $l_category_changed_serialized = serialize($l_category_changes); $l_category_changed_compressed = gzcompress($l_category_changed_serialized); } else { $l_category_changed_compressed = ''; } #if $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__CATEGORY_CHANGED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], $l_object_type_ids[$l_object_id], $l_category_name, $l_category_changed_compressed ); } else if ($l_category_data_status === self::C__UPDATE) { $this->m_log->debug ('Dataset updated.'); if (count($l_category_changes) > 0) { $l_category_changed_serialized = serialize($l_category_changes); $l_category_changed_compressed = gzcompress($l_category_changed_serialized); $l_log->triggerCMDBEvent( C__LOGBOOK_EVENT__CATEGORY_CHANGED, $g_comp_template_language_manager->get('LC__UNIVERSAL__IMPORT'), $l_object_ids[$l_object_id], $l_object_type_ids[$l_object_id], $l_category_name, $l_category_changed_compressed ); } #if } else if ($l_category_data_status === self::C__KEEP) { $this->m_log->debug('Dataset kept.'); } #if status // Save category data's identifier for referencing categories: $l_category_data_ids[$l_category_type_id][$l_category_id][$l_category_data_id] = $l_new_category_data_id; // Save for statistics that categorie has changed: $l_changed_categories = true; } #foreach category instances // We don't need the category DAO anymore: unset($l_cat_dao); // Update counter: if ($l_changed_categories === true && $l_found_objects[$l_object_id] === self::C__COMPARISON__SAME) { $l_object_counter['updated']++; } else if ($l_changed_categories === false && $l_found_objects[$l_object_id] === self::C__COMPARISON__SAME) { $l_object_counter['skipped']++; } #if } #foreach categories } #foreach objects // $this->m_log->notice( // sprintf( // 'Import was successful. %s object(s) created, %s updated, and %s skipped.', // $l_object_counter['created'], // $l_object_counter['updated'], // $l_object_counter['skipped'] // ) // ); unset($l_dao); return true; } #function /** * Compares two objects wether they are the same. One comes from the export * the another from the database. Used by $this->import(). * * @param array &$p_database_object Reference to object from database * @param array &$p_import_object Reference to object from export * @param int &$p_object_id Reference to object identifier * * @return int Result */ private function compare_objects(&$p_database_object, &$p_import_object, &$p_object_id) { $l_result = self::C__COMPARISON__FAILED; $l_badness = 0; if ($p_database_object->num_rows() !== 1) { $this->m_log->debug('No object found.'); $l_badness += 1000; } #if $l_existing_object = $p_database_object->get_row(); // Rating: if ($l_existing_object['isys_obj__id'] !== $p_import_object['id']) { $this->m_log->debug('No object with that ID found.'); $l_badness++; } #if $l_type = null; if (is_array($p_import_object['type']) && isset($p_import_object['type']['const'])) { $l_type = constant($p_import_object['type']['const']); } else if (is_string($p_import_object['type'])) { foreach ($this->m_object_types as $l_id => $l_const) { if ($l_const === $p_import_object['type']) { $l_type = $l_id; break; } #if } #foreach } #if if ($l_existing_object['isys_obj__isys_obj_type__id'] != $l_type) { $this->m_log->debug('Object type is different.'); $l_badness += 1000; } else{#if $l_title_type_exists++; } $l_title = null; if (isset($p_import_object[C__CATEGORY_DATA__VALUE])) { $l_title = $p_import_object[C__CATEGORY_DATA__VALUE]; } else if ($p_import_object[C__CATEGORY_DATA__TITLE]) { $l_title = $p_import_object[C__CATEGORY_DATA__TITLE]; } #if if ($l_existing_object['isys_obj__title'] !== $l_title) { $this->m_log->debug('Object title is different.'); $l_badness++; } else{#if $l_title_type_exists++; } if ($l_existing_object['isys_obj__sysid'] !== $p_import_object['sysid']) { $this->m_log->debug('Object SYSID is different.'); if($l_title_type_exists == 2) $l_badness++; else $l_badness +=1000; } #if if (isset($p_import_object['category_types'][C__CMDB__CATEGORY__TYPE_GLOBAL][C__CATG__GLOBAL][self::C__CATEGORY_ENTITIES][$l_object_id][self::C__PROPERTIES]['description'][C__CATEGORY_DATA__VALUE]) && $l_existing_object['isys_obj__description'] !== $p_import_object['category_types'][C__CMDB__CATEGORY__TYPE_GLOBAL][C__CATG__GLOBAL][self::C__CATEGORY_ENTITIES][$l_object_id][self::C__PROPERTIES]['description'][C__CATEGORY_DATA__VALUE]) { $this->m_log->debug('Object description is different.'); $l_badness++; } #if if (isset($p_import_object['created'])) { if (strtotime($l_existing_object['isys_obj__created']) != $p_import_object['created']) { $this->m_log->debug('Object\'s creation date is different.'); $l_badness++; } #if } #if if (isset($p_import_object['created_by'])) { if ($l_existing_object['isys_obj__created_by'] != $p_import_object['created_by']) { $this->m_log->debug('Object creator is different.'); $l_badness++; } #if } #if if (isset($p_import_object['updated'])) { if (strtotime($l_existing_object['isys_obj__updated']) != $p_import_object['updated']) { $this->m_log->debug('Object\'s date of last change is different.'); $l_badness++; } #if } #if if (isset($p_import_object['updated_by'])) { if ($l_existing_object['isys_obj__updated_by'] != $p_import_object['updated_by']) { $this->m_log->debug('Object updator is different.'); $l_badness++; } #if } #if if (isset($p_import_object['status'])) { if ($l_existing_object['isys_obj__status'] != $p_import_object['status']) { $this->m_log->debug('Object status is different.'); $l_badness++; } } #if if (isset($p_import_object['cmdb_status'])) { if ($l_existing_object['isys_obj__isys_cmdb_status__id'] != $p_import_object['cmdb_status']) { $this->m_log->debug('Object CMDB status is different.'); $l_badness++; } #if } #if // Scoring: if ($l_badness === 0) { $l_result = self::C__COMPARISON__SAME; } else if ($l_badness >= self::C__COMPARISON__THRESHOLD) { $p_object_id = -1; $l_result = self::C__COMPARISON__DIFFERENT; } else { $p_object_id = $l_existing_object['isys_obj__id']; $l_result = self::C__COMPARISON__PARTLY; } #if return $l_result; } #function private function fetch_all_categories() { global $g_comp_database; $l_dao = new isys_cmdb_dao($g_comp_database); $l_result = array( C__CMDB__CATEGORY__TYPE_GLOBAL => array(), C__CMDB__CATEGORY__TYPE_SPECIFIC => array() ); $l_tables = array( C__CMDB__CATEGORY__TYPE_GLOBAL => 'isysgui_catg', C__CMDB__CATEGORY__TYPE_SPECIFIC => 'isysgui_cats' ); foreach ($l_tables as $l_category_type => $l_table) { $l_res = $l_dao->get_isysgui($l_table); while ($l_row = $l_res->get_row()) { $l_new = array(); foreach ($l_row as $l_key => $l_value) { $l_new[substr(strstr($l_key, '__'), 2)] = $l_value; } #foreach $l_result[$l_category_type][$l_new['id']] = $l_new; } #while unset ($l_res); } #foreach unset ($l_dao); return $l_result; } #function /** * Resets all data and information about an import. Useful to 'recycle' * this class instance. */ public function reset() { $this->m_category_data_ids = null; $this->m_category_ids; $this->m_data; $this->m_info; $this->m_mandator; $this->m_object_ids; $this->m_object_type_ids; $this->m_object_types; $this->m_prepared; $this->m_property_ids; $this->m_scantime; $this->m_type; $this->m_version; $this->m_hostname; } #function /** * Gets object type identifiers. Useful after finishing an import. * * @return array */ public function get_object_type_ids() { return $this->m_object_type_ids; } #function /** * Gets object identifiers. Useful after finishing an import. * * @return array */ public function get_object_ids() { return $this->m_object_ids; } #function /** * Gets category identifiers. Useful after finishing an import. * * @return array */ public function get_category_ids() { return $this->m_category_ids; } #function /** * Gets category data identifiers. Useful after finishing an import. * * @return array */ public function get_category_data_ids() { return $this->m_category_data_ids; } #function /** * Gets property identifiers. Useful after finishing an import. * * @return array */ public function get_property_ids() { return $this->m_property_ids; } #function /** * @deleteme I'm only here for debugging... */ protected function debug() { global $g_comp_database; global $g_comp_template_language_manager; $this->m_log->notice('Debugging...'); // $l_cmdb_dao = new isys_cmdb_dao($g_comp_database); // $l_category_types = $l_cmdb_dao->get_category_types(); $l_all_categories = $this->fetch_all_categories(); $l_infos = array(); foreach($l_all_categories as $l_type => $l_categories) { foreach($l_categories as $l_category) { $l_info = array(); $l_info['type'] = $l_type; $l_info['class'] = $l_category['class_name']; $l_info['id'] = $l_category['id']; $l_info['const'] = $l_category['const']; $l_info['table'] = $l_category['source_table']; $l_info['title'] = $g_comp_template_language_manager->get($l_category['title']); $l_cat_dao = new $l_info['class']($g_comp_database); $l_properties = $l_cat_dao->get_data_information(); $l_todos = array(); foreach ($l_properties as $l_property_tag => $l_property_data) { if (isset($l_property_data['value'])) { if (!is_string($l_property_tag) || empty($l_property_tag)) { $l_todos[] = 'invalid property tag (value): ' . $l_property_tag; } if (!isset($l_property_data['formtag'])) { $l_todos[] = '(optional) form tag not given: ' . $l_property_tag; } else { if (!is_string($l_property_data['formtag']) || empty($l_property_data['formtag'])) { $l_todos[] = 'invalid form tag: ' . $l_property_tag; } } } else if (isset($l_property_data['ref'])) { if (!is_int($l_property_tag) || $l_property_tag < 0) { $l_todos[] = 'invalid property tag (ref): ' . $l_property_tag; } if ($l_property_data['filter'] === false) { $l_todos[] = ': ' . $l_property_tag; } } else { $l_todos[] = 'property has neither value nor ref: ' . $l_property_tag; } // if (isset($l_property_data['tag'])) { // $l_info['todo'][] = 'property with tag: ' . $l_property_tag; // } if (!is_string($l_property_data['title']) || empty($l_property_data['title'])) { $l_todos[] = 'property without title: ' . $l_property_tag; } if (isset($l_property_data['value']) && isset($l_property_data['ref'])) { $l_todos[] = 'property has value and ref: ' . $l_property_tag; } if (isset($l_property_data['value']) && isset($l_property_data[C__CATEGORY_DATA__EXPORT_HELPER])) { if (!isset($l_property_data['value'])) { $l_todos[] = 'property has helper, but no value: ' . $l_property_tag; } if (!class_exists($l_property_data[C__CATEGORY_DATA__EXPORT_HELPER])) { $l_todos[] = 'unknown property export helper: ' . $l_property_data[C__CATEGORY_DATA__EXPORT_HELPER]; } if (!isset($l_property_data[C__CATEGORY_DATA__METHOD])) { $l_todos[] = 'property export helper without proper method: ' . $l_property_data[C__CATEGORY_DATA__EXPORT_HELPER]; } if (!method_exists($l_property_data[C__CATEGORY_DATA__EXPORT_HELPER], $l_property_data[C__CATEGORY_DATA__METHOD])) { $l_todos[] = 'unknown property export method: ' . $l_property_data[C__CATEGORY_DATA__METHOD]; } if ($l_property_data[C__CATEGORY_DATA__METHOD] === 'dialog_plus') { $l_pos = strrpos($l_property_data[C__CATEGORY_DATA__PARAM], '_list'); $l_offset = strlen($l_property_data[C__CATEGORY_DATA__PARAM]) - 6; if ($l_pos !== false && $l_pos = $l_offset) { $l_todos[] = 'category reference found, but wrong method (dialog_plus): ' . $l_property_data[C__CATEGORY_DATA__TAG]; } } } if (isset($l_property_data['value']) && isset($l_property_data[C__CATEGORY_DATA__IMPORT_HELPER])) { if (!class_exists($l_property_data[C__CATEGORY_DATA__IMPORT_HELPER])) { $l_todos[] = 'unknown property import helper: ' . $l_property_data[C__CATEGORY_DATA__IMPORT_HELPER]; } $l_method = $l_property_data[C__CATEGORY_DATA__METHOD] . '_import'; if (!isset($l_method)) { $l_todos[] = 'property import helper without proper method: ' . $l_property_data[C__CATEGORY_DATA__IMPORT_HELPER]; } if (!method_exists($l_property_data[C__CATEGORY_DATA__IMPORT_HELPER], $l_method)) { $l_todos[] = 'unknown property import method: ' . $l_method; } } if (isset($l_property_data['ref']) && ( isset($l_property_data[C__CATEGORY_DATA__EXPORT_HELPER]) || isset($l_property_data[C__CATEGORY_DATA__IMPORT_HELPER]))) { $l_todos[] = 'property has helper and ref: ' . $l_property_tag; } } if (count($l_todos) > 0) { $l_info['todo'] = $l_todos; } $l_infos[] = $l_info; } } #var_dump($l_infos); $l_todos = 0; $l_categories = array(); foreach ($l_infos as $l_info) { if (isset($l_info['todo'])) { $l_todos++; $l_categories[] = $l_info; } } var_dump($l_categories); var_dump($l_todos); die; } } #class ?>