Exemplo n.º 1
0
/**
 * 
 *
 * @param string $ps_refinery_name 
 * 
 * @return array
 */
function caGenericImportSplitter($ps_refinery_name, $ps_item_prefix, $ps_table, $po_refinery_instance, &$pa_destination_data, $pa_group, $pa_item, $pa_source_data, $pa_options)
{
    global $g_ui_locale_id;
    $po_refinery_instance->setReturnsMultipleValues(true);
    $o_dm = Datamodel::load();
    $po_refinery_instance->setReturnsMultipleValues(true);
    $o_log = caGetOption('log', $pa_options, null);
    $o_reader = caGetOption('reader', $pa_options, null);
    $o_trans = caGetOption('transaction', $pa_options, null);
    $pn_value_index = caGetOption('valueIndex', $pa_options, 0);
    // We can probably always use the item destination – using group destination is a vestige of older code and no longer is used
    // but we're leaving it in for now as a fallback it item dest is not set for some reason
    $va_group_dest = isset($pa_item['destination']) && $pa_item['destination'] ? explode(".", $pa_item['destination']) : explode(".", $pa_group['destination']);
    $vs_terminal = array_pop($va_group_dest);
    $vs_dest_table = $va_group_dest[0];
    $va_group_dest[] = $vs_terminal;
    $pm_value = !isset($pa_source_data[$pa_item['source']]) && $o_reader ? caProcessImportItemSettingsForValue($o_reader->get($pa_item['source'], array('returnAsArray' => true)), $pa_item['settings']) : $pa_source_data[$pa_item['source']];
    if (is_array($pm_value)) {
        if (isset($pm_value[$pn_value_index])) {
            $va_delimited_items = $pm_value[$pn_value_index];
            // for input formats that support repeating values
        } else {
            $va_delimited_items = array_shift($va_delimited_items);
        }
    } else {
        $va_delimited_items = array($pm_value);
    }
    if (!is_array($va_delimited_items)) {
        $va_delimited_items = array($va_delimited_items);
    }
    $va_delimiter = $pa_item['settings']["{$ps_refinery_name}_delimiter"];
    if (!is_array($va_delimiter)) {
        $va_delimiter = array($va_delimiter);
    }
    if (sizeof($va_delimiter)) {
        foreach ($va_delimiter as $vn_index => $vs_delim) {
            if (!trim($vs_delim, "\t ")) {
                unset($va_delimiter[$vn_index]);
                continue;
            }
            $va_delimiter[$vn_index] = preg_quote($vs_delim, "!");
        }
    }
    $va_match_on = caGetOption('matchOn', $pa_options, null);
    if (!is_array($va_match_on) && $va_match_on) {
        $va_match_on = array($va_match_on);
    } elseif (is_array($va_match_on = $pa_item['settings']["{$ps_refinery_name}_matchOn"])) {
        $pa_options['matchOn'] = $va_match_on;
    }
    $pb_dont_create = caGetOption('dontCreate', $pa_options, (bool) $pa_item['settings']["{$ps_refinery_name}_dontCreate"]);
    $va_vals = array();
    $vn_c = 0;
    if (!($t_instance = $o_dm->getInstanceByTableName($ps_table, true))) {
        return array();
    }
    if ($o_trans) {
        $t_instance->setTransaction($o_trans);
    }
    $vs_label_fld = $t_instance->getLabelDisplayField();
    if (sizeof($va_group_dest) == 1 && $vs_terminal == $ps_table || $vs_terminal != $ps_table && sizeof($va_group_dest) > 1) {
        foreach ($va_delimited_items as $vn_x => $vs_delimited_item) {
            $va_items = sizeof($va_delimiter) ? preg_split("!(" . join("|", $va_delimiter) . ")!", $vs_delimited_item) : array($vs_delimited_item);
            foreach ($va_items as $vn_i => $vs_item) {
                $va_parents = $pa_item['settings']["{$ps_refinery_name}_parents"];
                if (!($vs_item = trim($vs_item))) {
                    if (is_array($va_parents) && sizeof($va_parents) > 0) {
                        // try to ladder up the parents hierarchy since the base value is blank (see PROV-972)
                        $vs_display_field = $t_instance->getLabelDisplayField();
                        while (sizeof($va_parents) > 0) {
                            $va_p = array_pop($va_parents);
                            if ($vs_laddered_val = BaseRefinery::parsePlaceholder($va_p[$vs_display_field], $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader, 'delimiter' => $va_delimiter, 'returnDelimitedValueAt' => $vn_x))) {
                                if ($o_log) {
                                    $o_log->logDebug(_t('[{$ps_refinery_name}] Used parent value %1 because the mapped value was blank', $vs_item));
                                }
                                $vs_item = $vs_laddered_val;
                                break;
                            }
                        }
                    }
                    if (!$vs_item) {
                        continue;
                    }
                }
                if (is_array($va_skip_values = $pa_item['settings']["{$ps_refinery_name}_skipIfValue"]) && in_array($vs_item, $va_skip_values)) {
                    if ($o_log) {
                        $o_log->logDebug(_t('[{$ps_refinery_name}] Skipped %1 because it was in the skipIfValue list', $vs_item));
                    }
                    continue;
                }
                // Set label
                $va_val = array();
                // Set value as hierarchy
                if ($va_hierarchy_setting = $pa_item['settings']["{$ps_refinery_name}_hierarchy"]) {
                    $va_attr_vals = $va_val = caProcessRefineryParents($ps_refinery_name, $ps_table, $va_hierarchy_setting, $pa_source_data, $pa_item, $pn_value_index, array_merge($pa_options, array('hierarchyMode' => true)));
                    $vs_item = $va_val['_preferred_label'];
                } else {
                    // Set type
                    if ($vs_type_opt = $pa_item['settings']["{$ps_refinery_name}_{$ps_item_prefix}Type"]) {
                        $va_val['_type'] = BaseRefinery::parsePlaceholder($vs_type_opt, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader));
                    }
                    if ((!isset($va_val['_type']) || !$va_val['_type']) && ($vs_type_opt = $pa_item['settings']["{$ps_refinery_name}_{$ps_item_prefix}TypeDefault"])) {
                        if (!($va_val['_type'] = BaseRefinery::parsePlaceholder($vs_type_opt, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader, 'delimiter' => $va_delimiter, 'returnDelimitedValueAt' => $vn_x)))) {
                            $va_val['_type'] = BaseRefinery::parsePlaceholder($vs_type_opt, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader));
                        }
                    }
                    // Set lot_status
                    if ($vs_type_opt = $pa_item['settings']["{$ps_refinery_name}_{$ps_item_prefix}Status"]) {
                        $va_val['_status'] = BaseRefinery::parsePlaceholder($vs_type_opt, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader));
                    }
                    if ((!isset($va_val['_status']) || !$va_val['_status']) && ($vs_type_opt = $pa_item['settings']["{$ps_refinery_name}_{$ps_item_prefix}StatusDefault"])) {
                        $va_val['_status'] = BaseRefinery::parsePlaceholder($vs_type_opt, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader));
                    }
                    if ((!isset($va_val['_type']) || !$va_val['_type']) && $o_log) {
                        $o_log->logWarn(_t("[{$ps_refinery_name}] No %2 type is set for %2 %1", $vs_item, $ps_item_prefix));
                    }
                    //
                    // Storage location specific options
                    //
                    if ($ps_refinery_name == 'storageLocationSplitter' && ($va_hier_delimiter = $pa_item['settings']['storageLocationSplitter_hierarchicalDelimiter'])) {
                        if (!is_array($va_hier_delimiter)) {
                            $va_hier_delimiter = array($va_hier_delimiter);
                        }
                        if (sizeof($va_hier_delimiter)) {
                            foreach ($va_hier_delimiter as $vn_index => $vs_delim) {
                                if (!trim($vs_delim, "\t ")) {
                                    unset($va_hier_delimiter[$vn_index]);
                                    continue;
                                }
                                $va_hier_delimiter[$vn_index] = preg_quote($vs_delim, "!");
                            }
                        }
                        $va_location_hier = preg_split("!(" . join("|", $va_hier_delimiter) . ")!", $vs_item);
                        if (sizeof($va_location_hier) > 1) {
                            $vn_location_id = null;
                            if (!is_array($va_types = $pa_item['settings']['storageLocationSplitter_hierarchicalStorageLocationTypes'])) {
                                $va_types = array();
                            }
                            $vs_item = array_pop($va_location_hier);
                            if (!($va_val['_type'] = array_pop($va_types))) {
                                $va_val['_type'] = $pa_item['settings']['storageLocationSplitter_storageLocationTypeDefault'];
                            }
                            foreach ($va_location_hier as $vn_i => $vs_parent) {
                                if (sizeof($va_types) > 0) {
                                    $vs_type = array_shift($va_types);
                                } else {
                                    if (!($vs_type = $pa_item['settings']['storageLocationSplitter_storageLocationType'])) {
                                        $vs_type = $pa_item['settings']['storageLocationSplitter_storageLocationTypeDefault'];
                                    }
                                }
                                if (!$vs_type) {
                                    break;
                                }
                                $vn_location_id = DataMigrationUtils::getStorageLocationID($vs_parent, $vn_location_id, $vs_type, $g_ui_locale_id, array('idno' => $vs_parent, 'parent_id' => $vn_location_id), $pa_options);
                            }
                            $va_val['parent_id'] = $va_val['_parent_id'] = $vn_location_id;
                        }
                    } else {
                        // Set parents
                        if ($va_parents) {
                            $va_val['parent_id'] = $va_val['_parent_id'] = caProcessRefineryParents($ps_refinery_name, $ps_table, $va_parents, $pa_source_data, $pa_item, $pn_value_index, $pa_options);
                        }
                        if (isset($pa_options['defaultParentID']) && (!isset($va_val['parent_id']) || !$va_val['parent_id'])) {
                            $va_val['parent_id'] = $va_val['_parent_id'] = $pa_options['defaultParentID'];
                        }
                    }
                    if (isset($pa_options['hierarchyID']) && $pa_options['hierarchyID'] && ($vs_hier_id_fld = $t_instance->getProperty('HIERARCHY_ID_FLD'))) {
                        $va_val[$vs_hier_id_fld] = $pa_options['hierarchyID'];
                    }
                    // Set attributes
                    if (is_array($va_attr_vals = caProcessRefineryAttributes($pa_item['settings']["{$ps_refinery_name}_attributes"], $pa_source_data, $pa_item, $vn_i, array('log' => $o_log, 'reader' => $o_reader)))) {
                        $va_val = array_merge($va_val, $va_attr_vals);
                    }
                    // Set interstitials
                    if (isset($pa_options['mapping']) && is_array($va_attr_vals = caProcessInterstitialAttributes($ps_refinery_name, $pa_options['mapping']->get('table_num'), $ps_table, $pa_source_data, $pa_item, $vn_i, array('log' => $o_log, 'reader' => $o_reader)))) {
                        $va_val = array_merge($va_val, $va_attr_vals);
                    }
                    // Set relationships on the related table
                    caProcessRefineryRelatedMultiple($po_refinery_instance, $pa_item, $pa_source_data, $vn_i, $o_log, $o_reader, $va_val, $va_attr_vals);
                    // Set nonpreferred labels
                    if (is_array($va_non_preferred_labels = $pa_item['settings']["{$ps_refinery_name}_nonPreferredLabels"])) {
                        $pa_options['nonPreferredLabels'] = array();
                        foreach ($va_non_preferred_labels as $va_label) {
                            foreach ($va_label as $vs_k => $vs_v) {
                                $va_label[$vs_k] = BaseRefinery::parsePlaceholder($vs_v, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' '));
                            }
                            $pa_options['nonPreferredLabels'][] = $va_label;
                        }
                    }
                }
                if ($vs_dest_table != $ps_table && sizeof($va_group_dest) > 1) {
                    $vs_item = BaseRefinery::parsePlaceholder($vs_item, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader, 'returnAsString' => true, 'delimiter' => ' '));
                    if (!is_array($va_attr_vals)) {
                        $va_attr_vals = array();
                    }
                    $va_attr_vals_with_parent = array_merge($va_attr_vals, array('parent_id' => $va_val['parent_id'] ? $va_val['parent_id'] : $va_val['_parent_id']));
                    $pa_options = array('matchOn' => array('idno', 'label')) + $pa_options;
                    switch ($ps_table) {
                        case 'ca_objects':
                            $vn_item_id = DataMigrationUtils::getObjectID($vs_item, $va_val['parent_id'], $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_object_lots':
                            if (isset($va_val['_status'])) {
                                $va_attr_vals['lot_status_id'] = $va_val['_status'];
                            }
                            unset($va_val['_status']);
                            $vn_item_id = DataMigrationUtils::getObjectLotID($vs_item, $vs_item, $va_val['_type'], $g_ui_locale_id, $va_attr_vals, $pa_options);
                            break;
                        case 'ca_entities':
                            $vn_item_id = DataMigrationUtils::getEntityID(DataMigrationUtils::splitEntityName($vs_item, $pa_options), $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_places':
                            $vn_item_id = DataMigrationUtils::getPlaceID($vs_item, $va_val['parent_id'], $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_occurrences':
                            $vn_item_id = DataMigrationUtils::getOccurrenceID($vs_item, $va_val['parent_id'], $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_collections':
                            $vn_item_id = DataMigrationUtils::getCollectionID($vs_item, $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_loans':
                            $vn_item_id = DataMigrationUtils::getLoanID($vs_item, $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_movements':
                            $vn_item_id = DataMigrationUtils::getMovementID($vs_item, $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_list_items':
                            if (!$pa_options['list_id']) {
                                if ($o_log) {
                                    $o_log->logDebug(_t('[importHelpers:caGenericImportSplitter] List was not specified'));
                                }
                                continue 2;
                            }
                            $va_attr_vals_with_parent['is_enabled'] = 1;
                            $vn_item_id = DataMigrationUtils::getListItemID($pa_options['list_id'], $vs_item, $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_storage_locations':
                            $vn_item_id = DataMigrationUtils::getStorageLocationID($vs_item, $va_val['parent_id'], $va_val['_type'], $g_ui_locale_id, $va_attr_vals_with_parent, $pa_options);
                            break;
                        case 'ca_object_representations':
                            if ($o_log) {
                                $o_log->logDebug(_t('[importHelpers:caGenericImportSplitter] Only media paths can be mapped for object representations.'));
                            }
                            continue 2;
                        default:
                            if ($o_log) {
                                $o_log->logDebug(_t('[importHelpers:caGenericImportSplitter] Invalid table %1', $ps_table));
                            }
                            continue 2;
                            break;
                    }
                    if ($vn_item_id) {
                        $va_vals[][$vs_terminal] = $vn_item_id;
                        continue;
                    } else {
                        if ($o_log && !$pb_dont_create) {
                            $o_log->logError(_t("[{$ps_refinery_name}Refinery] Could not add %2 %1", $vs_item, $ps_item_prefix));
                        }
                    }
                } elseif (sizeof($va_group_dest) == 1 && $vs_terminal == $ps_table) {
                    // Set relationship type
                    if ($vs_rel_type_opt = $pa_item['settings']["{$ps_refinery_name}_relationshipType"]) {
                        $va_val['_relationship_type'] = BaseRefinery::parsePlaceholder($vs_rel_type_opt, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader));
                    }
                    if ((!isset($va_val['_relationship_type']) || !$va_val['_relationship_type']) && ($vs_rel_type_opt = $pa_item['settings']["{$ps_refinery_name}_relationshipTypeDefault"])) {
                        if (!($va_val['_relationship_type'] = BaseRefinery::parsePlaceholder($vs_rel_type_opt, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader, 'delimiter' => $va_delimiter, 'returnDelimitedValueAt' => $vn_x)))) {
                            $va_val['_relationship_type'] = BaseRefinery::parsePlaceholder($vs_rel_type_opt, $pa_source_data, $pa_item, $pn_value_index, array('reader' => $o_reader));
                        }
                    }
                    if ((!isset($va_val['_relationship_type']) || !$va_val['_relationship_type']) && $o_log) {
                        $o_log->logWarn(_t("[{$ps_refinery_name}Refinery] No relationship type is set for %2 %1", $vs_item, $ps_item_prefix));
                    }
                    switch ($ps_table) {
                        case 'ca_entities':
                            $va_val['preferred_labels'] = DataMigrationUtils::splitEntityName($vs_item, $pa_options);
                            if (!isset($va_val['idno'])) {
                                $va_val['idno'] = $vs_item;
                            }
                            break;
                        case 'ca_list_items':
                            $va_val['preferred_labels'] = array('name_singular' => str_replace("_", " ", $vs_item), 'name_plural' => str_replace("_", " ", $vs_item));
                            $va_val['_list'] = $pa_options['list_id'];
                            if (!isset($va_val['idno'])) {
                                $va_val['idno'] = $vs_item;
                            }
                            break;
                        case 'ca_storage_locations':
                        case 'ca_movements':
                        case 'ca_loans':
                        case 'ca_collections':
                        case 'ca_occurrences':
                        case 'ca_places':
                        case 'ca_objects':
                            $va_val['preferred_labels'] = array('name' => $vs_item);
                            if (!isset($va_val['idno'])) {
                                $va_val['idno'] = $vs_item;
                            }
                            break;
                        case 'ca_object_lots':
                            $va_val['preferred_labels'] = array('name' => $vs_item);
                            if (!isset($va_val['idno_stub'])) {
                                $va_val['idno_stub'] = $vs_item;
                            }
                            if (isset($va_val['_status'])) {
                                $va_val['lot_status_id'] = $va_val['_status'];
                            }
                            unset($va_val['_status']);
                            break;
                        case 'ca_object_representations':
                            if (!($vs_batch_media_directory = $t_instance->getAppConfig()->get('batch_media_import_root_directory'))) {
                                break;
                            }
                            if (!isset($va_val['preferred_labels'])) {
                                $va_val['preferred_labels'] = array('name' => $vs_item);
                            }
                            if (isset($pa_item['settings']['objectRepresentationSplitter_mediaPrefix']) && $pa_item['settings']['objectRepresentationSplitter_mediaPrefix'] && isset($va_val['media']['media']) && $va_val['media']['media']) {
                                $va_val['media']['media'] = $vs_batch_media_directory . '/' . $pa_item['settings']['objectRepresentationSplitter_mediaPrefix'] . '/' . $va_val['media']['media'];
                            }
                            if (!isset($va_val['idno'])) {
                                $va_val['idno'] = $vs_item;
                            }
                            break;
                        default:
                            if ($o_log) {
                                $o_log->logDebug(_t('[importHelpers:caGenericImportSplitter] Invalid table %1', $ps_table));
                            }
                            continue 2;
                            break;
                    }
                    if (isset($pa_options['nonPreferredLabels']) && is_array($pa_options['nonPreferredLabels'])) {
                        $va_val['nonpreferred_labels'] = $pa_options['nonPreferredLabels'];
                    }
                } elseif (sizeof($va_group_dest) == 2 && $vs_terminal == 'preferred_labels') {
                    switch ($ps_table) {
                        case 'ca_entities':
                            $va_val = DataMigrationUtils::splitEntityName($vs_item, $pa_options);
                            break;
                        case 'ca_list_items':
                            $va_val = array('name_singular' => $vs_item, 'name_plural' => $vs_item);
                            break;
                        case 'ca_storage_locations':
                        case 'ca_movements':
                        case 'ca_loans':
                        case 'ca_collections':
                        case 'ca_occurrences':
                        case 'ca_places':
                        case 'ca_objects':
                            $va_val = array('name' => $vs_item);
                            break;
                        case 'ca_object_lots':
                            $va_val = array('name' => $vs_item);
                            break;
                        case 'ca_object_representations':
                            if ($o_log) {
                                $o_log->logDebug(_t('[importHelpers:caGenericImportSplitter] Cannot map preferred labels to object representations. Only media paths can be mapped.'));
                            }
                            continue 2;
                        default:
                            if ($o_log) {
                                $o_log->logDebug(_t('[importHelpers:caGenericImportSplitter] Invalid table %1', $ps_table));
                            }
                            continue 2;
                            break;
                    }
                } else {
                    if ($o_log) {
                        $o_log->logError(_t("[{$ps_refinery_name}Refinery] Could not add %2 %1: cannot map %3 using %1", $vs_item, $ps_item_prefix, join(".", $va_group_dest)));
                    }
                }
                $va_val['_matchOn'] = $va_match_on;
                if ($pb_dont_create) {
                    $va_val['_dontCreate'] = 1;
                }
                $va_vals[] = $va_val;
                $vn_c++;
            }
        }
    } else {
        if ($o_log) {
            $o_log->logError(_t("[{$ps_refinery_name}Refinery] Cannot map %1 using this refinery", $pa_group['destination']));
        }
        return array();
    }
    return $va_vals;
}
Exemplo n.º 2
0
 /**
  * Process template expression, replacing "^" prefixed placeholders with data values
  *
  * @param string $ps_placeholder An expression with at least one placeholder. (Eg. "^1"). Can also be a text expression with embedded placeholders (Eg. "This is ^1 and this is ^2). The placeholders are valid specifiers for the data reader being used prefixed with a caret ("^"). For flat formats like Excel, they will look like ^1, ^2, etc. For XML formats they will be Xpath. Eg. ^/teiHeader/encodingDesc/projectDesc
  * @param array $pa_source_data An array of data to use in substitutions. Array is indexed by placeholder name *without* the leading caret.
  * @param array $pa_item The mapping item information array containing settings for the current mapping.
  * @param int $pn_index The index of the value to return. For non-repeating values this should be omitted or set to zero. For repeating values, this is a zero-based index indicating which value is returned. If a value for the specified index does not exist null will be returned. If the index is set to null then an array with all values is returned.
  * @param array $pa_options An array of options. Options include:
  *		reader = An instance of BaseDataReader. Will be used to pull values for placeholders that are not defined in $pa_source_data. This is useful for formats like XML where placeholders may be arbitrary XPath expressions that must be executed rather than parsed. [Default is null]
  *		returnAsString = Return array of repeating values as string using delimiter. Has effect only is $pn_index parameter is set to null. [Default is false]
  *		delimiter = Delimiter to join array values with when returnAsString option is set; or the delimiter to use when breaking apart a value for return via the returnDelimitedValueAt option. [Default is ";"]
  *		returnDelimitedValueAt = Return a specific part of a value delimited by the "delimiter" option. Only has effect when returning a specific index of a repeating value (Eg. $pn_index is not null). The option value is a zero-based index. [Default is null – return entire value]
  *
  * @return mixed An array or string
  */
 public static function parsePlaceholder($ps_placeholder, $pa_source_data, $pa_item, $pn_index = 0, $pa_options = null)
 {
     $o_reader = caGetOption('reader', $pa_options, null);
     $ps_placeholder = trim($ps_placeholder);
     $vs_key = substr($ps_placeholder, 1);
     if ($ps_placeholder[0] == '^' && strpos($ps_placeholder, '^', 1) === false) {
         // Placeholder is a single caret-value
         if ($o_reader) {
             $vm_val = $o_reader->get($vs_key, array('returnAsArray' => true));
         } else {
             if (!isset($pa_source_data[substr($ps_placeholder, 1)])) {
                 return null;
             }
             $vm_val = $pa_source_data[substr($ps_placeholder, 1)];
         }
     } elseif (strpos($ps_placeholder, '^') !== false) {
         // Placeholder is a full template – requires extra processing
         if ($o_reader) {
             $va_tags = array();
             // get a list of all tags in placeholder
             if (preg_match_all(__CA_BUNDLE_DISPLAY_TEMPLATE_TAG_REGEX__, $ps_placeholder, $va_matches)) {
                 foreach ($va_matches[1] as $vn_i => $vs_possible_tag) {
                     $va_matches[1][$vn_i] = rtrim($vs_possible_tag, "/.");
                     // remove trailing slashes and periods
                 }
                 $va_tags = $va_matches[1];
             }
             // Make sure all tags are in source data array, otherwise try to pull them from the reader.
             // Some formats, mainly XML, can take expressions (XPath for XML) that are not precalculated in the array
             foreach ($va_tags as $vs_tag) {
                 if (isset($pa_source_data[$vs_tag])) {
                     continue;
                 }
                 $va_val = $o_reader->get($vs_key, array('returnAsArray' => true));
                 $pa_source_data[$vs_tag] = $va_val[$pn_index];
             }
             $vm_val = caProcessTemplate($ps_placeholder, $pa_source_data);
         } else {
             // Is plain text
             if (!isset($pa_source_data[substr($ps_placeholder, 1)])) {
                 return null;
             }
             $vm_val = $pa_source_data[substr($ps_placeholder, 1)];
         }
     } else {
         $vm_val = $ps_placeholder;
     }
     // Get specific index for repeating value
     if (is_array($vm_val) && !is_null($pn_index)) {
         $vm_val = isset($vm_val[$pn_index]) ? $vm_val[$pn_index] : null;
     }
     // If we're returning the entire array, do processing on members and return
     if (is_array($vm_val)) {
         foreach ($vm_val as $vn_i => $vs_val) {
             if (is_array($pa_item['settings']['original_values']) && ($vn_ix = array_search(mb_strtolower($vs_val), $pa_item['settings']['original_values'])) !== false) {
                 $vs_val = $pa_item['settings']['replacement_values'][$vn_ix];
             }
             $vm_val[$vn_i] = trim($vs_val);
         }
         $vm_val = caProcessImportItemSettingsForValue($vm_val, $pa_item['settings']);
         if (caGetOption("returnAsString", $pa_options, false)) {
             $va_delimiter = caGetOption("delimiter", $pa_options, ';');
             if (is_array($va_delimiter)) {
                 $vs_delimiter = array_shift($va_delimiter);
             } else {
                 $vs_delimiter = $va_delimiter;
             }
             return join($vs_delimiter, $vm_val);
         }
         return $vm_val;
     }
     if (!is_null($pn_index) && !is_null($vs_get_at_index = caGetOption('returnDelimitedValueAt', $pa_options, null)) && ($va_delimiter = caGetOption("delimiter", $pa_options, ';'))) {
         if (!is_array($va_delimiter)) {
             $va_delimiter = array($va_delimiter);
         }
         foreach ($va_delimiter as $vn_index => $vs_delim) {
             if (!trim($vs_delim, "\t ")) {
                 unset($va_delimiter[$vn_index]);
                 continue;
             }
             $va_delimiter[$vn_index] = preg_quote($vs_delim, "!");
         }
         $va_val = preg_split("!(" . join("|", $va_delimiter) . ")!", $vm_val);
         $vm_val = isset($va_val[$vs_get_at_index]) ? $va_val[$vs_get_at_index] : null;
     }
     $vm_val = trim($vm_val);
     if (is_array($pa_item['settings']['original_values']) && ($vn_i = array_search(mb_strtolower($vm_val), $pa_item['settings']['original_values'])) !== false) {
         $vm_val = $pa_item['settings']['replacement_values'][$vn_i];
     }
     $vm_val = caProcessImportItemSettingsForValue($vm_val, $pa_item['settings']);
     return trim($vm_val);
 }