/** * Perform mapping of extracted media metadata to CollectiveAccess bundles. * * @param BundlableLabelableBaseModelWithAttributes $po_instance Model instance to insert extracted metadata into * @param array $pa_metadata Extracted metadata * @param int $pn_locale_id The current locale as a numeric locale_id * @return bool True extracted metadata was mapped and the model changed, false if no change was made to the model */ function caExtractEmbeddedMetadata($po_instance, $pa_metadata, $pn_locale_id) { if (!is_array($pa_metadata)) { return false; } $vb_did_mapping = false; if (!($vs_media_metadata_config = $po_instance->getAppConfig()->get('media_metadata'))) { return false; } $o_metadata_config = Configuration::load($vs_media_metadata_config); $va_mappings = $o_metadata_config->getAssoc('import_mappings'); $vs_tablename = $po_instance->tableName(); // set extracted georef? $va_georef_elements = $o_metadata_config->getList('extract_embedded_exif_georeferencing_to'); $va_georef_containers = $o_metadata_config->getAssoc('extract_embedded_exif_georeferencing_to_container'); $va_date_elements = $o_metadata_config->getList('extract_embedded_exif_creation_date_to'); $va_date_containers = $o_metadata_config->getAssoc('extract_embedded_exif_creation_date_to_container'); if (isset($pa_metadata['EXIF']) && is_array($pa_metadata['EXIF']) && (is_array($va_georef_elements) && sizeof($va_georef_elements) || is_array($va_georef_containers) && sizeof($va_georef_containers) || is_array($va_date_elements) && sizeof($va_date_elements) || is_array($va_date_containers) && sizeof($va_date_containers))) { $va_exif_data = $pa_metadata['EXIF']; if (is_array($va_georef_elements)) { if (is_array($va_coords = caParseEXIFLatLong($va_exif_data))) { foreach ($va_georef_elements as $vs_element) { $va_tmp = explode('.', $vs_element); $po_instance->addAttribute(array($va_tmp[1] => "[" . $va_coords['latitude'] . ", " . $va_coords['longitude'] . "]", 'locale_id' => $pn_locale_id), $va_tmp[1]); } $vb_did_mapping = true; } } if (is_array($va_georef_containers)) { if (is_array($va_coords = caParseEXIFLatLong($va_exif_data))) { foreach ($va_georef_containers as $vs_container => $va_info) { $va_tmp = explode('.', $vs_container); $vs_value_element = array_pop(explode('.', $va_info['value'])); $va_data = array($vs_value_element => "[" . $va_coords['latitude'] . ", " . $va_coords['longitude'] . "]", 'locale_id' => $pn_locale_id); if (isset($va_info['map']) && is_array($va_info['map'])) { foreach ($va_info['map'] as $vs_sub_element => $vs_value) { $va_tmp2 = explode('.', $vs_sub_element); $vs_sub_element = array_pop($va_tmp2); if ($t_element = $po_instance->_getElementInstance($vs_sub_element)) { switch ($t_element->get('datatype')) { case 3: // List $t_list = new ca_lists(); $va_data[$vs_sub_element] = $t_list->getItemIDFromList($t_element->get('list_id'), $vs_value); break; default: $va_data[$vs_sub_element] = $vs_value; break; } } } } $po_instance->addAttribute($va_data, $va_tmp[1]); } $vb_did_mapping = true; } } if (is_array($va_date_elements)) { if (($vs_raw_date = $va_exif_data['IFD0']['DateTimeOriginal']) || ($vs_raw_date = $va_exif_data['EXIF']['DateTimeOriginal']) || ($vs_raw_date = $va_exif_data['ExifIFD']['DateTimeOriginal'])) { $va_date_tmp = preg_split('![: ]+!', $vs_raw_date); $vs_date = $va_date_tmp[0] . '-' . $va_date_tmp[1] . '-' . $va_date_tmp[2] . 'T' . $va_date_tmp[3] . ':' . $va_date_tmp[4] . ':' . $va_date_tmp[5]; foreach ($va_date_elements as $vs_element) { $va_tmp = explode('.', $vs_element); if (strlen($po_instance->get($vs_element)) > 0) { $po_instance->addAttribute(array($va_tmp[1] => $vs_date, 'locale_id' => $pn_locale_id), $va_tmp[1]); } else { $po_instance->replaceAttribute(array($va_tmp[1] => $vs_date, 'locale_id' => $pn_locale_id), $va_tmp[1]); } } $vb_did_mapping = true; } } if (is_array($va_date_containers)) { $t_list = new ca_lists(); if (($vs_raw_date = $va_exif_data['IFD0']['DateTimeOriginal']) || ($vs_raw_date = $va_exif_data['EXIF']['DateTimeOriginal']) || ($vs_raw_date = $va_exif_data['ExifIFD']['DateTimeOriginal'])) { $va_date_tmp = preg_split('![: ]+!', $vs_raw_date); $vs_date = $va_date_tmp[0] . '-' . $va_date_tmp[1] . '-' . $va_date_tmp[2] . 'T' . $va_date_tmp[3] . ':' . $va_date_tmp[4] . ':' . $va_date_tmp[5]; foreach ($va_date_containers as $vs_container => $va_info) { $va_tmp = explode('.', $vs_container); $vs_value_element = array_pop(explode('.', $va_info['value'])); $va_data = array($vs_value_element => $vs_date, 'locale_id' => $pn_locale_id); if (isset($va_info['map']) && is_array($va_info['map'])) { foreach ($va_info['map'] as $vs_sub_element => $vs_value) { $va_tmp2 = explode('.', $vs_sub_element); $vs_sub_element = array_pop($va_tmp2); if ($t_element = $po_instance->_getElementInstance($vs_sub_element)) { switch ($t_element->get('datatype')) { case 3: // List $va_data[$vs_sub_element] = $t_list->getItemIDFromList($t_element->get('list_id'), $vs_value); break; default: $va_data[$vs_sub_element] = $vs_value; break; } } } } $po_instance->addAttribute($va_data, $va_tmp[1]); } $vb_did_mapping = true; } } } if (!isset($va_mappings[$po_instance->tableName()])) { return $vb_did_mapping; } $va_mapping = $va_mappings[$vs_tablename]; $vs_type = $po_instance->getTypeCode(); if (isset($va_mapping[$vs_type]) && is_array($va_mapping[$vs_type])) { $va_mapping = $va_mapping[$vs_type]; } else { if (isset($va_mapping['__default__']) && is_array($va_mapping['__default__'])) { $va_mapping = $va_mapping['__default__']; } else { return $vb_did_mapping; } } foreach ($va_mapping as $vs_metadata => $va_attr) { $va_tmp = explode(":", $vs_metadata); $vs_delimiter = caGetOption('delimiter', $va_attr, false); foreach ($va_attr as $vs_attr) { if ($vs_attr == 'delimiter') { continue; } $va_metadata =& $pa_metadata; foreach ($va_tmp as $vs_el) { if (isset($va_metadata[$vs_el])) { $va_metadata =& $va_metadata[$vs_el]; } else { continue 2; } } if (is_array($va_metadata)) { $va_metadata = join(";", $va_metadata); } if (!is_int($va_metadata)) { // pass ints through for values like WhiteBalance = 0 if (!trim($va_metadata)) { continue 2; } } if (!caSeemsUTF8($va_metadata)) { $va_metadata = caEncodeUTF8Deep($va_metadata); } $va_tmp2 = explode(".", $vs_attr); switch ($va_tmp2[0]) { case 'preferred_labels': $po_instance->replaceLabel(array($va_tmp2[1] => $va_metadata), $pn_locale_id, null, true); break; case 'nonpreferred_labels': $po_instance->replaceLabel(array($va_tmp2[1] => $va_metadata), $pn_locale_id, null, false); break; default: if ($po_instance->hasField($vs_attr)) { $po_instance->set($vs_attr, $va_metadata); } else { // try as attribute if (sizeof($va_tmp2) == 2) { // format ca_objects.foo, we only want "foo" if ($vs_delimiter) { $va_m = explode($vs_delimiter, $va_metadata); $po_instance->removeAttributes($va_tmp2[1]); foreach ($va_m as $vs_m) { $po_instance->addAttribute(array($va_tmp2[1] => trim($vs_m), 'locale_id' => $pn_locale_id), $va_tmp2[1]); } } else { $po_instance->replaceAttribute(array($va_tmp2[1] => $va_metadata, 'locale_id' => $pn_locale_id), $va_tmp2[1]); } } } } $vb_did_mapping = true; } } return $vb_did_mapping; }
/** * Get bundle preview for a relationship bundle * @param BundlableLabelableBaseModelWithAttributes $t_rel_instance * @param array $pa_initial_values * @param string $ps_template * @param string $ps_delimiter * @return string */ function caGetBundlePreviewForRelationshipBundle($t_rel_instance, $pa_initial_values, $ps_template, $ps_delimiter = '; ') { if (!is_array($pa_initial_values) || sizeof($pa_initial_values) == 0) { return '""'; } // it's very unlikely that the preview will fit more then 10 items if (sizeof($pa_initial_values) > 10) { $pa_initial_values = array_slice($pa_initial_values, 0, 10); } if (!$t_rel_instance instanceof BundlableLabelableBaseModelWithAttributes) { return '""'; } $va_ids = $va_previews = array(); foreach ($pa_initial_values as $va_item) { $va_ids[] = $va_item['id']; } $o_res = $t_rel_instance->makeSearchResult($t_rel_instance->tableName(), $va_ids); while ($o_res->nextHit()) { $va_previews[] = $o_res->getWithTemplate($ps_template); } return caEscapeForBundlePreview(join($ps_delimiter, $va_previews)); }
/** * Prepopulate record fields according to rules in prepopulate.conf * * @param BundlableLabelableBaseModelWithAttributes $t_instance The table instance to prepopulate * @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(&$t_instance, $pa_options = null) { if (!$t_instance->getPrimaryKey()) { return false; } if ($vs_prepopulate_cfg = caGetOption('prepopulateConfig', $pa_options, null)) { $this->opo_plugin_config = Configuration::load($vs_prepopulate_cfg); } if (!($this->opo_plugin_config->get('prepopulate_fields_on_save') || $this->opo_plugin_config->get('prepopulate_fields_on_load'))) { return false; } $va_rules = $this->opo_plugin_config->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 (!$t_instance->inTransaction()) { $t_instance->setTransaction(new Transaction($t_instance->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 ($t_instance->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($t_instance->getTypeCode(), $va_rule['restrictToTypes'])) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because current record type " . $t_instance->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] = $t_instance->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, $t_instance->tableNum(), array($t_instance->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 ($t_instance->hasField($va_parts[1])) { switch (strtolower($vs_mode)) { case 'overwrite': // always set $t_instance->set($va_parts[1], $vs_value); break; case 'addifempty': default: if (!$t_instance->get($va_parts[1])) { $t_instance->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 ($t_instance->hasElement($va_parts[1])) { $va_attributes = $t_instance->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 $t_instance->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 (!$t_instance->get($vs_target)) { $t_instance->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 ($t_instance->hasElement($va_parts[1])) { $va_attr = $t_instance->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(); } } $t_instance->_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) { $t_instance->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) $t_instance->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 = $t_instance->getAppDatamodel()->getInstanceByTableName($t_instance->getLabelTableName(), true))) { continue; } if (!$t_label->hasField($va_parts[2])) { continue; } switch ($t_instance->getLabelCount($vb_preferred)) { case 0: // if no value exists, always add it (ignoring mode) $t_instance->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 = $t_instance->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) { $t_instance->editLabel($va_label['label_id'], $va_label, $g_ui_locale_id, null, $vb_preferred); } } else { $t_instance->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 = $t_instance->getMode(); $t_instance->setMode(ACCESS_WRITE); $t_instance->update(); $t_instance->setMode($vn_old_mode); //$_REQUEST['form_timestamp'] = $vn_timestamp; if ($t_instance->numErrors() > 0) { foreach ($t_instance->getErrors() as $vs_error) { Debug::msg("[prepopulateFields()] there was an error while updating the record: " . $vs_error); } if ($vb_we_set_transaction) { $t_instance->removeTransaction(false); } return false; } if ($vb_we_set_transaction) { $t_instance->removeTransaction(true); } return true; }