X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=WEB-INF%2Flib%2FttOrgImportHelper.class.php;h=b5a28c8e85909423bbc274ed4b876efed0f5807c;hb=f58ab716cb0cc4b8be8e48723b345bfab29697a6;hp=dda7f75df8b393bc065207b213f42d1de20b5bf6;hpb=f6afe28937ca24f05e0a4fc0f4b4054d1832f5a9;p=timetracker.git diff --git a/WEB-INF/lib/ttOrgImportHelper.class.php b/WEB-INF/lib/ttOrgImportHelper.class.php index dda7f75d..b5a28c8e 100644 --- a/WEB-INF/lib/ttOrgImportHelper.class.php +++ b/WEB-INF/lib/ttOrgImportHelper.class.php @@ -32,7 +32,6 @@ import('ttTaskHelper'); import('ttClientHelper'); import('ttInvoiceHelper'); import('ttTimeHelper'); -import('ttCustomFieldHelper'); import('ttExpenseHelper'); import('ttFavReportHelper'); @@ -46,7 +45,7 @@ class ttOrgImportHelper { var $firstPass = true; // True during first pass through the file. var $org_id = null; // Organization id (same as top group_id). var $current_group_id = null; // Current group id during parsing. - var $current_parent_group_id = null; // Current parent group id during parsing. + var $parents = array(); // A stack of parent group ids for current group all the way to the root including self. var $top_role_id = 0; // Top role id. // Entity maps for current group. They map XML ids with database ids. @@ -107,9 +106,10 @@ class ttOrgImportHelper { if ($name == 'GROUP') { // Create a new group. $this->current_group_id = $this->createGroup(array( - 'parent_id' => $this->current_parent_group_id, + 'parent_id' => $this->current_group_id, // Note: after insert current_group_id changes. 'org_id' => $this->org_id, 'name' => $attrs['NAME'], + 'description' => $attrs['DESCRIPTION'], 'currency' => $attrs['CURRENCY'], 'decimal_mark' => $attrs['DECIMAL_MARK'], 'lang' => $attrs['LANG'], @@ -135,16 +135,21 @@ class ttOrgImportHelper { $sql = "update tt_groups set org_id = $this->current_group_id where org_id is NULL and id = $this->current_group_id"; $affected = $mdb2->exec($sql); } - // Set parent group to create subgroups with this group as parent at next entry here. - $this->current_parent_group_id = $this->current_group_id; - return; - } - - if ($name == 'ROLES') { - // If we get here, we have to recycle $currentGroupRoleMap. - unset($this->currentGroupRoleMap); - $this->currentGroupRoleMap = array(); - // Role map is reconstructed after processing elements in XML. See below. + // Add self to parent stack. + array_push($this->parents, $this->current_group_id); + + // Recycle all maps as we are starting to work on new group. + // Note that for this to work properly all nested groups must be last entries in xml for each group. + unset($this->currentGroupRoleMap); $this->currentGroupRoleMap = array(); + unset($this->currentGroupTaskMap); $this->currentGroupTaskMap = array(); + unset($this->currentGroupProjectMap); $this->currentGroupProjectMap = array(); + unset($this->currentGroupClientMap); $this->currentGroupClientMap = array(); + unset($this->currentGroupUserMap); $this->currentGroupUserMap = array(); + unset($this->currentGroupInvoiceMap); $this->currentGroupInvoiceMap = array(); + unset($this->currentGroupLogMap); $this->currentGroupLogMap = array(); + unset($this->currentGroupCustomFieldMap); $this->currentGroupCustomFieldMap = array(); + unset($this->currentGroupCustomFieldOptionMap); $this->currentGroupCustomFieldOptionMap = array(); + unset($this->currentGroupFavReportMap); $this->currentGroupCustomFavReportMap = array(); return; } @@ -165,14 +170,6 @@ class ttOrgImportHelper { return; } - if ($name == 'TASKS') { - // If we get here, we have to recycle $currentGroupTaskMap. - unset($this->currentGroupTaskMap); - $this->currentGroupTaskMap = array(); - // Task map is reconstructed after processing elements in XML. See below. - return; - } - if ($name == 'TASK') { // We get here when processing tags for the current group. $task_id = ttTaskHelper::insert(array( @@ -184,15 +181,9 @@ class ttOrgImportHelper { if ($task_id) { // Add a mapping. $this->currentGroupTaskMap[$attrs['ID']] = $task_id; - } else $this->errors->add($i18n->get('error.db')); - return; - } - - if ($name == 'PROJECTS') { - // If we get here, we have to recycle $currentGroupProjectMap. - unset($this->currentGroupProjectMap); - $this->currentGroupProjectMap = array(); - // Project map is reconstructed after processing elements in XML. See below. + } else { + $this->errors->add($i18n->get('error.db')); + } return; } @@ -216,15 +207,9 @@ class ttOrgImportHelper { if ($project_id) { // Add a mapping. $this->currentGroupProjectMap[$attrs['ID']] = $project_id; - } else $this->errors->add($i18n->get('error.db')); - return; - } - - if ($name == 'CLIENTS') { - // If we get here, we have to recycle $currentGroupClientMap. - unset($this->currentGroupClientMap); - $this->currentGroupClientMap = array(); - // Client map is reconstructed after processing elements in XML. See below. + } else { + $this->errors->add($i18n->get('error.db')); + } return; } @@ -253,14 +238,6 @@ class ttOrgImportHelper { return; } - if ($name == 'USERS') { - // If we get here, we have to recycle $currentGroupUserMap. - unset($this->currentGroupUserMap); - $this->currentGroupUserMap = array(); - // User map is reconstructed after processing elements in XML. See below. - return; - } - if ($name == 'USER') { // We get here when processing tags for the current group. @@ -297,14 +274,6 @@ class ttOrgImportHelper { return; } - if ($name == 'INVOICES') { - // If we get here, we have to recycle $currentGroupInvoiceMap. - unset($this->currentGroupInvoiceMap); - $this->currentGroupInvoiceMap = array(); - // Invoice map is reconstructed after processing elements in XML. See below. - return; - } - if ($name == 'INVOICE') { // We get here when processing tags for the current group. $invoice_id = ttInvoiceHelper::insert(array( @@ -321,17 +290,9 @@ class ttOrgImportHelper { return; } - if ($name == 'LOG') { - // If we get here, we have to recycle $currentGroupLogMap. - unset($this->currentGroupLogMap); - $this->currentGroupLogMap = array(); - // Log map is reconstructed after processing elements in XML. See below. - return; - } - if ($name == 'LOG_ITEM') { // We get here when processing tags for the current group. - $log_item_id = ttTimeHelper::insert(array( + $log_item_id = $this->insertLogEntry(array( 'user_id' => $this->currentGroupUserMap[$attrs['USER_ID']], 'group_id' => $this->current_group_id, 'org_id' => $this->org_id, @@ -339,11 +300,11 @@ class ttOrgImportHelper { 'start' => $attrs['START'], 'finish' => $attrs['FINISH'], 'duration' => $attrs['DURATION'], - 'client' => $this->currentGroupClientMap[$attrs['CLIENT_ID']], - 'project' => $this->currentGroupProjectMap[$attrs['PROJECT_ID']], - 'task' => $this->currentGroupTaskMap[$attrs['TASK_ID']], - 'invoice' => $this->currentGroupInvoiceMap[$attrs['INVOICE_ID']], - 'note' => (isset($attrs['COMMENT']) ? $attrs['COMMENT'] : ''), + 'client_id' => $this->currentGroupClientMap[$attrs['CLIENT_ID']], + 'project_id' => $this->currentGroupProjectMap[$attrs['PROJECT_ID']], + 'task_id' => $this->currentGroupTaskMap[$attrs['TASK_ID']], + 'invoice_id' => $this->currentGroupInvoiceMap[$attrs['INVOICE_ID']], + 'comment' => (isset($attrs['COMMENT']) ? $attrs['COMMENT'] : ''), 'billable' => $attrs['BILLABLE'], 'paid' => $attrs['PAID'], 'status' => $attrs['STATUS'])); @@ -354,19 +315,11 @@ class ttOrgImportHelper { return; } - if ($name == 'CUSTOM_FIELDS') { - // If we get here, we have to recycle $currentGroupCustomFieldMap. - unset($this->currentGroupCustomFieldMap); - $this->currentGroupCustomFieldMap = array(); - // Custom field map is reconstructed after processing elements in XML. See below. - return; - } - if ($name == 'CUSTOM_FIELD') { // We get here when processing tags for the current group. - $custom_field_id = ttCustomFieldHelper::insertField(array( + $custom_field_id = $this->insertCustomField(array( 'group_id' => $this->current_group_id, - // 'org_id' => $this->org_id, TODO: add this when org_id field is added to the table. + 'org_id' => $this->org_id, 'type' => $attrs['TYPE'], 'label' => $attrs['LABEL'], 'required' => $attrs['REQUIRED'], @@ -378,19 +331,11 @@ class ttOrgImportHelper { return; } - if ($name == 'CUSTOM_FIELD_OPTIONS') { - // If we get here, we have to recycle $currentGroupCustomFieldOptionMap. - unset($this->currentGroupCustomFieldOptionMap); - $this->currentGroupCustomFieldOptionMap = array(); - // Custom field option map is reconstructed after processing elements in XML. See below. - return; - } - if ($name == 'CUSTOM_FIELD_OPTION') { // We get here when processing tags for the current group. - $custom_field_option_id = ttCustomFieldHelper::insertOption(array( - // 'group_id' => $this->current_group_id, TODO: add this when group_id field is added to the table. - // 'org_id' => $this->org_id, TODO: add this when org_id field is added to the table. + $custom_field_option_id = $this->insertCustomFieldOption(array( + 'group_id' => $this->current_group_id, + 'org_id' => $this->org_id, 'field_id' => $this->currentGroupCustomFieldMap[$attrs['FIELD_ID']], 'value' => $attrs['VALUE'])); if ($custom_field_option_id) { @@ -402,9 +347,9 @@ class ttOrgImportHelper { if ($name == 'CUSTOM_FIELD_LOG_ENTRY') { // We get here when processing tags for the current group. - if (!ttCustomFieldHelper::insertLogEntry(array( - // 'group_id' => $this->current_group_id, TODO: add this when group_id field is added to the table. - // 'org_id' => $this->org_id, TODO: add this when org_id field is added to the table. + if (!$this->insertCustomFieldLogEntry(array( + 'group_id' => $this->current_group_id, + 'org_id' => $this->org_id, 'log_id' => $this->currentGroupLogMap[$attrs['LOG_ID']], 'field_id' => $this->currentGroupCustomFieldMap[$attrs['FIELD_ID']], 'option_id' => $this->currentGroupCustomFieldOptionMap[$attrs['OPTION_ID']], @@ -456,14 +401,6 @@ class ttOrgImportHelper { return; } - if ($name == 'FAV_REPORTS') { - // If we get here, we have to recycle $currentGroupFavReportMap. - unset($this->currentGroupFavReportMap); - $this->currentGroupFavReportMap = array(); - // Favorite report map is reconstructed after processing elements in XML. See below. - return; - } - if ($name == 'FAV_REPORT') { $user_list = ''; if (strlen($attrs['USERS']) > 0) { @@ -541,6 +478,22 @@ class ttOrgImportHelper { } } + // endElement - callback handler for ending tags in XML. + // We use this only for process element endings and + // set current_group_id to an immediate parent. + // This is required to import group hierarchy correctly. + function endElement($parser, $name) { + // No need to care about first or second pass, as this is used only in second pass. + // See 2nd xml_set_element_handler, where this handler is set. + if ($name == 'GROUP') { + // Remove self from the parent stack. + $self = array_pop($this->parents); + // Set current group id to an immediate parent. + $len = count($this->parents); + $this->current_group_id = $len ? $this->parents[$len-1] : null; + } + } + // importXml - uncompresses the file, reads and parses its content. During parsing, // startElement, endElement, and dataElement functions are called as many times as necessary. // Actual import occurs in the endElement handler. @@ -575,7 +528,7 @@ class ttOrgImportHelper { // Initialize XML parser. $parser = xml_parser_create(); xml_set_object($parser, $this); - xml_set_element_handler($parser, 'startElement', false); + xml_set_element_handler($parser, 'startElement', false); // No need to process end tags in 1st pass. // We need to parse the file 2 times: // 1) First pass: determine if import is possible. @@ -608,9 +561,9 @@ class ttOrgImportHelper { // Now we can do a second pass, where real work is done. $parser = xml_parser_create(); xml_set_object($parser, $this); - xml_set_element_handler($parser, 'startElement', false); + xml_set_element_handler($parser, 'startElement', 'endElement'); // Need to process ending tags too. - // Read and parse the content of the file. During parsing, startElement is called back for each tag. + // Read and parse the content of the file. During parsing, startElement and endElement are called back for each tag. $file = fopen($filename, 'r'); while (($data = fread($file, 4096)) && $this->errors->no()) { if (!xml_parse($parser, $data, feof($file))) { @@ -656,7 +609,7 @@ class ttOrgImportHelper { global $i18n; $mdb2 = getConnection(); - $columns = '(parent_id, org_id, name, currency, decimal_mark, lang, date_format, time_format'. + $columns = '(parent_id, org_id, name, description, currency, decimal_mark, lang, date_format, time_format'. ', week_start, tracking_mode, project_required, task_required, record_type, bcc_email'. ', allow_ip, password_complexity, plugins, lock_spec'. ', workday_minutes, config, created, created_ip, created_by)'; @@ -665,6 +618,7 @@ class ttOrgImportHelper { $values .= $mdb2->quote($fields['parent_id']); $values .= ', '.$mdb2->quote($fields['org_id']); $values .= ', '.$mdb2->quote(trim($fields['name'])); + $values .= ', '.$mdb2->quote(trim($fields['description'])); $values .= ', '.$mdb2->quote(trim($fields['currency'])); $values .= ', '.$mdb2->quote($fields['decimal_mark']); $values .= ', '.$mdb2->quote($fields['lang']); @@ -913,4 +867,116 @@ class ttOrgImportHelper { $affected = $mdb2->exec($sql); return (!is_a($affected, 'PEAR_Error')); } + + // insertCustomField - a helper function to insert a custom field. + private function insertCustomField($fields) { + $mdb2 = getConnection(); + + $group_id = (int) $fields['group_id']; + $org_id = (int) $fields['org_id']; + $type = (int) $fields['type']; + $label = $fields['label']; + $required = (int) $fields['required']; + $status = $fields['status']; + + $sql = "insert into tt_custom_fields". + " (group_id, org_id, type, label, required, status)". + " values($group_id, $org_id, $type, ".$mdb2->quote($label).", $required, ".$mdb2->quote($status).")"; + $affected = $mdb2->exec($sql); + if (is_a($affected, 'PEAR_Error')) + return false; + + $last_id = 0; + $sql = "select last_insert_id() as last_insert_id"; + $res = $mdb2->query($sql); + $val = $res->fetchRow(); + $last_id = $val['last_insert_id']; + return $last_id; + } + + // insertCustomFieldOption - a helper function to insert a custom field option. + private function insertCustomFieldOption($fields) { + $mdb2 = getConnection(); + + $group_id = (int) $fields['group_id']; + $org_id = (int) $fields['org_id']; + $field_id = (int) $fields['field_id']; + $value = $fields['value']; + + $sql = "insert into tt_custom_field_options (group_id, org_id, field_id, value)". + " values ($group_id, $org_id, $field_id, ".$mdb2->quote($value).")"; + $affected = $mdb2->exec($sql); + if (is_a($affected, 'PEAR_Error')) + return false; + + $last_id = 0; + $sql = "select last_insert_id() as last_insert_id"; + $res = $mdb2->query($sql); + $val = $res->fetchRow(); + $last_id = $val['last_insert_id']; + return $last_id; + } + + // insertLogEntry - a helper function to insert a time log entry. + private function insertLogEntry($fields) { + global $user; + $mdb2 = getConnection(); + + $group_id = (int) $fields['group_id']; + $org_id = (int) $fields['org_id']; + $user_id = (int) $fields['user_id']; + $date = $fields['date']; + $start = $fields['start']; + $duration = $fields['duration']; + $client_id = $fields['client_id']; + $project_id = $fields['project_id']; + $task_id = $fields['task_id']; + $invoice_id = $fields['invoice_id']; + $comment = $fields['comment']; + $billable = (int) $fields['billable']; + $paid = (int) $fields['paid']; + $status = $fields['status']; + + $sql = "insert into tt_log". + " (user_id, group_id, org_id, date, start, duration, client_id, project_id, task_id, invoice_id, comment". + ", billable, paid, created, created_ip, created_by, status)". + " values ($user_id, $group_id, $org_id". + ", ".$mdb2->quote($date). + ", ".$mdb2->quote($start). + ", ".$mdb2->quote($duration). + ", ".$mdb2->quote($client_id). + ", ".$mdb2->quote($project_id). + ", ".$mdb2->quote($task_id). + ", ".$mdb2->quote($invoice_id). + ", ".$mdb2->quote($comment). + ", $billable, $paid". + ", now(), ".$mdb2->quote($_SERVER['REMOTE_ADDR']).", ".$mdb2->quote($user->id). + ", ". $mdb2->quote($status).")"; + $affected = $mdb2->exec($sql); + if (is_a($affected, 'PEAR_Error')) { + $this->errors->add($i18n->get('error.db')); // TODO: review whether or not to add error here in all insert calls. + return false; + } + + $log_id = $mdb2->lastInsertID('tt_log', 'id'); + return $log_id; + } + + // insertCustomFieldLogEntry - a helper function to insert a custom field log entry. + private function insertCustomFieldLogEntry($fields) { + $mdb2 = getConnection(); + + $group_id = (int) $fields['group_id']; + $org_id = (int) $fields['org_id']; + $log_id = (int) $fields['log_id']; + $field_id = (int) $fields['field_id']; + $option_id = $fields['option_id']; + $value = $fields['value']; + $status = $fields['status']; + + $sql = "insert into tt_custom_field_log (group_id, org_id, log_id, field_id, option_id, value, status)". + " values ($group_id, $org_id, $log_id, $field_id, ".$mdb2->quote($option_id).", ".$mdb2->quote($value).", ".$mdb2->quote($status).")"; + $affected = $mdb2->exec($sql); + return (!is_a($affected, 'PEAR_Error')); + } }