/**
  * 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;
 }
Example #2
0
 /**
  * Log a change
  * 
  * @access private
  * @param string $ps_change_type 'I', 'U' or 'D', meaning INSERT, UPDATE or DELETE
  * @param int $pn_user_id user identifier, defaults to null
  */
 protected function logChange($ps_change_type, $pn_user_id = null)
 {
     if (defined('__CA_DONT_LOG_CHANGES__')) {
         return null;
     }
     if (!$this->logChanges()) {
         return null;
     }
     $vb_is_metadata = $vb_is_metadata_value = false;
     if ($this->tableName() == 'ca_attributes') {
         $vb_log_changes_to_self = false;
         $va_subject_config = null;
         $vb_is_metadata = true;
     } elseif ($this->tableName() == 'ca_attribute_values') {
         $vb_log_changes_to_self = false;
         $va_subject_config = null;
         $vb_is_metadata_value = true;
     } else {
         $vb_log_changes_to_self = $this->getProperty('LOG_CHANGES_TO_SELF');
         $va_subject_config = $this->getProperty('LOG_CHANGES_USING_AS_SUBJECT');
     }
     global $AUTH_CURRENT_USER_ID;
     if (!$pn_user_id) {
         $pn_user_id = $AUTH_CURRENT_USER_ID;
     }
     if (!$pn_user_id) {
         $pn_user_id = null;
     }
     if (!in_array($ps_change_type, array('I', 'U', 'D'))) {
         return false;
     }
     // invalid change type (shouldn't happen)
     if (!($vn_row_id = $this->getPrimaryKey())) {
         return false;
     }
     // no logging without primary key value
     // get unit id (if set)
     global $g_change_log_unit_id;
     $vn_unit_id = $g_change_log_unit_id;
     if (!$vn_unit_id) {
         $vn_unit_id = null;
     }
     // get subject ids
     $va_subjects = array();
     if ($vb_is_metadata) {
         // special case for logging attribute changes
         if (($vn_id = $this->get('row_id')) > 0) {
             $va_subjects[$this->get('table_num')][] = $vn_id;
         }
     } elseif ($vb_is_metadata_value) {
         // special case for logging metadata changes
         $t_attr = new ca_attributes($this->get('attribute_id'));
         if (($vn_id = $t_attr->get('row_id')) > 0) {
             $va_subjects[$t_attr->get('table_num')][] = $vn_id;
         }
     } else {
         if (is_array($va_subject_config)) {
             if (is_array($va_subject_config['FOREIGN_KEYS'])) {
                 foreach ($va_subject_config['FOREIGN_KEYS'] as $vs_field) {
                     $va_relationships = $this->_DATAMODEL->getManyToOneRelations($this->tableName(), $vs_field);
                     if ($va_relationships['one_table']) {
                         $vn_table_num = $this->_DATAMODEL->getTableNum($va_relationships['one_table']);
                         if (!isset($va_subjects[$vn_table_num]) || !is_array($va_subjects[$vn_table_num])) {
                             $va_subjects[$vn_table_num] = array();
                         }
                         if (($vn_id = $this->get($vs_field)) > 0) {
                             $va_subjects[$vn_table_num][] = $vn_id;
                         }
                     }
                 }
             }
             if (is_array($va_subject_config['RELATED_TABLES'])) {
                 $o_db = $this->getDb();
                 if (!isset($o_db) || !$o_db) {
                     $o_db = new Db();
                     $o_db->dieOnError(false);
                 }
                 foreach ($va_subject_config['RELATED_TABLES'] as $vs_dest_table => $va_path_to_dest) {
                     $t_dest = $this->_DATAMODEL->getTableInstance($vs_dest_table);
                     if (!$t_dest) {
                         continue;
                     }
                     $vn_dest_table_num = $t_dest->tableNum();
                     $vs_dest_primary_key = $t_dest->primaryKey();
                     $va_path_to_dest[] = $vs_dest_table;
                     $vs_cur_table = $this->tableName();
                     $vs_sql = "SELECT " . $vs_dest_table . "." . $vs_dest_primary_key . " FROM " . $this->tableName() . "\n";
                     foreach ($va_path_to_dest as $vs_ltable) {
                         $va_relations = $this->_DATAMODEL->getRelationships($vs_cur_table, $vs_ltable);
                         $vs_sql .= "INNER JOIN {$vs_ltable} ON {$vs_cur_table}." . $va_relations[$vs_cur_table][$vs_ltable][0][0] . " = {$vs_ltable}." . $va_relations[$vs_cur_table][$vs_ltable][0][1] . "\n";
                         $vs_cur_table = $vs_ltable;
                     }
                     $vs_sql .= "WHERE " . $this->tableName() . "." . $this->primaryKey() . " = " . $this->getPrimaryKey();
                     if ($qr_subjects = $o_db->query($vs_sql)) {
                         if (!isset($va_subjects[$vn_dest_table_num]) || !is_array($va_subjects[$vn_dest_table_num])) {
                             $va_subjects[$vn_dest_table_num] = array();
                         }
                         while ($qr_subjects->nextRow()) {
                             if (($vn_id = $qr_subjects->get($vs_dest_primary_key)) > 0) {
                                 $va_subjects[$vn_dest_table_num][] = $vn_id;
                             }
                         }
                     } else {
                         print "<hr>Error in subject logging: ";
                         print "<br>{$vs_sql}<hr>\n";
                     }
                 }
             } else {
                 if (($vn_id = $this->get('row_id')) > 0) {
                     // At a minimum always log self as subject
                     $va_subjects[$this->get('table_num')][] = $vn_id;
                 }
             }
         }
     }
     if (!sizeof($va_subjects) && !$vb_log_changes_to_self) {
         return true;
     }
     if (!$this->opqs_change_log) {
         $o_db = $this->getDb();
         $o_db->dieOnError(false);
         $vs_change_log_database = '';
         if ($vs_change_log_database = $this->_CONFIG->get("change_log_database")) {
             $vs_change_log_database .= ".";
         }
         if (!($this->opqs_change_log = $o_db->prepare("\n\t\t\t\tINSERT INTO " . $vs_change_log_database . "ca_change_log\n\t\t\t\t(\n\t\t\t\t\tlog_datetime, user_id, unit_id, changetype,\n\t\t\t\t\tlogged_table_num, logged_row_id, batch_id\n\t\t\t\t)\n\t\t\t\tVALUES\n\t\t\t\t(?, ?, ?, ?, ?, ?, ?)\n\t\t\t"))) {
             // prepare failed - shouldn't happen
             return false;
         }
         if (!($this->opqs_change_log_snapshot = $o_db->prepare("\n\t\t\t\tINSERT IGNORE INTO " . $vs_change_log_database . "ca_change_log_snapshots\n\t\t\t\t(\n\t\t\t\t\tlog_id, snapshot\n\t\t\t\t)\n\t\t\t\tVALUES\n\t\t\t\t(?, ?)\n\t\t\t"))) {
             // prepare failed - shouldn't happen
             return false;
         }
         if (!($this->opqs_change_log_subjects = $o_db->prepare("\n\t\t\t\tINSERT IGNORE INTO " . $vs_change_log_database . "ca_change_log_subjects\n\t\t\t\t(\n\t\t\t\t\tlog_id, subject_table_num, subject_row_id\n\t\t\t\t)\n\t\t\t\tVALUES\n\t\t\t\t(?, ?, ?)\n\t\t\t"))) {
             // prepare failed - shouldn't happen
             return false;
         }
     }
     // get snapshot of changes made to record
     $va_snapshot = $this->getSnapshot($ps_change_type === 'U' ? true : false);
     $vs_snapshot = caSerializeForDatabase($va_snapshot, true);
     if (!($ps_change_type == 'U' && !sizeof($va_snapshot))) {
         // Create primary log entry
         global $g_change_log_batch_id;
         // Log batch_id as set in global by ca_batch_log model (app/models/ca_batch_log.php)
         $this->opqs_change_log->execute(time(), $pn_user_id, $vn_unit_id, $ps_change_type, $this->tableNum(), $vn_row_id, (int) $g_change_log_batch_id ? (int) $g_change_log_batch_id : null);
         $vn_log_id = $this->opqs_change_log->getLastInsertID();
         $this->opqs_change_log_snapshot->execute($vn_log_id, $vs_snapshot);
         global $g_change_log_delegate;
         if ($g_change_log_delegate && method_exists($g_change_log_delegate, "onLogChange")) {
             call_user_func(array($g_change_log_delegate, 'onLogChange'), $this->tableNum(), $vn_row_id, $vn_log_id);
         }
         foreach ($va_subjects as $vn_subject_table_num => $va_subject_ids) {
             foreach ($va_subject_ids as $vn_subject_row_id) {
                 $this->opqs_change_log_subjects->execute($vn_log_id, $vn_subject_table_num, $vn_subject_row_id);
             }
         }
     }
     return true;
 }
 /**
  * Return the specific attribute with the specified attribute_id (assuming it's attached to the current row)
  */
 public function getAttributeByID($pn_attribute_id, $pa_options = null)
 {
     if (isset($pa_options['row_id']) && $pa_options['row_id']) {
         $vn_row_id = $pa_options['row_id'];
     } else {
         $vn_row_id = $this->getPrimaryKey();
     }
     if (!$vn_row_id) {
         return null;
     }
     $t_attr = new ca_attributes($pn_attribute_id);
     if (!$t_attr->getPrimaryKey()) {
         return false;
     }
     if ((int) $t_attr->get('row_id') !== (int) $vn_row_id) {
         return false;
     }
     return $t_attr->getAttributeValues(array('returnAs' => 'attributeInstance'));
 }
Example #4
0
 /**
  *
  */
 public static function check_media_fixity($po_opts = null)
 {
     require_once __CA_LIB_DIR__ . "/core/Db.php";
     require_once __CA_MODELS_DIR__ . "/ca_object_representations.php";
     $ps_file_path = strtolower((string) $po_opts->getOption('file'));
     $ps_format = strtolower((string) $po_opts->getOption('format'));
     if (!in_array($ps_format, array('text', 'tab', 'csv'))) {
         $ps_format = 'text';
     }
     $o_db = new Db();
     $o_dm = Datamodel::load();
     $t_rep = new ca_object_representations();
     $vs_report_output = join($ps_format == 'tab' ? "\t" : ",", array(_t('Type'), _t('Error'), _t('Name'), _t('ID'), _t('Version'), _t('File path'), _t('Expected MD5'), _t('Actual MD5'))) . "\n";
     // Verify object representations
     $qr_reps = $o_db->query("SELECT representation_id, idno, media FROM ca_object_representations WHERE deleted = 0");
     print CLIProgressBar::start($vn_rep_count = $qr_reps->numRows(), _t('Checking object representations')) . "\n";
     $vn_errors = 0;
     while ($qr_reps->nextRow()) {
         $vn_representation_id = $qr_reps->get('representation_id');
         print CLIProgressBar::next(1, _t("Checking representation media %1", $vn_representation_id));
         $va_media_versions = $qr_reps->getMediaVersions('media');
         foreach ($va_media_versions as $vs_version) {
             $vs_path = $qr_reps->getMediaPath('media', $vs_version);
             $vs_database_md5 = $qr_reps->getMediaInfo('media', $vs_version, 'MD5');
             $vs_file_md5 = md5_file($vs_path);
             if ($vs_database_md5 !== $vs_file_md5) {
                 $t_rep->load($vn_representation_id);
                 $vs_message = _t("[Object representation][MD5 mismatch] %1; version %2 [%3]", $t_rep->get("ca_objects.preferred_labels.name") . " (" . $t_rep->get("ca_objects.idno") . "); representation_id={$vn_representation_id}", $vs_version, $vs_path);
                 switch ($ps_format) {
                     case 'text':
                     default:
                         $vs_report_output .= "{$vs_message}\n";
                         break;
                     case 'tab':
                     case 'csv':
                         $va_log = array(_t('Object representation'), "MD5 mismatch", caEscapeForDelimitedOutput($t_rep->get("ca_objects.preferred_labels.name") . " (" . $t_rep->get("ca_objects.idno") . ")"), $vn_representation_id, $vs_version, $vs_path, $vs_database_md5, $vs_file_md5);
                         $vs_report_output .= join($ps_format == 'tab' ? "\t" : ",", $va_log) . "\n";
                         break;
                 }
                 CLIUtils::addError($vs_message);
                 $vn_errors++;
             }
         }
     }
     print CLIProgressBar::finish();
     CLIUtils::addMessage(_t('%1 errors for %2 representations', $vn_errors, $vn_rep_count));
     // get all Media elements
     $va_elements = ca_metadata_elements::getElementsAsList(false, null, null, true, false, true, array(16));
     // 16=media
     if (is_array($va_elements) && sizeof($va_elements)) {
         if (is_array($va_element_ids = caExtractValuesFromArrayList($va_elements, 'element_id', array('preserveKeys' => false))) && sizeof($va_element_ids)) {
             $qr_c = $o_db->query("\n\t\t\t\t\t\tSELECT count(*) c\n\t\t\t\t\t\tFROM ca_attribute_values\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\telement_id in (?)\n\t\t\t\t\t", array($va_element_ids));
             if ($qr_c->nextRow()) {
                 $vn_count = $qr_c->get('c');
             } else {
                 $vn_count = 0;
             }
             print CLIProgressBar::start($vn_count, _t('Checking attribute media'));
             $vn_errors = 0;
             foreach ($va_elements as $vs_element_code => $va_element_info) {
                 $qr_vals = $o_db->query("SELECT value_id FROM ca_attribute_values WHERE element_id = ?", (int) $va_element_info['element_id']);
                 $va_vals = $qr_vals->getAllFieldValues('value_id');
                 foreach ($va_vals as $vn_value_id) {
                     $t_attr_val = new ca_attribute_values($vn_value_id);
                     if ($t_attr_val->getPrimaryKey()) {
                         $t_attr_val->setMode(ACCESS_WRITE);
                         $t_attr_val->useBlobAsMediaField(true);
                         print CLIProgressBar::next(1, _t("Checking attribute media %1", $vn_value_id));
                         $va_media_versions = $t_attr_val->getMediaVersions('value_blob');
                         foreach ($va_media_versions as $vs_version) {
                             $vs_path = $t_attr_val->getMediaPath('value_blob', $vs_version);
                             $vs_database_md5 = $t_attr_val->getMediaInfo('value_blob', $vs_version, 'MD5');
                             $vs_file_md5 = md5_file($vs_path);
                             if ($vs_database_md5 !== $vs_file_md5) {
                                 $t_attr = new ca_attributes($vn_attribute_id = $t_attr_val->get('attribute_id'));
                                 $vs_label = "attribute_id={$vn_attribute_id}; value_id={$vn_value_id}";
                                 if ($t_instance = $o_dm->getInstanceByTableNum($t_attr->get('table_num'), true)) {
                                     if ($t_instance->load($t_attr->get('row_id'))) {
                                         $vs_label = $t_instance->get($t_instance->tableName() . '.preferred_labels');
                                         if ($vs_idno = $t_instance->get($t_instance->getProperty('ID_NUMBERING_ID_FIELD'))) {
                                             $vs_label .= " ({$vs_label})";
                                         }
                                     }
                                 }
                                 $vs_message = _t("[Media attribute][MD5 mismatch] %1; value_id=%2; version %3 [%4]", $vs_label, $vn_value_id, $vs_version, $vs_path);
                                 switch ($ps_format) {
                                     case 'text':
                                     default:
                                         $vs_report_output .= "{$vs_message}\n";
                                         break;
                                     case 'tab':
                                     case 'csv':
                                         $va_log = array(_t('Media attribute'), _t("MD5 mismatch"), caEscapeForDelimitedOutput($vs_label), $vn_value_id, $vs_version, $vs_path, $vs_database_md5, $vs_file_md5);
                                         $vs_report_output .= join($ps_format == 'tab' ? "\t" : ",", $va_log);
                                         break;
                                 }
                                 CLIUtils::addError($vs_message);
                                 $vn_errors++;
                             }
                         }
                     }
                 }
             }
             print CLIProgressBar::finish();
             CLIUtils::addMessage(_t('%1 errors for %2 attributes', $vn_errors, $vn_rep_count));
         }
     }
     // get all File elements
     $va_elements = ca_metadata_elements::getElementsAsList(false, null, null, true, false, true, array(15));
     // 15=file
     if (is_array($va_elements) && sizeof($va_elements)) {
         if (is_array($va_element_ids = caExtractValuesFromArrayList($va_elements, 'element_id', array('preserveKeys' => false))) && sizeof($va_element_ids)) {
             $qr_c = $o_db->query("\n\t\t\t\t\t\tSELECT count(*) c\n\t\t\t\t\t\tFROM ca_attribute_values\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\telement_id in (?)\n\t\t\t\t\t", array($va_element_ids));
             if ($qr_c->nextRow()) {
                 $vn_count = $qr_c->get('c');
             } else {
                 $vn_count = 0;
             }
             print CLIProgressBar::start($vn_count, _t('Checking attribute files'));
             $vn_errors = 0;
             foreach ($va_elements as $vs_element_code => $va_element_info) {
                 $qr_vals = $o_db->query("SELECT value_id FROM ca_attribute_values WHERE element_id = ?", (int) $va_element_info['element_id']);
                 $va_vals = $qr_vals->getAllFieldValues('value_id');
                 foreach ($va_vals as $vn_value_id) {
                     $t_attr_val = new ca_attribute_values($vn_value_id);
                     if ($t_attr_val->getPrimaryKey()) {
                         $t_attr_val->setMode(ACCESS_WRITE);
                         $t_attr_val->useBlobAsFileField(true);
                         print CLIProgressBar::next(1, _t("Checking attribute file %1", $vn_value_id));
                         $vs_path = $t_attr_val->getFilePath('value_blob');
                         $vs_database_md5 = $t_attr_val->getFileInfo('value_blob', 'MD5');
                         $vs_file_md5 = md5_file($vs_path);
                         if ($vs_database_md5 !== $vs_file_md5) {
                             $t_attr = new ca_attributes($vn_attribute_id = $t_attr_val->get('attribute_id'));
                             $vs_label = "attribute_id={$vn_attribute_id}; value_id={$vn_value_id}";
                             if ($t_instance = $o_dm->getInstanceByTableNum($t_attr->get('table_num'), true)) {
                                 if ($t_instance->load($t_attr->get('row_id'))) {
                                     $vs_label = $t_instance->get($t_instance->tableName() . '.preferred_labels');
                                     if ($vs_idno = $t_instance->get($t_instance->getProperty('ID_NUMBERING_ID_FIELD'))) {
                                         $vs_label .= " ({$vs_label})";
                                     }
                                 }
                             }
                             $vs_message = _t("[File attribute][MD5 mismatch] %1; value_id=%2; version %3 [%4]", $vs_label, $vn_value_id, $vs_version, $vs_path);
                             switch ($ps_format) {
                                 case 'text':
                                 default:
                                     $vs_report_output .= "{$vs_message}\n";
                                     break;
                                 case 'tab':
                                 case 'csv':
                                     $va_log = array(_t('File attribute'), _t("MD5 mismatch"), caEscapeForDelimitedOutput($vs_label), $vn_value_id, $vs_version, $vs_path, $vs_database_md5, $vs_file_md5);
                                     $vs_report_output .= join($ps_format == 'tab' ? "\t" : ",", $va_log);
                                     break;
                             }
                             CLIUtils::addError($vs_message);
                             $vn_errors++;
                         }
                     }
                 }
             }
             print CLIProgressBar::finish();
             CLIUtils::addMessage(_t('%1 errors for %2 attributes', $vn_errors, $vn_rep_count));
         }
     }
     if ($ps_file_path) {
         file_put_contents($ps_file_path, $vs_report_output);
     }
     return true;
 }
 /**
  * Fetch details on an item from a remote data source and output results of the 'display' key in the response.
  *
  */
 public function GetDetail()
 {
     $pn_element_id = $this->request->getParameter('element_id', pInteger);
     $t_element = new ca_metadata_elements($pn_element_id);
     $va_data = array();
     if (!$t_element->getPrimaryKey()) {
         // error
         $va_items['error'] = array('label' => _t('ERROR: Invalid element_id'), 'idno' => '');
     } else {
         $vs_service = $t_element->getSetting('service');
         $va_settings = $t_element->getSettings();
         $pn_attribute_id = $this->request->getParameter('id', pInteger);
         $t_attr_val = new ca_attribute_values();
         if ($t_attr_val->load(array('attribute_id' => $pn_attribute_id, 'element_id' => $pn_element_id))) {
             $t_attr = new ca_attributes();
             if ($t_attr->load($pn_attribute_id)) {
                 if (!caCanRead($this->request->getUserID(), $t_attr->get('table_num'), $t_attr->get('row_id'), $t_element->get('element_code'))) {
                     $va_items['error'] = array('label' => _t('ERROR: You do not have access to this item'), 'idno' => '');
                 } else {
                     $vs_url = $t_attr_val->get('value_longtext2');
                     if (!($o_plugin = InformationServiceManager::getInformationServiceInstance($vs_service))) {
                         $va_items['error'] = array('label' => _t('ERROR: Invalid service'), 'idno' => '');
                     } else {
                         $vs_cache_key = md5(print_r($va_settings, true) . $vs_url);
                         if (CompositeCache::contains($vs_cache_key, 'InformationServiceExtendedInfo')) {
                             $va_data = CompositeCache::fetch($vs_cache_key, 'InformationServiceExtendedInfo');
                         } else {
                             $va_data = $o_plugin->getExtendedInformation($va_settings, $vs_url);
                             CompositeCache::save($vs_cache_key, $va_data, 'InformationServiceExtendedInfo');
                         }
                     }
                 }
             }
         }
     }
     $this->view->setVar('detail', $va_data);
     return $this->render('ajax_information_service_detail_html.php');
 }
 /**
  * Initiates user download of media stored in a media attribute, returning file in response to request.
  * Adds download output to response directly. No view is used.
  *
  * @param array $pa_options Array of options passed through to _initView 
  */
 public function DownloadAttributeMedia($pa_options = null)
 {
     if (!($pn_value_id = $this->request->getParameter('value_id', pInteger))) {
         return;
     }
     $t_attr_val = new ca_attribute_values($pn_value_id);
     if (!$t_attr_val->getPrimaryKey()) {
         return;
     }
     $t_attr = new ca_attributes($t_attr_val->get('attribute_id'));
     $vn_table_num = $this->opo_datamodel->getTableNum($this->ops_table_name);
     if ($t_attr->get('table_num') != $vn_table_num) {
         $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2580?r=' . urlencode($this->request->getFullUrlPath()));
         return;
     }
     $t_element = new ca_metadata_elements($t_attr->get('element_id'));
     $this->request->setParameter($this->opo_datamodel->getTablePrimaryKeyName($vn_table_num), $t_attr->get('row_id'));
     list($vn_subject_id, $t_subject) = $this->_initView($pa_options);
     $ps_version = $this->request->getParameter('version', pString);
     if (!$this->_checkAccess($t_subject)) {
         return false;
     }
     //
     // Does user have access to bundle?
     //
     if ($this->request->user->getBundleAccessLevel($this->ops_table_name, $t_element->get('element_code')) < __CA_BUNDLE_ACCESS_READONLY__) {
         $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2580?r=' . urlencode($this->request->getFullUrlPath()));
         return;
     }
     $t_attr_val->useBlobAsMediaField(true);
     if (!in_array($ps_version, $t_attr_val->getMediaVersions('value_blob'))) {
         $ps_version = 'original';
     }
     $o_view = new View($this->request, $this->request->getViewsDirectoryPath() . '/bundles/');
     // get value
     $t_element = new ca_metadata_elements($t_attr_val->get('element_id'));
     // check that value is a media attribute
     if ($t_element->get('datatype') != 16) {
         // 16=media
         return;
     }
     $vs_path = $t_attr_val->getMediaPath('value_blob', $ps_version);
     $vs_path_ext = pathinfo($vs_path, PATHINFO_EXTENSION);
     if ($vs_name = trim($t_attr_val->get('value_longtext2'))) {
         $vs_file_name = pathinfo($vs_name, PATHINFO_FILENAME);
         $vs_name = "{$vs_file_name}.{$vs_path_ext}";
     } else {
         $vs_name = _t("downloaded_file.%1", $vs_path_ext);
     }
     $o_view->setVar('file_path', $vs_path);
     $o_view->setVar('file_name', $vs_name);
     // send download
     $this->response->addContent($o_view->render('ca_attributes_download_media.php'));
 }
 /**
  * remove attribute from current row
  */
 public function _removeAttribute($pn_attribute_id, $po_trans = null, $pa_options = null)
 {
     $t_attr = new ca_attributes($pn_attribute_id);
     $t_attr->purify($this->purify());
     if ($po_trans) {
         $t_attr->setTransaction($po_trans);
     }
     if (!$t_attr->getPrimaryKey() || $t_attr->get('table_num') != $this->tableNum() || $this->getPrimaryKey() != $t_attr->get('row_id')) {
         $this->postError(1969, _t('Can\'t edit invalid attribute'), 'BaseModelWithAttributes->editAttribute()', $pa_options['error_source']);
         return false;
     }
     if (!$t_attr->removeAttribute()) {
         foreach ($t_attr->errors as $o_error) {
             $this->postError($o_error->getErrorNumber(), $o_error->getErrorDescription(), $o_error->getErrorContext(), $pa_options['error_source']);
         }
         return false;
     }
     //$this->setFieldValuesArray($this->addAttributesToFieldValuesArray());
     return true;
 }