protected function functionHandler($match) { $parser = new ExpressionParser($match[1], $this->_context, false); # Last Parameter = DEBUG $parser->run(); return $newValue = $parser->getReturn(); }
function executeSelectQuery(&$sqlQuery) { global $g_sqlGroupingFuncs; global $g_sqlSingleRecFuncs; $resultSets = array(); // create a copy $aliases = $sqlQuery->colAliases; $funcs = $sqlQuery->colFuncs; // Read all Tables for ($i = 0; $i < count($sqlQuery->tables); ++$i) { debug_printb("<br>[executeSelectQuery] Reading table " . $sqlQuery->tables[$i] . "<br>"); if (!($resultSets[$i] = $this->readTable($sqlQuery->tables[$i]))) { print_error_msg("Reading Table " . $sqlQuery->tables[$i] . " failed"); return false; } $resultSets[$i]->setColumnTableForAll($sqlQuery->tables[$i]); $resultSets[$i]->setColumnTableAliasForAll($sqlQuery->tableAliases[$i]); // set all functions to the ResultSet of the current table // if table and column name matches debug_printb("[executeSelectQuery] Setting functions for the current table:<br>"); for ($j = 0; $j < count($funcs); ++$j) { if (!$funcs[$j] || !$sqlQuery->colNames[$j]) { continue; } if ($sqlQuery->colTables[$j] == $sqlQuery->tables[$i] || $sqlQuery->colTables[$j] == $sqlQuery->tableAliases[$i]) { $colNr = $resultSets[$i]->findColNrByAttrs($sqlQuery->colNames[$j], $sqlQuery->colTables[$j], ""); if ($colNr == NOT_FOUND) { continue; } // create a new column for each function $resultSets[$i]->addColumn($sqlQuery->colNames[$j], $sqlQuery->colAliases[$j], $sqlQuery->colTables[$j], "", "str", "", $funcs[$j], "", true); $funcs[$j] = ""; } } // set all aliases where table, column name and function matches debug_printb("[executeSelectQuery] Setting aliases for the current table:<br>"); for ($j = 0; $j < count($aliases); ++$j) { if (!$aliases[$j]) { continue; } if ($sqlQuery->colTables[$j] == $sqlQuery->tables[$i] || $sqlQuery->colTables[$j] == $sqlQuery->tableAliases[$i]) { if (($colNr = $resultSets[$i]->findColNrByAttrs($sqlQuery->colNames[$j], $sqlQuery->colTables[$j], $sqlQuery->colFuncs[$j])) != NOT_FOUND) { $resultSets[$i]->setColumnAlias($colNr, $aliases[$j]); $aliases[$j] = ""; } } } if (TXTDBAPI_DEBUG) { debug_printb("<br>[executeSelectQuery] Dump of Table {$i} (" . $sqlQuery->tables[$i] . "):<br>"); $resultSets[$i]->dump(); } } // set remaining functions to the ResultSet where column name matches debug_printb("[executeSelectQuery] Setting remaining functions where column name matches:<br>"); for ($i = 0; $i < count($resultSets); ++$i) { for ($j = 0; $j < count($funcs); ++$j) { if (!$funcs[$j] || !$sqlQuery->colNames[$j]) { continue; } $colNr = $resultSets[$i]->findColNrByAttrs($sqlQuery->colNames[$j], "", ""); if ($colNr == NOT_FOUND) { // 'text' or 123 ? => add column if (!(is_numeric($sqlQuery->colNames[$j]) || has_quotes($sqlQuery->colNames[$j]))) { continue; } debug_print("Adding function with quoted string or number paremeter!<br>"); } // create a new column for each function $resultSets[$i]->addColumn($sqlQuery->colNames[$j], $sqlQuery->colAliases[$j], $sqlQuery->colTables[$j], "", "str", "", $funcs[$j], "", true); $funcs[$j] = ""; } } // set remaining aliases where column name and function matches debug_printb("[executeSelectQuery] Setting remaining aliases where column name and function matches:<br>"); for ($i = 0; $i < count($resultSets); ++$i) { for ($j = 0; $j < count($aliases); ++$j) { if (!$aliases[$j]) { continue; } if (($colNr = $resultSets[$i]->findColNrByAttrs($sqlQuery->colNames[$j], "", $sqlQuery->colFuncs[$j])) != NOT_FOUND) { $resultSets[$i]->setColumnAlias($colNr, $aliases[$j]); $aliases[$j] = ""; } } } debug_printb("[executeSelectQuery] Executing single-rec functions (on the separate ResultSet's):<br>"); // execute single-rec functions (on the separate ResultSet's) for ($i = 0; $i < count($resultSets); ++$i) { $resultSets[$i]->executeSingleRecFuncs(); } // A query without tables ? => make a dummy ResultSet $dummyResultSet = false; if (count($sqlQuery->tables) == 0) { $dummyResultSet = true; $rsMaster = new ResultSet(); $rsMaster->addColumn("(dummy)", "(dummy)", "(dummy)", "(dummy)", "str", "(dummy)", "", "", true); $rsMaster->append(); // else: real ResultSet } else { $dummyResultSet = false; // join the ResultSet's $rsMaster = $resultSets[0]; for ($i = 1; $i < count($resultSets); ++$i) { $rsMaster = $rsMaster->joinWithResultSet($resultSets[$i]); } } // from here we only work with $rsMaster and can free the other ResultSet's unset($resultSets); $resultSets = ""; // generate additional columns for the remaining functions (functions without params) for ($i = 0; $i < count($funcs); ++$i) { if ($funcs[$i]) { $rsMaster->addColumn($sqlQuery->colNames[$i], $sqlQuery->colAliases[$i], "", "", "str", "", $funcs[$i], execFunc($funcs[$i], "")); } } // generate additional columns from the WHERE-expression $rsMaster->generateAdditionalColumnsFromWhereExpr($sqlQuery->where_expr); // generate additional columns from ORDER BY $rsMaster->generateAdditionalColumnsFromArray($sqlQuery->orderColumns); // generate additional columns from GROUP BY $rsMaster->generateAdditionalColumnsFromArray($sqlQuery->groupColumns); // execute the new single-rec functions (on the Master ResultSet) $rsMaster->executeSingleRecFuncs(); // set row id's $rsMaster->reset(); $rId = -1; while (++$rsMaster->pos < count($rsMaster->rows)) { $rsMaster->rows[$rsMaster->pos]->id = ++$rId; } --$rsMaster->pos; debug_printb("<br>[executeSelectQuery] Master ResultSet:</b><br>"); if (TXTDBAPI_DEBUG) { $rsMaster->dump(); } // apply WHERE expression if ($sqlQuery->where_expr) { $ep = new ExpressionParser(); $rsMaster = $ep->getFilteredResultSet($rsMaster, $sqlQuery); } // free $ep unset($ep); $ep = ""; // stop if the WHERE expression failed if (txtdbapi_error_occurred()) { return false; } // check if we can use some optimization // (use the limit in group by, but only if there are no grouping function // in the groupRows. To be able to do this we must order before grouping) $optimizedPath = true; if (!$sqlQuery->limit || !$sqlQuery->orderColumns) { $optimizedPath = false; } else { for ($i = 0; $i < count($sqlQuery->colFuncs); ++$i) { if (in_array($sqlQuery->colFuncs[$i], $g_sqlGroupingFuncs)) { $optimizedPath = false; break; } } } if ($optimizedPath) { debug_printb("[executeSelectQuery] Using optimized path!<br>"); } else { debug_printb("[executeSelectQuery] Using normal path!<br>"); } // Order ResultSet (if optimizedPath) if ($optimizedPath) { debug_printb("[executeSelectQuery] Calling orderRows() (optimized path)..<br>"); if (count($sqlQuery->orderColumns) > 0) { $rsMaster->orderRows($sqlQuery->orderColumns, $sqlQuery->orderTypes); } } // Group ResultSet (process GROUP BY) $numGroupingFuncs = 0; for ($i = 0; $i < count($sqlQuery->colFuncs); ++$i) { if ($sqlQuery->colFuncs[$i] && in_array($sqlQuery->colFuncs[$i], $g_sqlGroupingFuncs)) { ++$numGroupingFuncs; break; } } if ($numGroupingFuncs > 0 || count($sqlQuery->groupColumns) > 0) { debug_printb("[executeSelectQuery] Calling groupRows()..<br>"); $rsMaster = $rsMaster->groupRows($sqlQuery, $optimizedPath); } // Order ResultSet (if NOT optimizedPath) if (!$optimizedPath) { debug_printb("[executeSelectQuery] Calling orderRows() (normal path)..<br>"); if (count($sqlQuery->orderColumns) > 0) { $rsMaster->orderRows($sqlQuery->orderColumns, $sqlQuery->orderTypes); } } // add direct value columns debug_printb("[executeSelectQuery] Adding direct value columns..<br>"); for ($i = 0; $i < count($sqlQuery->colNames); ++$i) { if ($sqlQuery->colNames[$i] && (is_numeric($sqlQuery->colNames[$i]) || has_quotes($sqlQuery->colNames[$i])) && !$sqlQuery->colTables[$i] && !$sqlQuery->colFuncs[$i] && $rsMaster->findColNrByAttrs($sqlQuery->colNames[$i], "", "") == NOT_FOUND) { $value = $sqlQuery->colNames[$i]; if (has_quotes($value)) { remove_quotes($value); } $rsMaster->addColumn($sqlQuery->colNames[$i], $sqlQuery->colAliases[$i], "", "", "str", "", "", $value, true); } } // return only the requested columns debug_printb("[executeSelectQuery] Removing unwanted columns...<br>"); $rsMaster->filterByColumnNamesInSqlQuery($sqlQuery); // order columns (not their data) debug_printb("[executeSelectQuery] Ordering columns (amog themself)...<br>"); if (!$rsMaster->orderColumnsBySqlQuery($sqlQuery)) { print_error_msg("Ordering the Columns (themself) failed"); return false; } // process DISTINCT if ($sqlQuery->distinct == 1) { $rsMaster = $rsMaster->makeDistinct($sqlQuery->limit); } // Apply Limit $rsMaster->reset(); $rsMaster = $rsMaster->limitResultSet($sqlQuery->limit); verbose_debug_print("<br>Limited ResultSet:<br>"); if (TXTDBAPI_VERBOSE_DEBUG) { $rsMaster->dump(); } $rsMaster->reset(); return $rsMaster; }
/** * If a request (data-pipelining tag) doesn't include any dynamic tags, it's returned as is. If * however it does contain said tag, this function will attempt to resolve it using the $result * array, returning the parsed request on success, or FALSE on failure to resolve. * * @param array $request */ private static function resolveRequest($request, $result) { $dataContext = self::makeContextData($result); foreach ($request as $key => $val) { $expressions = array(); preg_match_all('/\\$\\{(.*)\\}/imxsU', $val, $expressions); $expressionCount = count($expressions[0]); if ($expressionCount) { for ($i = 0; $i < $expressionCount; $i++) { $toReplace = $expressions[0][$i]; $expression = $expressions[1][$i]; try { $expressionResult = ExpressionParser::evaluate($expression, $dataContext); $request[$key] = str_replace($toReplace, $expressionResult, $request[$key]); } catch (Exception $e) { // ignore, maybe on the next pass we can resolve this return false; } } } } return $request; }
/** * Replace "^" tags (eg. ^forename) in a template with values from an array * * @param string $ps_template String with embedded tags. Tags are just alphanumeric strings prefixed with a caret ("^") * @param string $pm_tablename_or_num Table name or number of table from which values are being formatted * @param string $pa_row_ids An array of primary key values in the specified table to be pulled into the template * @param array $pa_options Supported options are: * returnAsArray = if true an array of processed template values is returned, otherwise the template values are returned as a string joined together with a delimiter. Default is false. * delimiter = value to string together template values with when returnAsArray is false. Default is ';' (semicolon) * relatedValues = array of field values to return in template when directly referenced. Array should be indexed numerically in parallel with $pa_row_ids * relationshipValues = array of field values to return in template for relationship when directly referenced. Should be indexed by row_id and then by relation_id * placeholderPrefix = attribute container to implicitly place primary record fields into. Ex. if the table is "ca_entities" and the placeholder is "address" then tags like ^city will resolve to ca_entities.address.city * requireLinkTags = if set then links are only added when explicitly defined with <l> tags. Default is to make the entire text a link in the absence of <l> tags. * resolveLinksUsing = * primaryIDs = row_ids for primary rows in related table, keyed by table name; when resolving ambiguous relationships the row_ids will be excluded from consideration. This option is rarely used and exists primarily to take care of a single * edge case: you are processing a template relative to a self-relationship such as ca_entities_x_entities that includes references to the subject table (ca_entities, in the case of ca_entities_x_entities). There are * two possible paths to take in this situations; primaryIDs lets you specify which ones you *don't* want to take by row_id. For interstitial editors, the ids will be set to a single id: that of the subject (Eg. ca_entities) row * from which the interstitial was launched. * @return mixed Output of processed templates */ function caProcessTemplateForIDs($ps_template, $pm_tablename_or_num, $pa_row_ids, $pa_options = null) { unset($pa_options['request']); unset($pa_options['template']); // we pass through options to get() and don't want templates if (!isset($pa_options['convertCodesToDisplayText'])) { $pa_options['convertCodesToDisplayText'] = true; } $pb_return_as_array = (bool) caGetOption('returnAsArray', $pa_options, false); if (!is_array($pa_row_ids) || !sizeof($pa_row_ids) || !$ps_template) { return $pb_return_as_array ? array() : ""; } unset($pa_options['returnAsArray']); if (!isset($pa_options['requireLinkTags'])) { $pa_options['requireLinkTags'] = true; } $va_primary_ids = caGetOption("primaryIDs", $pa_options, null); $o_dm = Datamodel::load(); $ps_tablename = is_numeric($pm_tablename_or_num) ? $o_dm->getTableName($pm_tablename_or_num) : $pm_tablename_or_num; $ps_resolve_links_using = caGetOption('resolveLinksUsing', $pa_options, $ps_tablename); $t_instance = $o_dm->getInstanceByTableName($ps_tablename, true); if ($ps_resolve_links_using != $ps_tablename) { $t_resolve_links_instance = $o_dm->getInstanceByTableName($ps_resolve_links_using, true); $vs_resolve_links_using_pk = $t_resolve_links_instance->primaryKey(); } $vs_pk = $t_instance->primaryKey(); $vs_delimiter = isset($pa_options['delimiter']) ? $pa_options['delimiter'] : '; '; $ps_template = str_replace("^_parent", "^{$ps_resolve_links_using}.parent.preferred_labels", $ps_template); $ps_template = str_replace("^_hierarchy", "^{$ps_resolve_links_using}._hierarchyName", $ps_template); $va_related_values = isset($pa_options['relatedValues']) && is_array($pa_options['relatedValues']) ? $pa_options['relatedValues'] : array(); $va_relationship_values = isset($pa_options['relationshipValues']) && is_array($pa_options['relationshipValues']) ? $pa_options['relationshipValues'] : array(); // Set up DomDocument XML parser $o_dom = new DOMDocument('1.0', 'utf-8'); $o_dom->preserveWhiteSpace = true; libxml_use_internal_errors(true); // don't reported mangled HTML errors $o_dom->loadHTML('<?xml encoding="utf-8">' . $ps_template); libxml_clear_errors(); // Parse units from template $o_xpath = new DOMXPath($o_dom); $o_units = $o_xpath->query('//unit[not(ancestor::unit)]'); // only find units not nested within other units (allows for units with units...) $va_units = array(); $ps_template = preg_replace("![\r\n\t]+!", "", html_entity_decode($ps_template)); //DomDocument kills newlines and tabs so we do the same to the template $ps_template = preg_replace("!relativeTo[ ]*\\=!i", "relativeto=", $ps_template); //DomDocument forces attribute names to all lower case so we need to adjust the template to match $ps_template = preg_replace("!restrictToTypes[ ]*\\=!i", "restricttotypes=", $ps_template); $ps_template = preg_replace("!restrictToRelationshipTypes[ ]*\\=!i", "restricttorelationshiptypes=", $ps_template); $ps_template = preg_replace("!([A-Za-z0-9]+)='([^']*)'!", "\$1=\"\$2\"", $ps_template); //DomDocument converts quotes around attributes from single to double quotes, so we need to normalize the template to match $ps_template = preg_replace("!\\>[ ]+\\<!", "><", $ps_template); $vn_unit_id = 1; foreach ($o_units as $o_unit) { if (!$o_unit) { continue; } $vs_html = (string) $o_dom->saveXML($o_unit); $vs_content = preg_replace("!^<[^\\>]+>!", "", $vs_html); $vs_content = preg_replace("!<[^\\>]+>\$!", "", $vs_content); $vs_content = preg_replace("!>[ ]+<\$!", "><", $vs_content); // DomDocument messes with white space and encodes entities so we normalize the directive here so the str_ireplace() replacement below doesn't fail $va_units[] = $va_unit = array('tag' => $vs_unit_tag = "[[#{$vn_unit_id}]]", 'directive' => preg_replace("![\r\n\t\"]+!", "", html_entity_decode($vs_html)), 'content' => $vs_content, 'relativeTo' => (string) $o_unit->getAttribute("relativeto"), 'delimiter' => (string) $o_unit->getAttribute("delimiter"), 'restrictToTypes' => (string) $o_unit->getAttribute("restricttotypes"), 'restrictToRelationshipTypes' => (string) $o_unit->getAttribute("restricttorelationshiptypes")); $ps_template = str_ireplace($va_unit['directive'], $vs_unit_tag, $ps_template); $vn_unit_id++; } $va_tags = array(); if (preg_match_all("!\\^([A-Za-z0-9_\\.]+[%]{1}[^ \\^\t\r\n\"\\'<>\\(\\)\\{\\}\\/\\[\\]]*|[A-Za-z0-9_\\.]+)!", $ps_template, $va_matches)) { $va_tags = $va_matches[1]; } $qr_res = $t_instance->makeSearchResult($ps_tablename, $pa_row_ids); if (!$qr_res) { return ''; } $va_proc_templates = array(); $vn_i = 0; // Parse template $o_dom->loadHTML('<?xml encoding="utf-8">' . $ps_template); libxml_clear_errors(); $o_if = $o_dom->getElementsByTagName("if"); // if $o_ifdefs = $o_dom->getElementsByTagName("ifdef"); // if defined $o_ifnotdefs = $o_dom->getElementsByTagName("ifnotdef"); // if not defined $o_mores = $o_dom->getElementsByTagName("more"); // more tags – content suppressed if there are no defined values following the tag pair $o_betweens = $o_dom->getElementsByTagName("between"); // between tags – content suppressed if there are not defined values on both sides of the tag pair $o_options = $o_dom->getElementsByTagName("options"); $va_if = array(); foreach ($o_if as $o_if) { if (!$o_if) { continue; } $vs_html = $o_dom->saveXML($o_if); $vs_content = preg_replace("!^<[^\\>]+>!", "", $vs_html); $vs_content = preg_replace("!<[^\\>]+>\$!", "", $vs_content); // // Hack to get around DomDocument trimming leading spaces off of parsed HTML // We try here to detect the trimming and shunt those spaces back where they belong. Seems to work :-) // if (preg_match("!([ ]+){$vs_content}!", $ps_template, $va_match_spaces)) { $vs_html = preg_replace("!{$vs_content}!", $va_match_spaces[1] . $vs_content, $vs_html); $vs_content = $va_match_spaces[1] . $vs_content; } $va_if[] = array('directive' => $vs_html, 'content' => $vs_content, 'rule' => $vs_rule = (string) $o_if->getAttribute('rule')); //$vs_code = preg_replace("!%(.*)$!", '', $vs_code); //if (!in_array($vs_code, $va_tags)) { $va_tags[] = $vs_code; } } //print_r($va_if); $va_ifdefs = array(); foreach ($o_ifdefs as $o_ifdef) { if (!$o_ifdef) { continue; } $vs_html = $o_dom->saveXML($o_ifdef); $vs_content = preg_replace("!^<[^\\>]+>!", "", $vs_html); $vs_content = preg_replace("!<[^\\>]+>\$!", "", $vs_content); // // Hack to get around DomDocument trimming leading spaces off of parsed HTML // We try here to detect the trimming and shunt those spaces back where they belong. Seems to work :-) // if (preg_match("!([ ]+){$vs_content}!", $ps_template, $va_match_spaces)) { $vs_html = preg_replace("!{$vs_content}!", $va_match_spaces[1] . $vs_content, $vs_html); $vs_content = $va_match_spaces[1] . $vs_content; } $va_ifdefs[$vs_code = (string) $o_ifdef->getAttribute('code')][] = array('directive' => $vs_html, 'content' => $vs_content); $vs_code = preg_replace("!%(.*)\$!", '', $vs_code); if (!in_array($vs_code, $va_tags)) { $va_tags[] = $vs_code; } } $va_ifnotdefs = array(); foreach ($o_ifnotdefs as $o_ifnotdef) { if (!$o_ifnotdef) { continue; } $vs_html = $o_dom->saveXML($o_ifnotdef); $vs_content = preg_replace("!^<[^\\>]+>!", "", $vs_html); $vs_content = preg_replace("!<[^\\>]+>\$!", "", $vs_content); // // Hack to get around DomDocument trimming leading spaces off of parsed HTML // We try here to detect the trimming and shunt those spaces back where they belong. Seems to work :-) // if (preg_match("!([ ]+){$vs_content}!", $ps_template, $va_match_spaces)) { $vs_html = preg_replace("!{$vs_content}!", $va_match_spaces[1] . $vs_content, $vs_html); $vs_content = $va_match_spaces[1] . $vs_content; } $va_ifnotdefs[$vs_code = (string) $o_ifnotdef->getAttribute('code')][] = array('directive' => $vs_html, 'content' => $vs_content); $vs_code = preg_replace("!%(.*)\$!", '', $vs_code); if (!in_array($vs_code, $va_tags)) { $va_tags[] = $vs_code; } } $va_mores = array(); foreach ($o_mores as $o_more) { if (!$o_more) { continue; } $vs_html = $o_dom->saveXML($o_more); $vs_content = preg_replace("!^<[^\\>]+>!", "", $vs_html); $vs_content = preg_replace("!<[^\\>]+>\$!", "", $vs_content); $va_mores[] = array('directive' => $vs_html, 'content' => $vs_content); } $va_betweens = array(); foreach ($o_betweens as $o_between) { if (!$o_between) { continue; } $vs_html = $o_dom->saveXML($o_between); $vs_content = preg_replace("!^<[^\\>]+>!", "", $vs_html); $vs_content = preg_replace("!<[^\\>]+>\$!", "", $vs_content); $va_betweens[] = array('directive' => $vs_html, 'content' => $vs_content); } $va_resolve_links_using_row_ids = array(); $va_tag_val_list = $va_defined_tag_list = array(); while ($qr_res->nextHit()) { $vs_pk_val = $qr_res->get($vs_pk); $va_proc_templates[$vn_i] = preg_replace("![\r\n\t]+!", "", html_entity_decode($ps_template)); // DomDocument messes with white space and encodes entities so we normalize things here so the str_ireplace() replacement below doesn't fail foreach ($va_units as $va_unit) { if (!$va_unit['content']) { continue; } $va_relative_to_tmp = $va_unit['relativeTo'] ? explode(".", $va_unit['relativeTo']) : array($ps_tablename); if (!($t_instance = $o_dm->getInstanceByTableName($va_relative_to_tmp[0], true))) { continue; } $vs_unit_delimiter = caGetOption('delimiter', $va_unit, '; '); // additional get options for pulling related records $va_get_options = array('returnAsArray' => true); if ($va_unit['restrictToTypes'] && strlen($va_unit['restrictToTypes']) > 0) { $va_get_options['restrictToTypes'] = explode('|', $va_unit['restrictToTypes']); } if ($va_unit['restrictToRelationshipTypes'] && strlen($va_unit['restrictToRelationshipTypes']) > 0) { $va_get_options['restrictToRelationshipTypes'] = explode('|', $va_unit['restrictToRelationshipTypes']); } if (sizeof($va_relative_to_tmp) == 1 && $va_relative_to_tmp[0] == $ps_tablename || sizeof($va_relative_to_tmp) >= 1 && $va_relative_to_tmp[0] == $ps_tablename && $va_relative_to_tmp[1] != 'related') { switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $qr_res->get($t_instance->tableName() . ".hierarchy." . $t_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $qr_res->get($t_instance->tableName() . ".parent." . $t_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $qr_res->get($t_instance->tableName() . ".children." . $t_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: $va_relative_ids = $pa_row_ids; break; } } else { switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $qr_res->get($t_instance->tableName() . ".hierarchy." . $t_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $qr_res->get($t_instance->tableName() . ".parent." . $t_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $qr_res->get($t_instance->tableName() . ".children." . $t_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'related': $va_relative_ids = $qr_res->get($t_instance->tableName() . ".related." . $t_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: $va_relative_ids = $qr_res->get($t_instance->tableName() . "." . $t_instance->primaryKey(), $va_get_options); break; } } $vs_tmpl_val = caProcessTemplateForIDs($va_unit['content'], $va_relative_to_tmp[0], $va_relative_ids, array_merge($pa_options, array('restrictToTypes' => caGetOption('restrictToTypes', $va_get_options, null), 'restrictToRelationshipTypes' => caGetOption('restrictToRelationshipTypes', $va_get_options, null)), array('delimiter' => $vs_unit_delimiter, 'resolveLinksUsing' => null))); $va_proc_templates[$vn_i] = str_ireplace($va_unit['tag'], $vs_tmpl_val, $va_proc_templates[$vn_i]); } if (!strlen(trim($va_proc_templates[$vn_i]))) { $va_proc_templates[$vn_i] = null; } if (!sizeof($va_tags)) { continue; } // if there are no tags in the template then we don't need to process further if ($ps_resolve_links_using != $ps_tablename) { $va_resolve_links_using_row_ids[] = $qr_res->get("{$ps_resolve_links_using}.{$vs_resolve_links_using_pk}"); } $va_tag_val_list[$vn_i] = array(); $va_defined_tag_list[$vn_i] = array(); $va_tag_opts = array(); foreach ($va_tags as $vs_tag) { $va_tmp = explode('.', $vs_tag); $vs_last_element = $va_tmp[sizeof($va_tmp) - 1]; $va_tag_opt_tmp = explode("%", $vs_last_element); if (sizeof($va_tag_opt_tmp) > 1) { $vs_tag_bit = array_shift($va_tag_opt_tmp); // get rid of getspec foreach ($va_tag_opt_tmp as $vs_tag_opt_raw) { $va_tag_tmp = explode("=", $vs_tag_opt_raw); $va_tag_tmp[0] = trim($va_tag_tmp[0]); $va_tag_tmp[1] = trim($va_tag_tmp[1]); if (in_array($va_tag_tmp[0], array('delimiter', 'hierarchicalDelimiter'))) { $va_tag_tmp[1] = str_replace("_", " ", $va_tag_tmp[1]); } if (sizeof($va_tag_line_tmp = explode("|", $va_tag_tmp[1])) > 1) { $va_tag_opts[trim($va_tag_tmp[0])] = $va_tag_line_tmp; } else { $va_tag_opts[trim($va_tag_tmp[0])] = $va_tag_tmp[1]; } } $va_tmp[sizeof($va_tmp) - 1] = $vs_tag_bit; // remove option from tag-part array $vs_tag_proc = join(".", $va_tmp); $va_proc_templates[$vn_i] = str_replace($vs_tag, $vs_tag_proc, $va_proc_templates[$vn_i]); $vs_tag = $vs_tag_proc; } $pa_options = array_merge($pa_options, $va_tag_opts); // Default label tag to hierarchies if (isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels'] && $vs_tag == 'label') { unset($va_related_values[$vs_pk_val][$vs_tag]); unset($va_relationship_values[$vs_pk_val][$vs_tag]); $va_tmp = array($ps_tablename, 'hierarchy', 'preferred_labels'); } if (!isset($va_relationship_values[$vs_pk_val])) { $va_relationship_values[$vs_pk_val] = array(0 => null); } foreach ($va_relationship_values[$vs_pk_val] as $vn_relation_id => $va_relationship_value_array) { $vb_is_related = false; $va_val = null; if (isset($va_relationship_value_array[$vs_tag]) && !(isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels'] && $vs_tag == 'label')) { $va_val = array($vs_val = $va_relationship_value_array[$vs_tag]); } else { if (isset($va_related_values[$vs_pk_val][$vs_tag])) { $va_val = array($vs_val = $va_related_values[$vs_pk_val][$vs_tag]); } else { // // see if this is a reference to a related table // if ($ps_tablename != $va_tmp[0] && ($t_tmp = $o_dm->getInstanceByTableName($va_tmp[0], true))) { // if the part of the tag before a "." (or the tag itself if there are no periods) is a related table then try to fetch it as related to the current record if (isset($pa_options['placeholderPrefix']) && $pa_options['placeholderPrefix'] && $va_tmp[0] != $pa_options['placeholderPrefix'] && sizeof($va_tmp) == 1) { $vs_get_spec = array_shift($va_tmp) . "." . $pa_options['placeholderPrefix']; if (sizeof($va_tmp) > 0) { $vs_get_spec .= "." . join(".", $va_tmp); } } else { $vs_get_spec = $vs_tag; } $va_spec_bits = explode(".", $vs_get_spec); if (sizeof($va_spec_bits) == 1 && $o_dm->getTableNum($va_spec_bits[0])) { $vs_get_spec .= ".preferred_labels"; } $va_additional_options = array('returnAsArray' => true); $vs_hierarchy_name = null; if (in_array($va_spec_bits[1], array('hierarchy', '_hierarchyName'))) { $t_rel = $o_dm->getInstanceByTableName($va_spec_bits[0], true); switch ($t_rel->getProperty('HIERARCHY_TYPE')) { case __CA_HIER_TYPE_SIMPLE_MONO__: $va_additional_options['removeFirstItems'] = 1; break; case __CA_HIER_TYPE_MULTI_MONO__: $vs_hierarchy_name = $t_rel->getHierarchyName($qr_res->get($t_rel->tableName() . "." . $t_rel->primaryKey())); $va_additional_options['removeFirstItems'] = 1; break; } } if ($va_spec_bits[1] != '_hierarchyName') { $va_val = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_additional_options, array("returnAsArray" => true, "returnAllLocales" => true))); } else { $va_val = array(); } if (is_array($va_primary_ids) && isset($va_primary_ids[$va_spec_bits[0]]) && is_array($va_primary_ids[$va_spec_bits[0]])) { foreach ($va_primary_ids[$va_spec_bits[0]] as $vn_primary_id) { unset($va_val[$vn_primary_id]); } } $va_val = caExtractValuesByUserLocale($va_val); $va_val_tmp = array(); foreach ($va_val as $vn_d => $va_vals) { $va_val_tmp = array_merge($va_val_tmp, $va_vals); } $va_val = $va_val_tmp; $va_val_proc = array(); switch ($va_spec_bits[1]) { case '_hierarchyName': if ($vs_hierarchy_name) { $va_val_proc[] = $vs_hierarchy_name; } break; case 'hierarchy': if (is_array($va_val) && sizeof($va_val) > 0) { if ($vs_hierarchy_name) { array_unshift($va_val, $vs_hierarchy_name); } foreach ($va_val as $va_hier) { if (!is_array($va_hier)) { $va_hier = array($va_hier); } $va_val_proc[] = join(caGetOption("delimiter", $va_tag_opts, "; "), $va_hier); } } break; case 'parent': if (is_array($va_val)) { foreach ($va_val as $va_label) { $va_val_proc[] = $va_label['name']; } } break; default: $vs_terminal = end($va_spec_bits); foreach ($va_val as $va_val_container) { if (!is_array($va_val_container)) { if ($va_val_container) { $va_val_proc[] = $va_val_container; } continue; } $va_val_proc[] = $va_val_container[$vs_terminal]; } break; } $va_val = $va_val_proc; $vb_is_related = true; } else { // // Handle non-related gets // // Default specifiers that end with a modifier to preferred labels if (sizeof($va_tmp) == 2 && in_array($va_tmp[1], array('hierarchy', 'children', 'parent', 'related'))) { array_push($va_tmp, 'preferred_labels'); } $vs_hierarchy_name = null; if (in_array($va_tmp[1], array('hierarchy', '_hierarchyName'))) { switch ($t_instance->getProperty('HIERARCHY_TYPE')) { case __CA_HIER_TYPE_SIMPLE_MONO__: $va_additional_options['removeFirstItems'] = 1; break; case __CA_HIER_TYPE_MULTI_MONO__: $vs_hierarchy_name = $t_instance->getHierarchyName($qr_res->get($t_instance->tableName() . "." . $t_instance->primaryKey())); $va_additional_options['removeFirstItems'] = 1; break; } } if ($va_tmp[0] == $ps_tablename) { array_shift($va_tmp); } // get rid of primary table if it's in the field spec if (!sizeof($va_tmp) && $t_instance->getProperty('LABEL_TABLE_NAME')) { $va_tmp[] = "preferred_labels"; } if (isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels']) { if (!in_array($va_tmp[0], array('hierarchy', 'children', 'parent', 'related')) && $va_tmp[1] == 'preferred_labels') { array_unshift($va_tmp, 'hierarchy'); } } if (isset($pa_options['placeholderPrefix']) && $pa_options['placeholderPrefix'] && $va_tmp[0] != $pa_options['placeholderPrefix']) { array_splice($va_tmp, -1, 0, $pa_options['placeholderPrefix']); } $vs_get_spec = "{$ps_tablename}." . join(".", $va_tmp); if (in_array($va_tmp[0], array('parent'))) { $va_val[] = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_tag_opts, array('returnAsArray' => false))); } else { $va_val_tmp = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_tag_opts, array('returnAsArray' => true))); $va_val = array(); if (is_array($va_val_tmp)) { foreach ($va_val_tmp as $vn_attr_id => $vm_attr_val) { if (is_array($vm_attr_val)) { if ($va_tmp[0] == 'hierarchy') { if ($vs_hierarchy_name) { array_shift($vm_attr_val); // remove root array_unshift($vm_attr_val, $vs_hierarchy_name); // replace with hierarchy name } if ($vs_delimiter_tmp = caGetOption('hierarchicalDelimiter', $va_tag_opts)) { $vs_tag_val_delimiter = $vs_delimiter_tmp; } elseif ($vs_delimiter_tmp = caGetOption('hierarchicalDelimiter', $pa_options)) { $vs_tag_val_delimiter = $vs_delimiter_tmp; } else { $vs_tag_val_delimiter = caGetOption('delimiter', $va_tag_opts, $vs_delimiter); } } else { $vs_tag_val_delimiter = caGetOption('delimiter', $va_tag_opts, $vs_delimiter); } $va_val[] = join($vs_tag_val_delimiter, $vm_attr_val); } else { $va_val[] = $vm_attr_val; } } } if (sizeof($va_val) > 1 && $va_tmp[0] == 'hierarchy') { $vs_tag_val_delimiter = caGetOption('delimiter', $va_tag_opts, $vs_delimiter); $va_val = array(join($vs_tag_val_delimiter, $va_val)); } } } } } if (is_array($va_val)) { if (sizeof($va_val) > 0) { foreach ($va_val as $vn_j => $vs_val) { if (!is_array($va_tag_val_list[$vn_i][$vn_j][$vs_tag]) || !in_array($vs_val, $va_tag_val_list[$vn_i][$vn_j][$vs_tag])) { $va_tag_val_list[$vn_i][$vn_j][$vs_tag][] = $vs_val; if (is_array($vs_val) && sizeof($vs_val) || strlen($vs_val) > 0) { $va_defined_tag_list[$vn_i][$vn_j][$vs_tag] = true; } } } } else { $va_tag_val_list[$vn_i][0][$vs_tag] = null; $va_defined_tag_list[$vn_i][0][$vs_tag] = false; } } } } $vn_i++; } foreach ($va_tag_val_list as $vn_i => $va_tags_list) { $va_acc = array(); foreach ($va_tags_list as $vn_j => $va_tags) { $va_tag_list = array(); $va_pt_vals = array(); $vs_template = $va_proc_templates[$vn_i]; // Process <if> foreach ($va_if as $va_def_con) { if (ExpressionParser::evaluate($va_def_con['rule'], $va_tags)) { $vs_template = str_replace($va_def_con['directive'], $va_def_con['content'], $vs_template); } else { $vs_template = str_replace($va_def_con['directive'], '', $vs_template); } } // Process <ifdef> (IF DEFined) foreach ($va_ifdefs as $vs_code => $va_def_con) { if (strpos($vs_code, "|") !== false) { $vs_bool = 'OR'; $va_tag_list = explode("|", $vs_code); $vb_output = false; } else { $vs_bool = 'AND'; $va_tag_list = explode(",", $vs_code); $vb_output = true; } foreach ($va_tag_list as $vs_tag_to_test) { $vb_value_is_set = (bool) (isset($va_tags[$vs_tag_to_test]) && sizeof($va_tags[$vs_tag_to_test]) > 1 || sizeof($va_tags[$vs_tag_to_test]) == 1 && strlen($va_tags[$vs_tag_to_test][0]) > 0); switch ($vs_bool) { case 'OR': if ($vb_value_is_set) { $vb_output = true; break 2; } // any must be defined; if any is defined output break; case 'AND': default: if (!$vb_value_is_set) { $vb_output = false; break 2; } // all must be defined; if any is not defined don't output break; } } foreach ($va_def_con as $va_ifdef) { if ($vb_output) { $vs_template = str_replace($va_ifdef['directive'], $va_ifdef['content'], $vs_template); } else { $vs_template = str_replace($va_ifdef['directive'], '', $vs_template); } } } // Process <ifnotdef> (IF NOT DEFined) foreach ($va_ifnotdefs as $vs_code => $va_notdef_con) { if (strpos($vs_code, "|") !== false) { $vs_bool = 'OR'; $va_tag_list = explode("|", $vs_code); $vb_output = false; } else { $vs_bool = 'AND'; $va_tag_list = explode(",", $vs_code); $vb_output = true; } $vb_output = true; foreach ($va_tag_list as $vs_tag_to_test) { $vb_value_is_set = (bool) (isset($va_tags[$vs_tag_to_test]) && sizeof($va_tags[$vs_tag_to_test]) > 1 || sizeof($va_tags[$vs_tag_to_test]) == 1 && strlen($va_tags[$vs_tag_to_test][0]) > 0); switch ($vs_bool) { case 'OR': if (!$vb_value_is_set) { $vb_output = true; break 2; } // any must be not defined; if anything is not set output break; case 'AND': default: if ($vb_value_is_set) { $vb_output = false; break 2; } // all must be not defined; if anything is set don't output break; } } foreach ($va_notdef_con as $va_ifnotdef) { if ($vb_output) { $vs_template = str_replace($va_ifnotdef['directive'], $va_ifnotdef['content'], $vs_template); } else { $vs_template = str_replace($va_ifnotdef['directive'], '', $vs_template); } } } // Process <more> tags foreach ($va_mores as $vn_more_index => $va_more) { if (($vn_pos = strpos($vs_template, $va_more['directive'])) !== false) { if (isset($va_mores[$vn_more_index + 1]) && ($vn_next_more_pos = strpos(substr($vs_template, $vn_pos + strlen($va_more['directive'])), $va_mores[$vn_more_index + 1]['directive'])) !== false) { $vn_next_more_pos += $vn_pos; $vs_partial_template = substr($vs_template, $vn_pos + strlen($va_more['directive']), $vn_next_more_pos - $vn_pos); } else { $vs_partial_template = substr($vs_template, $vn_pos + strlen($va_more['directive'])); } $vb_output = false; foreach (array_keys($va_defined_tag_list[$vn_i][$vn_j]) as $vs_defined_tag) { if (strpos($vs_partial_template, $vs_defined_tag) !== false) { // content is defined $vb_output = true; break; } } if ($vb_output) { $vs_template = preg_replace('!' . $va_more['directive'] . '!', $va_more['content'], $vs_template, 1); } else { $vs_template = preg_replace('!' . $va_more['directive'] . '!', '', $vs_template, 1); } } } // Process <between> tags - text to be output if it is between two defined values $va_between_positions = array(); foreach ($va_betweens as $vn_between_index => $va_between) { $vb_output_before = $vb_output_after = false; if (($vn_cur_pos = strpos($vs_template, $va_between['directive'])) !== false) { $va_between_positions[$vn_between_index] = $vn_cur_pos; // Get parts of template before tag and after tag $vs_partial_template_before = substr($vs_template, 0, $vn_cur_pos); $vs_partial_template_after = substr($vs_template, $vn_cur_pos + strlen($va_between['directive'])); // Only get the template between our current position and the next <between> tag if (isset($va_betweens[$vn_between_index + 1]) && ($vn_after_pos_relative = strpos($vs_partial_template_after, $va_betweens[$vn_between_index + 1]['directive'])) !== false) { $vs_partial_template_after = substr($vs_partial_template_after, 0, $vn_after_pos_relative); } // Check for defined value before and after tag foreach (array_keys($va_defined_tag_list[$vn_i][$vn_j]) as $vs_defined_tag) { if (strpos($vs_partial_template_before, $vs_defined_tag) !== false) { // content is defined $vb_output_after = true; } if (strpos($vs_partial_template_after, $vs_defined_tag) !== false) { // content is defined $vb_output_before = true; break; } if ($vb_output_before && $vb_output_after) { break; } } } if ($vb_output_before && $vb_output_after) { $vs_template = preg_replace('!' . $va_between['directive'] . '!', $va_between['content'], $vs_template, 1); } else { $vs_template = preg_replace('!' . $va_between['directive'] . '!', '', $vs_template, 1); } } // // Need to sort tags by length descending (longest first) // so that when we go to substitute and you have a tag followed by itself with a suffix // (ex. ^measurements and ^measurements2) we don't substitute both for the stub (ex. ^measurements) // $va_tags_tmp = array_keys($va_tags); usort($va_tags_tmp, function ($a, $b) { return strlen($b) - strlen($a); }); $vs_pt = $vs_template; foreach ($va_tags_tmp as $vs_tag) { $vs_pt = str_replace('^' . $vs_tag, is_array($va_tags[$vs_tag]) ? join(" | ", $va_tags[$vs_tag]) : $va_tags[$vs_tag], $vs_pt); } $va_pt_vals[] = $vs_pt; $va_acc[] = join(isset($pa_options['delimiter']) ? $pa_options['delimiter'] : $vs_delimiter, $va_pt_vals); } $va_proc_templates[$vn_i] = join($vs_delimiter, $va_acc); } foreach ($va_proc_templates as $vn_i => $vs_template) { if (!strlen(trim($vs_template))) { unset($va_proc_templates[$vn_i]); } } // Transform links $va_proc_templates = caCreateLinksFromText($va_proc_templates, $ps_resolve_links_using, $ps_resolve_links_using != $ps_tablename ? $va_resolve_links_using_row_ids : $pa_row_ids, null, null, $pa_options); // Kill any lingering tags (just in case) foreach ($va_proc_templates as $vn_i => $vs_proc_template) { $va_proc_templates[$vn_i] = preg_replace("!\\^([A-Za-z0-9_\\.]+[%]{1}[^ \\^\t\r\n\"\\'<>\\(\\)\\{\\}\\/\\[\\]]*|[A-Za-z0-9_\\.]+)!", "", $vs_proc_template); } if ($pb_return_as_array) { return $va_proc_templates; } return join($vs_delimiter, $va_proc_templates); }
/** * Processes single exporter item for a given record * * @param int $pn_item_id Primary of exporter item * @param int $pn_table_num Table num of item to export * @param int $pn_record_id Primary key value of item to export * @param array $pa_options * ignoreContext = don't switch context even though context may be set for current item * relationship_type_id, relationship_type_code, relationship_typename = * if this export is a sub-export (context-switch), we have no way of knowing the relationship * to the 'parent' element in the export, so there has to be a means to pass it down to make it accessable * logger = KLogger instance to use for logging. This option is mandatory! * @return array Item info */ public function processExporterItem($pn_item_id, $pn_table_num, $pn_record_id, $pa_options = array()) { $o_log = caGetOption('logger', $pa_options); // always set by exportRecord() $vb_ignore_context = caGetOption('ignoreContext', $pa_options); $o_log->logInfo(_t("Export mapping processor called with parameters [exporter_item_id:%1 table_num:%2 record_id:%3]", $pn_item_id, $pn_table_num, $pn_record_id)); $t_exporter_item = ca_data_exporters::loadExporterItemByID($pn_item_id); $t_instance = ca_data_exporters::loadInstanceByID($pn_record_id, $pn_table_num); // switch context to a different set of records if necessary and repeat current exporter item for all those selected records // (e.g. hierarchy children or related items in another table, restricted by types or relationship types) if (!$vb_ignore_context && ($vs_context = $t_exporter_item->getSetting('context'))) { $va_restrict_to_types = $t_exporter_item->getSetting('restrictToTypes'); $va_restrict_to_rel_types = $t_exporter_item->getSetting('restrictToRelationshipTypes'); $va_check_access = $t_exporter_item->getSetting('checkAccess'); $vn_new_table_num = $this->getAppDatamodel()->getTableNum($vs_context); $vb_context_is_related_table = false; if ($vn_new_table_num) { // switch to new table $vs_key = $this->getAppDatamodel()->getTablePrimaryKeyName($vs_context); } else { // this table, i.e. hierarchy context switch $vs_key = $t_instance->primaryKey(); $vn_new_table_num = $pn_table_num; } $o_log->logInfo(_t("Initiating context switch to '%1' for mapping ID %2 and record ID %3. The processor now tries to find matching records for the switch and calls himself for each of those items.", $vs_context, $pn_item_id, $pn_record_id)); switch ($vs_context) { case 'children': $va_related = $t_instance->getHierarchyChildren(); break; case 'parent': $va_related = array(); if ($vs_parent_id_fld = $t_instance->getProperty("HIERARCHY_PARENT_ID_FLD")) { $va_related[] = array($vs_key => $t_instance->get($vs_parent_id_fld)); } break; case 'ancestors': $va_parents = $t_instance->getHierarchyAncestors(null, array('idsOnly' => true)); $va_related = array(); foreach (array_unique($va_parents) as $vn_pk) { $va_related[] = array($vs_key => intval($vn_pk)); } break; case 'ca_sets': $t_set = new ca_sets(); $va_set_options = array(); if (isset($va_restrict_to_types[0])) { // the utility used below doesn't support passing multiple types so we just pass the first. // this should be enough for 99.99% of the actual use cases anyway $va_set_options['setType'] = $va_restrict_to_types[0]; } $va_set_options['checkAccess'] = $va_check_access; $va_set_options['setIDsOnly'] = true; $va_set_ids = $t_set->getSetsForItem($pn_table_num, $t_instance->getPrimaryKey(), $va_set_options); $va_related = array(); foreach (array_unique($va_set_ids) as $vn_pk) { $va_related[] = array($vs_key => intval($vn_pk)); } break; default: // plain old related table if ($vn_new_table_num) { $va_related = $t_instance->getRelatedItems($vs_context, array('restrictToTypes' => $va_restrict_to_types, 'restrictToRelationshipTypes' => $va_restrict_to_rel_types, 'checkAccess' => $va_check_access)); $vb_context_is_related_table = true; } else { return array(); } break; } $va_info = array(); if (is_array($va_related)) { $o_log->logDebug(_t("The current mapping will now be repreated for these items: %1", print_r($va_related, true))); foreach ($va_related as $va_rel) { // if we're dealing with a related table, pass on some info the relationship type to the context-switched invocation of processExporterItem(), // because we can't access that information from the related item simply because we don't exactly know where the call originated if ($vb_context_is_related_table) { $pa_options['relationship_typename'] = $va_rel['relationship_typename']; $pa_options['relationship_type_code'] = $va_rel['relationship_type_code']; $pa_options['relationship_type_id'] = $va_rel['relationship_type_id']; } $va_rel_export = $this->processExporterItem($pn_item_id, $vn_new_table_num, $va_rel[$vs_key], array_merge(array('ignoreContext' => true), $pa_options)); $va_info = array_merge($va_info, $va_rel_export); } } else { $o_log->logDebug(_t("No matching related items found for last context switch")); } return $va_info; } // end switch context // Don't prevent context switches for children of context-switched exporter items. This way you can // build cascades for jobs like exporting objects related to the creator of the record in question. unset($pa_options['ignoreContext']); $va_item_info = array(); $vs_source = $t_exporter_item->get('source'); $vs_element = $t_exporter_item->get('element'); $vb_repeat = $t_exporter_item->getSetting('repeat_element_for_multiple_values'); // if omitIfEmpty is set and get() returns nothing, we ignore this exporter item and all children if ($vs_omit_if_empty = $t_exporter_item->getSetting('omitIfEmpty')) { if (!(strlen($t_instance->get($vs_omit_if_empty)) > 0)) { return array(); } } // always return URL for export, not an HTML tag $va_get_options = array('returnURL' => true); if ($t_exporter_item->getSetting('convertCodesToDisplayText')) { $va_get_options['convertCodesToDisplayText'] = true; } if ($t_exporter_item->getSetting('returnIdno')) { $va_get_options['returnIdno'] = true; } if ($vs_delimiter = $t_exporter_item->getSetting("delimiter")) { $va_get_options['delimiter'] = $vs_delimiter; } if ($vs_template = $t_exporter_item->getSetting('template')) { $va_get_options['template'] = $vs_template; } if ($vs_locale = $t_exporter_item->getSetting('locale')) { // the global UI locale for some reason has a higher priority // than the locale setting in BaseModelWithAttributes::get // which is why we unset it here and restore it later global $g_ui_locale; $vs_old_ui_locale = $g_ui_locale; $g_ui_locale = null; $va_get_options['locale'] = $vs_locale; } if ($vs_source) { $o_log->logDebug(_t("Source for current mapping is %1", $vs_source)); $va_matches = array(); // CONSTANT value if (preg_match("/^_CONSTANT_:(.*)\$/", $vs_source, $va_matches)) { $o_log->logDebug(_t("This is a constant. Value for this mapping is '%1'", trim($va_matches[1]))); $va_item_info[] = array('text' => trim($va_matches[1]), 'element' => $vs_element); } else { if (in_array($vs_source, array("relationship_type_id", "relationship_type_code", "relationship_typename"))) { if (isset($pa_options[$vs_source]) && strlen($pa_options[$vs_source]) > 0) { $o_log->logDebug(_t("Source refers to releationship type information. Value for this mapping is '%1'", $pa_options[$vs_source])); $va_item_info[] = array('text' => $pa_options[$vs_source], 'element' => $vs_element); } } else { if (!$vb_repeat) { $vs_get = $t_instance->get($vs_source, $va_get_options); $o_log->logDebug(_t("Source is a simple get() for some bundle. Value for this mapping is '%1'", $vs_get)); $o_log->logDebug(_t("get() options are: %1", print_r($va_get_options, true))); $va_item_info[] = array('text' => $vs_get, 'element' => $vs_element); } else { // if user wants current element repeated in case of multiple returned values, go ahead and do that $va_get_options['delimiter'] = ';#;'; $vs_values = $t_instance->get($vs_source, $va_get_options); $o_log->logDebug(_t("Source is a get() that should be repeated for multiple values. Value for this mapping is '%1'. It includes the custom delimiter ';#;' that is later used to split the value into multiple values.", $vs_values)); $o_log->logDebug(_t("get() options are: %1", print_r($va_get_options, true))); $va_tmp = explode(";#;", $vs_values); foreach ($va_tmp as $vs_text) { $va_item_info[] = array('element' => $vs_element, 'text' => $vs_text); } } } } } else { if ($vs_template) { // templates without source are probably just static text, but you never know // -> run them through processor anyways $vs_proc_template = caProcessTemplateForIDs($vs_template, $pn_table_num, array($pn_record_id), array()); $o_log->logDebug(_t("Current mapping has no source but a template '%1'. Value from extracted via template processor is '%2'", $vs_template, $vs_proc_template)); $va_item_info[] = array('element' => $vs_element, 'text' => $vs_proc_template); } else { // no source, no template -> probably wrapper $o_log->logDebug(_t("Current mapping has no source and no template and is probably an XML/MARC wrapper element")); $va_item_info[] = array('element' => $vs_element); } } // reset UI locale if we unset it if ($vs_locale) { $g_ui_locale = $vs_old_ui_locale; } $o_log->logDebug(_t("We're now processing other settings like default, prefix, suffix, skipIfExpression, filterByRegExp, maxLength, plugins and replacements for this mapping")); $o_log->logDebug(_t("Local data before processing is: %1", print_r($va_item_info, true))); // handle other settings and plugin hooks $vs_default = $t_exporter_item->getSetting('default'); $vs_prefix = $t_exporter_item->getSetting('prefix'); $vs_suffix = $t_exporter_item->getSetting('suffix'); $vs_regexp = $t_exporter_item->getSetting('filterByRegExp'); $vn_max_length = $t_exporter_item->getSetting('maxLength'); $vs_skip_if_expr = $t_exporter_item->getSetting('skipIfExpression'); $vs_original_values = $t_exporter_item->getSetting('original_values'); $vs_replacement_values = $t_exporter_item->getSetting('replacement_values'); $va_replacements = ca_data_exporter_items::getReplacementArray($vs_original_values, $vs_replacement_values); foreach ($va_item_info as $vn_key => &$va_item) { // if returned value from plugin is null then we skip the item if (is_null($va_plugin_item = $this->opo_app_plugin_manager->hookExportItemBeforeSettings(array('instance' => $t_instance, 'exporter_item_instance' => $t_exporter_item, 'export_item' => $va_item)))) { continue; } else { $va_item = $va_plugin_item['export_item']; } // handle skipIfExpression setting if ($vs_skip_if_expr) { // Add current value as variable "value", accessible in expressions as ^value if (ExpressionParser::evaluate($vs_skip_if_expr, array_merge(array('value' => $va_item['text']), ca_data_exporters::$s_variables))) { unset($va_item_info[$vn_key]); continue; } } // filter by regex (deprecated since you can do the same thing and more with skipIfExpression) if (strlen($va_item['text']) > 0 && $vs_regexp) { if (!preg_match("!" . $vs_regexp . "!", $va_item['text'])) { unset($va_item_info[$vn_key]); continue; } } // do replacements $va_item['text'] = ca_data_exporter_items::replaceText($va_item['text'], $va_replacements); // if text is empty, fill in default // if text isn't empty, respect prefix and suffix if (strlen($va_item['text']) == 0) { if ($vs_default) { $va_item['text'] = $vs_default; } } else { if (strlen($vs_prefix) > 0 || strlen($vs_suffix) > 0) { $va_item['text'] = $vs_prefix . $va_item['text'] . $vs_suffix; } } if ($vn_max_length && strlen($va_item['text']) > $vn_max_length) { $va_item['text'] = substr($va_item['text'], 0, $vn_max_length) . " ..."; } // if this is a variable, set the value and delete it from the export tree $va_matches = array(); if (preg_match("/^_VARIABLE_:(.*)\$/", $va_item['element'], $va_matches)) { ca_data_exporters::$s_variables[$va_matches[1]] = $va_item['text']; unset($va_item_info[$vn_key]); continue; } // if returned value is null then we skip the item if (is_null($va_plugin_item = $this->opo_app_plugin_manager->hookExportItem(array('instance' => $t_instance, 'exporter_item_instance' => $t_exporter_item, 'export_item' => $va_item)))) { continue; } else { $va_item = $va_plugin_item['export_item']; } } $o_log->logInfo(_t("Extracted data for this mapping is as follows:")); foreach ($va_item_info as $va_tmp) { $o_log->logInfo(sprintf(" element:%-20s value: %-10s", $va_tmp['element'], $va_tmp['text'])); } $va_children = $t_exporter_item->getHierarchyChildren(); if (is_array($va_children) && sizeof($va_children) > 0) { $o_log->logInfo(_t("Now proceeding to process %1 direct children in the mapping hierarchy", sizeof($va_children))); foreach ($va_children as $va_child) { foreach ($va_item_info as &$va_info) { $va_child_export = $this->processExporterItem($va_child['item_id'], $pn_table_num, $pn_record_id, $pa_options); $va_info['children'] = array_merge((array) $va_info['children'], $va_child_export); } } } return $va_item_info; }
/** * * * @param string $ps_refinery_name * @param string $ps_table * @param array $pa_parents * @param array $pa_source_data * @param array $pa_item * @param int $pn_c * @param KLogger $o_log * * @return int */ function caProcessRefineryParents($ps_refinery_name, $ps_table, $pa_parents, $pa_source_data, $pa_item, $pn_c, $pa_options = null) { global $g_ui_locale_id; if (!is_array($pa_options)) { $pa_options = array(); } $o_log = caGetOption('log', $pa_options, null); $o_reader = caGetOption('reader', $pa_options, null); $o_trans = caGetOption('transaction', $pa_options, null); $vn_list_id = caGetOption('list_id', $pa_options, null); $vb_hierarchy_mode = caGetOption('hierarchyMode', $pa_options, false); if (!is_array($pa_parents)) { $pa_parents = array($pa_parents); } $vn_id = null; $pa_parents = array_reverse($pa_parents); foreach ($pa_parents as $vn_i => $va_parent) { if (!is_array($va_parent)) { $o_log->logWarn(_t('[%2] Parents options invalid. Did you forget to pass a list? Parents list passed was: %1', print_r($pa_parents, true), $ps_refinery_name)); break; } $vs_name = BaseRefinery::parsePlaceholder($va_parent['name'], $pa_source_data, $pa_item, $pn_c, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' ')); $vs_idno = BaseRefinery::parsePlaceholder($va_parent['idno'], $pa_source_data, $pa_item, $pn_c, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' ')); $vs_type = BaseRefinery::parsePlaceholder($va_parent['type'], $pa_source_data, $pa_item, $pn_c, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' ')); if (!$vs_name && !$vs_idno) { continue; } if (!$vs_name) { continue; } //$vs_name = $vs_idno; } $va_attributes = isset($va_parent['attributes']) && is_array($va_parent['attributes']) ? $va_parent['attributes'] : array(); foreach ($va_attributes as $vs_element_code => $va_attrs) { if (is_array($va_attrs)) { foreach ($va_attrs as $vs_k => $vs_v) { // BaseRefinery::parsePlaceholder may return an array if the input format supports repeated values (as XML does) // DataMigrationUtils::getCollectionID(), which ca_data_importers::importDataFromSource() uses to create related collections // only supports non-repeating attribute values, so we join any values here and call it a day. $va_attributes[$vs_element_code][$vs_k] = BaseRefinery::parsePlaceholder($vs_v, $pa_source_data, $pa_item, $pn_c, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' ')); } } else { $va_attributes[$vs_element_code] = array($vs_element_code => BaseRefinery::parsePlaceholder($va_attrs, $pa_source_data, $pa_item, $pn_c, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' '))); } } $va_attributes['idno'] = $vs_idno; $va_attributes['parent_id'] = $vn_id; if (isset($va_parent['rules']) && is_array($va_parent['rules'])) { foreach ($va_parent['rules'] as $va_rule) { $vm_ret = ExpressionParser::evaluate($va_rule['trigger'], $pa_source_data); if (!ExpressionParser::hadError() && (bool) $vm_ret) { foreach ($va_rule['actions'] as $va_action) { if (!is_array($va_action) && strtolower($va_action) == 'skip') { $va_action = array('action' => 'skip'); } switch ($vs_action_code = strtolower($va_action['action'])) { case 'set': switch ($va_action['target']) { case 'name': $vs_name = BaseRefinery::parsePlaceholder($va_action['value'], $pa_source_data, $pa_item, $pn_c, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' ')); break; case 'type': $vs_type = BaseRefinery::parsePlaceholder($va_action['value'], $pa_source_data, $pa_item, $pn_c, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' ')); break; default: $va_attributes[$va_action['target']] = BaseRefinery::parsePlaceholder($va_action['value'], $pa_source_data, $pa_item, $pn_c, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' ')); break; } break; case 'skip': default: if ($o_log) { if ($vs_action_code != 'skip') { $o_log->logInfo(_t('[%3] Parent was skipped using rule "%1" with default action because an invalid action ("%2") was specified', $va_rule['trigger'], $vs_action_code, $ps_refinery_name)); } else { $o_log->logDebug(_t('[%3] Parent was skipped using rule "%1" with action "%2"', $va_rule['trigger'], $vs_action_code, $ps_refinery_name)); } } continue 4; break; } } } elseif (ExpressionParser::hadError() && $o_log) { $o_log->logError(_t('[%3] Error processing rule "%1" as an error occurred. Error number was "%2"', $va_rule['trigger'], ExpressionParser::$s_last_error, $ps_refinery_name)); } } } $va_match_on = caGetOption("{$ps_refinery_name}_dontMatchOnLabel", $pa_item['settings'], false) ? array('idno') : array('idno', 'label'); $pa_options = array_merge(array('matchOn' => $va_match_on), $pa_options); switch ($ps_table) { case 'ca_objects': $vn_id = DataMigrationUtils::getObjectID($vs_name, $vn_id, $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels']['name'] = $va_attributes['_preferred_labels'] = $vs_name; break; case 'ca_entities': $vn_id = DataMigrationUtils::getEntityID($va_entity_label = DataMigrationUtils::splitEntityName($vs_name, $pa_options), $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels'] = $va_entity_label; $va_attributes['_preferred_labels'] = $vs_name; break; case 'ca_places': if (!$vn_id) { // get place hierarchy root require_once __CA_MODELS_DIR__ . "/ca_places.php"; $t_place = new ca_places(); if ($o_trans) { $t_place->setTransaction($o_trans); } $vn_id = $pa_options['defaultParentID']; if (!$vn_id) { $vn_id = $t_place->getHierarchyRootID($pa_options['hierarchyID']); } $va_attributes['parent_id'] = $vn_id; } $vn_id = DataMigrationUtils::getPlaceID($vs_name, $vn_id, $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels']['name'] = $va_attributes['_preferred_labels'] = $vs_name; break; case 'ca_occurrences': $vn_id = DataMigrationUtils::getOccurrenceID($vs_name, $vn_id, $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels']['name'] = $va_attributes['_preferred_labels'] = $vs_name; break; case 'ca_collections': $vn_id = DataMigrationUtils::getCollectionID($vs_name, $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels']['name'] = $va_attributes['_preferred_labels'] = $vs_name; break; case 'ca_loans': $vn_id = DataMigrationUtils::getLoanID($vs_name, $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels']['name'] = $va_attributes['_preferred_labels'] = $vs_name; break; case 'ca_movements': $vn_id = DataMigrationUtils::getMovementID($vs_name, $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels']['name'] = $va_attributes['_preferred_labels'] = $vs_name; break; case 'ca_list_items': if (!$vn_list_id) { if ($o_log) { $o_log->logDebug(_t('[importHelpers:caProcessRefineryParents] List was not specified')); } return null; } if (!$vn_id) { // get place hierarchy root require_once __CA_MODELS_DIR__ . "/ca_lists.php"; $t_list = new ca_lists(); if ($o_trans) { $t_list->setTransaction($o_trans); } $vn_id = $t_list->getRootItemIDForList($vn_list_id); $va_attributes['parent_id'] = $vn_id; } $vn_id = DataMigrationUtils::getListItemID($vn_list_id, $vs_name, $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels']['name_singular'] = $va_attributes['preferred_labels']['name_plural'] = $vs_name; break; case 'ca_storage_locations': if (!$vn_id) { // get storage location hierarchy root require_once __CA_MODELS_DIR__ . "/ca_storage_locations.php"; $t_loc = new ca_storage_locations(); if ($o_trans) { $t_loc->setTransaction($o_trans); } $vn_id = $t_loc->getHierarchyRootID(); $va_attributes['parent_id'] = $vn_id; } $vn_id = DataMigrationUtils::getStorageLocationID($vs_name, $vn_id, $vs_type, $g_ui_locale_id, $va_attributes, $pa_options); $va_attributes['preferred_labels']['name'] = $va_attributes['_preferred_labels'] = $vs_name; break; default: if ($o_log) { $o_log->logDebug(_t('[importHelpers:caProcessRefineryParents] Invalid table %1', $ps_table)); } return null; break; } $va_attributes['locale_id'] = $g_ui_locale_id; if ($o_log) { $o_log->logDebug(_t('[%6] Got parent %1 (%2) with id %3 and type %4 for %5', $vs_name, $vs_idno, $vn_id, $vs_type, $vs_name, $ps_refinery_name)); } } if ($vb_hierarchy_mode) { return $va_attributes; } return $vn_id; }
/** * Tests ExpressionParser::evaluate */ public function testEvaluate() { $actualOutput = ExpressionParser::evaluate($this->input, $this->dataContext); // Expected result $this->assertEquals('no_prefix_id.Ee > 0', $actualOutput); }
/** * */ public function validateUsingMetadataDictionaryRules($pa_options = null) { if (!$this->getPrimaryKey()) { return null; } $o_db = $this->getDb(); $o_dm = Datamodel::load(); $t_violation = new ca_metadata_dictionary_rule_violations(); $va_rules = ca_metadata_dictionary_rules::getRules(array('bundles' => caGetOption('bundles', $pa_options, null))); $vn_violation_count = 0; $va_violations = array(); foreach ($va_rules as $va_rule) { $va_expression_tags = caGetTemplateTags($va_rule['expression']); $t_violation->clear(); $vb_skip = !$this->hasBundle($va_rule['bundle_name'], $this->getTypeID()); if (!$vb_skip) { // create array of values present in rule $va_row = array($va_rule['bundle_name'] => $vs_val = $this->get($va_rule['bundle_name'])); foreach ($va_expression_tags as $vs_tag) { $va_row[$vs_tag] = $this->get($vs_tag); } } // is there a violation recorded for this rule and row? if ($t_found = ca_metadata_dictionary_rule_violations::find(array('rule_id' => $va_rule['rule_id'], 'row_id' => $this->getPrimaryKey(), 'table_num' => $this->tableNum()), array('returnAs' => 'firstModelInstance'))) { $t_violation = $t_found; } if (!$vb_skip && ExpressionParser::evaluate($va_rule['expression'], $va_row)) { // violation if ($t_violation->getPrimaryKey()) { $t_violation->setMode(ACCESS_WRITE); $t_violation->update(); } else { $t_violation->setMode(ACCESS_WRITE); $t_violation->set('rule_id', $va_rule['rule_id']); $t_violation->set('table_num', $this->tableNum()); $t_violation->set('row_id', $this->getPrimaryKey()); $t_violation->insert(); } $va_violations[$va_rule['rule_level']][$va_rule['bundle_name']][] = $va_rule; $vn_violation_count++; } else { if ($t_violation->getPrimaryKey()) { $t_violation->setMode(ACCESS_WRITE); $t_violation->delete(true); // remove violation } } } return $va_violations; }
/** * */ public static function validate_using_metadata_dictionary_rules($po_opts = null) { require_once __CA_MODELS_DIR__ . '/ca_metadata_dictionary_rules.php'; require_once __CA_MODELS_DIR__ . '/ca_metadata_dictionary_rule_violations.php'; $o_dm = Datamodel::load(); $t_violation = new ca_metadata_dictionary_rule_violations(); $va_rules = ca_metadata_dictionary_rules::getRules(); print CLIProgressBar::start(sizeof($va_rules), _t('Evaluating')); $vn_total_rows = $vn_rule_num = 0; $vn_num_rules = sizeof($va_rules); foreach ($va_rules as $va_rule) { $vn_rule_num++; $va_expression_tags = caGetTemplateTags($va_rule['expression']); $va_tmp = explode(".", $va_rule['bundle_name']); if (!($t_instance = $o_dm->getInstanceByTableName($va_tmp[0]))) { CLIUtils::addError(_t("Table for bundle %1 is not valid", $va_tmp[0])); continue; } $vs_bundle_name_proc = str_replace("{$vs_table_name}.", "", $va_rule['bundle_name']); $vn_table_num = $t_instance->tableNum(); $qr_records = call_user_func_array(($vs_table_name = $t_instance->tableName()) . "::find", array(array('deleted' => 0), array('returnAs' => 'searchResult'))); if (!$qr_records) { continue; } $vn_total_rows += $qr_records->numHits(); CLIProgressBar::setTotal($vn_total_rows); $vn_count = 0; while ($qr_records->nextHit()) { $vn_count++; print CLIProgressBar::next(1, _t("Rule %1 [%2/%3]: record %4", $va_rule['rule_settings']['label'], $vn_rule_num, $vn_num_rules, $vn_count)); $t_violation->clear(); $vn_id = $qr_records->getPrimaryKey(); $vb_skip = !$t_instance->hasBundle($va_rule['bundle_name'], $qr_records->get('type_id')); if (!$vb_skip) { // create array of values present in rule $va_row = array($va_rule['bundle_name'] => $vs_val = $qr_records->get($va_rule['bundle_name'])); foreach ($va_expression_tags as $vs_tag) { $va_row[$vs_tag] = $qr_records->get($vs_tag); } } // is there a violation recorded for this rule and row? if ($t_found = ca_metadata_dictionary_rule_violations::find(array('rule_id' => $va_rule['rule_id'], 'row_id' => $vn_id, 'table_num' => $vn_table_num), array('returnAs' => 'firstModelInstance'))) { $t_violation = $t_found; } if (!$vb_skip && ExpressionParser::evaluate($va_rule['expression'], $va_row)) { // violation if ($t_violation->getPrimaryKey()) { $t_violation->setMode(ACCESS_WRITE); $t_violation->update(); } else { $t_violation->setMode(ACCESS_WRITE); $t_violation->set('rule_id', $va_rule['rule_id']); $t_violation->set('table_num', $t_instance->tableNum()); $t_violation->set('row_id', $qr_records->getPrimaryKey()); $t_violation->insert(); } } else { if ($t_violation->getPrimaryKey()) { $t_violation->delete(true); // remove violation } } } } print CLIProgressBar::finish(); }
/** * Returns list of variables defined in the expression * * @param string $ps_expression * @return array */ public static function getVariableList($ps_expression) { $o_exp = new ExpressionParser(); if ($o_exp->tokenize($ps_expression)) { } $va_vars = array(); while ($va_token = $o_exp->getToken()) { if ($va_token['type'] == EEP_TOKEN_VARIABLE) { $va_vars[] = $va_token['varname']; } } return $va_vars; }
/** * Generates standard-format inspector panels for editors * * @param View $po_view Inspector view object * @param array $pa_options Optional array of options. Supported options are: * backText = a string to use as the "back" button text; default is "Results" * * @return string HTML implementing the inspector */ function caEditorInspector($po_view, $pa_options = null) { require_once __CA_MODELS_DIR__ . '/ca_sets.php'; require_once __CA_MODELS_DIR__ . '/ca_data_exporters.php'; $t_item = $po_view->getVar('t_item'); $vs_table_name = $t_item->tableName(); if (($vs_priv_table_name = $vs_table_name) == 'ca_list_items') { $vs_priv_table_name = 'ca_lists'; } $vn_item_id = $t_item->getPrimaryKey(); $o_result_context = $po_view->getVar('result_context'); $t_ui = $po_view->getVar('t_ui'); $t_type = method_exists($t_item, "getTypeInstance") ? $t_item->getTypeInstance() : null; $vs_type_name = method_exists($t_item, "getTypeName") ? $t_item->getTypeName() : ''; if (!$vs_type_name) { $vs_type_name = $t_item->getProperty('NAME_SINGULAR'); } $va_reps = $po_view->getVar('representations'); $o_dm = Datamodel::load(); if ($t_item->isHierarchical()) { $va_ancestors = $po_view->getVar('ancestors'); $vn_parent_id = $t_item->get($t_item->getProperty('HIERARCHY_PARENT_ID_FLD')); } else { $va_ancestors = array(); $vn_parent_id = null; } // action extra to preserve currently open screen across next/previous links $vs_screen_extra = $po_view->getVar('screen') ? '/' . $po_view->getVar('screen') : ''; if ($vs_type_name == "list item") { $vs_style = "style='height:auto;'"; } if ($vn_item_id | $po_view->request->getAction() === 'Delete') { $vs_buf = '<h3 class="nextPrevious" ' . $vs_style . '>' . caEditorFindResultNavigation($po_view->request, $t_item, $o_result_context, $pa_options) . "</h3>\n"; } $vs_color = null; if ($t_type) { $vs_color = trim($t_type->get('color')); } if (!$vs_color && $t_ui) { $vs_color = trim($t_ui->get('color')); } if (!$vs_color) { $vs_color = "FFFFFF"; } $vs_buf .= "<h4><div id='caColorbox' style='border: 6px solid #{$vs_color};'>\n"; $vs_icon = null; if ($t_type) { $vs_icon = $t_type->getMediaTag('icon', 'icon'); } if (!$vs_icon && $t_ui) { $vs_icon = $t_ui->getMediaTag('icon', 'icon'); } if ($vs_icon) { $vs_buf .= "<div id='inspectoricon' style='border-right: 6px solid #{$vs_color}; border-bottom: 6px solid #{$vs_color}; -moz-border-radius-bottomright: 8px; -webkit-border-bottom-right-radius: 8px;'>\n{$vs_icon}</div>\n"; } if ($po_view->request->getAction() === 'Delete' && $po_view->request->getParameter('confirm', pInteger)) { $vs_buf .= "<strong>" . _t("Deleted %1", $vs_type_name) . "</strong>\n"; $vs_buf .= "<br style='clear: both;'/></div></h4>\n"; } else { if ($vn_item_id) { if (!$po_view->request->config->get("{$vs_priv_table_name}_inspector_disable_headline")) { if ($po_view->request->user->canDoAction("can_edit_" . $vs_priv_table_name) && sizeof($t_item->getTypeList()) > 1) { $vs_buf .= "<strong>" . _t("Editing %1", $vs_type_name) . ": </strong>\n"; } else { $vs_buf .= "<strong>" . _t("Viewing %1", $vs_type_name) . ": </strong>\n"; } } if ($t_item->hasField('is_deaccessioned') && $t_item->get('is_deaccessioned') && $t_item->get('deaccession_date', array('getDirectDate' => true)) <= caDateToHistoricTimestamp(_t('now'))) { // If currently deaccessioned then display deaccession message $vs_buf .= "<br/><div class='inspectorDeaccessioned'>" . _t('Deaccessioned %1', $t_item->get('deaccession_date')) . "</div>\n"; if ($vs_deaccession_notes = $t_item->get('deaccession_notes')) { TooltipManager::add(".inspectorDeaccessioned", $vs_deaccession_notes); } } else { if ($po_view->request->user->canDoAction('can_see_current_location_in_inspector_ca_objects')) { if ($t_ui && method_exists($t_item, "getObjectHistory") && (is_array($va_placements = $t_ui->getPlacementsForBundle('ca_objects_history')) && sizeof($va_placements) > 0)) { // // Output current "location" of object in life cycle. Configuration is taken from a ca_objects_history bundle configured for the current editor // $va_placement = array_shift($va_placements); $va_bundle_settings = $va_placement['settings']; if (is_array($va_history = $t_item->getObjectHistory($va_bundle_settings, array('limit' => 1, 'currentOnly' => true))) && sizeof($va_history) > 0) { $va_current_location = array_shift(array_shift($va_history)); if (!($vs_inspector_current_location_label = $po_view->request->config->get("ca_objects_inspector_current_location_label"))) { $vs_inspector_current_location_label = _t('Current'); } if ($va_current_location['display']) { $vs_buf .= "<div class='inspectorCurrentLocation'><strong>" . $vs_inspector_current_location_label . ':</strong><br/>' . $va_current_location['display'] . "</div>"; } } } elseif (method_exists($t_item, "getLastLocationForDisplay")) { // If no ca_objects_history bundle is configured then display the last storage location if ($vs_current_location = $t_item->getLastLocationForDisplay("<ifdef code='ca_storage_locations.parent.preferred_labels'>^ca_storage_locations.parent.preferred_labels ➜ </ifdef>^ca_storage_locations.preferred_labels.name")) { $vs_buf .= "<br/><div class='inspectorCurrentLocation'>" . _t('Location: %1', $vs_current_location) . "</div>\n"; $vs_full_location_hierarchy = $t_item->getLastLocationForDisplay("^ca_storage_locations.hierarchy.preferred_labels.name%delimiter=_➜_"); if ($vs_full_location_hierarchy !== $vs_current_location) { TooltipManager::add(".inspectorCurrentLocation", $vs_full_location_hierarchy); } } } } } // // Display flags; expressions for these are defined in app.conf in the <table_name>_inspector_display_flags directive // if (is_array($va_display_flags = $po_view->request->config->getAssoc("{$vs_table_name}_inspector_display_flags"))) { $va_display_flag_buf = array(); foreach ($va_display_flags as $vs_exp => $vs_display_flag) { $va_exp_vars = array(); foreach (ExpressionParser::getVariableList($vs_exp) as $vs_var_name) { $va_exp_vars[$vs_var_name] = $t_item->get($vs_var_name, array('returnIdno' => true)); } if (ExpressionParser::evaluate($vs_exp, $va_exp_vars)) { $va_display_flag_buf[] = $t_item->getWithTemplate("{$vs_display_flag}"); } } if (!($vs_display_flag_delim = $po_view->request->config->get("{$vs_table_name}_inspector_display_flags_delimiter"))) { $vs_display_flag_delim = '; '; } if (sizeof($va_display_flag_buf) > 0) { $vs_buf .= join($vs_display_flag_delim, $va_display_flag_buf); } } $vs_label = ''; $vb_dont_use_labels_for_ca_objects = (bool) $t_item->getAppConfig()->get('ca_objects_dont_use_labels'); if (!($vs_table_name === 'ca_objects' && $vb_dont_use_labels_for_ca_objects)) { if ($vs_get_spec = $po_view->request->config->get("{$vs_table_name}_inspector_display_title")) { $vs_label = caProcessTemplateForIDs($vs_get_spec, $vs_table_name, array($t_item->getPrimaryKey())); } else { $va_object_collection_collection_ancestors = $po_view->getVar('object_collection_collection_ancestors'); if ($t_item->tableName() == 'ca_objects' && $t_item->getAppConfig()->get('ca_objects_x_collections_hierarchy_enabled') && is_array($va_object_collection_collection_ancestors) && sizeof($va_object_collection_collection_ancestors)) { $va_collection_links = array(); foreach ($va_object_collection_collection_ancestors as $va_collection_ancestor) { $va_collection_links[] = caEditorLink($po_view->request, $va_collection_ancestor['label'], '', 'ca_collections', $va_collection_ancestor['collection_id']); } $vs_label .= join(" / ", $va_collection_links) . ' > '; } if (method_exists($t_item, 'getLabelForDisplay')) { $vn_parent_index = sizeof($va_ancestors) - 1; if ($vn_parent_id && ($vs_table_name != 'ca_places' || $vn_parent_index > 0)) { $va_parent = $va_ancestors[$vn_parent_index]; $vs_disp_fld = $t_item->getLabelDisplayField(); if ($va_parent['NODE'][$vs_disp_fld] && ($vs_editor_link = caEditorLink($po_view->request, $va_parent['NODE'][$vs_disp_fld], '', $vs_table_name, $va_parent['NODE'][$t_item->primaryKey()]))) { $vs_label .= $vs_editor_link . ' > ' . $t_item->getLabelForDisplay(); } else { $vs_label .= ($va_parent['NODE'][$vs_disp_fld] ? $va_parent['NODE'][$vs_disp_fld] . ' > ' : '') . $t_item->getLabelForDisplay(); } } else { $vs_label .= $t_item->getLabelForDisplay(); if ($vs_table_name === 'ca_editor_uis' && in_array($po_view->request->getAction(), array('EditScreen', 'DeleteScreen', 'SaveScreen'))) { $t_screen = new ca_editor_ui_screens($po_view->request->getParameter('screen_id', pInteger)); if (!($vs_screen_name = $t_screen->getLabelForDisplay())) { $vs_screen_name = _t('new screen'); } $vs_label .= " > " . $vs_screen_name; } } } else { $vs_label .= $t_item->get('name'); } } } $vb_show_idno = (bool) ($vs_idno = $t_item->get($t_item->getProperty('ID_NUMBERING_ID_FIELD'))); if (!$vs_label) { switch ($vs_table_name) { default: if ($vs_table_name === 'ca_objects' && $vb_dont_use_labels_for_ca_objects) { $vs_label = $vs_idno; $vb_show_idno = false; } else { $vs_label = '[' . _t('BLANK') . ']'; } break; } } $vs_buf .= "<div class='recordTitle {$vs_table_name}' style='width:190px; overflow:hidden;'>{$vs_label}" . ($vb_show_idno ? "<a title='{$vs_idno}'>" . ($vs_idno ? " ({$vs_idno})" : '') : "") . "</a></div>"; if ($vs_table_name === 'ca_object_lots' && $t_item->getPrimaryKey()) { $vs_buf .= "<div id='inspectorLotMediaDownload'><strong>" . (($vn_num_objects = $t_item->numObjects()) == 1 ? _t('Lot contains %1 object', $vn_num_objects) : _t('Lot contains %1 objects', $vn_num_objects)) . "</strong>\n"; } if ($po_view->request->config->get("include_custom_inspector")) { if (file_exists($po_view->request->getViewsDirectoryPath() . "/bundles/inspector_info.php")) { $vo_inspector_view = new View($po_view->request, $po_view->request->getViewsDirectoryPath() . "/bundles/"); $vo_inspector_view->setVar('t_item', $t_item); $vs_buf .= $vo_inspector_view->render('inspector_info.php'); } } } else { $vs_parent_name = ''; if ($vn_parent_id = $po_view->request->getParameter('parent_id', pInteger)) { $t_parent = clone $t_item; $t_parent->load($vn_parent_id); $vs_parent_name = $t_parent->getLabelForDisplay(); } $vs_buf .= "<div class='creatingNew'>" . _t("Creating new %1", $vs_type_name) . " " . ($vs_parent_name ? _t("%1 > New %2", $vs_parent_name, $vs_type_name) : '') . "</div>\n"; $vs_buf .= "<br/>\n"; } // ------------------------------------------------------------------------------------- if ($t_item->getPrimaryKey()) { if (sizeof($va_reps) > 0) { $va_imgs = array(); $vs_buf .= "<div id='inspectorMedia'>"; $vn_r = $vn_primary_index = 0; foreach ($va_reps as $va_rep) { if (!($va_rep['info']['preview170']['WIDTH'] && $va_rep['info']['preview170']['HEIGHT'])) { continue; } if ($vb_is_primary = isset($va_rep['is_primary']) && (bool) $va_rep['is_primary']) { $vn_primary_index = $vn_r; } $va_imgs[] = "{url:'" . $va_rep['urls']['preview170'] . "', width: " . $va_rep['info']['preview170']['WIDTH'] . ", height: " . $va_rep['info']['preview170']['HEIGHT'] . ", link: '#', onclick: 'caMediaPanel.showPanel(\\'" . caNavUrl($po_view->request, '*', '*', 'GetMediaOverlay', array($t_item->primaryKey() => $vn_item_id, 'representation_id' => $va_rep['representation_id'])) . "\\')'}"; $vn_r++; } if (sizeof($va_reps) > 1) { $vs_buf .= "\n\t\t\t\t\t<div class='leftScroll'>\n\t\t\t\t\t\t<a href='#' onclick='inspectorInfoRepScroller.scrollToPreviousImage(); return false;'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_SCROLL_LT__) . "</a>\n\t\t\t\t\t</div>\n\t\t"; } if (sizeof($va_imgs) > 0) { $vs_buf .= "\n\t\t\t\t<div id='inspectorInfoRepScrollingViewer' style='position: relative;'>\n\t\t\t\t\t<div id='inspectorInfoRepScrollingViewerContainer'>\n\t\t\t\t\t\t<div id='inspectorInfoRepScrollingViewerImageContainer'></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t"; if (sizeof($va_reps) > 1) { $vs_buf .= "\n\t\t\t\t\t<div class='rightScroll'>\n\t\t\t\t\t\t<a href='#' onclick='inspectorInfoRepScroller.scrollToNextImage(); return false;'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_SCROLL_RT__) . "</a>\n\t\t\t\t\t</div>\n\t\t"; } TooltipManager::add(".leftScroll", _t('Previous')); TooltipManager::add(".rightScroll", _t('Next')); $vs_buf .= "<script type='text/javascript'>"; $vs_buf .= "\n\t\t\t\t\tvar inspectorInfoRepScroller = caUI.initImageScroller([" . join(",", $va_imgs) . "], 'inspectorInfoRepScrollingViewerImageContainer', {\n\t\t\t\t\t\t\tcontainerWidth: 170, containerHeight: 170,\n\t\t\t\t\t\t\timageCounterID: 'inspectorInfoRepScrollingViewerCounter',\n\t\t\t\t\t\t\tscrollingImageClass: 'inspectorInfoRepScrollerImage',\n\t\t\t\t\t\t\tscrollingImagePrefixID: 'inspectorInfoRep',\n\t\t\t\t\t\t\tinitialIndex: {$vn_primary_index}\n\t\t\t\t\t\t\t\n\t\t\t\t\t});\n\t\t\t\t</script>"; } $vs_buf .= "</div>\n"; if ($vs_get_spec = $po_view->request->config->get("{$vs_table_name}_inspector_display_below_media")) { $vs_buf .= caProcessTemplateForIDs($vs_get_spec, $vs_table_name, array($t_item->getPrimaryKey())); } } // // Output configurable additional info from config, if set // if ($vs_additional_info = $po_view->request->config->get("{$vs_table_name}_inspector_additional_info")) { if (is_array($vs_additional_info)) { $vs_buf .= "<br/>"; foreach ($vs_additional_info as $vs_info) { $vs_buf .= caProcessTemplateForIDs($vs_info, $vs_table_name, array($t_item->getPrimaryKey()), array('requireLinkTags' => true)) . "<br/>\n"; } } else { $vs_buf .= "<br/>" . caProcessTemplateForIDs($vs_additional_info, $vs_table_name, array($t_item->getPrimaryKey()), array('requireLinkTags' => true)) . "<br/>\n"; } } $vs_buf .= "<div id='toolIcons'>"; if ($vn_item_id) { # --- watch this link $vs_watch = ""; if (in_array($vs_table_name, array('ca_objects', 'ca_object_lots', 'ca_entities', 'ca_places', 'ca_occurrences', 'ca_collections', 'ca_storage_locations'))) { require_once __CA_MODELS_DIR__ . '/ca_watch_list.php'; $t_watch_list = new ca_watch_list(); $vs_watch = "<div class='watchThis'><a href='#' title='" . _t('Add/remove item to/from watch list.') . "' onclick='caToggleItemWatch(); return false;' id='caWatchItemButton'>" . caNavIcon($po_view->request, $t_watch_list->isItemWatched($vn_item_id, $t_item->tableNum(), $po_view->request->user->get("user_id")) ? __CA_NAV_BUTTON_UNWATCH__ : __CA_NAV_BUTTON_WATCH__) . "</a></div>"; $vs_buf .= "\n<script type='text/javascript'>\n\t\tfunction caToggleItemWatch() {\n\t\t\tvar url = '" . caNavUrl($po_view->request, $po_view->request->getModulePath(), $po_view->request->getController(), 'toggleWatch', array($t_item->primaryKey() => $vn_item_id)) . "';\n\t\t\t\n\t\t\tjQuery.getJSON(url, {}, function(data, status) {\n\t\t\t\tif (data['status'] == 'ok') {\n\t\t\t\t\tjQuery('#caWatchItemButton').html((data['state'] == 'watched') ? '" . addslashes(caNavIcon($po_view->request, __CA_NAV_BUTTON_UNWATCH__)) . "' : '" . addslashes(caNavIcon($po_view->request, __CA_NAV_BUTTON_WATCH__)) . "');\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log('Error toggling watch status for item: ' + data['errors']);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\t</script>\n"; } $vs_buf .= "{$vs_watch}\n"; TooltipManager::add("#caWatchItemButton", _t('Watch/Unwatch this record')); if ($po_view->request->user->canDoAction("can_change_type_{$vs_table_name}")) { $vs_buf .= "<div id='inspectorChangeType'><div id='inspectorChangeTypeButton'><a href='#' onclick='caTypeChangePanel.showPanel(); return false;'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_CHANGE__ . " Change Type", array('title' => _t('Change type'))) . "</a></div></div>\n"; $vo_change_type_view = new View($po_view->request, $po_view->request->getViewsDirectoryPath() . "/bundles/"); $vo_change_type_view->setVar('t_item', $t_item); FooterManager::add($vo_change_type_view->render("change_type_html.php")); TooltipManager::add("#inspectorChangeType", _t('Change Record Type')); } if ($t_item->getPrimaryKey() && $po_view->request->config->get($vs_table_name . '_show_add_child_control_in_inspector')) { $vb_show_add_child_control = true; if (is_array($va_restrict_add_child_control_to_types = $po_view->request->config->getList($vs_table_name . '_restrict_child_control_in_inspector_to_types')) && sizeof($va_restrict_add_child_control_to_types)) { $t_type_instance = $t_item->getTypeInstance(); if (!in_array($t_type_instance->get('idno'), $va_restrict_add_child_control_to_types) && !in_array($t_type_instance->getPrimaryKey(), $va_restrict_add_child_control_to_types)) { $vb_show_add_child_control = false; } } if ($vb_show_add_child_control) { if ((bool) $po_view->request->config->get($vs_table_name . '_enforce_strict_type_hierarchy')) { // strict menu $vs_type_list = $t_item->getTypeListAsHTMLFormElement('type_id', array('style' => 'width: 90px; font-size: 9px;'), array('childrenOfCurrentTypeOnly' => true, 'directChildrenOnly' => $po_view->request->config->get($vs_table_name . '_enforce_strict_type_hierarchy') == '~' ? false : true, 'returnHierarchyLevels' => true, 'access' => __CA_BUNDLE_ACCESS_EDIT__)); } else { // all types $vs_type_list = $t_item->getTypeListAsHTMLFormElement('type_id', array('style' => 'width: 90px; font-size: 9px;'), array('access' => __CA_BUNDLE_ACCESS_EDIT__)); } if ($vs_type_list) { $vs_buf .= "<div id='inspectorCreateChild'><div id='inspectorCreateChildButton'><a href='#' onclick='caCreateChildPanel.showPanel(); return false;'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_CHILD__, array('title' => _t('Create Child Record'))) . "</a></div></div>\n"; $vo_create_child_view = new View($po_view->request, $po_view->request->getViewsDirectoryPath() . "/bundles/"); $vo_create_child_view->setVar('t_item', $t_item); $vo_create_child_view->setVar('type_list', $vs_type_list); FooterManager::add($vo_create_child_view->render("create_child_html.php")); TooltipManager::add("#inspectorCreateChildButton", _t('Create a child record under this one')); } } } } if ($po_view->request->user->canDoAction('can_duplicate_' . $vs_table_name) && $t_item->getPrimaryKey()) { $vs_buf .= '<div id="caDuplicateItemButton">'; $vs_buf .= caFormTag($po_view->request, 'Edit', 'DuplicateItemForm', $po_view->request->getModulePath() . '/' . $po_view->request->getController(), 'post', 'multipart/form-data', '_top', array('disableUnsavedChangesWarning' => true, 'noTimestamp' => true)); $vs_buf .= caFormSubmitLink($po_view->request, caNavIcon($po_view->request, __CA_NAV_BUTTON_DUPLICATE__), '', 'DuplicateItemForm'); $vs_buf .= caHTMLHiddenInput($t_item->primaryKey(), array('value' => $t_item->getPrimaryKey())); $vs_buf .= caHTMLHiddenInput('mode', array('value' => 'dupe')); $vs_buf .= "</form>"; $vs_buf .= "</div>"; TooltipManager::add("#caDuplicateItemButton", _t('Duplicate this %1', mb_strtolower($vs_type_name, 'UTF-8'))); } // // Download media in lot ($vn_num_objects is only set for object lots) if ($vn_num_objects > 0) { $vs_buf .= "<div id='inspectorLotMediaDownloadButton'>" . caNavLink($po_view->request, caNavIcon($po_view->request, __CA_NAV_BUTTON_DOWNLOAD__), "button", $po_view->request->getModulePath(), $po_view->request->getController(), 'getLotMedia', array('lot_id' => $t_item->getPrimaryKey(), 'download' => 1), array()) . "</div>\n"; TooltipManager::add('#inspectorLotMediaDownloadButton', _t("Download all media associated with objects in this lot")); } // // Download media in set if ($vs_table_name == 'ca_sets' && sizeof($t_item->getItemRowIDs()) > 0) { $vs_buf .= "<div id='inspectorSetMediaDownloadButton'>" . caNavLink($po_view->request, caNavIcon($po_view->request, __CA_NAV_BUTTON_DOWNLOAD__), "button", $po_view->request->getModulePath(), $po_view->request->getController(), 'getSetMedia', array('set_id' => $t_item->getPrimaryKey(), 'download' => 1), array()) . "</div>\n"; TooltipManager::add('#inspectorSetMediaDownloadButton', _t("Download all media associated with records in this set")); } $vs_more_info = ''; // list of sets in which item is a member $t_set = new ca_sets(); if (is_array($va_sets = caExtractValuesByUserLocale($t_set->getSetsForItem($t_item->tableNum(), $t_item->getPrimaryKey(), array('user_id' => $po_view->request->getUserID(), 'access' => __CA_SET_READ_ACCESS__)))) && sizeof($va_sets)) { $va_links = array(); foreach ($va_sets as $vn_set_id => $va_set) { $va_links[] = "<a href='" . caEditorUrl($po_view->request, 'ca_sets', $vn_set_id) . "'>" . $va_set['name'] . "</a>"; } $vs_more_info .= "<div><strong>" . (sizeof($va_links) == 1 ? _t("In set") : _t("In sets")) . "</strong> " . join(", ", $va_links) . "</div>\n"; } // export options if ($vn_item_id && ($vs_select = $po_view->getVar('available_mappings_as_html_select'))) { $vs_more_info .= "<div class='inspectorExportControls'>" . caFormTag($po_view->request, 'exportItem', 'caExportForm', null, 'post', 'multipart/form-data', '_top', array('disableUnsavedChangesWarning' => true)); $vs_more_info .= $vs_select; $vs_more_info .= caHTMLHiddenInput($t_item->primaryKey(), array('value' => $t_item->getPrimaryKey())); $vs_more_info .= caHTMLHiddenInput('download', array('value' => 1)); $vs_more_info .= caFormSubmitLink($po_view->request, 'Export ›', 'button', 'caExportForm'); $vs_more_info .= "</form></div>"; } $va_creation = $t_item->getCreationTimestamp(); $va_last_change = $t_item->getLastChangeTimestamp(); if ($va_creation['timestamp'] || $va_last_change['timestamp']) { $vs_more_info .= "<div class='inspectorChangeDateList'>"; if ($va_creation['timestamp']) { if (!trim($vs_name = $va_creation['fname'] . ' ' . $va_creation['lname'])) { $vs_name = null; } $vs_interval = ($vn_t = time() - $va_creation['timestamp']) == 0 ? _t('Just now') : _t('%1 ago', caFormatInterval($vn_t, 2)); $vs_more_info .= "<div class='inspectorChangeDateListLine' id='caInspectorCreationDate'>" . ($vs_name ? _t('<strong>Created</strong><br/>%1 by %2', $vs_interval, $vs_name) : _t('<strong>Created</strong><br/>%1', $vs_interval)) . "</div>"; TooltipManager::add("#caInspectorCreationDate", "<h2>" . _t('Created on') . "</h2>" . _t('Created on %1', caGetLocalizedDate($va_creation['timestamp'], array('dateFormat' => 'delimited')))); } if ($va_last_change['timestamp'] && $va_creation['timestamp'] != $va_last_change['timestamp']) { if (!trim($vs_name = $va_last_change['fname'] . ' ' . $va_last_change['lname'])) { $vs_name = null; } $vs_interval = ($vn_t = time() - $va_last_change['timestamp']) == 0 ? _t('Just now') : _t('%1 ago', caFormatInterval($vn_t, 2)); $vs_more_info .= "<div class='inspectorChangeDateListLine' id='caInspectorChangeDate'>" . ($vs_name ? _t('<strong>Last changed</strong><br/>%1 by %2', $vs_interval, $vs_name) : _t('<strong>Last changed</strong><br/>%1', $vs_interval)) . "</div>"; TooltipManager::add("#caInspectorChangeDate", "<h2>" . _t('Last changed on') . "</h2>" . _t('Last changed on %1', caGetLocalizedDate($va_last_change['timestamp'], array('dateFormat' => 'delimited')))); } if (method_exists($t_item, 'getMetadataDictionaryRuleViolations') && is_array($va_violations = $t_item->getMetadataDictionaryRuleViolations()) && ($vn_num_violations = sizeof($va_violations)) > 0) { $va_violation_messages = array(); foreach ($va_violations as $vn_violation_id => $va_violation) { $vs_label = $t_item->getDisplayLabel($va_violation['bundle_name']); $va_violation_messages[] = "<li><em><u>{$vs_label}</u></em> " . $va_violation['violationMessage'] . "</li>"; } $vs_more_info .= "<div id='caInspectorViolationsList'>" . ($vs_num_violations_display = "<img src='" . $po_view->request->getThemeUrlPath() . "/graphics/icons/warning_small.gif' border='0'/> " . ($vn_num_violations > 1 ? _t('%1 problems require attention', $vn_num_violations) : _t('%1 problem requires attention', $vn_num_violations))) . "</div>\n"; TooltipManager::add("#caInspectorViolationsList", "<h2>{$vs_num_violations_display}</h2><ol>" . join("\n", $va_violation_messages)) . "</ol>\n"; } $vs_more_info .= "</div>\n"; } if ($vs_get_spec = $po_view->request->config->get("{$vs_table_name}_inspector_display_more_info")) { $vs_more_info .= caProcessTemplateForIDs($vs_get_spec, $vs_table_name, array($t_item->getPrimaryKey())); } if ($vs_more_info) { $vs_buf .= "<div class='button info'><a href='#' id='inspectorMoreInfo'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_INFO2__) . "</a></div>\n\t\t\t<div id='inspectorInfo' >"; $vs_buf .= $vs_more_info . "</div>\n"; TooltipManager::add("#inspectorMoreInfo", _t('See more information about this record')); } $vs_buf .= "</div><!--End tooIcons-->"; } // ------------------------------------------------------------------------------------- // // Item-specific information // // // Output info for related items // if (!$t_item->getPrimaryKey()) { // only applies to new records $vs_rel_table = $po_view->request->getParameter('rel_table', pString); $vn_rel_type_id = $po_view->request->getParameter('rel_type_id', pString); $vn_rel_id = $po_view->request->getParameter('rel_id', pInteger); if ($vs_rel_table && $po_view->request->datamodel->tableExists($vs_rel_table) && $vn_rel_type_id && $vn_rel_id) { $t_rel = $po_view->request->datamodel->getTableInstance($vs_rel_table); if ($t_rel && $t_rel->load($vn_rel_id)) { $vs_buf .= '<strong>' . _t("Will be related to %1", $t_rel->getTypeName()) . '</strong>: ' . $t_rel->getLabelForDisplay(); } } } // // Output lot info for ca_objects // $vb_is_currently_part_of_lot = true; if (!($vn_lot_id = $t_item->get('lot_id'))) { $vn_lot_id = $po_view->request->getParameter('lot_id', pInteger); $vb_is_currently_part_of_lot = false; } if ($vs_table_name === 'ca_objects' && $vn_lot_id) { require_once __CA_MODELS_DIR__ . '/ca_object_lots.php'; $va_lot_lots = caGetTypeListForUser('ca_object_lots', array('access' => __CA_BUNDLE_ACCESS_READONLY__)); $t_lot = new ca_object_lots($vn_lot_id); if ($t_lot->get('deleted') == 0 && in_array($t_lot->get('type_id'), $va_lot_lots)) { if (!($vs_lot_displayname = $t_lot->get('idno_stub'))) { if (!($vs_lot_displayname = $t_lot->getLabelForDisplay())) { $vs_lot_displayname = "Lot {$vn_lot_id}"; } } if ($vs_lot_displayname) { if (!($vs_part_of_lot_msg = $po_view->request->config->get("ca_objects_inspector_part_of_lot_msg"))) { $vs_part_of_lot_msg = _t('Part of lot'); } if (!($vs_will_be_part_of_lot_msg = $po_view->request->config->get("ca_objects_inspector_will_be_part_of_lot_msg"))) { $vs_will_be_part_of_lot_msg = _t('Will be part of lot'); } $vs_buf .= "<strong>" . ($vb_is_currently_part_of_lot ? $vs_part_of_lot_msg : $vs_will_be_part_of_lot_msg) . "</strong>: " . caNavLink($po_view->request, $vs_lot_displayname, '', 'editor/object_lots', 'ObjectLotEditor', 'Edit', array('lot_id' => $vn_lot_id)); } } } $va_object_container_types = $po_view->request->config->getList('ca_objects_container_types'); $va_object_component_types = $po_view->request->config->getList('ca_objects_component_types'); $vb_can_add_component = $vs_table_name === 'ca_objects' && $t_item->getPrimaryKey() && $po_view->request->user->canDoAction('can_create_ca_objects') && $t_item->canTakeComponents(); if (method_exists($t_item, 'getComponentCount')) { if ($vn_component_count = $t_item->getComponentCount()) { if ($t_ui && ($vs_component_list_screen = $t_ui->getScreenWithBundle("ca_objects_components_list", $po_view->request)) && $vs_component_list_screen !== $po_view->request->getActionExtra()) { $vs_component_count_link = caNavLink($po_view->request, $vn_component_count == 1 ? _t('%1 component', $vn_component_count) : _t('%1 components', $vn_component_count), '', '*', '*', $po_view->request->getAction() . '/' . $vs_component_list_screen, array($t_item->primaryKey() => $t_item->getPrimaryKey())); } else { $vs_component_count_link = $vn_component_count == 1 ? _t('%1 component', $vn_component_count) : _t('%1 components', $vn_component_count); } $vs_buf .= "<br/><strong>" . _t('Has') . ":</strong> {$vs_component_count_link}"; } } if ($vb_can_add_component) { $vs_buf .= ' <a href="#" onclick=\'caObjectComponentPanel.showPanel("' . caNavUrl($po_view->request, '*', 'ObjectComponent', 'Form', array('parent_id' => $t_item->getPrimaryKey())) . '"); return false;\')>' . caNavIcon($po_view->request, __CA_NAV_BUTTON_ADD__) . '</a>'; $vo_change_type_view = new View($po_view->request, $po_view->request->getViewsDirectoryPath() . "/bundles/"); $vo_change_type_view->setVar('t_item', $t_item); FooterManager::add($vo_change_type_view->render("create_component_html.php")); } // // Output lot info for ca_object_lots // if ($vs_table_name === 'ca_object_lots' && $t_item->getPrimaryKey()) { $va_component_types = $po_view->request->config->getList('ca_objects_component_types'); if (is_array($va_component_types) && sizeof($va_component_types)) { $vs_buf .= "<strong>" . (($vn_num_objects = $t_item->numObjects(null, array('return' => 'objects'))) == 1 ? _t('Lot contains %1 object', $vn_num_objects) : _t('Lot contains %1 objects', $vn_num_objects)) . "</strong>\n"; $vs_buf .= "<strong>" . (($vn_num_components = $t_item->numObjects(null, array('return' => 'components'))) == 1 ? _t('Lot contains %1 component', $vn_num_components) : _t('Lot contains %1 components', $vn_num_components)) . "</strong>\n"; } else { $vs_buf .= "<strong>" . (($vn_num_objects = $t_item->numObjects()) == 1 ? _t('Lot contains %1 object', $vn_num_objects) : _t('Lot contains %1 objects', $vn_num_objects)) . "</strong>\n"; } if ((bool) $po_view->request->config->get('allow_automated_renumbering_of_objects_in_a_lot') && ($va_nonconforming_objects = $t_item->getObjectsWithNonConformingIdnos())) { $vs_buf .= '<br/><br/><em>' . (($vn_c = sizeof($va_nonconforming_objects)) == 1 ? _t('There is %1 object with non-conforming numbering', $vn_c) : _t('There are %1 objects with non-conforming numbering', $vn_c)) . "</em>\n"; $vs_buf .= "<a href='#' onclick='jQuery(\"#inspectorNonConformingNumberList\").toggle(250); return false;'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_ADD__); $vs_buf .= "<div id='inspectorNonConformingNumberList' class='inspectorNonConformingNumberList'><div class='inspectorNonConformingNumberListScroll'><ol>\n"; foreach ($va_nonconforming_objects as $vn_object_id => $va_object_info) { $vs_buf .= '<li>' . caEditorLink($po_view->request, $va_object_info['idno'], '', 'ca_objects', $vn_object_id) . "</li>\n"; } $vs_buf .= "</ol></div>"; $vs_buf .= caNavLink($po_view->request, _t('Re-number objects') . ' ›', 'button', $po_view->request->getModulePath(), $po_view->request->getController(), 'renumberObjects', array('lot_id' => $t_item->getPrimaryKey())); $vs_buf .= "</div>\n"; } require_once __CA_MODELS_DIR__ . '/ca_objects.php'; $t_object = new ca_objects(); $vs_buf .= "<div class='inspectorLotObjectTypeControls'><form action='#' id='caAddObjectToLotForm'>"; if ((bool) $po_view->request->config->get('ca_objects_enforce_strict_type_hierarchy')) { // strict menu $vs_buf .= _t('Add new %1 to lot', $t_object->getTypeListAsHTMLFormElement('type_id', array('id' => 'caAddObjectToLotForm_type_id'), array('childrenOfCurrentTypeOnly' => true, 'directChildrenOnly' => $po_view->request->config->get('ca_objects_enforce_strict_type_hierarchy') == '~' ? false : true, 'returnHierarchyLevels' => true, 'access' => __CA_BUNDLE_ACCESS_EDIT__))); } else { // all types $vs_buf .= _t('Add new %1 to lot', $t_object->getTypeListAsHTMLFormElement('type_id', array('id' => 'caAddObjectToLotForm_type_id'), array('access' => __CA_BUNDLE_ACCESS_EDIT__))); } $vs_buf .= " <a href='#' onclick='caAddObjectToLotForm()'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_ADD__) . '</a>'; $vs_buf .= "</form></div>\n"; $vs_buf .= "<script type='text/javascript'>\n\tfunction caAddObjectToLotForm() { \n\t\twindow.location='" . caEditorUrl($po_view->request, 'ca_objects', 0, false, array('lot_id' => $t_item->getPrimaryKey(), 'rel' => 1, 'type_id' => '')) . "' + jQuery('#caAddObjectToLotForm_type_id').val();\n\t}\n\tjQuery(document).ready(function() {\n\t\tjQuery('#objectLotsNonConformingNumberList').hide();\n\t});\n</script>\n"; } // // Output related objects for ca_object_representations // if ($vs_table_name === 'ca_object_representations') { foreach (array('ca_objects', 'ca_object_lots', 'ca_entities', 'ca_places', 'ca_occurrences', 'ca_collections', 'ca_storage_locations', 'ca_loans', 'ca_movements') as $vs_rel_table) { if (sizeof($va_objects = $t_item->getRelatedItems($vs_rel_table))) { $vs_buf .= "<div><strong>" . _t("Related %1", $o_dm->getTableProperty($vs_rel_table, 'NAME_PLURAL')) . "</strong>: <br/>\n"; $vs_screen = ''; if ($t_ui = ca_editor_uis::loadDefaultUI($vs_rel_table, $po_view->request, null)) { $vs_screen = $t_ui->getScreenWithBundle('ca_object_representations', $po_view->request); } foreach ($va_objects as $vn_rel_id => $va_rel_info) { if ($vs_label = array_shift($va_rel_info['labels'])) { $vs_buf .= caEditorLink($po_view->request, '← ' . $vs_label . ' (' . $va_rel_info['idno'] . ')', '', $vs_rel_table, $va_rel_info[$o_dm->getTablePrimaryKeyName($vs_rel_table)], array(), array(), array('action' => 'Edit' . ($vs_screen ? "/{$vs_screen}" : ""))) . "<br/>\n"; } } $vs_buf .= "</div>\n"; } } } // // Output related object reprsentation for ca_representation_annotation // if ($vs_table_name === 'ca_representation_annotations') { if ($vn_representation_id = $t_item->get('representation_id')) { $vs_buf .= "<div><strong>" . _t("Applied to representation") . "</strong>: <br/>\n"; $t_rep = new ca_object_representations($vn_representation_id); $vs_buf .= caNavLink($po_view->request, '← ' . $t_rep->getLabelForDisplay(), '', 'editor/object_representations', 'ObjectRepresentationEditor', 'Edit/' . $po_view->getVar('representation_editor_screen'), array('representation_id' => $vn_representation_id)) . '<br/>'; $vs_buf .= "</div>\n"; } } // // Output extra useful info for sets // if ($vs_table_name === 'ca_sets') { $vn_set_item_count = $t_item->getItemCount(array('user_id' => $po_view->request->getUserID())); if ($vn_set_item_count > 0 && $po_view->request->user->canDoAction('can_batch_edit_' . $o_dm->getTableName($t_item->get('table_num')))) { $vs_buf .= caNavButton($po_view->request, __CA_NAV_BUTTON_BATCH_EDIT__, _t('Batch edit'), 'editorBatchSetEditorLink', 'batch', 'Editor', 'Edit', array('set_id' => $t_item->getPrimaryKey()), array(), array('icon_position' => __CA_NAV_BUTTON_ICON_POS_LEFT__, 'no_background' => true, 'dont_show_content' => true)); } $vs_buf .= "<div><strong>" . _t("Number of items") . "</strong>: {$vn_set_item_count}<br/>\n"; if ($t_item->getPrimaryKey()) { $vn_set_table_num = $t_item->get('table_num'); $vs_set_table_name = $o_dm->getTableName($vn_set_table_num); $vs_buf .= "<strong>" . _t("Type of content") . "</strong>: " . caGetTableDisplayName($vn_set_table_num) . "<br/>\n"; $vs_buf .= "</div>\n"; if ($po_view->request->user->canDoAction('can_duplicate_' . $vs_set_table_name)) { $vs_buf .= '<div style="border-top: 1px solid #aaaaaa; margin-top: 5px; font-size: 10px; text-align: right;" ></div>'; $vs_buf .= caFormTag($po_view->request, 'DuplicateItems', 'caDupeSetItemsForm', 'manage/sets/SetEditor', 'post', 'multipart/form-data', '_top', array('disableUnsavedChangesWarning' => true)); $vs_buf .= _t("Duplicate items in this set and add to") . " "; $vs_buf .= caHTMLSelect('setForDupes', array(_t('current set') => 'current', _t('new set') => 'new')); $vs_buf .= caHTMLHiddenInput('set_id', array('value' => $t_item->getPrimaryKey())); $vs_buf .= caFormSubmitLink($po_view->request, _t('Go') . " ›", "button", "caDupeSetItemsForm"); $vs_buf .= "</form>"; $vs_buf .= '<div style="border-top: 1px solid #aaaaaa; margin-top: 5px; font-size: 10px; text-align: right;" ></div>'; } } else { if ($vn_set_table_num = $po_view->request->getParameter('table_num', pInteger)) { $vs_buf .= "<div><strong>" . _t("Type of content") . "</strong>: " . caGetTableDisplayName($vn_set_table_num) . "<br/>\n"; $vs_buf .= "</div>\n"; } } $t_user = new ca_users(($vn_user_id = $t_item->get('user_id')) ? $vn_user_id : $po_view->request->getUserID()); if ($t_user->getPrimaryKey()) { $vs_buf .= "<div><strong>" . _t('Owner') . "</strong>: " . $t_user->get('fname') . ' ' . $t_user->get('lname') . "</div>\n"; } if ($po_view->request->user->canDoAction('can_export_' . $vs_set_table_name) && $t_item->getPrimaryKey() && sizeof(ca_data_exporters::getExporters($vn_set_table_num)) > 0) { $vs_buf .= '<div style="border-top: 1px solid #aaaaaa; margin-top: 5px; font-size: 10px; text-align: right;" id="caExportItemButton">'; $vs_buf .= _t('Export this set of records') . " "; $vs_buf .= "<a class='button' onclick='jQuery(\"#exporterFormList\").show();' style='text-align:right;' href='#'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_ADD__) . "</a>"; $vs_buf .= caFormTag($po_view->request, 'ExportData', 'caExportForm', 'manage/MetadataExport', 'post', 'multipart/form-data', '_top', array('disableUnsavedChangesWarning' => true)); $vs_buf .= "<div id='exporterFormList'>"; $vs_buf .= ca_data_exporters::getExporterListAsHTMLFormElement('exporter_id', $vn_set_table_num, array('id' => 'caExporterList'), array('width' => '135px')); $vs_buf .= caHTMLHiddenInput('set_id', array('value' => $t_item->getPrimaryKey())); $vs_buf .= caFormSubmitLink($po_view->request, _t('Export') . " ›", "button", "caExportForm"); $vs_buf .= "</div>\n"; $vs_buf .= "</form>"; $vs_buf .= "</div>"; $vs_buf .= "<script type='text/javascript'>"; $vs_buf .= "jQuery(document).ready(function() {"; $vs_buf .= "jQuery(\"#exporterFormList\").hide();"; $vs_buf .= "});"; $vs_buf .= "</script>"; } } // // Output extra useful info for set items // if ($vs_table_name === 'ca_set_items') { AssetLoadManager::register("panel"); $t_set = new ca_sets(); if ($t_set->load($vn_set_id = $t_item->get('set_id'))) { $vs_buf .= "<div><strong>" . _t("Part of set") . "</strong>: " . caEditorLink($po_view->request, $t_set->getLabelForDisplay(), '', 'ca_sets', $vn_set_id) . "<br/>\n"; $t_content_instance = $t_item->getAppDatamodel()->getInstanceByTableNum($vn_item_table_num = $t_item->get('table_num')); if ($t_content_instance->load($vn_row_id = $t_item->get('row_id'))) { $vs_label = $t_content_instance->getLabelForDisplay(); if ($vs_id_fld = $t_content_instance->getProperty('ID_NUMBERING_ID_FIELD')) { $vs_label .= " (" . $t_content_instance->get($vs_id_fld) . ")"; } $vs_buf .= "<strong>" . _t("Is %1", caGetTableDisplayName($vn_item_table_num, false) . "</strong>: " . caEditorLink($po_view->request, $vs_label, '', $vn_item_table_num, $vn_row_id)) . "<br/>\n"; } $vs_buf .= "</div>\n"; } } // // Output extra useful info for lists // if ($vs_table_name === 'ca_lists' && $t_item->getPrimaryKey()) { $vs_buf .= "<strong>" . _t("Number of items") . "</strong>: " . $t_item->numItemsInList() . "<br/>\n"; $t_list_item = new ca_list_items(); $t_list_item->load(array('list_id' => $t_item->getPrimaryKey(), 'parent_id' => null)); $vs_type_list = $t_list_item->getTypeListAsHTMLFormElement('type_id', array('style' => 'width: 90px; font-size: 9px;'), array('access' => __CA_BUNDLE_ACCESS_EDIT__)); if ($vs_type_list) { $vs_buf .= '<div style="border-top: 1px solid #aaaaaa; margin-top: 5px; font-size: 10px;">'; $vs_buf .= caFormTag($po_view->request, 'Edit', 'NewChildForm', 'administrate/setup/list_item_editor/ListItemEditor', 'post', 'multipart/form-data', '_top', array('disableUnsavedChangesWarning' => true)); $vs_buf .= _t('Add a %1 to this list', $vs_type_list) . caHTMLHiddenInput($t_list_item->primaryKey(), array('value' => '0')) . caHTMLHiddenInput('parent_id', array('value' => $t_list_item->getPrimaryKey())); $vs_buf .= caFormSubmitLink($po_view->request, caNavIcon($po_view->request, __CA_NAV_BUTTON_ADD__), '', 'NewChildForm'); $vs_buf .= "</form></div>\n"; } } // // Output containing list for list items // if ($vs_table_name === 'ca_list_items') { if ($t_list = $po_view->getVar('t_list')) { $vn_list_id = $t_list->getPrimaryKey(); $vs_buf .= "<strong>" . _t("Part of") . "</strong>: " . caEditorLink($po_view->request, $t_list->getLabelForDisplay(), '', 'ca_lists', $vn_list_id) . "<br/>\n"; if ($t_item->get('is_default')) { $vs_buf .= "<strong>" . _t("Is default for list") . "</strong><br/>\n"; } } } // // Output containing relationship type name for relationship types // if ($vs_table_name === 'ca_relationship_types') { if (!($t_rel_instance = $t_item->getAppDatamodel()->getInstanceByTableNum($t_item->get('table_num'), true))) { if ($vn_parent_id = $po_view->request->getParameter('parent_id', pInteger)) { $t_rel_type = new ca_relationship_types($vn_parent_id); $t_rel_instance = $t_item->getAppDatamodel()->getInstanceByTableNum($t_rel_type->get('table_num'), true); } } if ($t_rel_instance) { $vs_buf .= "<div><strong>" . _t("Is a") . "</strong>: " . $t_rel_instance->getProperty('NAME_SINGULAR') . "<br/></div>\n"; } } // // Output extra useful info for metadata elements // if ($vs_table_name === 'ca_metadata_elements' && $t_item->getPrimaryKey()) { $vs_buf .= "<div><strong>" . _t("Element code") . "</strong>: " . $t_item->get('element_code') . "<br/></div>\n"; if (sizeof($va_uis = $t_item->getUIs()) > 0) { $vs_buf .= "<div><strong>" . _t("Referenced by user interfaces") . "</strong>:<br/>\n"; foreach ($va_uis as $vn_ui_id => $va_ui_info) { $vs_buf .= caNavLink($po_view->request, $va_ui_info['name'], '', 'administrate/setup/interface_screen_editor', 'InterfaceScreenEditor', 'Edit', array('ui_id' => $vn_ui_id, 'screen_id' => $va_ui_info['screen_id'])); $vs_buf .= " (" . $o_dm->getTableProperty($va_ui_info['editor_type'], 'NAME_PLURAL') . ")<br/>\n"; } $vs_buf .= "</div>\n"; } } // // Output related objects for ca_editor_uis and ca_editor_ui_screens // if ($vs_table_name === 'ca_editor_uis') { $vs_buf .= "<div><strong>" . _t("Number of screens") . "</strong>: " . (int) $t_item->getScreenCount() . "\n"; if ($t_item->getPrimaryKey()) { $vs_buf .= "<div><strong>" . _t("Edits") . "</strong>: " . caGetTableDisplayName($t_item->get('editor_type')) . "<br/>\n"; } else { $vs_buf .= "<div><strong>" . _t("Edits") . "</strong>: " . caGetTableDisplayName($po_view->request->getParameter('editor_type', pInteger)) . "<br/>\n"; } $vs_buf .= "</div>\n"; } // // Output related objects for ca_editor_uis and ca_editor_ui_screens // if ($vs_table_name === 'ca_editor_ui_screens') { $t_ui = new ca_editor_uis($vn_ui_id = $t_item->get('ui_id')); $vs_buf .= "<div><strong>" . _t("Part of") . "</strong>: " . caNavLink($po_view->request, $t_ui->getLabelForDisplay(), '', 'administrate/setup/interface_editor', 'InterfaceEditor', 'Edit', array('ui_id' => $vn_ui_id)) . "\n"; $vs_buf .= "</div>\n"; } // // Output extra useful info for bundle displays // if ($vs_table_name === 'ca_bundle_displays') { $vs_buf .= "<div><strong>" . _t("Number of placements") . "</strong>: " . $t_item->getPlacementCount(array('user_id' => $po_view->request->getUserID())) . "<br/>\n"; if ($t_item->getPrimaryKey()) { $vn_content_table_num = $t_item->get('table_num'); $vs_buf .= "<strong>" . _t("Type of content") . "</strong>: " . caGetTableDisplayName($vn_content_table_num) . "\n"; $vs_buf .= "</div>\n"; } else { if ($vn_content_table_num = $po_view->request->getParameter('table_num', pInteger)) { $vs_buf .= "<div><strong>" . _t("Type of content") . "</strong>: " . caGetTableDisplayName($vn_content_table_num) . "\n"; $vs_buf .= "</div>\n"; } } $t_user = new ca_users(($vn_user_id = $t_item->get('user_id')) ? $vn_user_id : $po_view->request->getUserID()); if ($t_user->getPrimaryKey()) { $vs_buf .= "<div><strong>" . _t('Owner') . "</strong>: " . $t_user->get('fname') . ' ' . $t_user->get('lname') . "</div>\n"; } } // // Output extra useful info for search forms // if ($vs_table_name === 'ca_search_forms') { $vs_buf .= "<div><strong>" . _t("Number of placements") . "</strong>: " . $t_item->getPlacementCount(array('user_id' => $po_view->request->getUserID())) . "<br/>\n"; if ($t_item->getPrimaryKey()) { $vn_content_table_num = $t_item->get('table_num'); $vs_buf .= "<strong>" . _t("Searches for") . "</strong>: " . caGetTableDisplayName($vn_content_table_num) . "\n"; $vs_buf .= "</div>\n"; } else { if ($vn_content_table_num = $po_view->request->getParameter('table_num', pInteger)) { $vs_buf .= "<strong>" . _t("Searches for") . "</strong>: " . caGetTableDisplayName($vn_content_table_num) . "\n"; $vs_buf .= "</div>\n"; } } $t_user = new ca_users(($vn_user_id = $t_item->get('user_id')) ? $vn_user_id : $po_view->request->getUserID()); if ($t_user->getPrimaryKey()) { $vs_buf .= "<div><strong>" . _t('Owner') . "</strong>: " . $t_user->get('fname') . ' ' . $t_user->get('lname') . "</div>\n"; } } // // Output extra useful info for tours // if ($vs_table_name === 'ca_tours' && $t_item->getPrimaryKey()) { $vs_buf .= "<br/><strong>" . _t("Number of stops") . "</strong>: " . $t_item->getStopCount() . "<br/>\n"; } // // Output containing tour for tour stops // if ($vs_table_name === 'ca_tour_stops') { $t_tour = new ca_tours($vn_tour_id = $t_item->get('tour_id')); $vs_buf .= "<strong>" . _t("Part of") . "</strong>: " . caEditorLink($po_view->request, $t_tour->getLabelForDisplay(), '', 'ca_tours', $vn_tour_id) . "<br/>\n"; } // // Output extra useful info for bundle mappings // if ($vs_table_name === 'ca_bundle_mappings') { if ($t_item->getPrimaryKey()) { $vn_content_table_num = $t_item->get('table_num'); $vs_buf .= "<br/><strong>" . _t("Type of content") . "</strong>: " . caGetTableDisplayName($vn_content_table_num) . "<br/>\n"; $vs_buf .= "<strong>" . _t("Type") . "</strong>: " . $t_item->getChoiceListValue('direction', $t_item->get('direction')) . "<br/>\n"; $vs_buf .= "<strong>" . _t("Target format") . "</strong>: " . $t_item->get('target') . "<br/>\n"; $va_stats = $t_item->getMappingStatistics(); $vs_buf .= "<div><strong>" . _t("Number of groups") . "</strong>: " . $va_stats['groupCount'] . "<br/>\n"; $vs_buf .= "<strong>" . _t("Number of rules") . "</strong>: " . $va_stats['ruleCount'] . "<br/>\n"; $vs_buf .= "</div>\n"; } else { if ($vn_content_table_num = $po_view->request->getParameter('table_num', pInteger)) { $vs_buf .= "<div><strong>" . _t("Type of content") . "</strong>: " . caGetTableDisplayName($vn_content_table_num) . "<br/>\n"; $vs_buf .= "<strong>" . _t("Type") . "</strong>: " . $t_item->getChoiceListValue('direction', $po_view->request->getParameter('direction', pString)) . "<br/>\n"; $vs_buf .= "<strong>" . _t("Target format") . "</strong>: " . $po_view->request->getParameter('target', pString) . "<br/>\n"; $vs_buf .= "<div><strong>" . _t("Number of groups") . "</strong>: 0<br/>\n"; $vs_buf .= "<strong>" . _t("Number of rules") . "</strong>: 0</div>\n"; $vs_buf .= "</div>\n"; } } } // // Output configurable additional info from config, if set // if ($vs_additional_info = $po_view->request->config->get("{$vs_table_name}_inspector_additional_info")) { if (is_array($vs_additional_info)) { $vs_buf .= "<br/>"; foreach ($vs_additional_info as $vs_info) { $vs_buf .= caProcessTemplateForIDs($vs_info, $vs_table_name, array($t_item->getPrimaryKey()), array('requireLinkTags' => true)) . "<br/>\n"; } } else { $vs_buf .= "<br/>" . caProcessTemplateForIDs($vs_additional_info, $vs_table_name, array($t_item->getPrimaryKey()), array('requireLinkTags' => true)) . "<br/>\n"; } } // ------------------------------------------------------------------------------------- // Export if ($t_item->getPrimaryKey() && $po_view->request->config->get($vs_table_name . '_show_add_child_control_in_inspector')) { $vb_show_add_child_control = true; if (is_array($va_restrict_add_child_control_to_types = $po_view->request->config->getList($vs_table_name . '_restrict_child_control_in_inspector_to_types')) && sizeof($va_restrict_add_child_control_to_types)) { $t_type_instance = $t_item->getTypeInstance(); if (!in_array($t_type_instance->get('idno'), $va_restrict_add_child_control_to_types) && !in_array($t_type_instance->getPrimaryKey(), $va_restrict_add_child_control_to_types)) { $vb_show_add_child_control = false; } } } if ($po_view->request->user->canDoAction('can_export_' . $vs_table_name) && $t_item->getPrimaryKey() && sizeof(ca_data_exporters::getExporters($t_item->tableNum())) > 0) { $vs_buf .= '<div style="border-top: 1px solid #aaaaaa; margin-top: 5px; font-size: 10px; text-align: right;" id="caExportItemButton">'; $vs_buf .= _t('Export this %1', mb_strtolower($vs_type_name, 'UTF-8')) . " "; $vs_buf .= "<a class='button' onclick='jQuery(\"#exporterFormList\").show();' style='text-align:right;' href='#'>" . caNavIcon($po_view->request, __CA_NAV_BUTTON_ADD__) . "</a>"; $vs_buf .= caFormTag($po_view->request, 'ExportSingleData', 'caExportForm', 'manage/MetadataExport', 'post', 'multipart/form-data', '_top', array('disableUnsavedChangesWarning' => true)); $vs_buf .= "<div id='exporterFormList'>"; $vs_buf .= ca_data_exporters::getExporterListAsHTMLFormElement('exporter_id', $t_item->tableNum(), array('id' => 'caExporterList'), array('width' => '120px')); $vs_buf .= caHTMLHiddenInput('item_id', array('value' => $t_item->getPrimaryKey())); $vs_buf .= caFormSubmitLink($po_view->request, _t('Export') . " ›", "button", "caExportForm"); $vs_buf .= "</div>\n"; $vs_buf .= "</form>"; $vs_buf .= "</div>"; $vs_buf .= "<script type='text/javascript'>"; $vs_buf .= "jQuery(document).ready(function() {"; $vs_buf .= "jQuery(\"#exporterFormList\").hide();"; $vs_buf .= "});"; $vs_buf .= "</script>"; } $vs_buf .= "</div></h4>\n"; $vs_buf .= "<script type='text/javascript'>\n\t\t\tvar inspectorCookieJar = jQuery.cookieJar('caCookieJar');"; if ($t_item->getPrimaryKey()) { if ($vs_more_info) { $vs_buf .= "\t\t\t\n\t\t\tif (inspectorCookieJar.get('inspectorMoreInfoIsOpen') == undefined) {\t\t// default is to have info open\n\t\t\t\tinspectorCookieJar.set('inspectorMoreInfoIsOpen', 1);\n\t\t\t}\n\t\t\tif (inspectorCookieJar.get('inspectorMoreInfoIsOpen') == 1) {\n\t\t\t\tjQuery('#inspectorInfo').toggle(0);\n\t\t\t\tjQuery('#inspectorMoreInfo').html('" . addslashes(caNavIcon($po_view->request, __CA_NAV_BUTTON_COLLAPSE__)) . "');\n\t\t\t}\n\t\t\n\t\t\tjQuery('#inspectorMoreInfo').click(function() {\n\t\t\t\tjQuery('#inspectorInfo').slideToggle(350, function() { \n\t\t\t\t\tinspectorCookieJar.set('inspectorMoreInfoIsOpen', (this.style.display == 'block') ? 1 : 0); \n\t\t\t\t\tjQuery('#inspectorMoreInfo').html((this.style.display == 'block') ? '" . addslashes(caNavIcon($po_view->request, __CA_NAV_BUTTON_COLLAPSE__)) . "' : '" . addslashes(caNavIcon($po_view->request, __CA_NAV_BUTTON_INFO2__)) . "');\n\t\t\t\t\tcaResizeSideNav();\n\t\t\t\t}); \n\t\t\t\treturn false;\n\t\t\t});\n\t\t"; } if (sizeof($va_reps)) { $vs_buf .= "\n\t\tif (inspectorCookieJar.get('inspectorShowMediaIsOpen') == undefined) {\t\t// default is to have media open\n\t\t\tinspectorCookieJar.set('inspectorShowMediaIsOpen', 1);\n\t\t}\n\t\t\n\t\tif (inspectorCookieJar.get('inspectorShowMediaIsOpen') == 1) {\n\t\t\tjQuery('#inspectorMedia').toggle();\n\t\t}\n\t\n\t\tjQuery('#caColorbox').on('click', function(e) {\n\t\t\tif (e.altKey) {\n\t\t\t\tjQuery('#inspectorMedia').slideToggle(200, function() { \n\t\t\t\t\tinspectorCookieJar.set('inspectorShowMediaIsOpen', (this.style.display == 'block') ? 1 : 0); \n\t\t\t\t\t\tcaResizeSideNav();\n\t\t\t\t}); \n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t\t\t\t\t"; } } $vs_buf .= "</script>\n"; } $o_app_plugin_manager = new ApplicationPluginManager(); $va_hookAppend = $o_app_plugin_manager->hookAppendToEditorInspector(array("t_item" => $t_item)); if (is_string($va_hookAppend["caEditorInspectorAppend"])) { $vs_buf .= $va_hookAppend["caEditorInspectorAppend"]; } return $vs_buf; }
/** * */ public function refine(&$pa_destination_data, $pa_group, $pa_item, $pa_source_data, $pa_options = null) { $o_log = isset($pa_options['log']) && is_object($pa_options['log']) ? $pa_options['log'] : null; $pm_value = $pa_source_data[$pa_item['source']]; // not actually used $va_item_dest = explode(".", $pa_item['destination']); $vs_item_terminal = array_pop($va_item_dest); $vs_group_terminal = array_pop($va_item_dest); $o_tep = new TimeExpressionParser(); $o_tep->setLanguage('en_US'); switch ($vs_mode = $pa_item['settings']['dateJoiner_mode']) { default: case 'range': $vs_date_expression = $pa_item['settings']['dateJoiner_expression']; $vs_date_start = $pa_item['settings']['dateJoiner_start']; $vs_date_end = $pa_item['settings']['dateJoiner_end']; if ($vs_date_expression && ($vs_exp = BaseRefinery::parsePlaceholder($vs_date_expression, $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { if ($o_tep->parse($vs_exp)) { return $o_tep->getText(); } else { if ($o_log) { $o_log->logWarn(_t('[dateJoinerRefinery] Could not parse date expression %1 assembled from range', $vs_exp)); } } } $va_date = array(); if ($vs_date_start = BaseRefinery::parsePlaceholder($vs_date_start, $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' '))) { if (!($vs_skip_start_exp = $pa_item['settings']['dateJoiner_skipStartIfExpression']) || !ExpressionParser::evaluate($vs_skip_start_exp, array_merge($pa_source_data, array('start' => $vs_date_start, 'end' => $vs_date_end, 'expression' => $ps_expression)))) { $va_date[] = $vs_date_start; } elseif ($vs_skip_start_replacement = $pa_item['settings']['dateJoiner_skipStartIfExpressionReplacementValue']) { $va_date[] = $vs_skip_start_replacement; } } if ($vs_date_end = BaseRefinery::parsePlaceholder($vs_date_end, $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' '))) { if (!($vs_skip_end_exp = $pa_item['settings']['dateJoiner_skipEndIfExpression']) || !ExpressionParser::evaluate($vs_skip_end_exp, array_merge($pa_source_data, array('start' => $vs_date_start, 'end' => $vs_date_end, 'expression' => $ps_expression)))) { $va_date[] = $vs_date_end; } elseif ($vs_skip_end_replacement = $pa_item['settings']['dateJoiner_skipEndIfExpressionReplacementValue']) { $va_date[] = $vs_skip_end_replacement; } } foreach ($va_date as $vn_i => $vs_date) { $va_date[$vn_i] = preg_replace("![^\\d]+\$!", "", $vs_date); } $vs_date_expression = join(" - ", $va_date); if ($vs_date_expression && ($vs_exp = BaseRefinery::parsePlaceholder($vs_date_expression, $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { if ($o_tep->parse($vs_exp)) { return $o_tep->getText(); } else { if ($o_log) { $o_log->logWarn(_t('[dateJoinerRefinery] Could not parse date expression %1 assembled from range', $vs_exp)); } } } break; case 'multiColumnDate': $va_month_list = $o_tep->getMonthList(); $va_date = array(); if ($vs_date_month = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_month'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { if (($vn_m = array_search($vs_date_month, $va_month_list)) !== false) { $vs_date_month = $vn_m + 1; } $va_date[] = $vs_date_month; } if ($vs_date_day = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_day'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { $va_date[] = $vs_date_day; } if ($vs_date_year = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_year'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { $va_date[] = $vs_date_year; } if (sizeof($va_date)) { // TODO: this is assuming US-style dates for now if ($o_tep->parse(join("/", $va_date))) { return $o_tep->getText(); } else { if ($o_log) { $o_log->logWarn(_t('[dateJoinerRefinery] Could not parse date expression %1 assembled from multiColumnDate', join("/", $va_date))); } } } break; case 'multiColumnRange': $va_dates = array(); $va_month_list = $o_tep->getMonthList(); // Process start date $va_date = array(); if ($vs_date_month = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_startMonth'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { if (($vn_m = array_search($vs_date_month, $va_month_list)) !== false) { $vs_date_month = $vn_m + 1; } $va_date[] = $vs_date_month; } if ($vs_date_day = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_startDay'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { $va_date[] = $vs_date_day; } if ($vs_date_year = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_startYear'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { $va_date[] = $vs_date_year; } if (sizeof($va_date)) { if ($o_tep->parse(join("/", $va_date))) { // TODO: this is assuming US-style dates for now $va_dates[] = $o_tep->getText(); } else { if ($o_log) { $o_log->logWarn(_t('[dateJoinerRefinery] Could not parse date expression %1 assembled from multiColumnRange', join("/", $va_date))); } } } // Process end date $va_date = array(); if ($vs_date_month = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_endMonth'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { if (($vn_m = array_search($vs_date_month, $va_month_list)) !== false) { $vs_date_month = $vn_m + 1; } $va_date[] = $vs_date_month; } if ($vs_date_day = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_endDay'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { $va_date[] = $vs_date_day; } if ($vs_date_year = trim(BaseRefinery::parsePlaceholder($pa_item['settings']['dateJoiner_endYear'], $pa_source_data, $pa_item, $vn_c, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true, 'delimiter' => ' ')))) { $va_date[] = $vs_date_year; } if (sizeof($va_date)) { if ($o_tep->parse(join("/", $va_date))) { // TODO: this is assuming US-style dates for now $va_dates[] = $o_tep->getText(); } else { if ($o_log) { $o_log->logWarn(_t('[dateJoinerRefinery] Could not parse date expression %1 assembled from multiColumnRange', join("/", $va_date))); } } } if (sizeof($va_dates) > 0) { return join(" - ", $va_dates); } break; } return null; }
/** * Random expressions we used for testing while writing the AST processor. Might as well leave them in here */ public function testEvaluate() { $this->assertTrue(ExpressionParser::evaluate('"Software is great" =~ /Soft/')); $this->assertFalse(ExpressionParser::evaluate('"Software is great" =~ /soft/')); $this->assertFalse(ExpressionParser::evaluate('"Software is great" !~ /Soft/')); $this->assertTrue(ExpressionParser::evaluate('"Software is great" !~ /soft/')); $this->assertEquals(true, ExpressionParser::evaluate('5 > 1')); $this->assertEquals(false, ExpressionParser::evaluate('5 > 6')); $this->assertEquals(false, ExpressionParser::evaluate('5 < 1')); $this->assertEquals(true, ExpressionParser::evaluate('5 < 6')); $this->assertEquals(false, ExpressionParser::evaluate('5 <= 1')); $this->assertEquals(true, ExpressionParser::evaluate('5 <= 6')); $this->assertEquals(true, ExpressionParser::evaluate('5 <= 5')); $this->assertEquals(true, ExpressionParser::evaluate('5 >= 1')); $this->assertEquals(false, ExpressionParser::evaluate('5 >= 6')); $this->assertEquals(true, ExpressionParser::evaluate('5 >= 5')); $this->assertEquals(true, ExpressionParser::evaluate('5 != 1')); $this->assertEquals(false, ExpressionParser::evaluate('5 != 5')); $this->assertEquals(false, ExpressionParser::evaluate('5 = 1')); $this->assertEquals(true, ExpressionParser::evaluate('5 = 5')); $this->assertEquals(true, ExpressionParser::evaluate('"Seth" IN ["Julia", "Allison", "Sophie", "Maria", "Angie", "Seth"]')); $this->assertEquals(false, ExpressionParser::evaluate('"Joe" IN ["Julia", "Allison", "Sophie", "Maria", "Angie", "Seth"]')); $this->assertEquals(false, ExpressionParser::evaluate('"Seth" NOT IN ["Julia", "Allison", "Sophie", "Maria", "Angie", "Seth"]')); $this->assertEquals(true, ExpressionParser::evaluate('"Joe" NOT IN ["Julia", "Allison", "Sophie", "Maria", "Angie", "Seth"]')); $this->assertEquals(3.1725, ExpressionParser::evaluate('avg(abs(-1.345), max(4,5))')); $this->assertEquals(4, ExpressionParser::evaluate('length("test")')); $this->assertEquals(1, ExpressionParser::evaluate('length(4)')); $this->assertEquals('Stefan parses', ExpressionParser::evaluate('"Stefan" + " parses"')); $this->assertEquals(11, ExpressionParser::evaluate('6 + 5')); $this->assertEquals(15, ExpressionParser::evaluate('6 + 5 + 4')); $this->assertEquals(1, ExpressionParser::evaluate('6 - 5')); $this->assertEquals(30, ExpressionParser::evaluate('6 * 5')); $this->assertEquals(2, ExpressionParser::evaluate('4 ÷ 2')); $this->assertEquals(49.5, ExpressionParser::evaluate('1 ÷ 2 ÷ 3 + 4 * (5 * 2 - 6) * 3')); $this->assertEquals(13, ExpressionParser::evaluate('5 + 4 * 2')); $this->assertEquals(14, ExpressionParser::evaluate('5 * 2 + 4')); }
/** * Returns array of attributes, each of which is an array of values ready for display. * The returned array is indexed by attribute element ID. Each array value is an array * indexed by attribute_id. The corresponding values are arrays of attribute values indexed by element_code * * @param $pm_element_code_or_id string|integer - * @param $pn_row_id integer - * @param $pa_options array - * convertLineBreaks = if set to true, will attempt to convert line break characters to HTML <p> and <br> tags; default is false. * locale = if set to a valid locale_id or locale code, values will be returned in locale *if available*, otherwise will fallback to values in languages that are available using the standard fallback mechanism. Default is to use user's current locale. * returnAllLocales = if set to true, values for all locales are returned, locale option is ignored and the returned array is indexed first by attribute_id and then by locale_id. Default is false. * indexByRowID = if true first index of returned array is $pn_row_id, otherwise it is the element_id of the retrieved metadata element * convertCodesToDisplayText = * filter = * @return array */ public function getAttributeDisplayValues($pm_element_code_or_id, $pn_row_id, $pa_options = null) { if (!is_array($pa_options)) { $pa_options = array(); } $ps_filter_expression = caGetOption('filter', $pa_options, null); $va_attribute_list = $this->getAttributesByElement($pm_element_code_or_id, array('row_id' => $pn_row_id)); if (!is_array($va_attribute_list)) { return array(); } $va_attributes = array(); $vs_table_name = $this->tableName(); $vs_container_element_code = $this->_getElementCode($pm_element_code_or_id); foreach ($va_attribute_list as $o_attribute) { $va_values = $o_attribute->getValues(); $va_raw_values = array(); $va_display_values = array(); foreach ($va_values as $o_value) { $vs_element_code = $this->_getElementCode($o_value->getElementID()); if (get_class($o_value) == 'ListAttributeValue') { $t_element = $this->_getElementInstance($o_value->getElementID()); $vn_list_id = !isset($pa_options['convertCodesToDisplayText']) || !$pa_options['convertCodesToDisplayText'] ? null : $t_element->get('list_id'); } else { $vn_list_id = null; } if ($ps_filter_expression) { $va_raw_values[$vs_container_element_code == $vs_element_code ? "{$vs_table_name}.{$vs_element_code}" : "{$vs_table_name}.{$vs_container_element_code}.{$vs_element_code}"] = $va_raw_values[$vs_element_code] = $o_value->getDisplayValue(array('list_id' => $vn_list_id, 'returnIdno' => true)); } if (isset($pa_options['convertLineBreaks']) && $pa_options['convertLineBreaks']) { $vs_converted_value = preg_replace("!(\n|\r\n){2}!", "<p/>", $o_value->getDisplayValue(array_merge($pa_options, array('list_id' => $vn_list_id)))); $va_display_values[$vs_element_code] = preg_replace("![\n]{1}!", "<br/>", $vs_converted_value); } else { $va_display_values[$vs_element_code] = $o_value->getDisplayValue(array_merge($pa_options, array('list_id' => $vn_list_id))); } } // Process filter if defined if ($ps_filter_expression && !ExpressionParser::evaluate($ps_filter_expression, $va_raw_values)) { continue; } if (isset($pa_options['indexByRowID']) && $pa_options['indexByRowID']) { $vs_index = $pn_row_id; } else { $vs_index = $o_attribute->getElementID(); } $va_attributes[$vs_index][(int) $o_attribute->getLocaleID()][$o_attribute->getAttributeID()] = $va_display_values; } if (!isset($pa_options['returnAllLocales']) || !$pa_options['returnAllLocales']) { // if desired try to return values in a preferred language/locale $va_preferred_locales = null; if (isset($pa_options['locale']) && $pa_options['locale']) { $va_preferred_locales = array($pa_options['locale']); } return caExtractValuesByUserLocale($va_attributes, null, $va_preferred_locales, array()); } return $va_attributes; }
/** * */ private static function _processChildren(SearchResult $pr_res, $po_nodes, array $pa_vals, array $pa_options = null) { if (!is_array($pa_options)) { $pa_options = []; } if (!$po_nodes) { return ''; } $vs_acc = ''; $ps_tablename = $pr_res->tableName(); $o_dm = Datamodel::load(); $t_instance = $o_dm->getInstanceByTableName($ps_tablename, true); $ps_delimiter = caGetOption('delimiter', $pa_options, '; '); $pb_is_case = caGetOption('isCase', $pa_options, false, ['castTo' => 'boolean']); $pb_quote = caGetOption('quote', $pa_options, false, ['castTo' => 'boolean']); $pa_primary_ids = caGetOption('primaryIDs', $pa_options, null); $pb_include_blanks = caGetOption('includeBlankValuesInArray', $pa_options, false); unset($pa_options['quote']); $vn_last_unit_omit_count = null; foreach ($po_nodes as $vn_index => $o_node) { switch ($vs_tag = strtolower($o_node->tag)) { case 'case': if (!$pb_is_case) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, array_merge($pa_options, ['isCase' => true])); } break; case 'if': if (strlen($vs_rule = $o_node->rule) && ExpressionParser::evaluate($vs_rule, $pa_vals)) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, DisplayTemplateParser::_getValues($pr_res, DisplayTemplateParser::_getTags($o_node->children, $pa_options), $pa_options), $pa_options); if ($pb_is_case) { break 2; } } break; case 'ifdef': case 'ifnotdef': $vb_defined = DisplayTemplateParser::_evaluateCodeAttribute($pr_res, $o_node, ['index' => caGetOption('index', $pa_options, null), 'mode' => $vs_tag == 'ifdef' ? 'present' : 'not_present']); if ($vs_tag == 'ifdef' && $vb_defined || $vs_tag == 'ifnotdef' && $vb_defined) { // Make sure returned values are not empty $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, DisplayTemplateParser::_getValues($pr_res, DisplayTemplateParser::_getTags($o_node->children, $pa_options), $pa_options), $pa_options); if ($pb_is_case) { break 2; } } break; case 'ifcount': $vn_min = (int) $o_node->min; $vn_max = (int) $o_node->max; if (!is_array($va_codes = DisplayTemplateParser::_getCodesFromAttribute($o_node)) || !sizeof($va_codes)) { break; } $pa_check_access = $t_instance->hasField('access') ? caGetOption('checkAccess', $pa_options, null) : null; if (!is_array($pa_check_access) || !sizeof($pa_check_access)) { $pa_check_access = null; } $vb_bool = DisplayTemplateParser::_getCodesBooleanModeAttribute($o_node); $va_restrict_to_types = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'restrictToTypes']); $va_exclude_types = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'excludeTypes']); $va_restrict_to_relationship_types = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'restrictToRelationshipTypes']); $va_exclude_to_relationship_types = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'excludeRelationshipTypes']); $vm_count = $vb_bool == 'AND' ? 0 : []; foreach ($va_codes as $vs_code) { $va_vals = $pr_res->get($vs_code, ['checkAccess' => $pa_check_access, 'returnAsArray' => true, 'restrictToTypes' => $va_restrict_to_types, 'excludeTypes' => $va_exclude_types, 'restrictToRelationshipTypes' => $va_restrict_to_relationship_types, 'excludeRelationshipTypes' => $va_exclude_to_relationship_types]); if (is_array($va_vals)) { if ($vb_bool == 'AND') { $vm_count += sizeof($va_vals); } else { $vm_count[$vs_code] = sizeof($va_vals); } } } if ($vb_bool == 'AND') { if ($vn_min <= $vm_count && ($vn_max >= $vm_count || !$vn_max)) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, DisplayTemplateParser::_getValues($pr_res, DisplayTemplateParser::_getTags($o_node->children, $pa_options), $pa_options), $pa_options); if ($pb_is_case) { break 2; } } } else { $vb_all_have_count = true; foreach ($vm_count as $vs_code => $vn_count) { if (!($vn_min <= $vn_count && ($vn_max >= $vn_count || !$vn_max))) { $vb_all_have_count = false; break 2; } } if ($vb_all_have_count) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, $pa_options); if ($pb_is_case) { break 2; } } } break; case 'more': // Does a placeholder with value follow this tag? // NOTE: We don't take into account <ifdef> and friends when finding a set placeholder; it may be set but not visible due to a conditional // This case is not covered at the moment on the assumption that if you're using <more> you're not using conditionals. This may or may not be a good assumption. for ($vn_i = $vn_index + 1; $vn_i < sizeof($po_nodes); $vn_i++) { if ($po_nodes[$vn_i] && $po_nodes[$vn_i]->tag == '~text~' && is_array($va_following_tags = caGetTemplateTags($po_nodes[$vn_i]->text))) { foreach ($va_following_tags as $vs_following_tag) { if (isset($pa_vals[$vs_following_tag]) && strlen($pa_vals[$vs_following_tag])) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, $pa_options); if ($pb_is_case) { break 2; } } } } } break; case 'between': // Does a placeholder with value precede this tag? // NOTE: We don't take into account <ifdef> and friends when finding a set placeholder; it may be set but not visible due to a conditional // This case is not covered at the moment on the assumption that if you're using <between> you're not using conditionals. This may or may not be a good assumption. $vb_has_preceding_value = false; for ($vn_i = 0; $vn_i < $vn_index; $vn_i++) { if ($po_nodes[$vn_i] && $po_nodes[$vn_i]->tag == '~text~' && is_array($va_preceding_tags = caGetTemplateTags($po_nodes[$vn_i]->text))) { foreach ($va_preceding_tags as $vs_preceding_tag) { if (isset($pa_vals[$vs_preceding_tag]) && strlen($pa_vals[$vs_preceding_tag])) { $vb_has_preceding_value = true; } } } } if ($vb_has_preceding_value) { // Does it have a value immediately following it? for ($vn_i = $vn_index + 1; $vn_i < sizeof($po_nodes); $vn_i++) { if ($po_nodes[$vn_i] && $po_nodes[$vn_i]->tag == '~text~' && is_array($va_following_tags = caGetTemplateTags($po_nodes[$vn_i]->text))) { foreach ($va_following_tags as $vs_following_tag) { if (isset($pa_vals[$vs_following_tag]) && strlen($pa_vals[$vs_following_tag])) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, $pa_options); if ($pb_is_case) { break 2; } } break; } } } } break; case 'expression': if ($vs_exp = trim($o_node->getInnerText())) { $vs_acc .= ExpressionParser::evaluate(DisplayTemplateParser::_processChildren($pr_res, $o_node->children, DisplayTemplateParser::_getValues($pr_res, DisplayTemplateParser::_getTags($o_node->children, $pa_options), $pa_options), array_merge($pa_options, ['quote' => true])), $pa_vals); if ($pb_is_case) { break 2; } } break; case 'unit': $va_relative_to_tmp = $o_node->relativeTo ? explode(".", $o_node->relativeTo) : [$ps_tablename]; if ($va_relative_to_tmp[0] && !($t_rel_instance = $o_dm->getInstanceByTableName($va_relative_to_tmp[0], true))) { continue; } $vn_last_unit_omit_count = 0; // <unit> attributes $vs_unit_delimiter = $o_node->delimiter ? (string) $o_node->delimiter : $ps_delimiter; $vb_unique = $o_node->unique ? (bool) $o_node->unique : false; $vb_aggregate_unique = $o_node->aggregateUnique ? (bool) $o_node->aggregateUnique : false; $vs_unit_skip_if_expression = (string) $o_node->skipIfExpression; $vn_start = (int) $o_node->start; $vn_length = (int) $o_node->length; $pa_check_access = $t_instance->hasField('access') ? caGetOption('checkAccess', $pa_options, null) : null; if (!is_array($pa_check_access) || !sizeof($pa_check_access)) { $pa_check_access = null; } // additional get options for pulling related records $va_get_options = ['returnAsArray' => true, 'checkAccess' => $pa_check_access]; $va_get_options['restrictToTypes'] = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'restrictToTypes']); $va_get_options['excludeTypes'] = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'excludeTypes']); $va_get_options['restrictToRelationshipTypes'] = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'restrictToRelationshipTypes']); $va_get_options['excludeRelationshipTypes'] = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'excludeRelationshipTypes']); if ($o_node->sort) { $va_get_options['sort'] = preg_split('![ ,;]+!', $o_node->sort); $va_get_options['sortDirection'] = $o_node->sortDirection; } if (sizeof($va_relative_to_tmp) == 1 && $va_relative_to_tmp[0] == $ps_tablename || sizeof($va_relative_to_tmp) >= 1 && $va_relative_to_tmp[0] == $ps_tablename && $va_relative_to_tmp[1] != 'related') { $vs_relative_to_container = null; switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".hierarchy." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".parent." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".children." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'siblings': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".siblings." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: // If relativeTo is not set to a valid attribute try to guess from template if ($t_rel_instance->isValidMetadataElement(join(".", array_slice($va_relative_to_tmp, 1, 1)), true)) { $vs_relative_to_container = join(".", array_slice($va_relative_to_tmp, 0, 2)); } else { $va_tags = caGetTemplateTags($o_node->getInnerText()); foreach ($va_tags as $vs_tag) { $va_tag = explode('.', $vs_tag); while (sizeof($va_tag) > 1) { $vs_end = array_pop($va_tag); if ($t_rel_instance->isValidMetadataElement($vs_end, true)) { $va_tag[] = $vs_end; $vs_relative_to_container = join(".", $va_tag); break 2; } } } } $va_relative_ids = array($pr_res->getPrimaryKey()); break; } // process template for all records selected by unit tag $va_tmpl_val = DisplayTemplateParser::evaluate($o_node->getInnerText(), $ps_tablename, $va_relative_ids, array_merge($pa_options, ['sort' => $va_get_options['sort'], 'sortDirection' => $va_get_options['sortDirection'], 'returnAsArray' => true, 'delimiter' => $vs_unit_delimiter, 'skipIfExpression' => $vs_unit_skip_if_expression, 'placeholderPrefix' => (string) $o_node->relativeTo, 'restrictToTypes' => $va_get_options['restrictToTypes'], 'excludeTypes' => $va_get_options['excludeTypes'], 'isUnit' => true, 'unitStart' => $vn_start, 'unitLength' => $vn_length, 'relativeToContainer' => $vs_relative_to_container, 'includeBlankValuesInTopLevelForPrefetch' => false, 'unique' => $vb_unique, 'aggregateUnique' => $vb_aggregate_unique])); if ($vb_unique) { $va_tmpl_val = array_unique($va_tmpl_val); } if ($vn_start > 0 || !is_null($vn_length)) { $vn_last_unit_omit_count = sizeof($va_tmpl_val) - ($vn_length - $vn_start); } if (caGetOption('returnAsArray', $pa_options, false)) { return $va_tmpl_val; } $vs_acc .= join($vs_unit_delimiter, $va_tmpl_val); if ($pb_is_case) { break 2; } } else { switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".hierarchy." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".parent." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".children." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'siblings': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".siblings." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'related': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".related." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: if (method_exists($t_instance, 'isSelfRelationship') && $t_instance->isSelfRelationship() && is_array($pa_primary_ids) && isset($pa_primary_ids[$t_rel_instance->tableName()])) { $va_relative_ids = array_values($t_instance->getRelatedIDsForSelfRelationship($pa_primary_ids[$t_rel_instance->tableName()], array($pr_res->getPrimaryKey()))); } else { $va_relative_ids = $pr_res->get($t_rel_instance->primaryKey(true), $va_get_options); $va_relative_ids = is_array($va_relative_ids) ? array_values($va_relative_ids) : array(); } break; } $va_tmpl_val = DisplayTemplateParser::evaluate($o_node->getInnerText(), $va_relative_to_tmp[0], $va_relative_ids, array_merge($pa_options, ['sort' => $va_unit['sort'], 'sortDirection' => $va_unit['sortDirection'], 'delimiter' => $vs_unit_delimiter, 'returnAsArray' => true, 'skipIfExpression' => $vs_unit_skip_if_expression, 'placeholderPrefix' => (string) $o_node->relativeTo, 'restrictToTypes' => $va_get_options['restrictToTypes'], 'excludeTypes' => $va_get_options['excludeTypes'], 'isUnit' => true, 'unitStart' => $vn_start, 'unitLength' => $vn_length, 'includeBlankValuesInTopLevelForPrefetch' => false, 'unique' => $vb_unique, 'aggregateUnique' => $vb_aggregate_unique])); if ($vb_unique) { $va_tmpl_val = array_unique($va_tmpl_val); } if ($vn_start > 0 || !is_null($vn_length)) { $vn_num_vals = sizeof($va_tmpl_val); $va_tmpl_val = array_slice($va_tmpl_val, $vn_start, $vn_length > 0 ? $vn_length : null); $vn_last_unit_omit_count = $vn_num_vals - ($vn_length - $vn_start); } if (caGetOption('returnAsArray', $pa_options, false)) { return $va_tmpl_val; } $vs_acc .= join($vs_unit_delimiter, $va_tmpl_val); if ($pb_is_case) { break 2; } } break; case 'whenunitomits': if ($vn_last_unit_omit_count > 0) { $vs_proc_template = caProcessTemplate($o_node->getInnerText(), array_merge($pa_vals, ['omitcount' => (int) $vn_last_unit_omit_count]), ['quote' => $pb_quote]); $vs_acc .= $vs_proc_template; } break; default: if ($o_node->children && sizeof($o_node->children) > 0) { $vs_proc_template = DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, $pa_options); } else { $vs_proc_template = caProcessTemplate($o_node->html(), $pa_vals, ['quote' => $pb_quote]); } if ($vs_tag === 'l') { $va_proc_templates = caCreateLinksFromText(["{$vs_proc_template}"], $ps_tablename, [$pr_res->getPrimaryKey()], null, caGetOption('linkTarget', $pa_options, null), array_merge(['addRelParameter' => true, 'requireLinkTags' => false], $pa_options)); $vs_proc_template = array_shift($va_proc_templates); } elseif (strlen($vs_tag) && $vs_tag[0] !== '~') { if ($o_node->children && sizeof($o_node->children) > 0) { $vs_attr = ''; if ($o_node->attributes) { foreach ($o_node->attributes as $attribute => $value) { $vs_attr .= " {$attribute}=\"" . htmlspecialchars(caProcessTemplate($value, $pa_vals, ['quote' => $pb_quote])) . "\""; } } $vs_proc_template = "<{$vs_tag}{$vs_attr}>{$vs_proc_template}</{$vs_tag}>"; } elseif ($o_node->attributes && sizeof($o_node->attributes) > 0) { $vs_attr = ''; foreach ($o_node->attributes as $attribute => $value) { $vs_attr .= " {$attribute}=\"" . htmlspecialchars(caProcessTemplate($value, $pa_vals, ['quote' => $pb_quote])) . "\""; } switch (strtolower($vs_tag)) { case 'br': case 'hr': case 'meta': case 'link': case 'base': case 'img': case 'embed': case 'param': case 'area': case 'col': case 'input': $vs_proc_template = "<{$vs_tag}{$vs_attr} />"; break; default: $vs_proc_template = "<{$vs_tag}{$vs_attr}></{$vs_tag}>"; break; } } else { $vs_proc_template = $o_node->html(); } } $vs_acc .= $vs_proc_template; break; } } return $vs_acc; }
/** * Misc function that checks if the OSML tag $node has an if attribute, returns * true if the expression is true or no if attribute is set * * @param DOMElement $node */ private function checkIf(DOMElement &$node) { if ($if = $node->getAttribute('if')) { $expressions = array(); preg_match_all('/(\\$\\{)(.*)(\\})/imsxU', $if, $expressions); if (!count($expressions[2])) { throw new ExpressionException("Invalid os:If tag, missing condition expression"); } $expression = $expressions[2][0]; $expressionResult = ExpressionParser::evaluate($expression, $this->dataContext); return $expressionResult ? true : false; } return true; }
/** * Returns array of attributes, each of which is an array of values ready for display. * The returned array is indexed by attribute element ID. Each array value is an array * indexed by attribute_id. The corresponding values are arrays of attribute values indexed by element_code * * @param $pm_element_code_or_id string|integer - * @param $pn_row_id integer - * @param $pa_options array - * convertLineBreaks = if set to true, will attempt to convert line break characters to HTML <p> and <br> tags; default is false. * locale = if set to a valid locale_id or locale code, values will be returned in locale *if available*, otherwise will fallback to values in languages that are available using the standard fallback mechanism. Default is to use user's current locale. * returnAllLocales = if set to true, values for all locales are returned, locale option is ignored and the returned array is indexed first by attribute_id and then by locale_id. Default is false. * indexByRowID = if true first index of returned array is $pn_row_id, otherwise it is the element_id of the retrieved metadata element * indexValuesByValueID = index value array by value_id [default=false] * indexValuesByElementCode = index value array by element code [default=true] * indexValuesByElementCodeAndValueID = index value array by element codes, each of which has a sub-array indexed by value_id. Implies indexValuesByElementCode. [default=false] * convertCodesToDisplayText = * filter = * ignoreLocale = if set all values are returned regardless of locale, but in the flattened structure returned when returnAllLocales is false * sort = the full bundle specification for the element value or subvalue (if the element is a container) to sort returned values on. * sortDirection = determines the direction of the sort. Valid values are ASC (ascending) and DESC (descending). [Default=ASC] * @return array */ public function getAttributeDisplayValues($pm_element_code_or_id, $pn_row_id, $pa_options = null) { if (!is_array($pa_options)) { $pa_options = array(); } $ps_filter_expression = caGetOption('filter', $pa_options, null); $pb_ignore_locale = caGetOption('ignoreLocale', $pa_options, null); $ps_sort = caGetOption('sort', $pa_options, null); $ps_sort_direction = caGetOption('sortDirection', $pa_options, 'asc', array('forceLowercase' => true, 'validValues' => array('asc', 'desc'))); $pb_index_by_element_code = caGetOption('indexValuesByElementCode', $pa_options, true); $pb_index_by_value_id = caGetOption('indexValuesByValueID', $pa_options, false); $pb_index_by_element_code_and_value_id = caGetOption('indexValuesByElementCodeAndValueID', $pa_options, false); if ($pb_index_by_element_code_and_value_id) { $pb_index_by_element_code = true; } $va_attribute_list = $this->getAttributesByElement($pm_element_code_or_id, array('row_id' => $pn_row_id)); if (!is_array($va_attribute_list)) { return array(); } $va_attributes = array(); $vs_table_name = $this->tableName(); $vs_container_element_code = $this->_getElementCode($pm_element_code_or_id); $vs_sort_fld = null; if ($ps_sort) { if (is_array($ps_sort)) { $ps_sort = array_shift($ps_sort); } $va_sort_tmp = explode(".", $ps_sort); if ($va_sort_tmp[0] == $vs_table_name && $va_sort_tmp[1] == $vs_container_element_code) { $vs_sort_fld = array_pop($va_sort_tmp); } } foreach ($va_attribute_list as $o_attribute) { $va_values = $o_attribute->getValues(); $va_raw_values = array(); $va_display_values = array(); $vs_sort_key = null; foreach ($va_values as $o_value) { $vs_element_code = $this->_getElementCode($o_value->getElementID()); if (get_class($o_value) == 'ListAttributeValue') { $t_element = $this->_getElementInstance($o_value->getElementID()); $vn_list_id = !isset($pa_options['convertCodesToDisplayText']) || !(bool) $pa_options['convertCodesToDisplayText'] ? null : $t_element->get('list_id'); } else { $vn_list_id = null; } if ($ps_filter_expression) { $va_raw_values[$vs_container_element_code == $vs_element_code ? "{$vs_table_name}.{$vs_element_code}" : "{$vs_table_name}.{$vs_container_element_code}.{$vs_element_code}"] = $va_raw_values[$vs_element_code] = $o_value->getDisplayValue(array('list_id' => $vn_list_id, 'returnIdno' => true)); } if (isset($pa_options['convertLineBreaks']) && $pa_options['convertLineBreaks']) { $vs_converted_value = preg_replace("!(\n|\r\n){2}!", "<p/>", $o_value->getDisplayValue(array_merge($pa_options, array('list_id' => $vn_list_id)))); $vs_display_value = preg_replace("![\n]{1}!", "<br/>", $vs_converted_value); } else { $vs_display_value = $o_value->getDisplayValue(array_merge($pa_options, array('list_id' => $vn_list_id))); } if ($pb_index_by_element_code) { if ($pb_index_by_element_code_and_value_id) { $va_display_values[$vs_element_code][$o_value->getValueID()] = $vs_display_value; } else { $va_display_values[$vs_element_code] = $vs_display_value; } } if ($pb_index_by_value_id) { $va_display_values[$o_value->getValueID()] = $vs_display_value; } if ($vs_sort_fld && $vs_sort_fld == $vs_element_code) { $vs_sort_key = $o_value->getDisplayValue(array_merge($pa_options, array('getDirectDate' => true, 'list_id' => $vn_list_id))); } } if (!$vs_sort_key) { $vs_sort_key = '0'; } // Process filter if defined if ($ps_filter_expression && !ExpressionParser::evaluate($ps_filter_expression, $va_raw_values)) { continue; } if (isset($pa_options['indexByRowID']) && $pa_options['indexByRowID']) { $vs_index = $pn_row_id; } else { $vs_index = $o_attribute->getElementID(); } if ($pb_ignore_locale) { $va_attributes[$vs_sort_key][$vs_index][$o_attribute->getAttributeID()] = $va_display_values; } else { $va_attributes[$vs_sort_key][$vs_index][(int) $o_attribute->getLocaleID()][$o_attribute->getAttributeID()] = $va_display_values; } } ksort($va_attributes); if ($ps_sort_direction == 'desc') { $va_attributes = array_reverse($va_attributes); } $va_sorted_attr = array(); foreach ($va_attributes as $vs_sort_key => $va_attr_by_index) { foreach ($va_attr_by_index as $vs_index => $va_attr_by_id) { foreach ($va_attr_by_id as $vs_id => $va_attr) { if ($pb_ignore_locale) { $va_sorted_attr[$vs_index][$vs_id] = $va_attr; } else { foreach ($va_attr as $vn_attr_id => $va_val) { $va_sorted_attr[$vs_index][$vs_id][$vn_attr_id] = $va_val; } } } } } $va_attributes = $va_sorted_attr; if (!$pb_ignore_locale) { if (!isset($pa_options['returnAllLocales']) || !$pa_options['returnAllLocales']) { // if desired try to return values in a preferred language/locale $va_preferred_locales = null; if (isset($pa_options['locale']) && $pa_options['locale']) { $va_preferred_locales = array($pa_options['locale']); } return caExtractValuesByUserLocale($va_attributes, null, $va_preferred_locales, array()); } } return $va_attributes; }
/** * Statically evaluate an expression, returning the value */ public static function evaluate($ps_expression, $pa_variables = null) { $e = new ExpressionParser(); return $e->evaluateExpression($ps_expression, $pa_variables); }
/** * * * @param string $ps_source * @param string $ps_mapping * @param array $pa_options * user_id = user to execute import for * description = Text describing purpose of import to be logged. * showCLIProgressBar = Show command-line progress bar. Default is false. * format = Format of data being imported. MANDATORY * useNcurses = Use ncurses library to format output * logDirectory = path to directory where logs should be written * logLevel = KLogger constant for minimum log level to record. Default is KLogger::INFO. Constants are, in descending order of shrillness: * KLogger::EMERG = Emergency messages (system is unusable) * KLogger::ALERT = Alert messages (action must be taken immediately) * KLogger::CRIT = Critical conditions * KLogger::ERR = Error conditions * KLogger::WARN = Warnings * KLogger::NOTICE = Notices (normal but significant conditions) * KLogger::INFO = Informational messages * KLogger::DEBUG = Debugging messages * dryRun = do import but don't actually save data * environment = an array of environment values to provide to the import process. The keys manifest themselves as mappable tags. * forceImportForPrimaryKeys = list of primary key ids to force mapped source data into. The number of keys passed should equal or exceed the number of rows in the source data. [Default is empty] * transaction = transaction to perform import within. Will not be used if noTransaction option is set. [Default is to create a new transaction] * noTransaction = don't wrap the import in a transaction. [Default is false] */ public static function importDataFromSource($ps_source, $ps_mapping, $pa_options = null) { ca_data_importers::$s_num_import_errors = 0; ca_data_importers::$s_num_records_processed = 0; ca_data_importers::$s_num_records_skipped = 0; ca_data_importers::$s_import_error_list = array(); $opa_app_plugin_manager = new ApplicationPluginManager(); $va_notices = $va_errors = array(); $pb_no_transaction = caGetOption('noTransaction', $pa_options, false, array('castTo' => 'bool')); $pa_force_import_for_primary_keys = caGetOption('forceImportForPrimaryKeys', $pa_options, null); if (!($t_mapping = ca_data_importers::mappingExists($ps_mapping))) { return null; } $o_event = ca_data_import_events::newEvent(isset($pa_options['user_id']) ? $pa_options['user_id'] : null, $pa_options['format'], $ps_source, isset($pa_options['description']) ? $pa_options['description'] : ''); $o_trans = null; if (!$pb_no_transaction) { if (!($o_trans = caGetOption('transaction', $pa_options, null))) { $o_trans = new Transaction(); } $t_mapping->setTransaction($o_trans); } $po_request = caGetOption('request', $pa_options, null); $pb_dry_run = caGetOption('dryRun', $pa_options, false); $pn_file_number = caGetOption('fileNumber', $pa_options, 0); $pn_number_of_files = caGetOption('numberOfFiles', $pa_options, 1); $o_config = Configuration::load(); if (!is_array($pa_options) || !isset($pa_options['logLevel']) || !$pa_options['logLevel']) { $pa_options['logLevel'] = KLogger::INFO; } if (!is_array($pa_options) || !isset($pa_options['logDirectory']) || !$pa_options['logDirectory'] || !file_exists($pa_options['logDirectory'])) { if (!($pa_options['logDirectory'] = $o_config->get('batch_metadata_import_log_directory'))) { $pa_options['logDirectory'] = "."; } } if (!is_writeable($pa_options['logDirectory'])) { $pa_options['logDirectory'] = caGetTempDirPath(); } $o_log = new KLogger($pa_options['logDirectory'], $pa_options['logLevel']); $vb_show_cli_progress_bar = isset($pa_options['showCLIProgressBar']) && $pa_options['showCLIProgressBar'] ? true : false; $o_progress = caGetOption('progressBar', $pa_options, new ProgressBar('WebUI')); if ($vb_show_cli_progress_bar) { $o_progress->setMode('CLI'); $o_progress->set('outputToTerminal', true); } if ($vb_use_ncurses = isset($pa_options['useNcurses']) && $pa_options['useNcurses'] ? true : false) { $vb_use_ncurses = caCLIUseNcurses(); } $vn_error_window_height = null; $vn_max_x = $vn_max_y = null; if ($vb_use_ncurses) { ncurses_init(); $r_screen = ncurses_newwin(0, 0, 0, 0); ncurses_border(0, 0, 0, 0, 0, 0, 0, 0); ncurses_getmaxyx($r_screen, $vn_max_y, $vn_max_x); $vn_error_window_height = $vn_max_y - 8; $r_errors = ncurses_newwin($vn_error_window_height, $vn_max_x - 4, 4, 2); ncurses_wborder($r_errors, 0, 0, 0, 0, 0, 0, 0, 0); ncurses_wattron($r_errors, NCURSES_A_REVERSE); ncurses_mvwaddstr($r_errors, 0, 1, _t(" Recent errors ")); ncurses_wattroff($r_errors, NCURSES_A_REVERSE); $r_progress = ncurses_newwin(3, $vn_max_x - 4, $vn_max_y - 4, 2); ncurses_wborder($r_progress, 0, 0, 0, 0, 0, 0, 0, 0); ncurses_wattron($r_progress, NCURSES_A_REVERSE); ncurses_mvwaddstr($r_progress, 0, 1, _t(" Progress ")); ncurses_wattroff($r_progress, NCURSES_A_REVERSE); $r_status = ncurses_newwin(3, $vn_max_x - 4, 1, 2); ncurses_wborder($r_status, 0, 0, 0, 0, 0, 0, 0, 0); ncurses_wattron($r_status, NCURSES_A_REVERSE); ncurses_mvwaddstr($r_status, 0, 1, _t(" Import status ")); ncurses_wattroff($r_status, NCURSES_A_REVERSE); ncurses_refresh(0); ncurses_wrefresh($r_progress); ncurses_wrefresh($r_errors); ncurses_wrefresh($r_status); } $o_log->logInfo(_t('Started import of %1 using mapping %2', $ps_source, $t_mapping->get("importer_code"))); $t = new Timer(); $vn_start_time = time(); $va_log_import_error_opts = array('startTime' => $vn_start_time, 'window' => $r_errors, 'log' => $o_log, 'request' => $po_request, 'progressCallback' => isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback']) ? $ps_callback : null, 'reportCallback' => isset($pa_options['reportCallback']) && ($ps_callback = $pa_options['reportCallback']) ? $ps_callback : null); global $g_ui_locale_id; // constant locale set by index.php for web requests $vn_locale_id = isset($pa_options['locale_id']) && (int) $pa_options['locale_id'] ? (int) $pa_options['locale_id'] : $g_ui_locale_id; $o_dm = $t_mapping->getAppDatamodel(); $o_progress->start(_t('Reading %1', $ps_source), array('window' => $r_progress)); if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) { $ps_callback($po_request, $pn_file_number, $pn_number_of_files, $ps_source, 0, 100, _t('Reading %1', $ps_source), time() - $vn_start_time, memory_get_usage(true), 0, ca_data_importers::$s_num_import_errors); } // Open file $ps_format = isset($pa_options['format']) && $pa_options['format'] ? $pa_options['format'] : null; if (!($o_reader = $t_mapping->getDataReader($ps_source, $ps_format))) { ca_data_importers::logImportError(_t("Could not open source %1 (format=%2)", $ps_source, $ps_format), $va_log_import_error_opts); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } if (!$o_reader->read($ps_source, array('basePath' => $t_mapping->getSetting('basePath')))) { ca_data_importers::logImportError(_t("Could not read source %1 (format=%2)", $ps_source, $ps_format), $va_log_import_error_opts); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } $o_log->logDebug(_t('Finished reading input source at %1 seconds', $t->getTime(4))); $vn_num_items = $o_reader->numRows(); $o_progress->setTotal($vn_num_items); $o_progress->start(_t('Importing from %1', $ps_source), array('window' => $r_progress)); if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) { $ps_callback($po_request, $pn_file_number, $pn_number_of_files, $ps_source, 0, $vn_num_items, _t('Importing from %1', $ps_source), time() - $vn_start_time, memory_get_usage(true), 0, ca_data_importers::$s_num_import_errors); } // What are we importing? $vn_table_num = $t_mapping->get('table_num'); if (!($t_subject = $o_dm->getInstanceByTableNum($vn_table_num))) { // invalid table if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } $t_subject->setTransaction($o_trans); $vs_subject_table_name = $t_subject->tableName(); $t_label = $t_subject->getLabelTableInstance(); $t_label->setTransaction($o_trans); $vs_label_display_fld = $t_subject->getLabelDisplayField(); $vs_subject_table = $t_subject->tableName(); $vs_type_id_fld = $t_subject->getTypeFieldName(); $vs_idno_fld = $t_subject->getProperty('ID_NUMBERING_ID_FIELD'); // get mapping rules $va_mapping_rules = $t_mapping->getRules(); // get mapping groups $va_mapping_groups = $t_mapping->getGroups(); $va_mapping_items = $t_mapping->getItems(); // // Mapping-level settings // $vs_type_mapping_setting = $t_mapping->getSetting('type'); $vn_num_initial_rows_to_skip = $t_mapping->getSetting('numInitialRowsToSkip'); if (!in_array($vs_import_error_policy = $t_mapping->getSetting('errorPolicy'), array('ignore', 'stop'))) { $vs_import_error_policy = 'ignore'; } if (!in_array($vs_existing_record_policy = $t_mapping->getSetting('existingRecordPolicy'), array('none', 'skip_on_idno', 'skip_on_preferred_labels', 'merge_on_idno', 'merge_on_preferred_labels', 'merge_on_idno_and_preferred_labels', 'merge_on_idno_with_replace', 'merge_on_preferred_labels_with_replace', 'merge_on_idno_and_preferred_labels_with_replace', 'overwrite_on_idno', 'overwrite_on_preferred_labels', 'overwrite_on_idno_and_preferred_labels'))) { $vs_existing_record_policy = 'none'; } // Analyze mapping for figure out where type, idno, preferred label and other mandatory fields are coming from $vn_type_id_mapping_item_id = $vn_idno_mapping_item_id = null; $va_preferred_label_mapping_ids = array(); $va_mandatory_field_mapping_ids = array(); $va_mandatory_fields = $t_subject->getMandatoryFields(); foreach ($va_mapping_items as $vn_item_id => $va_item) { $vs_destination = $va_item['destination']; if (sizeof($va_dest_tmp = explode(".", $vs_destination)) >= 2) { if ($va_dest_tmp[0] == $vs_subject_table && $va_dest_tmp[1] == 'preferred_labels') { if (isset($va_dest_tmp[2])) { $va_preferred_label_mapping_ids[$vn_item_id] = $va_dest_tmp[2]; } else { $va_preferred_label_mapping_ids[$vn_item_id] = $vs_label_display_fld; } continue; } } switch ($vs_destination) { case 'representation_id': if ($vs_subject_table == 'ca_representation_annotations') { $vn_type_id_mapping_item_id = $vn_item_id; } break; case "{$vs_subject_table}.{$vs_type_id_fld}": $vn_type_id_mapping_item_id = $vn_item_id; break; case "{$vs_subject_table}.{$vs_idno_fld}": $vn_idno_mapping_item_id = $vn_item_id; break; } foreach ($va_mandatory_fields as $vs_mandatory_field) { if ($vs_mandatory_field == $vs_type_id_fld) { continue; } // type is handled separately if ($vs_destination == "{$vs_subject_table}.{$vs_mandatory_field}") { $va_mandatory_field_mapping_ids[$vs_mandatory_field] = $vn_item_id; } } } $va_items_by_group = array(); foreach ($va_mapping_items as $vn_item_id => $va_item) { $va_items_by_group[$va_item['group_id']][$va_item['item_id']] = $va_item; } $o_log->logDebug(_t('Finished analyzing mapping at %1 seconds', $t->getTime(4))); // // Set up environment // $va_environment = caGetOption('environment', $pa_options, array(), array('castTo' => 'array')); if (is_array($va_environment_config = $t_mapping->getEnvironment())) { foreach ($va_environment_config as $vn_i => $va_environment_item) { $va_env_tmp = explode("|", $va_environment_item['value']); if (!($o_env_reader = $t_mapping->getDataReader($ps_source, $ps_format))) { break; } if (!$o_env_reader->read($ps_source, array('basePath' => ''))) { break; } $o_env_reader->nextRow(); switch (sizeof($va_env_tmp)) { case 1: $vs_env_value = $o_env_reader->get($va_environment_item['value'], array('returnAsArray' => false)); break; case 2: $vn_seek = (int) $va_env_tmp[0]; $o_reader->seek($vn_seek > 0 ? $vn_seek - 1 : $vn_seek); $o_env_reader->nextRow(); $vs_env_value = $o_env_reader->get($va_env_tmp[1], array('returnAsArray' => false)); $o_reader->seek(0); break; default: $vs_env_value = $va_environment_item['value']; break; } $va_environment[$va_environment_item['name']] = $vs_env_value; } } // // Run through rows // $vn_row = 0; ca_data_importers::$s_num_records_processed = 0; while ($o_reader->nextRow()) { $va_mandatory_field_values = array(); $vs_preferred_label_for_log = null; if ($vn_row < $vn_num_initial_rows_to_skip) { // skip over initial header rows $vn_row++; continue; } $vn_row++; $t->startTimer(); $o_log->logDebug(_t('Started reading row %1 at %2 seconds', $vn_row, $t->getTime(4))); $t_subject = $o_dm->getInstanceByTableNum($vn_table_num); if ($o_trans) { $t_subject->setTransaction($o_trans); } $t_subject->setMode(ACCESS_WRITE); // Update status display if ($vb_use_ncurses && ca_data_importers::$s_num_records_processed) { ncurses_mvwaddstr($r_status, 1, 2, _t("Items processed/skipped: %1/%2", ca_data_importers::$s_num_records_processed, ca_data_importers::$s_num_records_skipped) . str_repeat(" ", 5) . _t("Errors: %1 (%2)", ca_data_importers::$s_num_import_errors, sprintf("%3.1f", ca_data_importers::$s_num_import_errors / ca_data_importers::$s_num_records_processed * 100) . "%") . str_repeat(" ", 6) . _t("Mapping: %1", $ps_mapping) . str_repeat(" ", 5) . _t("Source: %1", $ps_source) . str_repeat(" ", 5) . date("Y-m-d H:i:s") . str_repeat(" ", 5)); ncurses_refresh(0); ncurses_wrefresh($r_status); } // // Get data for current row // $va_row = array_merge($o_reader->getRow(), $va_environment); // // Apply rules // foreach ($va_mapping_rules as $va_rule) { if (!isset($va_rule['trigger']) || !$va_rule['trigger']) { continue; } if (!isset($va_rule['actions']) || !is_array($va_rule['actions']) || !sizeof($va_rule['actions'])) { continue; } $vm_ret = ExpressionParser::evaluate($va_rule['trigger'], $va_row); if (!ExpressionParser::hadError() && (bool) $vm_ret) { foreach ($va_rule['actions'] as $va_action) { if (!is_array($va_action) && strtolower($va_action) == 'skip') { $va_action = array('action' => 'skip'); } switch ($vs_action_code = strtolower($va_action['action'])) { case 'set': $va_row[$va_action['target']] = $va_action['value']; // TODO: transform value using mapping rules? break; case 'skip': default: if ($vs_action_code != 'skip') { $o_log->logInfo(_t('Row was skipped using rule "%1" with default action because an invalid action ("%2") was specified', $va_rule['trigger'], $vs_action_code)); } else { $o_log->logDebug(_t('Row was skipped using rule "%1" with action "%2"', $va_rule['trigger'], $vs_action_code)); } continue 4; break; } } } } // // Perform mapping and insert // // Get minimal info for imported row (type_id, idno, label) // Get type if ($vn_type_id_mapping_item_id) { // Type is specified in row $vs_type = ca_data_importers::getValueFromSource($va_mapping_items[$vn_type_id_mapping_item_id], $o_reader, array('environment' => $va_environment)); } else { // Type is constant for all rows $vs_type = $vs_type_mapping_setting; } // Get idno $vs_idno = null; if ($vn_idno_mapping_item_id) { // idno is specified in row $vs_idno = ca_data_importers::getValueFromSource($va_mapping_items[$vn_idno_mapping_item_id], $o_reader, array('environment' => $va_environment)); if (isset($va_mapping_items[$vn_idno_mapping_item_id]['settings']['default']) && strlen($va_mapping_items[$vn_idno_mapping_item_id]['settings']['default']) && !strlen($vs_idno)) { $vs_idno = $va_mapping_items[$vn_idno_mapping_item_id]['settings']['default']; } if (!is_array($vs_idno) && $vs_idno[0] == '^' && preg_match("!^\\^[^ ]+\$!", $vs_idno)) { // Parse placeholder when it's at the beginning of the value if (!is_null($vm_parsed_val = BaseRefinery::parsePlaceholder($vs_idno, $va_row, $va_item, null, array('reader' => $o_reader, 'returnAsString' => true)))) { $vs_idno = $vm_parsed_val; } } // Apply prefix/suffix *AFTER* setting default if ($vs_idno && isset($va_mapping_items[$vn_idno_mapping_item_id]['settings']['prefix']) && strlen($va_mapping_items[$vn_idno_mapping_item_id]['settings']['prefix'])) { $vs_idno = $va_mapping_items[$vn_idno_mapping_item_id]['settings']['prefix'] . $vs_idno; } if ($vs_idno && isset($va_mapping_items[$vn_idno_mapping_item_id]['settings']['suffix']) && strlen($va_mapping_items[$vn_idno_mapping_item_id]['settings']['suffix'])) { $vs_idno .= $va_mapping_items[$vn_idno_mapping_item_id]['settings']['suffix']; } if (isset($va_mapping_items[$vn_idno_mapping_item_id]['settings']['formatWithTemplate']) && strlen($va_mapping_items[$vn_idno_mapping_item_id]['settings']['formatWithTemplate'])) { $vs_idno = caProcessTemplate($va_mapping_items[$vn_idno_mapping_item_id]['settings']['formatWithTemplate'], $va_row); } } else { $vs_idno = "%"; } $vb_idno_is_template = (bool) preg_match('![%]+!', $vs_idno); // get preferred labels $va_pref_label_values = array(); foreach ($va_preferred_label_mapping_ids as $vn_preferred_label_mapping_id => $vs_preferred_label_mapping_fld) { $vs_label_val = ca_data_importers::getValueFromSource($va_mapping_items[$vn_preferred_label_mapping_id], $o_reader, array('environment' => $va_environment)); // If a template is specified format the label value with it so merge-on-preferred_label doesn't fail if (isset($va_mapping_items[$vn_preferred_label_mapping_id]['settings']['formatWithTemplate']) && strlen($va_mapping_items[$vn_preferred_label_mapping_id]['settings']['formatWithTemplate'])) { $vs_label_val = caProcessTemplate($va_mapping_items[$vn_preferred_label_mapping_id]['settings']['formatWithTemplate'], $va_row); } $va_pref_label_values[$vs_preferred_label_mapping_fld] = $vs_label_val; } $vs_display_label = isset($va_pref_label_values[$vs_label_display_fld]) ? $va_pref_label_values[$vs_label_display_fld] : $vs_idno; // // Look for existing record? // if (is_array($pa_force_import_for_primary_keys) && sizeof($pa_force_import_for_primary_keys) > 0) { $vn_id = array_shift($pa_force_import_for_primary_keys); if (!$t_subject->load($vn_id)) { $o_log->logInfo(_t('[%1] Skipped import because of forced primary key \'%1\' does not exist', $vn_id)); ca_data_importers::$s_num_records_skipped++; continue; // skip because primary key does not exist } } elseif ($vs_existing_record_policy != 'none') { switch ($vs_existing_record_policy) { case 'skip_on_idno': if (!$vb_idno_is_template) { $va_ids = call_user_func_array($t_subject->tableName() . "::find", array(array('type_id' => $vs_type, $t_subject->getProperty('ID_NUMBERING_ID_FIELD') => $vs_idno, 'deleted' => 0), array('returnAs' => 'ids'))); if (is_array($va_ids) && sizeof($va_ids) > 0) { $o_log->logInfo(_t('[%1] Skipped import because of existing record matched on identifier by policy %2', $vs_idno, $vs_existing_record_policy)); ca_data_importers::$s_num_records_skipped++; continue 2; // skip because idno matched } } break; case 'skip_on_preferred_labels': $va_ids = call_user_func_array($t_subject->tableName() . "::find", array(array('type_id' => $vs_type, 'preferred_labels' => $va_pref_label_values, 'deleted' => 0), array('returnAs' => 'ids'))); if (is_array($va_ids) && sizeof($va_ids) > 0) { $o_log->logInfo(_t('[%1] Skipped import because of existing record matched on label by policy %2', $vs_idno, $vs_existing_record_policy)); ca_data_importers::$s_num_records_skipped++; continue 2; // skip because label matched } break; case 'merge_on_idno_and_preferred_labels': case 'merge_on_idno': case 'merge_on_idno_and_preferred_labels_with_replace': case 'merge_on_idno_with_replace': if (!$vb_idno_is_template) { $va_ids = call_user_func_array($t_subject->tableName() . "::find", array(array('type_id' => $vs_type, $t_subject->getProperty('ID_NUMBERING_ID_FIELD') => $vs_idno, 'deleted' => 0), array('returnAs' => 'ids'))); if (is_array($va_ids) && sizeof($va_ids) > 0) { $t_subject->load($va_ids[0]); $o_log->logInfo(_t('[%1] Merged with existing record matched on identifer by policy %2', $vs_idno, $vs_existing_record_policy)); break; } } if (in_array($vs_existing_record_policy, array('merge_on_idno', 'merge_on_idno_with_replace'))) { break; } // fall through if merge_on_idno_and_preferred_labels // fall through if merge_on_idno_and_preferred_labels case 'merge_on_preferred_labels': case 'merge_on_preferred_labels_with_replace': $va_ids = call_user_func_array($t_subject->tableName() . "::find", array(array('type_id' => $vs_type, 'preferred_labels' => $va_pref_label_values, 'deleted' => 0), array('returnAs' => 'ids'))); if (is_array($va_ids) && sizeof($va_ids) > 0) { $t_subject->load($va_ids[0]); $o_log->logInfo(_t('[%1] Merged with existing record matched on label by policy %2', $vs_idno, $vs_existing_record_policy)); } break; case 'overwrite_on_idno_and_preferred_labels': case 'overwrite_on_idno': if (!$vb_idno_is_template && $vs_idno) { $va_ids = call_user_func_array($t_subject->tableName() . "::find", array(array('type_id' => $vs_type, $t_subject->getProperty('ID_NUMBERING_ID_FIELD') => $vs_idno, 'deleted' => 0), array('returnAs' => 'ids'))); if (is_array($va_ids) && sizeof($va_ids) > 0) { $t_subject->load($va_ids[0]); $t_subject->setMode(ACCESS_WRITE); $t_subject->delete(true, array('hard' => true)); if ($t_subject->numErrors()) { ca_data_importers::logImportError(_t('[%1] Could not delete existing record matched on identifier by policy %2', $vs_idno, $vs_existing_record_policy)); // Don't stop? } else { $o_log->logInfo(_t('[%1] Overwrote existing record matched on identifier by policy %2', $vs_idno, $vs_existing_record_policy)); $t_subject->clear(); break; } } } if ($vs_existing_record_policy == 'overwrite_on_idno') { break; } // fall through if overwrite_on_idno_and_preferred_labels // fall through if overwrite_on_idno_and_preferred_labels case 'overwrite_on_preferred_labels': $va_ids = call_user_func_array($t_subject->tableName() . "::find", array(array('type_id' => $vs_type, 'preferred_labels' => $va_pref_label_values, 'deleted' => 0), array('returnAs' => 'ids'))); if (is_array($va_ids) && sizeof($va_ids) > 0) { $t_subject->load($va_ids[0]); $t_subject->setMode(ACCESS_WRITE); $t_subject->delete(true, array('hard' => true)); if ($t_subject->numErrors()) { ca_data_importers::logImportError(_t('[%1] Could not delete existing record matched on label by policy %2', $vs_idno, $vs_existing_record_policy)); // Don't stop? } else { $o_log->logInfo(_t('[%1] Overwrote existing record matched on label by policy %2', $vs_idno, $vs_existing_record_policy)); break; } $t_subject->clear(); } break; } } $o_progress->next(_t("Importing %1", $vs_idno), array('window' => $r_progress)); if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) { $ps_callback($po_request, $pn_file_number, $pn_number_of_files, $ps_source, ca_data_importers::$s_num_records_processed, $vn_num_items, _t("[%3/%4] Processing %1 (%2)", caTruncateStringWithEllipsis($vs_display_label, 50), $vs_idno, ca_data_importers::$s_num_records_processed, $vn_num_items), time() - $vn_start_time, memory_get_usage(true), ca_data_importers::$s_num_records_processed, ca_data_importers::$s_num_import_errors); } $vb_output_subject_preferred_label = false; $va_content_tree = array(); foreach ($va_items_by_group as $vn_group_id => $va_items) { $va_group = $va_mapping_groups[$vn_group_id]; $vs_group_destination = $va_group['destination']; $va_group_tmp = explode(".", $vs_group_destination); if (sizeof($va_items) < 2 && sizeof($va_group_tmp) > 2) { array_pop($va_group_tmp); } $vs_target_table = $va_group_tmp[0]; if (!($t_target = $o_dm->getInstanceByTableName($vs_target_table, true))) { // Invalid target table $o_log->logWarn(_t('[%1] Skipped group %2 because target %3 is invalid', $vs_idno, $vn_group_id, $vs_target_table)); continue; } if ($o_trans) { $t_target->setTransaction($o_trans); } $va_group_buf = array(); foreach ($va_items as $vn_item_id => $va_item) { if ($vb_use_as_single_value = caGetOption('useAsSingleValue', $va_item['settings'], false)) { // Force repeating values to be imported as a single value $va_vals = array(ca_data_importers::getValueFromSource($va_item, $o_reader, array('delimiter' => caGetOption('delimiter', $va_item['settings'], ''), 'returnAsArray' => false))); } else { $va_vals = ca_data_importers::getValueFromSource($va_item, $o_reader, array('returnAsArray' => true, 'environment' => $va_environment)); } if (!sizeof($va_vals)) { $va_vals = array(0 => null); } // consider missing values equivalent to blanks // Do value conversions foreach ($va_vals as $vn_i => $vm_val) { if (isset($va_item['settings']['default']) && strlen($va_item['settings']['default']) && !strlen($vm_val)) { $vm_val = $va_item['settings']['default']; } // Apply prefix/suffix *AFTER* setting default if ($vm_val && isset($va_item['settings']['prefix']) && strlen($va_item['settings']['prefix'])) { $vm_val = $va_item['settings']['prefix'] . $vm_val; } if ($vm_val && isset($va_item['settings']['suffix']) && strlen($va_item['settings']['suffix'])) { $vm_val .= $va_item['settings']['suffix']; } if (!is_array($vm_val) && $vm_val[0] == '^' && preg_match("!^\\^[^ ]+\$!", $vm_val)) { // Parse placeholder if (!is_null($vm_parsed_val = BaseRefinery::parsePlaceholder($vm_val, $va_row, $va_item, $vn_i, array('reader' => $o_reader, 'returnAsString' => true)))) { $vm_val = $vm_parsed_val; } } if (isset($va_item['settings']['formatWithTemplate']) && strlen($va_item['settings']['formatWithTemplate'])) { $vm_val = caProcessTemplate($va_item['settings']['formatWithTemplate'], array_replace($va_row, array((string) $va_item['source'] => ca_data_importers::replaceValue($vm_val, $va_item))), array('getFrom' => $o_reader)); } if (isset($va_item['settings']['applyRegularExpressions']) && is_array($va_item['settings']['applyRegularExpressions'])) { if (is_array($va_item['settings']['applyRegularExpressions'])) { foreach ($va_item['settings']['applyRegularExpressions'] as $vn_regex_index => $va_regex) { if (!strlen($va_regex['match'])) { continue; } $vm_val = preg_replace("!" . str_replace("!", "\\!", $va_regex['match']) . "!" . (isset($va_regex['caseSensitive']) && (bool) $va_regex['caseSensitive'] ? '' : 'i'), $va_regex['replaceWith'], $vm_val); } } } $va_vals[$vn_i] = $vm_val; if ($o_reader->valuesCanRepeat()) { $va_row[$va_item['source']][$vn_i] = $va_row[mb_strtolower($va_item['source'])][$vn_i] = $vm_val; } else { $va_row[$va_item['source']] = $va_row[mb_strtolower($va_item['source'])] = $vm_val; } } // Process each value $vn_c = -1; foreach ($va_vals as $vn_i => $vm_val) { $vn_c++; if (isset($va_item['settings']['convertNewlinesToHTML']) && (bool) $va_item['settings']['convertNewlinesToHTML'] && is_string($vm_val)) { $vm_val = nl2br($vm_val); } // Get location in content tree for addition of new content $va_item_dest = explode(".", $va_item['destination']); $vs_item_terminal = $va_item_dest[sizeof($va_item_dest) - 1]; if (isset($va_item['settings']['restrictToTypes']) && is_array($va_item['settings']['restrictToTypes']) && !in_array($vs_type, $va_item['settings']['restrictToTypes'])) { $o_log->logInfo(_t('[%1] Skipped row %2 because of type restriction', $vs_idno, $vn_row)); continue 4; } if (isset($va_item['settings']['skipRowIfEmpty']) && (bool) $va_item['settings']['skipRowIfEmpty'] && !strlen($vm_val)) { $o_log->logInfo(_t('[%1] Skipped row %2 because value for %3 in group %4 is empty', $vs_idno, $vn_row, $vs_item_terminal, $vn_group_id)); continue 4; } if (isset($va_item['settings']['skipRowIfValue']) && is_array($va_item['settings']['skipRowIfValue']) && strlen($vm_val) && in_array($vm_val, $va_item['settings']['skipRowIfValue'])) { $o_log->logInfo(_t('[%1] Skipped row %2 because value for %3 in group %4 matches value %5', $vs_idno, $vn_row, $vs_item_terminal, $vn_group_id)); continue 4; } if (isset($va_item['settings']['skipRowIfNotValue']) && is_array($va_item['settings']['skipRowIfNotValue']) && strlen($vm_val) && !in_array($vm_val, $va_item['settings']['skipRowIfNotValue'])) { $o_log->logInfo(_t('[%1] Skipped row %2 because value for %3 in group %4 is not in list of values', $vs_idno, $vn_row, $vs_item_terminal, $vn_group_id, $vm_val)); continue 4; } if (isset($va_item['settings']['skipGroupIfEmpty']) && (bool) $va_item['settings']['skipGroupIfEmpty'] && !strlen($vm_val)) { $o_log->logInfo(_t('[%1] Skipped group %2 because value for %3 is empty', $vs_idno, $vn_group_id, $vs_item_terminal)); continue 3; } if (isset($va_item['settings']['skipGroupIfExpression']) && strlen(trim($va_item['settings']['skipGroupIfExpression']))) { if ($vm_ret = ExpressionParser::evaluate($va_item['settings']['skipGroupIfExpression'], $va_row)) { $o_log->logInfo(_t('[%1] Skipped group %2 because expression %3 is true', $vs_idno, $vn_group_id, $va_item['settings']['skipGroupIfExpression'])); continue 3; } } if (isset($va_item['settings']['skipGroupIfValue']) && is_array($va_item['settings']['skipGroupIfValue']) && strlen($vm_val) && in_array($vm_val, $va_item['settings']['skipGroupIfValue'])) { $o_log->logInfo(_t('[%1] Skipped group %2 because value for %3 matches value %4', $vs_idno, $vn_group_id, $vs_item_terminal, $vm_val)); continue 3; } if (isset($va_item['settings']['skipGroupIfNotValue']) && is_array($va_item['settings']['skipGroupIfNotValue']) && strlen($vm_val) && !in_array($vm_val, $va_item['settings']['skipGroupIfNotValue'])) { $o_log->logInfo(_t('[%1] Skipped group %2 because value for %3 matches is not in list of values', $vs_idno, $vn_group_id, $vs_item_terminal)); continue 3; } if (isset($va_item['settings']['skipIfExpression']) && strlen(trim($va_item['settings']['skipIfExpression']))) { if ($vm_ret = ExpressionParser::evaluate($va_item['settings']['skipIfExpression'], $va_row)) { $o_log->logInfo(_t('[%1] Skipped mapping because expression %2 is true', $vs_idno, $va_item['settings']['skipIfExpression'])); continue 2; } } if (isset($va_item['settings']['skipIfEmpty']) && (bool) $va_item['settings']['skipIfEmpty'] && !strlen($vm_val)) { $o_log->logInfo(_t('[%1] Skipped mapping because value for %2 is empty', $vs_idno, $vs_item_terminal)); continue 2; } if ($vn_type_id_mapping_item_id && $vn_item_id == $vn_type_id_mapping_item_id) { continue; } if ($vn_idno_mapping_item_id && $vn_item_id == $vn_idno_mapping_item_id) { continue; } if (is_null($vm_val)) { continue; } // Get mapping error policy $vb_item_error_policy_is_default = false; if (!isset($va_item['settings']['errorPolicy']) || !in_array($vs_item_error_policy = $va_item['settings']['errorPolicy'], array('ignore', 'stop'))) { $vs_item_error_policy = 'ignore'; $vb_item_error_policy_is_default = true; } // if (isset($va_item['settings']['relationshipType']) && strlen($vs_rel_type = $va_item['settings']['relationshipType']) && $vs_target_table != $vs_subject_table) { $va_group_buf[$vn_c]['_relationship_type'] = $vs_rel_type; } // Is it a constant value? if (preg_match("!^_CONSTANT_:[\\d]+:(.*)!", $va_item['source'], $va_matches)) { $va_group_buf[$vn_c][$vs_item_terminal] = $va_matches[1]; // Set it and go onto the next item if ($vs_target_table == $vs_subject_table_name && ($vs_k = array_search($vn_item_id, $va_mandatory_field_mapping_ids)) !== false) { $va_mandatory_field_values[$vs_k] = $vm_val; } continue; } // Perform refinery call (if required) per value if (isset($va_item['settings']['refineries']) && is_array($va_item['settings']['refineries'])) { foreach ($va_item['settings']['refineries'] as $vs_refinery) { if (!$vs_refinery) { continue; } if ($o_refinery = RefineryManager::getRefineryInstance($vs_refinery)) { $va_refined_values = $o_refinery->refine($va_content_tree, $va_group, $va_item, $va_row, array('mapping' => $t_mapping, 'source' => $ps_source, 'subject' => $t_subject, 'locale_id' => $vn_locale_id, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'reader' => $o_reader, 'valueIndex' => $vn_i)); if (!$va_refined_values || is_array($va_refined_values) && !sizeof($va_refined_values)) { continue 2; } if ($o_refinery->returnsMultipleValues()) { foreach ($va_refined_values as $va_refined_value) { $va_refined_value['_errorPolicy'] = $vs_item_error_policy; if (!is_array($va_group_buf[$vn_c])) { $va_group_buf[$vn_c] = array(); } $va_group_buf[$vn_c] = array_merge($va_group_buf[$vn_c], $va_refined_value); $vn_c++; } } else { $va_group_buf[$vn_c]['_errorPolicy'] = $vs_item_error_policy; $va_group_buf[$vn_c][$vs_item_terminal] = $va_refined_values; $vn_c++; } if ($vs_target_table == $vs_subject_table_name && ($vs_k = array_search($vn_item_id, $va_mandatory_field_mapping_ids)) !== false) { $va_mandatory_field_values[$vs_k] = $vm_val; } continue 2; } else { ca_data_importers::logImportError(_t('[%1] Invalid refinery %2 specified', $vs_idno, $vs_refinery)); } } } if ($vs_target_table == $vs_subject_table_name && ($vs_k = array_search($vn_item_id, $va_mandatory_field_mapping_ids)) !== false) { $va_mandatory_field_values[$vs_k] = $vm_val; } $vn_max_length = !is_array($vm_val) && isset($va_item['settings']['maxLength']) && (int) $va_item['settings']['maxLength'] ? (int) $va_item['settings']['maxLength'] : null; if (isset($va_item['settings']['delimiter']) && $va_item['settings']['delimiter']) { if (!is_array($va_item['settings']['delimiter'])) { $va_item['settings']['delimiter'] = array($va_item['settings']['delimiter']); } if (sizeof($va_item['settings']['delimiter'])) { foreach ($va_item['settings']['delimiter'] as $vn_index => $vs_delim) { $va_item['settings']['delimiter'][$vn_index] = preg_quote($vs_delim, "!"); } $va_val_list = preg_split("!(" . join("|", $va_item['settings']['delimiter']) . ")!", $vm_val); // Add delimited values foreach ($va_val_list as $vs_list_val) { $vs_list_val = trim(ca_data_importers::replaceValue($vs_list_val, $va_item)); if ($vn_max_length && mb_strlen($vs_list_val) > $vn_max_length) { $vs_list_val = mb_substr($vs_list_val, 0, $vn_max_length); } $va_group_buf[$vn_c] = array($vs_item_terminal => $vs_list_val, '_errorPolicy' => $vs_item_error_policy); $vn_c++; } $vn_row++; continue; // Don't add "regular" value below } } if ($vn_max_length && mb_strlen($vm_val) > $vn_max_length) { $vm_val = mb_substr($vm_val, 0, $vn_max_length); } switch ($vs_item_terminal) { case 'preferred_labels': case 'nonpreferred_labels': if ($t_instance = $o_dm->getInstanceByTableName($vs_target_table, true)) { $va_group_buf[$vn_c][$t_instance->getLabelDisplayField()] = $vm_val; } if ($o_trans) { $t_instance->setTransaction($o_trans); } if (!$vb_item_error_policy_is_default || !isset($va_group_buf[$vn_c]['_errorPolicy'])) { if (is_array($va_group_buf[$vn_c])) { $va_group_buf[$vn_c]['_errorPolicy'] = $vs_item_error_policy; } } if ($vs_item_terminal == 'preferred_labels') { $vs_preferred_label_for_log = $vm_val; } break; default: $va_group_buf[$vn_c][$vs_item_terminal] = $vm_val; if (!$vb_item_error_policy_is_default || !isset($va_group_buf[$vn_c]['_errorPolicy'])) { if (is_array($va_group_buf[$vn_c])) { $va_group_buf[$vn_c]['_errorPolicy'] = $vs_item_error_policy; } } break; } } // end foreach($va_vals as $vm_val) } foreach ($va_group_buf as $vn_group_index => $va_group_data) { $va_ptr =& $va_content_tree; foreach ($va_group_tmp as $vs_tmp) { if (!is_array($va_ptr[$vs_tmp])) { $va_ptr[$vs_tmp] = array(); } $va_ptr =& $va_ptr[$vs_tmp]; if ($vs_tmp == $vs_target_table) { // add numeric index after table to ensure repeat values don't overwrite each other $va_parent =& $va_ptr; $va_ptr[] = array(); $va_ptr =& $va_ptr[sizeof($va_ptr) - 1]; } } $va_ptr = $va_group_data; } } // // Process out self-relationships // if (is_array($va_content_tree[$vs_subject_table])) { $va_self_related_content = array(); foreach ($va_content_tree[$vs_subject_table] as $vn_i => $va_element_data) { if (isset($va_element_data['_relationship_type'])) { $va_self_related_content[] = $va_element_data; unset($va_content_tree[$vs_subject_table][$vn_i]); } } if (sizeof($va_self_related_content) > 0) { $va_content_tree["related.{$vs_subject_table}"] = $va_self_related_content; } } $vn_row++; $o_log->logDebug(_t('Finished building content tree for %1 at %2 seconds', $vs_idno, $t->getTime(4))); $o_log->logDebug(_t("Content tree is\n%1", print_R($va_content_tree, true))); // // Process data in subject record // //print_r($va_content_tree); //die("END\n\n"); //continue; $opa_app_plugin_manager->hookDataImportContentTree(array('mapping' => $t_mapping, 'content_tree' => &$va_content_tree, 'idno' => &$vs_idno, 'transaction' => &$o_trans, 'log' => &$o_log, 'reader' => $o_reader, 'environment' => $va_environment, 'importEvent' => $o_event, 'importEventSource' => $vn_row)); //print_r($va_content_tree); //die("done\n"); if (!sizeof($va_content_tree) && !str_replace("%", "", $vs_idno)) { continue; } if (!$t_subject->getPrimaryKey()) { $o_event->beginItem($vn_row, $t_subject->tableNum(), 'I'); $t_subject->setMode(ACCESS_WRITE); $t_subject->set($vs_type_id_fld, $vs_type); if ($vb_idno_is_template) { $t_subject->setIdnoWithTemplate($vs_idno); } else { $t_subject->set($vs_idno_fld, $vs_idno, array('assumeIdnoForRepresentationID' => true, 'assumeIdnoStubForLotID' => true)); // assumeIdnoStubForLotID forces ca_objects.lot_id values to always be considered as a potential idno_stub first, before use as a ca_objects.lot_id } // Look for parent_id in the content tree $vs_parent_id_fld = $t_subject->getProperty('HIERARCHY_PARENT_ID_FLD'); foreach ($va_content_tree as $vs_table_name => $va_content) { if ($vs_table_name == $vs_subject_table) { foreach ($va_content as $va_element_data) { foreach ($va_element_data as $vs_element => $va_element_content) { switch ($vs_element) { case $vs_parent_id_fld: if ($va_element_content[$vs_parent_id_fld]) { $t_subject->set($vs_parent_id_fld, $va_element_content[$vs_parent_id_fld], array('treatParentIDAsIdno' => true)); } break; } } } } } foreach ($va_mandatory_field_mapping_ids as $vs_mandatory_field => $vn_mandatory_mapping_item_id) { $t_subject->set($vs_mandatory_field, $va_mandatory_field_values[$vs_mandatory_field], array('assumeIdnoStubForLotID' => true)); } $t_subject->insert(); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("Could not insert new record"), array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_import_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to import error policy')); if ($vb_use_ncurses) { ncurses_end(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); if ($o_trans) { $o_trans->rollback(); } return false; } continue; } $o_log->logDebug(_t('Created idno %1 at %2 seconds', $vs_idno, $t->getTime(4))); } else { $o_event->beginItem($vn_row, $t_subject->tableNum(), 'U'); // update $t_subject->setMode(ACCESS_WRITE); if ($vb_idno_is_template) { $t_subject->setIdnoWithTemplate($vs_idno); } else { $t_subject->set($vs_idno_fld, $vs_idno, array('assumeIdnoStubForLotID' => true)); // assumeIdnoStubForLotID forces ca_objects.lot_id values to always be considered as a potential idno_stub first, before use as a ca_objects.lot_di } $t_subject->update(); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("Could not update matched record"), array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_import_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to import error policy')); if ($vb_use_ncurses) { ncurses_end(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); if ($o_trans) { $o_trans->rollback(); } return false; } continue; } $t_subject->clearErrors(); if (sizeof($va_preferred_label_mapping_ids) && $t_subject->getPreferredLabelCount() > 0) { $t_subject->removeAllLabels(__CA_LABEL_TYPE_PREFERRED__); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("Could not update remove preferred labels from matched record"), array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_import_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to import error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); return false; } } } $o_log->logDebug(_t('Updated idno %1 at %2 seconds', $vs_idno, $t->getTime(4))); } if ($vs_idno_fld && ($o_idno = $t_subject->getIDNoPlugInInstance())) { $va_values = $o_idno->htmlFormValuesAsArray($vs_idno_fld, $t_subject->get($vs_idno_fld)); if (!is_array($va_values)) { $va_values = array($va_values); } if (($vs_proc_idno = join($o_idno->getSeparator(), $va_values)) && $vs_proc_idno != $vs_idno) { $t_subject->set($vs_idno_fld, $vs_proc_idno); $t_subject->update(); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("Could update idno"), array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_import_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to import error policy')); if ($vb_use_ncurses) { ncurses_end(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); if ($o_trans) { $o_trans->rollback(); } return false; } continue; } } } $va_elements_set_for_this_record = array(); foreach ($va_content_tree as $vs_table_name => $va_content) { if ($vs_table_name == $vs_subject_table) { foreach ($va_content as $vn_i => $va_element_data) { foreach ($va_element_data as $vs_element => $va_element_content) { if (is_array($va_element_content)) { $vs_item_error_policy = $va_element_content['_errorPolicy']; unset($va_element_content['_errorPolicy']); } else { $vs_item_error_policy = null; } $t_subject->clearErrors(); $t_subject->setMode(ACCESS_WRITE); switch ($vs_element) { case 'preferred_labels': $t_subject->addLabel($va_element_content, $vn_locale_id, isset($va_element_content['type_id']) ? $va_element_content['type_id'] : null, true); if ($t_subject->numErrors() == 0) { $vb_output_subject_preferred_label = true; } if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add preferred label to %2. Record was deleted because no preferred label could be applied: ", $vs_idno, $t_subject->tableName()), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); $t_subject->delete(true, array('hard' => false)); if ($vs_import_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to import error policy %1', $vs_import_error_policy)); if ($vb_use_ncurses) { ncurses_end(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); if ($o_trans) { $o_trans->rollback(); } return false; } if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } continue 5; } break; case 'nonpreferred_labels': $t_subject->addLabel($va_element_content, $vn_locale_id, isset($va_element_content['type_id']) ? $va_element_content['type_id'] : null, false); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add non-preferred label to %2:", $vs_idno, $t_subject->tableName()), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); if ($o_trans) { $o_trans->rollback(); } return false; } } break; default: if ($t_subject->hasField($vs_element)) { $t_subject->set($vs_element, $va_element_content[$vs_element], array('assumeIdnoStubForLotID' => true)); $t_subject->update(); break; } if ($vs_subject_table == 'ca_representation_annotations' && $vs_element == 'properties') { foreach ($va_element_content as $vs_prop => $vs_prop_val) { $t_subject->setPropertyValue($vs_prop, $vs_prop_val); } break; } if (is_array($va_element_content)) { $va_element_content['locale_id'] = $vn_locale_id; } if (!isset($va_elements_set_for_this_record[$vs_element]) && !$va_elements_set_for_this_record[$vs_element] && in_array($vs_existing_record_policy, array('merge_on_idno_with_replace', 'merge_on_preferred_labels_with_replace', 'merge_on_idno_and_preferred_labels_with_replace'))) { $t_subject->removeAttributes($vs_element, array('force' => true)); } $va_elements_set_for_this_record[$vs_element] = true; $t_subject->addAttribute($va_element_content, $vs_element, null, array('showRepeatCountErrors' => true, 'alwaysTreatValueAsIdno' => true)); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Failed to add value for %2; values were %3: ", $vs_idno, $vs_element, ca_data_importers::formatValuesForLog($va_element_content)), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); if ($o_trans) { $o_trans->rollback(); } return false; } } $t_subject->update(); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Invalid %2; values were %3: ", $vs_idno, $vs_element, ca_data_importers::formatValuesForLog($va_element_content)), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); if ($o_trans) { $o_trans->rollback(); } return false; } } break; } } } } else { // related $vs_table_name = preg_replace('!^related\\.!', '', $vs_table_name); foreach ($va_content as $vn_i => $va_element_data) { $va_match_on = caGetOption('_matchOn', $va_element_data, null); $vb_dont_create = caGetOption('_dontCreate', $va_element_data, null); $va_data_for_rel_table = $va_element_data; $va_nonpreferred_labels = isset($va_data_for_rel_table['nonpreferred_labels']) ? $va_data_for_rel_table['nonpreferred_labels'] : null; unset($va_data_for_rel_table['preferred_labels']); unset($va_data_for_rel_table['_relationship_type']); unset($va_data_for_rel_table['_type']); unset($va_data_for_rel_table['_parent_id']); unset($va_data_for_rel_table['_errorPolicy']); unset($va_data_for_rel_table['_matchOn']); $va_data_for_rel_table = array_merge($va_data_for_rel_table, ca_data_importers::_extractIntrinsicValues($va_data_for_rel_table, $vs_table_name)); $t_subject->clearErrors(); switch ($vs_table_name) { case 'ca_objects': if ($vn_rel_id = DataMigrationUtils::getObjectID($va_element_data['preferred_labels']['name'], $va_element_data['_parent_id'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, trim($va_element_data['_relationship_type']), null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related object with relationship %2:", $vs_idno, trim($va_element_data['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_object_lots': $vs_idno_stub = null; if (is_array($va_element_data['idno_stub'])) { $vs_idno_stub = isset($va_element_data['idno_stub']['idno_stub']) ? $va_element_data['idno_stub']['idno_stub'] : ''; } else { $vs_idno_stub = isset($va_element_data['idno_stub']) ? $va_element_data['idno_stub'] : ''; } if ($vn_rel_id = DataMigrationUtils::getObjectLotID($vs_idno_stub, $va_element_data['preferred_labels']['name'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno_stub']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, trim($va_element_data['_relationship_type']), null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related object lot with relationship %2:", $vs_idno, trim($va_element_data['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_entities': if ($vn_rel_id = DataMigrationUtils::getEntityID($va_element_data['preferred_labels'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, trim($va_element_data['_relationship_type']), null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related entity with relationship %2:", $vs_idno, trim($va_element_data['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_places': if ($vn_rel_id = DataMigrationUtils::getPlaceID($va_element_data['preferred_labels']['name'], $va_element_data['_parent_id'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, trim($va_element_data['_relationship_type']), null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related place with relationship %2:", $vs_idno, trim($va_element_data['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_collections': if ($vn_rel_id = DataMigrationUtils::getCollectionID($va_element_data['preferred_labels']['name'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, $vs_rel_type, null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related collection with relationship %2:", $vs_idno, $vs_rel_type), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_occurrences': if ($vn_rel_id = DataMigrationUtils::getOccurrenceID($va_element_data['preferred_labels']['name'], $va_element_data['_parent_id'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, $vs_rel_type, null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related occurrence with relationship %2:", $vs_idno, $vs_rel_type), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_storage_locations': if ($vn_rel_id = DataMigrationUtils::getStorageLocationID($va_element_data['preferred_labels']['name'], $va_element_data['_parent_id'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, trim($va_element_data['_relationship_type']), null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related storage location with relationship %2:", $vs_idno, trim($va_element_data['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_list_items': $va_data_for_rel_table['is_enabled'] = 1; $va_data_for_rel_table['preferred_labels'] = $va_element_data['preferred_labels']; if ($vn_rel_id = DataMigrationUtils::getListItemID($va_element_data['_list'], $va_element_data['idno'] ? $va_element_data['idno'] : null, $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, trim($va_element_data['_relationship_type']), null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related list item with relationship %2:", $vs_idno, trim($va_element_data['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_object_representations': if ($vn_rel_id = DataMigrationUtils::getObjectRepresentationID($va_element_data['preferred_labels']['name'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels, 'matchMediaFilesWithoutExtension' => true))) { $t_subject->linkRepresentation($vn_rel_id, null, null, null, null, array('type_id' => trim($va_element_data['_relationship_type']), 'is_primary' => true)); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related object representation with:", $vs_idno), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } // // if (($vs_subject_table_name == 'ca_objects') && $va_element_data['media']['media']) { // unset($va_data_for_rel_table['media']); // // foreach($va_data_for_rel_table as $vs_key => $vm_val) { // // Attributes, including intrinsics are in two-level format, eg. idno is $va_attributes['idno']['idno'] // // but addRepresentations() expects intrinsics to be single level (eg. $va_attributes['idno']) so // // we do some rewriting here // if (is_array($vm_val) && isset($vm_val[$vs_key])) { // $va_data_for_rel_table[$vs_key] = $vm_val[$vs_key]; // } // } // // if (!($t_subject->addRepresentation($va_element_data['media']['media'], isset($va_element_data['_type']) ? $va_element_data['_type'] : caGetDefaultItemID('object_representation_types'), $vn_locale_id, 0, 0, true, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on)))) { // $vs_error = join("; ", $t_subject->getErrors()); // ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); // if ($vs_item_error_policy == 'stop') { // $o_log->logAlert(_t('Import stopped due to mapping error policy')); // if($vb_use_ncurses) { ncurses_end(); } // if ($o_trans) { $o_trans->rollback(); } // return false; // } // } // } break; case 'ca_loans': if ($vn_rel_id = DataMigrationUtils::getLoanID($va_element_data['preferred_labels']['name'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, trim($va_element_data['_relationship_type']), null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related loan with relationship %2:", $vs_idno, trim($va_element_data['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; case 'ca_movements': if ($vn_rel_id = DataMigrationUtils::getMovementID($va_element_data['preferred_labels']['name'], $va_element_data['_type'], $vn_locale_id, $va_data_for_rel_table, array('dontCreate' => $vb_dont_create, 'matchOn' => $va_match_on, 'log' => $o_log, 'transaction' => $o_trans, 'importEvent' => $o_event, 'importEventSource' => $vn_row, 'nonPreferredLabels' => $va_nonpreferred_labels))) { if (!($vs_rel_type = $va_element_data['_relationship_type']) && !($vs_rel_type = $va_element_data['idno']['_relationship_type'])) { break; } $t_subject->addRelationship($vs_table_name, $vn_rel_id, trim($va_element_data['_relationship_type']), null, null, null, null, array('interstitialValues' => $va_element_data['_interstitial'])); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related movement with relationship %2:", $vs_idno, trim($va_element_data['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_item_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to mapping error policy')); if ($vb_use_ncurses) { ncurses_end(); } if ($o_trans) { $o_trans->rollback(); } return false; } } } break; } if (is_array($va_element_data['_related_related']) && sizeof($va_element_data['_related_related'])) { foreach ($va_element_data['_related_related'] as $vs_rel_rel_table => $va_rel_rels) { foreach ($va_rel_rels as $vn_i => $va_rel_rel) { if (!($t_rel_instance = $o_dm->getInstanceByTableName($vs_table_name))) { $o_log->logWarn(_t("[%1] Could not instantiate related table %2", $vs_idno, $vs_table_name)); continue; } if ($o_trans) { $t_rel_instance->setTransaction($o_trans); } if ($t_rel_instance->load($vn_rel_id)) { if ($t_rel_rel = $t_rel_instance->addRelationship($vs_rel_rel_table, $va_rel_rel['id'], $va_rel_rel['_relationship_type'])) { $o_log->logInfo(_t('[%1] Related %2 (%3) to related %4 with relationship %5', $vs_idno, $o_dm->getTableProperty($vs_rel_rel_table, 'NAME_SINGULAR'), $va_rel_rel['id'], $t_rel_instance->getProperty('NAME_SINGULAR'), trim($va_rel_rel['_relationship_type']))); } else { if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add related %2 (%3) to related %4 with relationship %5:", $vs_idno, $o_dm->getTableProperty($vs_rel_rel_table, 'NAME_SINGULAR'), $va_rel_rel['id'], $t_rel_instance->getProperty('NAME_SINGULAR'), trim($va_rel_rel['_relationship_type'])), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); } } } } } } } } } // $t_subject->update(); // // if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Invalid %2; values were %3: ", $vs_idno, 'attributes', ca_data_importers::formatValuesForLog($va_element_content)), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { // ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); // if ($vs_item_error_policy == 'stop') { // $o_log->logAlert(_t('Import stopped due to mapping error policy')); // if($vb_use_ncurses) { ncurses_end(); } // // $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); // // if ($o_trans) { $o_trans->rollback(); } // return false; // } // } // $o_log->logDebug(_t('Finished inserting content tree for %1 at %2 seconds into database', $vs_idno, $t->getTime(4))); if (!$vb_output_subject_preferred_label && $t_subject->getPreferredLabelCount() == 0) { $t_subject->addLabel(array($vs_label_display_fld => '???'), $vn_locale_id, null, true); if ($vs_error = DataMigrationUtils::postError($t_subject, _t("[%1] Could not add default label", $vs_idno), __CA_DATA_IMPORT_ERROR__, array('dontOutputLevel' => true, 'dontPrint' => true))) { ca_data_importers::logImportError($vs_error, $va_log_import_error_opts); if ($vs_import_error_policy == 'stop') { $o_log->logAlert(_t('Import stopped due to import error policy')); if ($vb_use_ncurses) { ncurses_end(); } $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_FAILURE__, _t('Failed to import %1', $vs_idno)); if ($o_trans) { $o_trans->rollback(); } return false; } } } $o_log->logInfo(_t('[%1] Imported %2 as %3 ', $vs_idno, $vs_preferred_label_for_log, $vs_subject_table_name)); $o_event->endItem($t_subject->getPrimaryKey(), __CA_DATA_IMPORT_ITEM_SUCCESS__, _t('Imported %1', $vs_idno)); ca_data_importers::$s_num_records_processed++; } $o_log->logInfo(_t('Import of %1 completed using mapping %2: %3 imported/%4 skipped/%5 errors', $ps_source, $t_mapping->get('importer_code'), ca_data_importers::$s_num_records_processed, ca_data_importers::$s_num_records_skipped, ca_data_importers::$s_num_import_errors)); //if ($vb_show_cli_progress_bar) { $o_progress->finish(); //} if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) { $ps_callback($po_request, $pn_file_number, $pn_number_of_files, $ps_source, $vn_num_items, $vn_num_items, _t('Import completed'), time() - $vn_start_time, memory_get_usage(true), ca_data_importers::$s_num_records_processed, ca_data_importers::$s_num_import_errors); } if (isset($pa_options['reportCallback']) && ($ps_callback = $pa_options['reportCallback'])) { $va_general = array('elapsedTime' => time() - $vn_start_time, 'numErrors' => ca_data_importers::$s_num_import_errors, 'numProcessed' => ca_data_importers::$s_num_records_processed); $ps_callback($po_request, $va_general, ca_data_importers::$s_import_error_list, true); } if ($vb_use_ncurses) { ncurses_end(); } if ($pb_dry_run) { if ($o_trans) { $o_trans->rollback(); } $o_log->logInfo(_t('Rollback successful import run in "dry run" mode')); } else { if ($o_trans) { $o_trans->commit(); } } return true; }
/** * Prepopulate record fields according to rules in prepopulate.conf * * @param array $pa_options Options array. Available options are: * prepopulateConfig = override path to prepopulate.conf, e.g. for testing purposes * @return bool success or not */ public function prepopulateFields($pa_options = null) { if (!$this->getPrimaryKey()) { return false; } if (!($vs_prepopulate_cfg = caGetOption('prepopulateConfig', $pa_options, null))) { $vs_prepopulate_cfg = $this->getAppConfig()->get('prepopulate_config'); } $o_prepopulate_conf = Configuration::load($vs_prepopulate_cfg); if (!($o_prepopulate_conf->get('prepopulate_fields_on_save') || $o_prepopulate_conf->get('prepopulate_fields_on_load'))) { return false; } $va_rules = $o_prepopulate_conf->get('prepopulate_rules'); if (!$va_rules || !is_array($va_rules) || sizeof($va_rules) < 1) { return false; } global $g_ui_locale_id; // we need to unset the form timestamp to disable the 'Changes have been made since you loaded this data' warning when we update() $this // the warning makes sense because an update()/insert() is called before we arrive here but after the form_timestamp ... but we chose to ignore it $vn_timestamp = $_REQUEST['form_timestamp']; unset($_REQUEST['form_timestamp']); $vb_we_set_transaction = true; if (!$this->inTransaction()) { $this->setTransaction(new Transaction($this->getDb())); $vb_we_set_transaction = true; } // process rules $va_expression_vars = array(); // we only process those if and when we need them foreach ($va_rules as $vs_rule_key => $va_rule) { if ($this->tableName() != $va_rule['table']) { continue; } // check target $vs_target = $va_rule['target']; if (strlen($vs_target) < 1) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because target is not set"); continue; } // check template $vs_template = $va_rule['template']; if (strlen($vs_template) < 1) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because template is not set"); continue; } $vs_mode = caGetOption('mode', $va_rule, 'merge'); // respect restrictToTypes option if ($va_rule['restrictToTypes'] && is_array($va_rule['restrictToTypes']) && sizeof($va_rule['restrictToTypes']) > 0) { if (!in_array($this->getTypeCode(), $va_rule['restrictToTypes'])) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because current record type " . $this->getTypeCode() . " is not in restrictToTypes"); continue; } } // skip this rule if expression is true if ($va_rule['skipIfExpression'] && strlen($va_rule['skipIfExpression']) > 0) { $va_tags = caGetTemplateTags($va_rule['skipIfExpression']); foreach ($va_tags as $vs_tag) { if (!isset($va_expression_vars[$vs_tag])) { $va_expression_vars[$vs_tag] = $this->get($vs_tag, array('returnIdno' => true, 'delimiter' => ';')); } } if (ExpressionParser::evaluate($va_rule['skipIfExpression'], $va_expression_vars)) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because skipIfExpression evaluated true"); continue; } } // evaluate template $vs_value = caProcessTemplateForIDs($vs_template, $this->tableNum(), array($this->getPrimaryKey()), array('path' => true)); Debug::msg("[prepopulateFields()] processed template for rule {$vs_rule_key} value is: " . $vs_value); // inject into target $va_parts = explode('.', $vs_target); // intrinsic or simple (non-container) attribute if (sizeof($va_parts) == 2) { // intrinsic if ($this->hasField($va_parts[1])) { switch (strtolower($vs_mode)) { case 'overwrite': // always set $this->set($va_parts[1], $vs_value); break; case 'addifempty': default: if (!$this->get($va_parts[1])) { $this->set($va_parts[1], $vs_value); } else { Debug::msg("[prepopulateFields()] rule {$vs_rule_key}: intrinsic skipped because it already has value and mode is addIfEmpty or merge"); } break; } // attribute/element } elseif ($this->hasElement($va_parts[1])) { $va_attributes = $this->getAttributesByElement($va_parts[1]); if (sizeof($va_attributes) > 1) { Debug::msg("[prepopulateFields()] containers with multiple values are not supported"); continue; } switch (strtolower($vs_mode)) { case 'overwrite': // always replace first value we find $this->replaceAttribute(array($va_parts[1] => $vs_value, 'locale_id' => $g_ui_locale_id), $va_parts[1]); break; default: case 'addifempty': // only add value if none exists if (!$this->get($vs_target)) { $this->replaceAttribute(array($va_parts[1] => $vs_value, 'locale_id' => $g_ui_locale_id), $va_parts[1]); } break; } } // "container" } elseif (sizeof($va_parts) == 3) { // actual container if ($this->hasElement($va_parts[1])) { $va_attr = $this->getAttributesByElement($va_parts[1]); switch (sizeof($va_attr)) { case 1: switch (strtolower($vs_mode)) { case 'overwrite': $vo_attr = array_pop($va_attr); $va_value = array($va_parts[2] => $vs_value); foreach ($vo_attr->getValues() as $o_val) { if ($o_val->getElementCode() != $va_parts[2]) { $va_value[$o_val->getElementCode()] = $o_val->getDisplayValue(); } } $this->_editAttribute($vo_attr->getAttributeID(), $va_value); break; case 'addifempty': $vo_attr = array_pop($va_attr); $va_value = array($va_parts[2] => $vs_value); $vb_update = false; foreach ($vo_attr->getValues() as $o_val) { if ($o_val->getElementCode() != $va_parts[2]) { $va_value[$o_val->getElementCode()] = $o_val->getDisplayValue(); } else { if (!$o_val->getDisplayValue()) { $vb_update = true; } } } if ($vb_update) { $this->editAttribute($vo_attr->getAttributeID(), $va_parts[1], $va_value); } break; default: Debug::msg("[prepopulateFields()] unsupported mode {$vs_mode} for target bundle"); break; } break; case 0: // if no container value exists, always add it (ignoring mode) $this->addAttribute(array($va_parts[2] => $vs_value, 'locale_id' => $g_ui_locale_id), $va_parts[1]); break; default: Debug::msg("[prepopulateFields()] containers with multiple values are not supported"); break; } // labels } elseif ($va_parts[1] == 'preferred_labels' || $va_parts[1] == 'nonpreferred_labels') { $vb_preferred = $va_parts[1] == 'preferred_labels'; if (!($t_label = $this->getAppDatamodel()->getInstanceByTableName($this->getLabelTableName(), true))) { continue; } if (!$t_label->hasField($va_parts[2])) { continue; } switch ($this->getLabelCount($vb_preferred)) { case 0: // if no value exists, always add it (ignoring mode) $this->addLabel(array($va_parts[2] => $vs_value), $g_ui_locale_id, null, $vb_preferred); break; case 1: switch (strtolower($vs_mode)) { case 'overwrite': case 'addifempty': $va_labels = $this->getLabels(null, $vb_preferred ? __CA_LABEL_TYPE_PREFERRED__ : __CA_LABEL_TYPE_NONPREFERRED__); if (sizeof($va_labels)) { $va_labels = caExtractValuesByUserLocale($va_labels); $va_label = array_shift($va_labels); $va_label = $va_label[0]; $va_label[$va_parts[2]] = $vs_value; $vb_update = false; if (strtolower($vs_mode) == 'overwrite') { $va_label[$va_parts[2]] = $vs_value; $vb_update = true; } else { if (strlen(trim($va_label[$va_parts[2]])) == 0) { // in addifempty mode only edit label when field is not set $va_label[$va_parts[2]] = $vs_value; $vb_update = true; } } if ($vb_update) { $this->editLabel($va_label['label_id'], $va_label, $g_ui_locale_id, null, $vb_preferred); } } else { $this->addLabel(array($va_parts[2] => $vs_value), $g_ui_locale_id, null, $vb_preferred); } break; default: Debug::msg("[prepopulateFields()] unsupported mode {$vs_mode} for target bundle"); break; } break; default: Debug::msg("[prepopulateFields()] records with multiple labels are not supported"); break; } } } } $vn_old_mode = $this->getMode(); $this->setMode(ACCESS_WRITE); $this->update(); $this->setMode($vn_old_mode); $_REQUEST['form_timestamp'] = $vn_timestamp; if ($this->numErrors() > 0) { foreach ($this->getErrors() as $vs_error) { Debug::msg("[prepopulateFields()] there was an error while updating the record: " . $vs_error); } if ($vb_we_set_transaction) { $this->removeTransaction(false); } return false; } if ($vb_we_set_transaction) { $this->removeTransaction(true); } return true; }
/** * get() value for attribute * * @param array $pa_value_list * @param BaseModel $pt_instance * @param array Options * * @return array|string */ private function _getAttributeValue($pa_value_list, $pt_instance, $pa_options) { $va_path_components =& $pa_options['pathComponents']; $vs_delimiter = isset($pa_options['delimiter']) ? $pa_options['delimiter'] : ';'; $va_return_values = array(); $vn_id = $this->get($pt_instance->primaryKey(true)); $vs_table_name = $pt_instance->tableName(); if (is_array($pa_value_list) && sizeof($pa_value_list)) { $va_val_proc = array(); foreach ($pa_value_list as $o_attribute) { $t_attr_element = $pt_instance->_getElementInstance($o_attribute->getElementID()); $vn_attr_type = $t_attr_element->get('datatype'); $va_acc = array(); $va_values = $o_attribute->getValues(); if ($pa_options['useLocaleCodes']) { if (!$o_attribute->getLocaleID() || !($vm_locale_id = SearchResult::$opo_locales->localeIDToCode($o_attribute->getLocaleID()))) { $vm_locale_id = __CA_DEFAULT_LOCALE__; } } else { if (!($vm_locale_id = $o_attribute->getLocaleID())) { $vm_locale_id = SearchResult::$opo_locales->localeCodeToID(__CA_DEFAULT_LOCALE__); } } $vb_did_return_value = false; foreach ($va_values as $o_value) { $vs_val_proc = null; $vb_dont_return_value = false; $vs_element_code = $o_value->getElementCode(); $va_auth_spec = null; if (is_a($o_value, "AuthorityAttributeValue")) { $va_auth_spec = $va_path_components['components']; if ($pt_instance->hasElement($va_path_components['subfield_name'], null, true, array('dontCache' => false))) { array_shift($va_auth_spec); array_shift($va_auth_spec); array_shift($va_auth_spec); } elseif ($pt_instance->hasElement($va_path_components['field_name'], null, true, array('dontCache' => false))) { array_shift($va_auth_spec); array_shift($va_auth_spec); $va_path_components['subfield_name'] = null; } } if ($va_path_components['subfield_name'] && $va_path_components['subfield_name'] !== $vs_element_code && !$o_value instanceof InformationServiceAttributeValue) { $vb_dont_return_value = true; if (!$pa_options['filter']) { continue; } } if (is_a($o_value, "AuthorityAttributeValue") && sizeof($va_auth_spec) > 0) { array_unshift($va_auth_spec, $vs_auth_table_name = $o_value->tableName()); if ($qr_res = caMakeSearchResult($vs_auth_table_name, array($o_value->getID()))) { if ($qr_res->nextHit()) { unset($pa_options['returnWithStructure']); $va_options['returnAsArray'] = true; $va_val_proc = $qr_res->get(join(".", $va_auth_spec), $pa_options); if (is_array($va_val_proc)) { foreach ($va_val_proc as $vn_i => $vs_v) { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID() . "_{$vn_i}"][$vs_element_code] = $vs_v; } } } } continue; } if (is_null($vs_val_proc)) { switch ($o_value->getType()) { case __CA_ATTRIBUTE_VALUE_LIST__: $t_element = $pt_instance->_getElementInstance($o_value->getElementID()); $vn_list_id = $t_element->get('list_id'); $vs_val_proc = $o_value->getDisplayValue(array_merge($pa_options, array('output' => $pa_options['output'], 'list_id' => $vn_list_id))); break; case __CA_ATTRIBUTE_VALUE_INFORMATIONSERVICE__: //ca_objects.informationservice.ulan_container // support subfield notations like ca_objects.wikipedia.abstract, but only if we're not already at subfield-level, e.g. ca_objects.container.wikipedia if ($va_path_components['subfield_name'] && $vs_element_code != $va_path_components['subfield_name'] && $vs_element_code == $va_path_components['field_name']) { $vs_val_proc = $o_value->getExtraInfo($va_path_components['subfield_name']); $vb_dont_return_value = false; break; } // support ca_objects.container.wikipedia.abstract if ($vs_element_code == $va_path_components['subfield_name'] && $va_path_components['num_components'] == 4) { $vs_val_proc = $o_value->getExtraInfo($va_path_components['components'][3]); $vb_dont_return_value = false; break; } // support ca_objects.wikipedia or ca_objects.container.wikipedia (Eg. no "extra" value specified) if ($vs_element_code == $va_path_components['field_name'] || $vs_element_code == $va_path_components['subfield_name']) { $vs_val_proc = $o_value->getDisplayValue(array_merge($pa_options, array('output' => $pa_options['output']))); $vb_dont_return_value = false; break; } continue 2; default: $vs_val_proc = $o_value->getDisplayValue(array_merge($pa_options, array('output' => $pa_options['output']))); break; } } if ($vn_attr_type == __CA_ATTRIBUTE_VALUE_CONTAINER__ && !$va_path_components['subfield_name'] && !$pa_options['returnWithStructure']) { if (strlen($vs_val_proc) > 0) { $va_val_proc[] = $vs_val_proc; } $vs_val_proc = join($vs_delimiter, $va_val_proc); } $va_spec = $va_path_components['components']; array_pop($va_spec); $va_acc[join('.', $va_spec) . '.' . $vs_element_code] = $o_value->getDisplayValue(array_merge($pa_options, array('output' => 'idno'))); if (!$vb_dont_return_value) { $vb_did_return_value = true; if ($pa_options['makeLink']) { $vs_val_proc = array_shift(caCreateLinksFromText(array($vs_val_proc), $vs_table_name, array($vn_id))); } if ($pa_options['returnWithStructure']) { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()][$vs_element_code] = $vs_val_proc; } else { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()] = $vs_val_proc; } } } if ($va_path_components['subfield_name'] && $pa_options['returnBlankValues'] && !$vb_did_return_value) { // value is missing so insert blank if ($pa_options['returnWithStructure']) { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()][$va_path_components['subfield_name']] = ''; } else { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()] = ''; } } if ($pa_options['filter']) { $va_tags = caGetTemplateTags($pa_options['filter']); $va_vars = array(); foreach ($va_tags as $vs_tag) { if (isset($va_acc[$vs_tag])) { $va_vars[$vs_tag] = $va_acc[$vs_tag]; } else { $va_vars[$vs_tag] = $this->get($vs_tag, array('convertCodesToIdno' => true)); } } if (ExpressionParser::evaluate($pa_options['filter'], $va_vars)) { unset($va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()]); continue; } } } } else { // is blank if ($pa_options['returnWithStructure'] && $pa_options['returnBlankValues']) { $va_return_values[(int) $vn_id][null][null][$va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : $va_path_components['field_name']] = ''; } } if (!$pa_options['returnAllLocales']) { $va_return_values = caExtractValuesByUserLocale($va_return_values); } if ($pa_options['returnWithStructure']) { return is_array($va_return_values) ? $va_return_values : array(); } // // Flatten array for return as string or simple array value // $va_flattened_values = $this->_flattenArray($va_return_values, $pa_options); if ($pa_options['returnAsArray']) { return $va_flattened_values; } else { return sizeof($va_flattened_values) > 0 ? join($pa_options['delimiter'], $va_flattened_values) : null; } }
/** * Replace "^" prefixed tags (eg. ^forename) in a template with values from an array * * @param string $ps_template String with embedded tags. Tags are just alphanumeric strings prefixed with a caret ("^") * @param string $pm_tablename_or_num Table name or number of table from which values are being formatted * @param string $pa_row_ids An array of primary key values in the specified table to be pulled into the template * @param array $pa_options Supported options are: * returnAsArray = if true an array of processed template values is returned, otherwise the template values are returned as a string joined together with a delimiter. Default is false. * delimiter = value to string together template values with when returnAsArray is false. Default is ';' (semicolon) * relatedValues = array of field values to return in template when directly referenced. Array should be indexed numerically in parallel with $pa_row_ids * relationshipValues = array of field values to return in template for relationship when directly referenced. Should be indexed by row_id and then by relation_id * placeholderPrefix = attribute container to implicitly place primary record fields into. Ex. if the table is "ca_entities" and the placeholder is "address" then tags like ^city will resolve to ca_entities.address.city * requireLinkTags = if set then links are only added when explicitly defined with <l> tags. Default is to make the entire text a link in the absence of <l> tags. * resolveLinksUsing = * primaryIDs = row_ids for primary rows in related table, keyed by table name; when resolving ambiguous relationships the row_ids will be excluded from consideration. This option is rarely used and exists primarily to take care of a single * edge case: you are processing a template relative to a self-relationship such as ca_entities_x_entities that includes references to the subject table (ca_entities, in the case of ca_entities_x_entities). There are * two possible paths to take in this situations; primaryIDs lets you specify which ones you *don't* want to take by row_id. For interstitial editors, the ids will be set to a single id: that of the subject (Eg. ca_entities) row * from which the interstitial was launched. * sort = optional list of tag values to sort repeating values within a row template on. The tag must appear in the template. You can specify more than one tag by separating the tags with semicolons. * sortDirection = The direction of the sort of repeating values within a row template. May be either ASC (ascending) or DESC (descending). [Default is ASC] * linkTarget = Optional target to use when generating <l> tag-based links. By default links point to standard detail pages, but plugins may define linkTargets that point elsewhere. * skipIfExpression = skip the elements in $pa_row_ids for which the given expression does not evaluate true * includeBlankValuesInArray = include blank template values in returned array when returnAsArray is set. If you need the returned array of values to line up with the row_ids in $pa_row_ids this should be set. [Default is false] * * @return mixed Output of processed templates */ function caProcessTemplateForIDs($ps_template, $pm_tablename_or_num, $pa_row_ids, $pa_options = null) { foreach (array('request', 'template', 'restrictToTypes', 'restrict_to_types', 'restrict_to_relationship_types', 'restrictToRelationshipTypes', 'useLocaleCodes') as $vs_k) { unset($pa_options[$vs_k]); } if (!isset($pa_options['convertCodesToDisplayText'])) { $pa_options['convertCodesToDisplayText'] = true; } $pb_return_as_array = (bool) caGetOption('returnAsArray', $pa_options, false); if (($pa_sort = caGetOption('sort', $pa_options, null)) && !is_array($pa_sort)) { $pa_sort = explode(";", $pa_sort); } $ps_sort_direction = caGetOption('sortDirection', $pa_options, null, array('forceUppercase' => true)); if (!in_array($ps_sort_direction, array('ASC', 'DESC'))) { $ps_sort_direction = 'ASC'; } $pa_check_access = caGetOption('checkAccess', $pa_options, null); if (!is_array($pa_row_ids) || !sizeof($pa_row_ids) || !$ps_template) { return $pb_return_as_array ? array() : ""; } unset($pa_options['returnAsArray']); if (!isset($pa_options['requireLinkTags'])) { $pa_options['requireLinkTags'] = true; } $ps_skip_if_expression = caGetOption('skipIfExpression', $pa_options, false); $va_primary_ids = caGetOption("primaryIDs", $pa_options, null); $o_dm = Datamodel::load(); $ps_tablename = is_numeric($pm_tablename_or_num) ? $o_dm->getTableName($pm_tablename_or_num) : $pm_tablename_or_num; $ps_resolve_links_using = caGetOption('resolveLinksUsing', $pa_options, $ps_tablename); $t_instance = $o_dm->getInstanceByTableName($ps_tablename, true); if ($ps_resolve_links_using != $ps_tablename) { $t_resolve_links_instance = $o_dm->getInstanceByTableName($ps_resolve_links_using, true); $vs_resolve_links_using_pk = $t_resolve_links_instance->primaryKey(); } $vs_pk = $t_instance->primaryKey(); $vs_delimiter = isset($pa_options['delimiter']) ? $pa_options['delimiter'] : '; '; $ps_template = str_replace("^_parent", "^{$ps_resolve_links_using}.parent.preferred_labels", $ps_template); $ps_template = str_replace("^_hierarchy", "^{$ps_resolve_links_using}._hierarchyName", $ps_template); $va_related_values = isset($pa_options['relatedValues']) && is_array($pa_options['relatedValues']) ? $pa_options['relatedValues'] : array(); $va_relationship_values = isset($pa_options['relationshipValues']) && is_array($pa_options['relationshipValues']) ? $pa_options['relationshipValues'] : array(); $o_doc = str_get_dom($ps_template); // parse template $ps_template = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_doc->html())); // replace template with parsed version; this allows us to do text find/replace later // Parse units from template $o_units = $o_doc('unit'); // only process non-nested <unit> tags $va_units = array(); $vn_unit_id = 1; foreach ($o_units as $o_unit) { if (!$o_unit) { continue; } $vs_html = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_unit->html())); $vs_content = $o_unit->getInnerText(); // is this nested in another unit? We skip these foreach ($va_units as $va_tmp) { if (strpos($va_tmp['directive'], $vs_html) !== false) { continue 2; } } $va_units[] = $va_unit = array('tag' => $vs_unit_tag = "[[#{$vn_unit_id}]]", 'directive' => $vs_html, 'content' => $vs_content, 'relativeTo' => (string) $o_unit->getAttribute("relativeto"), 'delimiter' => ($vs_d = (string) $o_unit->getAttribute("delimiter")) ? $vs_d : null, 'restrictToTypes' => (string) $o_unit->getAttribute("restricttotypes"), 'restrictToRelationshipTypes' => (string) $o_unit->getAttribute("restricttorelationshiptypes"), 'sort' => explode(";", $o_unit->getAttribute("sort")), 'sortDirection' => (string) $o_unit->getAttribute("sortDirection"), 'skipIfExpression' => (string) $o_unit->getAttribute("skipIfExpression")); $ps_template = str_ireplace($va_unit['directive'], $vs_unit_tag, $ps_template); $vn_unit_id++; } $o_doc = str_get_dom($ps_template); // parse template again with units replaced by unit tags in the format [[#X]] $ps_template = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_doc->html())); // replace template with parsed version; this allows us to do text find/replace later $va_tags = array(); if (preg_match_all(__CA_BUNDLE_DISPLAY_TEMPLATE_TAG_REGEX__, $ps_template, $va_matches)) { $va_tags = $va_matches[1]; } $va_directive_tags = array(); $va_directive_tag_vals = array(); $qr_res = caMakeSearchResult($ps_tablename, $pa_row_ids); if (!$qr_res) { return ''; } $va_proc_templates = array(); $vn_i = 0; $o_ifs = $o_doc("if"); // if $o_ifdefs = $o_doc("ifdef"); // if defined $o_ifnotdefs = $o_doc("ifnotdef"); // if not defined $o_mores = $o_doc("more"); // more tags - content suppressed if there are no defined values following the tag pair $o_betweens = $o_doc("between"); // between tags - content suppressed if there are not defined values on both sides of the tag pair $va_if = array(); foreach ($o_ifs as $o_if) { if (!$o_if) { continue; } $vs_html = $o_if->html(); $vs_content = $o_if->getInnerText(); $va_if[] = array('directive' => $vs_html, 'content' => $vs_content, 'rule' => $vs_rule = (string) $o_if->getAttribute('rule')); } foreach ($o_ifdefs as $o_ifdef) { if (!$o_ifdef) { continue; } $vs_code = (string) $o_ifdef->getAttribute('code'); $vs_code_proc = preg_replace("!%(.*)\$!", '', $vs_code); $va_directive_tags = array_merge($va_directive_tags, preg_split('![,\\|]{1}!', $vs_code_proc)); } foreach ($o_ifnotdefs as $o_ifnotdef) { if (!$o_ifnotdef) { continue; } $vs_code = (string) $o_ifnotdef->getAttribute('code'); $vs_code_proc = preg_replace("!%(.*)\$!", '', $vs_code); $va_directive_tags = array_merge($va_directive_tags, preg_split('![,\\|]{1}!', $vs_code_proc)); } $va_mores = array(); foreach ($o_mores as $o_more) { if (!$o_more) { continue; } $vs_html = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_more->html())); $vs_content = $o_more->getInnerText(); $va_mores[] = array('directive' => $vs_html, 'content' => $vs_content); } $va_betweens = array(); foreach ($o_betweens as $o_between) { if (!$o_between) { continue; } $vs_html = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_between->html())); $vs_content = $o_between->getInnerText(); $va_betweens[] = array('directive' => $vs_html, 'content' => $vs_content); } $va_resolve_links_using_row_ids = array(); $va_tag_val_list = $va_defined_tag_list = array(); $va_expression_vars = array(); /** @var $qr_res SearchResult */ while ($qr_res->nextHit()) { $vs_pk_val = $qr_res->get($vs_pk, array('checkAccess' => $pa_check_access)); if (is_array($pa_check_access) && sizeof($pa_check_access) && !in_array($qr_res->get("{$ps_tablename}.access"), $pa_check_access)) { continue; } $vs_template = $ps_template; // check if we skip this row because of skipIfExpression if (strlen($ps_skip_if_expression) > 0) { $va_expression_tags = caGetTemplateTags($ps_skip_if_expression); foreach ($va_expression_tags as $vs_expression_tag) { if (!isset($va_expression_vars[$vs_expression_tag])) { $va_expression_vars[$vs_expression_tag] = $qr_res->get($vs_expression_tag, array('assumeDisplayField' => true, 'returnIdno' => true, 'delimiter' => ';')); } } if (ExpressionParser::evaluate($ps_skip_if_expression, $va_expression_vars)) { continue; } } // Grab values for codes used in ifdef and ifnotdef directives $va_directive_tag_vals = array(); foreach ($va_directive_tags as $vs_directive_tag) { $va_directive_tag_vals[$vs_directive_tag] = $qr_res->get($vs_directive_tag, array('assumeDisplayField' => true, 'convertCodesToDisplayText' => true, 'dontUseElementTemplate' => true)); } $o_parsed_template = str_get_dom($vs_template); while (sizeof($vo_templates = $o_parsed_template('ifcount:not(:has(ifdef,ifndef,ifcount)),ifdef:not(:has(ifdef,ifndef,ifcount)),ifndef:not(:has(ifdef,ifndef,ifcount))')) > 0) { foreach ($vo_templates as $vn_index => $vo_element) { $vs_code = $vo_element->code; switch ($vo_element->tag) { case 'ifdef': if (strpos($vs_code, "|") !== false) { $vs_bool = 'OR'; $va_tag_list = explode("|", $vs_code); $vb_output = false; } else { $vs_bool = 'AND'; $va_tag_list = explode(",", $vs_code); $vb_output = true; } foreach ($va_tag_list as $vs_tag_to_test) { $vs_tag_to_test = preg_replace("!%.*\$!", "", $vs_tag_to_test); $vb_value_is_set = isset($va_directive_tag_vals[$vs_tag_to_test]) && strlen($va_directive_tag_vals[$vs_tag_to_test]) > 1; switch ($vs_bool) { case 'OR': if ($vb_value_is_set) { $vb_output = true; break 2; } // any must be defined; if any is defined output break; case 'AND': default: if (!$vb_value_is_set) { $vb_output = false; break 2; } // all must be defined; if any is not defined don't output break; } } if ($vb_output) { $vs_template = str_replace($vo_element->html(), $vo_element->getInnerText(), $vs_template); } else { $vs_template = str_replace($vo_element->html(), '', $vs_template); } break; case 'ifndef': if (strpos($vs_code, "|") !== false) { $vs_bool = 'OR'; $va_tag_list = explode("|", $vs_code); $vb_output = false; } else { $vs_bool = 'AND'; $va_tag_list = explode(",", $vs_code); $vb_output = true; } $vb_output = true; foreach ($va_tag_list as $vs_tag_to_test) { $vb_value_is_set = (bool) (isset($va_directive_tag_vals[$vs_tag_to_test]) && strlen($va_directive_tag_vals[$vs_tag_to_test]) > 0); switch ($vs_bool) { case 'OR': if (!$vb_value_is_set) { $vb_output = true; break 2; } // any must be not defined; if anything is not set output break; case 'AND': default: if ($vb_value_is_set) { $vb_output = false; break 2; } // all must be not defined; if anything is set don't output break; } } if ($vb_output) { $vs_template = str_replace($vo_element->html(), $vo_element->getInnerText(), $vs_template); } else { $vs_template = str_replace($vo_element->html(), '', $vs_template); } break; case 'ifcount': if (is_array($va_if_codes = preg_split("![\\|,;]+!", $vs_code))) { $vn_min = (int) $vo_element->min; $vn_max = (int) $vo_element->max; $va_restrict_to_types = preg_split("![,; ]+!", $vo_element->restrictToTypes); $va_restrict_to_relationship_types = preg_split("![,; ]+!", $vo_element->restrictToRelationshipTypes); $vn_count = 0; foreach ($va_if_codes as $vs_if_code) { if ($t_table = $o_dm->getInstanceByTableName($vs_if_code, true)) { $va_count_vals = $qr_res->get($vs_if_code . "." . $t_table->primaryKey(), array('restrictToTypes' => $va_restrict_to_types, 'restrictToRelationshipTypes' => $va_restrict_to_relationship_types, 'returnAsArray' => true, 'checkAccess' => $pa_check_access)); } else { $va_count_vals = $qr_res->get($vs_if_code, array('returnAsArray' => true, 'restrictToTypes' => $va_restrict_to_types, 'restrictToRelationshipTypes' => $va_restrict_to_relationship_types, 'checkAccess' => $pa_check_access)); } if (is_array($va_count_vals)) { $va_bits = explode(".", $vs_if_code); $vs_fld = array_pop($va_bits); foreach ($va_count_vals as $vs_count_val) { if (is_array($vs_count_val)) { if (isset($vs_count_val[$vs_fld]) && !trim($vs_count_val[$vs_fld])) { continue; } $vb_is_set = false; foreach ($vs_count_val as $vs_f => $vs_v) { if (trim($vs_v)) { $vb_is_set = true; break; } } if (!$vb_is_set) { continue; } } else { if (!trim($vs_count_val)) { continue; } } $vn_count++; } } } if ($vn_min <= $vn_count && ($vn_max >= $vn_count || !$vn_max)) { $vs_template = str_replace($vo_element->html(), $vo_element->getInnerText(), $vs_template); } else { $vs_template = str_replace($vo_element->html(), '', $vs_template); } } break; } } $o_parsed_template = str_get_dom($vs_template); // reparse } $va_proc_templates[$vn_i] = $vs_template; foreach ($va_units as $k => $va_unit) { if (!$va_unit['content']) { continue; } $va_relative_to_tmp = $va_unit['relativeTo'] ? explode(".", $va_unit['relativeTo']) : array($ps_tablename); if (!($t_rel_instance = $o_dm->getInstanceByTableName($va_relative_to_tmp[0], true))) { continue; } $vs_unit_delimiter = caGetOption('delimiter', $va_unit, $vs_delimiter); $vs_unit_skip_if_expression = caGetOption('skipIfExpression', $va_unit, false); // additional get options for pulling related records $va_get_options = array('returnAsArray' => true, 'checkAccess' => $pa_check_access); if ($va_unit['restrictToTypes'] && strlen($va_unit['restrictToTypes']) > 0) { $va_get_options['restrictToTypes'] = preg_split('![\\|,;]+!', $va_unit['restrictToTypes']); } if ($va_unit['restrictToRelationshipTypes'] && strlen($va_unit['restrictToRelationshipTypes']) > 0) { $va_get_options['restrictToRelationshipTypes'] = preg_split('![\\|,;]+!', $va_unit['restrictToRelationshipTypes']); } if ($va_unit['sort'] && is_array($va_unit['sort'])) { $va_get_options['sort'] = $va_unit['sort']; $va_get_options['sortDirection'] = $va_unit['sortDirection']; } if (sizeof($va_relative_to_tmp) == 1 && $va_relative_to_tmp[0] == $ps_tablename || sizeof($va_relative_to_tmp) >= 1 && $va_relative_to_tmp[0] == $ps_tablename && $va_relative_to_tmp[1] != 'related') { switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".hierarchy." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".parent." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".children." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: $va_relative_ids = array($vs_pk_val); break; } // process template for all records selected by unit tag $va_tmpl_val = caProcessTemplateForIDs($va_unit['content'], $va_relative_to_tmp[0], $va_relative_ids, array_merge($pa_options, array('sort' => $va_get_options['sort'], 'sortDirection' => $va_get_options['sortDirection'], 'returnAsArray' => true, 'delimiter' => $vs_unit_delimiter, 'resolveLinksUsing' => null, 'skipIfExpression' => $vs_unit_skip_if_expression))); $va_proc_templates[$vn_i] = str_ireplace($va_unit['tag'], join($vs_unit_delimiter, $va_tmpl_val), $va_proc_templates[$vn_i]); } else { switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".hierarchy." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".parent." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".children." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'related': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".related." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: if (method_exists($t_instance, 'isSelfRelationship') && $t_instance->isSelfRelationship()) { $va_relative_ids = array_values($t_instance->getRelatedIDsForSelfRelationship($va_primary_ids[$t_rel_instance->tableName()], array($vs_pk_val))); } else { $va_relative_ids = array_values($qr_res->get($t_rel_instance->tableName() . "." . $t_rel_instance->primaryKey(), $va_get_options)); } break; } $vs_tmpl_val = caProcessTemplateForIDs($va_unit['content'], $va_relative_to_tmp[0], $va_relative_ids, array_merge($pa_options, array('sort' => $va_unit['sort'], 'sortDirection' => $va_unit['sortDirection'], 'delimiter' => $vs_unit_delimiter, 'resolveLinksUsing' => null, 'skipIfExpression' => $vs_unit_skip_if_expression))); $va_proc_templates[$vn_i] = str_ireplace($va_unit['tag'], $vs_tmpl_val, $va_proc_templates[$vn_i]); } } if (!strlen(trim($va_proc_templates[$vn_i]))) { $va_proc_templates[$vn_i] = null; } if (!sizeof($va_tags)) { $vn_i++; continue; } // if there are no tags in the template then we don't need to process further if ($ps_resolve_links_using !== $ps_tablename) { $va_resolve_links_using_row_ids += $qr_res->get("{$ps_resolve_links_using}.{$vs_resolve_links_using_pk}", array('returnAsArray' => true, 'checkAccess' => $pa_check_access)); // we need to remove "primary_ids" from the list, since for self-relations these will be the side(s) of the relations we're viewing *from* if (is_array($va_primary_ids[$ps_resolve_links_using]) && sizeof($va_primary_ids[$ps_resolve_links_using])) { $va_resolve_links_using_row_ids = array_values(array_diff($va_resolve_links_using_row_ids, $va_primary_ids[$ps_resolve_links_using])); } } $va_tag_val_list[$vn_i] = array(); $va_defined_tag_list[$vn_i] = array(); $va_tag_opts = $va_tag_filters = array(); foreach ($va_tags as $vs_tag) { $va_tmp = explode('.', $vs_tag); $vs_last_element = $va_tmp[sizeof($va_tmp) - 1]; $va_tag_opt_tmp = explode("%", $vs_last_element); if (sizeof($va_tag_opt_tmp) > 1) { $vs_tag_bit = array_shift($va_tag_opt_tmp); // get rid of getspec foreach ($va_tag_opt_tmp as $vs_tag_opt_raw) { if (preg_match("!^\\[([^\\]]+)\\]\$!", $vs_tag_opt_raw, $va_matches)) { if (sizeof($va_filter = explode("=", $va_matches[1])) == 2) { $va_tag_filters[$va_filter[0]] = $va_filter[1]; } continue; } $va_tag_tmp = explode("=", $vs_tag_opt_raw); $va_tag_tmp[0] = trim($va_tag_tmp[0]); $va_tag_tmp[1] = trim($va_tag_tmp[1]); if (in_array($va_tag_tmp[0], array('delimiter', 'hierarchicalDelimiter'))) { $va_tag_tmp[1] = str_replace("_", " ", $va_tag_tmp[1]); } if (sizeof($va_tag_line_tmp = explode("|", $va_tag_tmp[1])) > 1) { $va_tag_opts[trim($va_tag_tmp[0])] = $va_tag_line_tmp; } else { $va_tag_opts[trim($va_tag_tmp[0])] = $va_tag_tmp[1]; } } $va_tmp[sizeof($va_tmp) - 1] = $vs_tag_bit; // remove option from tag-part array $vs_tag_proc = join(".", $va_tmp); $va_proc_templates[$vn_i] = str_replace($vs_tag, $vs_tag_proc, $va_proc_templates[$vn_i]); $vs_tag = $vs_tag_proc; } switch ($vs_tag) { case 'DATE': $vs_format = urldecode(caGetOption('format', $va_tag_opts, 'd M Y')); $va_proc_templates[$vn_i] = str_replace("^{$vs_tag}", date($vs_format), $va_proc_templates[$vn_i]); continue 2; break; } $pa_options = array_merge($pa_options, $va_tag_opts); // Default label tag to hierarchies if (isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels'] && $vs_tag == 'label') { unset($va_related_values[$vs_pk_val][$vs_tag]); unset($va_relationship_values[$vs_pk_val][$vs_tag]); $va_tmp = array($ps_tablename, 'hierarchy', 'preferred_labels'); } if (!isset($va_relationship_values[$vs_pk_val])) { $va_relationship_values[$vs_pk_val] = array(0 => null); } foreach ($va_relationship_values[$vs_pk_val] as $vn_relation_id => $va_relationship_value_array) { $vb_is_related = false; $va_val = null; if (isset($va_relationship_value_array[$vs_tag]) && !(isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels'] && $vs_tag == 'label')) { $va_val = array($vs_val = $va_relationship_value_array[$vs_tag]); } elseif (isset($va_relationship_value_array[$vs_tag])) { $va_val = array($vs_val = $va_relationship_value_array[$vs_tag]); } else { if (isset($va_related_values[$vs_pk_val][$vs_tag])) { $va_val = array($vs_val = $va_related_values[$vs_pk_val][$vs_tag]); } else { // // see if this is a reference to a related table // if (in_array($vs_tag, array("relationship_typename", "relationship_type_id", "relationship_typecode", "relationship_type_code"))) { $vb_is_related = true; switch ($vs_tag) { case 'relationship_typename': $vs_spec = 'preferred_labels.' . (caGetOption('orientation', $pa_options, 'LTOR') == 'LTOR' ? 'typename' : 'typename_reverse'); break; case 'relationship_type_id': $vs_spec = 'type_id'; break; case 'relationship_typecode': case 'relationship_type_code': default: $vs_spec = 'type_code'; break; } $vs_rel = $qr_res->get("ca_relationship_types.{$vs_spec}", array_merge($pa_options, $va_tag_opts, array('returnAsArray' => false))); $va_val = array($vs_rel); } elseif ($ps_tablename != $va_tmp[0] && ($t_tmp = $o_dm->getInstanceByTableName($va_tmp[0], true))) { // if the part of the tag before a "." (or the tag itself if there are no periods) is a related table then try to fetch it as related to the current record if (isset($pa_options['placeholderPrefix']) && $pa_options['placeholderPrefix'] && $va_tmp[0] != $pa_options['placeholderPrefix'] && sizeof($va_tmp) == 1) { $vs_get_spec = array_shift($va_tmp) . "." . $pa_options['placeholderPrefix']; if (sizeof($va_tmp) > 0) { $vs_get_spec .= "." . join(".", $va_tmp); } } else { $vs_get_spec = $vs_tag; } $va_spec_bits = explode(".", $vs_get_spec); if (sizeof($va_spec_bits) == 1 && $o_dm->getTableNum($va_spec_bits[0])) { $vs_get_spec .= ".preferred_labels"; } $va_additional_options = array('returnAsArray' => true, 'checkAccess' => $pa_check_access); $vs_hierarchy_name = null; $vb_is_hierarchy = false; if (in_array($va_spec_bits[1], array('hierarchy', '_hierarchyName'))) { $t_rel = $o_dm->getInstanceByTableName($va_spec_bits[0], true); switch ($t_rel->getProperty('HIERARCHY_TYPE')) { case __CA_HIER_TYPE_SIMPLE_MONO__: $va_additional_options['removeFirstItems'] = 1; break; case __CA_HIER_TYPE_MULTI_MONO__: $vs_hierarchy_name = $t_rel->getHierarchyName($qr_res->get($t_rel->tableName() . "." . $t_rel->primaryKey(), array('checkAccess' => $pa_check_access))); $va_additional_options['removeFirstItems'] = 1; break; } } if ($va_spec_bits[1] != '_hierarchyName') { $va_val = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_additional_options, array('returnWithStructure' => true, 'returnBlankValues' => true, 'returnAllLocales' => true, 'useLocaleCodes' => false, 'filters' => $va_tag_filters, 'primaryIDs' => $va_primary_ids))); } else { $va_val = array(); } if (is_array($va_primary_ids) && isset($va_primary_ids[$va_spec_bits[0]]) && is_array($va_primary_ids[$va_spec_bits[0]])) { foreach ($va_primary_ids[$va_spec_bits[0]] as $vn_primary_id) { unset($va_val[$vn_primary_id]); } } if ($va_spec_bits[1] !== 'hierarchy') { $va_val = caExtractValuesByUserLocale($va_val); $va_val_tmp = array(); foreach ($va_val as $vn_d => $va_vals) { if (is_array($va_vals)) { $va_val_tmp = array_merge($va_val_tmp, array_values($va_vals)); } else { $va_val_tmp[] = $va_vals; } } $va_val = $va_val_tmp; } $va_val_proc = array(); switch ($va_spec_bits[1]) { case '_hierarchyName': if ($vs_hierarchy_name) { $va_val_proc[] = $vs_hierarchy_name; } break; case 'hierarchy': if (is_array($va_val) && sizeof($va_val) > 0) { $va_hier_list = array(); if ($vs_hierarchy_name) { array_unshift($va_hier_list, $vs_hierarchy_name); } $vs_name = end($va_spec_bits); foreach ($va_val as $va_hier) { $va_hier = caExtractValuesByUserLocale($va_hier); foreach ($va_hier as $va_hier_item) { foreach ($va_hier_item as $va_hier_value) { $va_hier_list[] = $va_hier_value[$vs_name] ? $va_hier_value[$vs_name] : array_shift($va_hier_value); } } } $va_val_proc[] = join(caGetOption("delimiter", $va_tag_opts, $vs_delimiter), $va_hier_list); } break; case 'parent': if (is_array($va_val)) { foreach ($va_val as $vm_label) { if (is_array($vm_label)) { $t_rel = $o_dm->getInstanceByTableName($va_spec_bits[0], true); if (!$t_rel || !method_exists($t_rel, "getLabelDisplayField")) { $va_val_proc[] = join("; ", $vm_label); } else { $va_val_proc[] = $vm_label[$t_rel->getLabelDisplayField()]; } } else { $va_val_proc[] = $vm_label; } } } break; default: $vs_terminal = end($va_spec_bits); foreach ($va_val as $va_val_container) { if (!is_array($va_val_container)) { if ($va_val_container) { $va_val_proc[] = $va_val_container; } continue; } // Add display field to *_labels terminals if (in_array($vs_terminal, array('preferred_labels', 'nonpreferred_labels')) && !$va_val_container[$vs_terminal]) { $t_rel = $o_dm->getInstanceByTableName($va_spec_bits[0], true); $vs_terminal = $t_rel->getLabelDisplayField(); } $va_val_proc[] = $va_val_container[$vs_terminal]; } break; } $va_val = $va_val_proc; $vb_is_related = true; } else { // // Handle non-related gets // // Default specifiers that end with a modifier to preferred labels if (sizeof($va_tmp) == 2 && in_array($va_tmp[1], array('hierarchy', 'children', 'parent', 'related'))) { array_push($va_tmp, 'preferred_labels'); } $vs_hierarchy_name = null; if (in_array($va_tmp[1], array('hierarchy', '_hierarchyName'))) { switch ($t_instance->getProperty('HIERARCHY_TYPE')) { case __CA_HIER_TYPE_SIMPLE_MONO__: $va_additional_options['removeFirstItems'] = 1; break; case __CA_HIER_TYPE_MULTI_MONO__: $vs_hierarchy_name = $t_instance->getHierarchyName($qr_res->get($t_instance->tableName() . "." . $t_instance->primaryKey(), array('checkAccess' => $pa_check_access))); $va_additional_options['removeFirstItems'] = 1; break; } } if ($va_tmp[0] == $ps_tablename) { array_shift($va_tmp); } // get rid of primary table if it's in the field spec if (!sizeof($va_tmp) && $t_instance->getProperty('LABEL_TABLE_NAME')) { $va_tmp[] = "preferred_labels"; } if (isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels']) { if (!in_array($va_tmp[0], array('hierarchy', 'children', 'parent', 'related')) && $va_tmp[1] == 'preferred_labels') { array_unshift($va_tmp, 'hierarchy'); } } if (isset($pa_options['placeholderPrefix']) && $pa_options['placeholderPrefix'] && $va_tmp[0] != $pa_options['placeholderPrefix']) { array_splice($va_tmp, -1, 0, $pa_options['placeholderPrefix']); } $vs_get_spec = "{$ps_tablename}." . join(".", $va_tmp); if (in_array($va_tmp[0], array('parent'))) { $va_val[] = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_tag_opts, array('returnAsArray' => false))); } elseif ($va_tmp[0] == '_hierarchyName') { $va_val[] = $vs_hierarchy_name; } else { $va_val_tmp = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_tag_opts, array('returnAsArray' => true, 'returnBlankValues' => true, 'assumeDisplayField' => true, 'filters' => $va_tag_filters, 'checkAccess' => $pa_check_access))); $va_val = array(); if (is_array($va_val_tmp)) { //$va_val_tmp = array_reverse($va_val_tmp); if ($va_tmp[0] == 'hierarchy') { if ($vs_hierarchy_name) { array_shift($va_val_tmp); // remove root array_unshift($va_val_tmp, $vs_hierarchy_name); // replace with hierarchy name } if ($vs_delimiter_tmp = caGetOption('hierarchicalDelimiter', $va_tag_opts)) { $vs_tag_val_delimiter = $vs_delimiter_tmp; } elseif ($vs_delimiter_tmp = caGetOption('hierarchicalDelimiter', $pa_options)) { $vs_tag_val_delimiter = $vs_delimiter_tmp; } elseif ($vs_delimiter_tmp = caGetOption('delimiter', $va_tag_opts, $vs_delimiter)) { $vs_tag_val_delimiter = $vs_delimiter_tmp; } else { $vs_tag_val_delimiter = $vs_delimiter; } } else { $vs_tag_val_delimiter = caGetOption('delimiter', $va_tag_opts, $vs_delimiter); } foreach ($va_val_tmp as $vn_attr_id => $vm_attr_val) { if (is_array($vm_attr_val)) { $va_val[] = join($vs_tag_val_delimiter, $vm_attr_val); } else { $va_val[] = $vm_attr_val; } } } if (sizeof($va_val) > 1 && $va_tmp[0] == 'hierarchy') { $vs_tag_val_delimiter = caGetOption('delimiter', $va_tag_opts, $vs_delimiter); $va_val = array(join($vs_tag_val_delimiter, $va_val)); } } } } } if (is_array($va_val)) { if (sizeof($va_val) > 0) { foreach ($va_val as $vn_j => $vs_val) { if (!is_array($va_tag_val_list[$vn_i][$vn_j][$vs_tag]) || !in_array($vs_val, $va_tag_val_list[$vn_i][$vn_j][$vs_tag])) { $va_tag_val_list[$vn_i][$vn_j][$vs_tag][] = $vs_val; if (is_array($vs_val) && sizeof($vs_val) || strlen($vs_val) > 0) { $va_defined_tag_list[$vn_i][$vn_j][$vs_tag] = true; } } } } else { $va_tag_val_list[$vn_i][0][$vs_tag] = null; $va_defined_tag_list[$vn_i][0][$vs_tag] = false; } } } } $vn_i++; } foreach ($va_tag_val_list as $vn_i => $va_tags_list) { // do sorting? if (is_array($pa_sort)) { $va_sorted_values = $va_sorted_values_tmp = array(); foreach ($va_tags_list as $vn_j => $va_values_by_field) { $vs_key = ''; foreach ($pa_sort as $vn_k => $vs_sort) { if (!isset($va_values_by_field[$vs_sort])) { continue; } $vs_subkey = null; foreach ($va_values_by_field[$vs_sort] as $vn_x => $vs_sort_subval) { if ($va_date = caDateToHistoricTimestamps($vs_sort_subval)) { // try to treat it as a date if ($ps_sort_direction == 'DESC' && ($va_date[0] < $vs_subkey || is_null($vs_subkey))) { $vs_subkey = $va_date[0]; } elseif ($va_date[0] > $vs_subkey || is_null($vs_subkey)) { $vs_subkey = $va_date[0]; } } else { $vs_sort_subval = str_pad($vs_sort_subval, 20, ' ', STR_PAD_LEFT); if ($ps_sort_direction == 'DESC' && ($vs_sort_subval < $vs_subkey || is_null($vs_subkey))) { $vs_subkey = $vs_sort_subval; } elseif ($vs_sort_subval > $vs_subkey || is_null($vs_subkey)) { $vs_subkey = $vs_sort_subval; } } } $vs_key .= $vs_subkey; $va_sorted_values_tmp[$vs_key][] = $va_values_by_field; } } ksort($va_sorted_values_tmp); foreach ($va_sorted_values_tmp as $vs_key => $va_value_list) { foreach ($va_value_list as $vn_x => $va_val) { $va_sorted_values[$vs_key . $vn_x] = $va_val; } } if ($ps_sort_direction == 'DESC') { $va_sorted_values = array_reverse($va_sorted_values); } if (sizeof($va_sorted_values) > 0) { $va_tag_val_list[$vn_i] = $va_tags_list = $va_sorted_values; } } $va_acc = array(); foreach ($va_tags_list as $vn_j => $va_tags) { $va_tag_list = array(); $va_pt_vals = array(); $vs_template = $va_proc_templates[$vn_i]; // Process <if> foreach ($va_if as $va_def_con) { if (ExpressionParser::evaluate($va_def_con['rule'], $va_tags)) { $vs_template = str_replace($va_def_con['directive'], $va_def_con['content'], $vs_template); } else { $vs_template = str_replace($va_def_con['directive'], '', $vs_template); } } // Process <more> tags foreach ($va_mores as $vn_more_index => $va_more) { if (($vn_pos = strpos($vs_template, $va_more['directive'])) !== false) { if (isset($va_mores[$vn_more_index + 1]) && ($vn_next_more_pos = strpos(substr($vs_template, $vn_pos + strlen($va_more['directive'])), $va_mores[$vn_more_index + 1]['directive'])) !== false) { $vn_next_more_pos += $vn_pos; $vs_partial_template = substr($vs_template, $vn_pos + strlen($va_more['directive']), $vn_next_more_pos - $vn_pos); } else { $vs_partial_template = substr($vs_template, $vn_pos + strlen($va_more['directive'])); } $vb_output = false; foreach (array_keys($va_defined_tag_list[$vn_i][$vn_j]) as $vs_defined_tag) { if (strpos($vs_partial_template, $vs_defined_tag) !== false) { // content is defined $vb_output = true; break; } } if ($vb_output) { $vs_template = preg_replace('!' . $va_more['directive'] . '!', $va_more['content'], $vs_template, 1); } else { $vs_template = preg_replace('!' . $va_more['directive'] . '!', '', $vs_template, 1); } } } // Process <between> tags - text to be output if it is between two defined values $va_between_positions = array(); foreach ($va_betweens as $vn_between_index => $va_between) { $vb_output_before = $vb_output_after = false; if (($vn_cur_pos = strpos($vs_template, $va_between['directive'])) !== false) { $va_between_positions[$vn_between_index] = $vn_cur_pos; // Get parts of template before tag and after tag $vs_partial_template_before = substr($vs_template, 0, $vn_cur_pos); $vs_partial_template_after = substr($vs_template, $vn_cur_pos + strlen($va_between['directive'])); // Only get the template between our current position and the next <between> tag if (isset($va_betweens[$vn_between_index + 1]) && ($vn_after_pos_relative = strpos($vs_partial_template_after, $va_betweens[$vn_between_index + 1]['directive'])) !== false) { $vs_partial_template_after = substr($vs_partial_template_after, 0, $vn_after_pos_relative); } // Check for defined value before and after tag foreach (array_keys($va_defined_tag_list[$vn_i][$vn_j]) as $vs_defined_tag) { if (strpos($vs_partial_template_before, $vs_defined_tag) !== false) { // content is defined $vb_output_after = true; } if (strpos($vs_partial_template_after, $vs_defined_tag) !== false) { // content is defined $vb_output_before = true; break; } if ($vb_output_before && $vb_output_after) { break; } } } if ($vb_output_before && $vb_output_after) { $vs_template = preg_replace('!' . $va_between['directive'] . '!', $va_between['content'], $vs_template, 1); } else { $vs_template = preg_replace('!' . $va_between['directive'] . '!', '', $vs_template, 1); } } // // Need to sort tags by length descending (longest first) // so that when we go to substitute and you have a tag followed by itself with a suffix // (ex. ^measurements and ^measurements2) we don't substitute both for the stub (ex. ^measurements) // $va_tags_tmp = array_keys($va_tags); usort($va_tags_tmp, function ($a, $b) { return strlen($b) - strlen($a); }); $vs_pt = $vs_template; foreach ($va_tags_tmp as $vs_tag) { $vs_pt = str_replace('^' . $vs_tag, is_array($va_tags[$vs_tag]) ? join(" | ", $va_tags[$vs_tag]) : $va_tags[$vs_tag], $vs_pt); } if ($vs_pt) { $va_pt_vals[] = $vs_pt; } if ($vs_acc_val = join(isset($pa_options['delimiter']) ? $pa_options['delimiter'] : $vs_delimiter, $va_pt_vals)) { $va_acc[] = $vs_acc_val; } } $va_proc_templates[$vn_i] = join($vs_delimiter, $va_acc); } if ($pb_return_as_array && !caGetOption('includeBlankValuesInArray', $pa_options, false)) { foreach ($va_proc_templates as $vn_i => $vs_template) { if (!strlen(trim($vs_template))) { unset($va_proc_templates[$vn_i]); } } } // Transform links $va_proc_templates = caCreateLinksFromText($va_proc_templates, $ps_resolve_links_using, $ps_resolve_links_using != $ps_tablename ? $va_resolve_links_using_row_ids : $pa_row_ids, null, caGetOption('linkTarget', $pa_options, null), array_merge(array('addRelParameter' => true), $pa_options)); // Kill any lingering tags (just in case) foreach ($va_proc_templates as $vn_i => $vs_proc_template) { $va_proc_templates[$vn_i] = preg_replace("!\\^([A-Za-z0-9_\\.]+[%]{1}[^ \\^\t\r\n\"\\'<>\\(\\)\\{\\}\\/\\[\\]]*|[A-Za-z0-9_\\.]+)!", "", $vs_proc_template); $va_proc_templates[$vn_i] = str_replace("<![CDATA[", "", $va_proc_templates[$vn_i]); $va_proc_templates[$vn_i] = str_replace("]]>", "", $va_proc_templates[$vn_i]); } if ($pb_return_as_array) { return $va_proc_templates; } return join($vs_delimiter, $va_proc_templates); }
/** * Processes single exporter item for a given record * * @param int $pn_item_id Primary of exporter item * @param int $pn_table_num Table num of item to export * @param int $pn_record_id Primary key value of item to export * @param array $pa_options * ignoreContext = don't switch context even though context may be set for current item * relationship_type_id, relationship_type_code, relationship_typename = * if this export is a sub-export (context-switch), we have no way of knowing the relationship * to the 'parent' element in the export, so there has to be a means to pass it down to make it accessible * attribute_id = signals that this is an export relative to a specific attribute instance * this triggers special behavior that allows getting container values in a kind of sub-export * it's really only useful for Containers but in theory can be any attribute * logger = KLogger instance to use for logging. This option is mandatory! * @return array Item info */ public function processExporterItem($pn_item_id, $pn_table_num, $pn_record_id, $pa_options = array()) { $o_log = caGetOption('logger', $pa_options); // always set by exportRecord() $vb_ignore_context = caGetOption('ignoreContext', $pa_options); $vn_attribute_id = caGetOption('attribute_id', $pa_options); $o_log->logInfo(_t("Export mapping processor called with parameters [exporter_item_id:%1 table_num:%2 record_id:%3]", $pn_item_id, $pn_table_num, $pn_record_id)); $t_exporter_item = ca_data_exporters::loadExporterItemByID($pn_item_id); $t_instance = ca_data_exporters::loadInstanceByID($pn_record_id, $pn_table_num); // switch context to a different set of records if necessary and repeat current exporter item for all those selected records // (e.g. hierarchy children or related items in another table, restricted by types or relationship types) if (!$vb_ignore_context && ($vs_context = $t_exporter_item->getSetting('context'))) { $va_restrict_to_types = $t_exporter_item->getSetting('restrictToTypes'); $va_restrict_to_rel_types = $t_exporter_item->getSetting('restrictToRelationshipTypes'); $va_restrict_to_bundle_vals = $t_exporter_item->getSetting('restrictToBundleValues'); $va_check_access = $t_exporter_item->getSetting('checkAccess'); $va_sort = $t_exporter_item->getSetting('sort'); $vn_new_table_num = $this->getAppDatamodel()->getTableNum($vs_context); $vb_context_is_related_table = false; $va_related = null; if ($vn_new_table_num) { // switch to new table $vs_key = $this->getAppDatamodel()->getTablePrimaryKeyName($vs_context); } else { // this table, i.e. hierarchy context switch $vs_key = $t_instance->primaryKey(); } $o_log->logInfo(_t("Initiating context switch to '%1' for mapping ID %2 and record ID %3. The processor now tries to find matching records for the switch and calls itself for each of those items.", $vs_context, $pn_item_id, $pn_record_id)); switch ($vs_context) { case 'children': $va_related = $t_instance->getHierarchyChildren(); break; case 'parent': $va_related = array(); if ($vs_parent_id_fld = $t_instance->getProperty("HIERARCHY_PARENT_ID_FLD")) { $va_related[] = array($vs_key => $t_instance->get($vs_parent_id_fld)); } break; case 'ancestors': $va_parents = $t_instance->getHierarchyAncestors(null, array('idsOnly' => true)); $va_related = array(); foreach (array_unique($va_parents) as $vn_pk) { $va_related[] = array($vs_key => intval($vn_pk)); } break; case 'ca_sets': $t_set = new ca_sets(); $va_set_options = array(); if (isset($va_restrict_to_types[0])) { // the utility used below doesn't support passing multiple types so we just pass the first. // this should be enough for 99.99% of the actual use cases anyway $va_set_options['setType'] = $va_restrict_to_types[0]; } $va_set_options['checkAccess'] = $va_check_access; $va_set_options['setIDsOnly'] = true; $va_set_ids = $t_set->getSetsForItem($pn_table_num, $t_instance->getPrimaryKey(), $va_set_options); $va_related = array(); foreach (array_unique($va_set_ids) as $vn_pk) { $va_related[] = array($vs_key => intval($vn_pk)); } break; case 'ca_list_items.firstLevel': if ($t_instance->tableName() == 'ca_lists') { $o_dm = Datamodel::load(); $va_related = array(); $va_items_legacy_format = $t_instance->getListItemsAsHierarchy(null, array('maxLevels' => 1, 'dontIncludeRoot' => true)); $vn_new_table_num = $o_dm->getTableNum('ca_list_items'); $vs_key = 'item_id'; foreach ($va_items_legacy_format as $va_item_legacy_format) { $va_related[$va_item_legacy_format['NODE']['item_id']] = $va_item_legacy_format['NODE']; } break; } else { return array(); } break; default: if ($vn_new_table_num) { $va_options = array('restrictToTypes' => $va_restrict_to_types, 'restrictToRelationshipTypes' => $va_restrict_to_rel_types, 'restrictToBundleValues' => $va_restrict_to_bundle_vals, 'checkAccess' => $va_check_access, 'sort' => $va_sort); $o_log->logDebug(_t("Calling getRelatedItems with options: %1.", print_r($va_options, true))); $va_related = $t_instance->getRelatedItems($vs_context, $va_options); $vb_context_is_related_table = true; } else { // container or invalid context $va_context_tmp = explode('.', $vs_context); if (sizeof($va_context_tmp) != 2) { $o_log->logError(_t("Invalid context %1. Ignoring this mapping.", $vs_context)); return array(); } $va_attrs = $t_instance->getAttributesByElement($va_context_tmp[1]); $va_info = array(); if (is_array($va_attrs) && sizeof($va_attrs) > 0) { $o_log->logInfo(_t("Switching context for element code: %1.", $va_context_tmp[1])); $o_log->logDebug(_t("Raw attribute value array is as follows. The mapping will now be repeated for each (outer) attribute. %1", print_r($va_attrs, true))); foreach ($va_attrs as $vo_attr) { $va_attribute_export = $this->processExporterItem($pn_item_id, $pn_table_num, $pn_record_id, array_merge(array('ignoreContext' => true, 'attribute_id' => $vo_attr->getAttributeID()), $pa_options)); $va_info = array_merge($va_info, $va_attribute_export); } } else { $o_log->logInfo(_t("Switching context for element code %1 failed. Either there is no attribute with that code attached to the current row or the code is invalid. Mapping is ignored for current row.", $va_context_tmp[1])); } return $va_info; } break; } $va_info = array(); if (is_array($va_related)) { $o_log->logDebug(_t("The current mapping will now be repreated for these items: %1", print_r($va_related, true))); if (!$vn_new_table_num) { $vn_new_table_num = $pn_table_num; } foreach ($va_related as $va_rel) { // if we're dealing with a related table, pass on some info the relationship type to the context-switched invocation of processExporterItem(), // because we can't access that information from the related item simply because we don't exactly know where the call originated if ($vb_context_is_related_table) { $pa_options['relationship_typename'] = $va_rel['relationship_typename']; $pa_options['relationship_type_code'] = $va_rel['relationship_type_code']; $pa_options['relationship_type_id'] = $va_rel['relationship_type_id']; } $va_rel_export = $this->processExporterItem($pn_item_id, $vn_new_table_num, $va_rel[$vs_key], array_merge(array('ignoreContext' => true), $pa_options)); $va_info = array_merge($va_info, $va_rel_export); } } else { $o_log->logDebug(_t("No matching related items found for last context switch")); } return $va_info; } // end switch context // Don't prevent context switches for children of context-switched exporter items. This way you can // build cascades for jobs like exporting objects related to the creator of the record in question. unset($pa_options['ignoreContext']); $va_item_info = array(); $vs_source = $t_exporter_item->get('source'); $vs_element = $t_exporter_item->get('element'); $vb_repeat = $t_exporter_item->getSetting('repeat_element_for_multiple_values'); // if omitIfEmpty is set and get() returns nothing, we ignore this exporter item and all children if ($vs_omit_if_empty = $t_exporter_item->getSetting('omitIfEmpty')) { if (!(strlen($t_instance->get($vs_omit_if_empty)) > 0)) { return array(); } } // if omitIfNotEmpty is set and get() returns a value, we ignore this exporter item and all children if ($vs_omit_if_not_empty = $t_exporter_item->getSetting('omitIfNotEmpty')) { if (strlen($t_instance->get($vs_omit_if_not_empty)) > 0) { return array(); } } // always return URL for export, not an HTML tag $va_get_options = array('returnURL' => true); if ($vs_delimiter = $t_exporter_item->getSetting("delimiter")) { $va_get_options['delimiter'] = $vs_delimiter; } if ($vs_template = $t_exporter_item->getSetting('template')) { $va_get_options['template'] = $vs_template; } if ($vs_locale = $t_exporter_item->getSetting('locale')) { // the global UI locale for some reason has a higher priority // than the locale setting in BaseModelWithAttributes::get // which is why we unset it here and restore it later global $g_ui_locale; $vs_old_ui_locale = $g_ui_locale; $g_ui_locale = null; $va_get_options['locale'] = $vs_locale; } // AttributeValue settings that are simply passed through by the exporter if ($t_exporter_item->getSetting('convertCodesToDisplayText')) { $va_get_options['convertCodesToDisplayText'] = true; // try to return text suitable for display for system lists stored in intrinsics (ex. ca_objects.access, ca_objects.status, ca_objects.source_id) // this does not affect list attributes } else { $va_get_options['convertCodesToIdno'] = true; // if display text is not requested try to return list item idno's... since underlying integer ca_list_items.item_id values are unlikely to be useful in an export context } if ($t_exporter_item->getSetting('returnIdno')) { $va_get_options['returnIdno'] = true; } if ($t_exporter_item->getSetting('start_as_iso8601')) { $va_get_options['start_as_iso8601'] = true; } if ($t_exporter_item->getSetting('end_as_iso8601')) { $va_get_options['end_as_iso8601'] = true; } if ($t_exporter_item->getSetting('dontReturnValueIfOnSameDayAsStart')) { $va_get_options['dontReturnValueIfOnSameDayAsStart'] = true; } if ($vs_date_format = $t_exporter_item->getSetting('dateFormat')) { $va_get_options['dateFormat'] = $vs_date_format; } // context was switched to attribute if ($vn_attribute_id) { $o_log->logInfo(_t("Processing mapping in attribute mode for attribute_id = %1.", $vn_attribute_id)); if ($vs_source) { // trying to find the source only makes sense if the source is set $t_attr = new ca_attributes($vn_attribute_id); $va_values = $t_attr->getAttributeValues(); $va_src_tmp = explode('.', $vs_source); if (sizeof($va_src_tmp) == 2) { $o_dm = Datamodel::load(); if ($t_attr->get('table_num') == $o_dm->getTableNum($va_src_tmp[0])) { $vs_source = $va_src_tmp[1]; } } $o_log->logDebug(_t("Trying to find code %1 in value array for the current attribute.", $vs_source)); $o_log->logDebug(_t("Value array is %1.", print_r($va_values, true))); foreach ($va_values as $vo_val) { $va_display_val_options = array(); if ($vo_val instanceof ListAttributeValue) { // figure out list_id -- without it we can't pull display values $t_element = new ca_metadata_elements($vo_val->getElementID()); $va_display_val_options = array('list_id' => $t_element->get('list_id')); if ($t_exporter_item->getSetting('returnIdno') || $t_exporter_item->getSetting('convertCodesToIdno')) { $va_display_val_options['output'] = 'idno'; } elseif ($t_exporter_item->getSetting('convertCodesToDisplayText')) { $va_display_val_options['output'] = 'text'; } } $o_log->logDebug(_t("Trying to match code from array %1 and the code we're looking for %2.", $vo_val->getElementCode(), $vs_source)); if ($vo_val->getElementCode() == $vs_source) { $vs_display_value = $vo_val->getDisplayValue($va_display_val_options); $o_log->logDebug(_t("Found value %1.", $vs_display_value)); $va_item_info[] = array('text' => $vs_display_value, 'element' => $vs_element); } } } else { // no source in attribute context probably means this is some form of wrapper, e.g. a MARC field $va_item_info[] = array('element' => $vs_element); } } else { if ($vs_source) { $o_log->logDebug(_t("Source for current mapping is %1", $vs_source)); $va_matches = array(); // CONSTANT value if (preg_match("/^_CONSTANT_:(.*)\$/", $vs_source, $va_matches)) { $o_log->logDebug(_t("This is a constant. Value for this mapping is '%1'", trim($va_matches[1]))); $va_item_info[] = array('text' => trim($va_matches[1]), 'element' => $vs_element); } else { if (in_array($vs_source, array("relationship_type_id", "relationship_type_code", "relationship_typename"))) { if (isset($pa_options[$vs_source]) && strlen($pa_options[$vs_source]) > 0) { $o_log->logDebug(_t("Source refers to releationship type information. Value for this mapping is '%1'", $pa_options[$vs_source])); $va_item_info[] = array('text' => $pa_options[$vs_source], 'element' => $vs_element); } } else { if (!$vb_repeat) { $vs_get = $t_instance->get($vs_source, $va_get_options); $o_log->logDebug(_t("Source is a simple get() for some bundle. Value for this mapping is '%1'", $vs_get)); $o_log->logDebug(_t("get() options are: %1", print_r($va_get_options, true))); $va_item_info[] = array('text' => $vs_get, 'element' => $vs_element); } else { // user wants current element repeated in case of multiple returned values $va_get_options['delimiter'] = ';#;'; $vs_values = $t_instance->get($vs_source, $va_get_options); $o_log->logDebug(_t("Source is a get() that should be repeated for multiple values. Value for this mapping is '%1'. It includes the custom delimiter ';#;' that is later used to split the value into multiple values.", $vs_values)); $o_log->logDebug(_t("get() options are: %1", print_r($va_get_options, true))); $va_tmp = explode(";#;", $vs_values); foreach ($va_tmp as $vs_text) { $va_item_info[] = array('element' => $vs_element, 'text' => $vs_text); } } } } } else { if ($vs_template) { // templates without source are probably just static text, but you never know // -> run them through processor anyways $vs_proc_template = caProcessTemplateForIDs($vs_template, $pn_table_num, array($pn_record_id), array()); $o_log->logDebug(_t("Current mapping has no source but a template '%1'. Value from extracted via template processor is '%2'", $vs_template, $vs_proc_template)); $va_item_info[] = array('element' => $vs_element, 'text' => $vs_proc_template); } else { // no source, no template -> probably wrapper $o_log->logDebug(_t("Current mapping has no source and no template and is probably an XML/MARC wrapper element")); $va_item_info[] = array('element' => $vs_element); } } } // reset UI locale if we unset it if ($vs_locale) { $g_ui_locale = $vs_old_ui_locale; } $o_log->logDebug(_t("We're now processing other settings like default, prefix, suffix, skipIfExpression, filterByRegExp, maxLength, plugins and replacements for this mapping")); $o_log->logDebug(_t("Local data before processing is: %1", print_r($va_item_info, true))); // handle other settings and plugin hooks $vs_default = $t_exporter_item->getSetting('default'); $vs_prefix = $t_exporter_item->getSetting('prefix'); $vs_suffix = $t_exporter_item->getSetting('suffix'); //$vs_regexp = $t_exporter_item->getSetting('filterByRegExp'); // Deprecated -- remove? $vn_max_length = $t_exporter_item->getSetting('maxLength'); $vs_skip_if_expr = $t_exporter_item->getSetting('skipIfExpression'); $vs_original_values = $t_exporter_item->getSetting('original_values'); $vs_replacement_values = $t_exporter_item->getSetting('replacement_values'); $va_replacements = ca_data_exporter_items::getReplacementArray($vs_original_values, $vs_replacement_values); foreach ($va_item_info as $vn_key => &$va_item) { $this->opo_app_plugin_manager->hookExportItemBeforeSettings(array('instance' => $t_instance, 'exporter_item_instance' => $t_exporter_item, 'export_item' => &$va_item)); // handle dontReturnValueIfOnSameDayAsStart if (caGetOption('dontReturnValueIfOnSameDayAsStart', $va_get_options, false)) { if (strlen($va_item['text']) < 1) { unset($va_item_info[$vn_key]); } } // handle skipIfExpression setting if ($vs_skip_if_expr) { // Add current value as variable "value", accessible in expressions as ^value $va_vars = array_merge(array('value' => $va_item['text']), ca_data_exporters::$s_variables); if (ExpressionParser::evaluate($vs_skip_if_expr, $va_vars)) { unset($va_item_info[$vn_key]); continue; } } // filter by regex (deprecated since you can do the same thing and more with skipIfExpression) -- remove? //if((strlen($va_item['text'])>0) && $vs_regexp) { // if(!preg_match("!".$vs_regexp."!i", $va_item['text'])) { // unset($va_item_info[$vn_key]); // continue; // } //} // do replacements $va_item['text'] = ca_data_exporter_items::replaceText($va_item['text'], $va_replacements); // if text is empty, fill in default // if text isn't empty, respect prefix and suffix if (strlen($va_item['text']) == 0) { if ($vs_default) { $va_item['text'] = $vs_default; } } else { if (strlen($vs_prefix) > 0 || strlen($vs_suffix) > 0) { $va_item['text'] = $vs_prefix . $va_item['text'] . $vs_suffix; } } if ($vn_max_length && strlen($va_item['text']) > $vn_max_length) { $va_item['text'] = substr($va_item['text'], 0, $vn_max_length) . " ..."; } // if this is a variable, set the value and delete it from the export tree $va_matches = array(); if (preg_match("/^_VARIABLE_:(.*)\$/", $va_item['element'], $va_matches)) { ca_data_exporters::$s_variables[$va_matches[1]] = $va_item['text']; unset($va_item_info[$vn_key]); continue; } // if returned value is null then we skip the item $this->opo_app_plugin_manager->hookExportItem(array('instance' => $t_instance, 'exporter_item_instance' => $t_exporter_item, 'export_item' => &$va_item)); } $o_log->logInfo(_t("Extracted data for this mapping is as follows:")); foreach ($va_item_info as $va_tmp) { $o_log->logInfo(sprintf(" element:%-20s value: %-10s", $va_tmp['element'], $va_tmp['text'])); } $va_children = $t_exporter_item->getHierarchyChildren(); if (is_array($va_children) && sizeof($va_children) > 0) { $o_log->logInfo(_t("Now proceeding to process %1 direct children in the mapping hierarchy", sizeof($va_children))); foreach ($va_children as $va_child) { foreach ($va_item_info as &$va_info) { $va_child_export = $this->processExporterItem($va_child['item_id'], $pn_table_num, $pn_record_id, $pa_options); $va_info['children'] = array_merge((array) $va_info['children'], $va_child_export); } } } return $va_item_info; }