/** 
  * Check it a file already exists in the database as a representation
  *
  * @param string $ps_filepath The full path to the file
  * @return mixed ca_object_representations instance representing the first representation that contains the file, if representation exists with this file, false if the file does not yet exist
  */
 static function mediaExists($ps_filepath)
 {
     if (!file_exists($ps_filepath)) {
         return null;
     }
     $vs_md5 = md5_file($ps_filepath);
     $t_rep = new ca_object_representations();
     if ($t_rep->load(array('md5' => $vs_md5, 'deleted' => 0))) {
         return $t_rep;
     }
     return false;
 }
 /**
  * Saves all bundles on the specified screen in the database by extracting 
  * required data from the supplied request
  * $pm_screen can be a screen tag (eg. "Screen5") or a screen_id (eg. 5)
  *
  * Calls processBundlesBeforeBaseModelSave() method in subclass right before invoking insert() or update() on
  * the BaseModel, if the method is defined. Passes the following parameters to processBundlesBeforeBaseModelSave():
  *		array $pa_bundles An array of bundles to be saved
  *		string $ps_form_prefix The form prefix
  *		RequestHTTP $po_request The current request
  *		array $pa_options Optional array of parameters; expected to be the same as that passed to saveBundlesForScreen()
  *
  * The processBundlesBeforeBaseModelSave() is useful for those odd cases where you need to do some processing before the basic
  * database record defined by the model (eg. intrinsic fields and hierarchy coding) is inserted or updated. You usually don't need 
  * to use it.
  *
  * @param mixed $pm_screen
  * @param RequestHTTP $ps_request
  * @param array $pa_options Options are:
  *		dryRun = Go through the motions of saving but don't actually write information to the database
  *		batch = Process save in "batch" mode. Specifically this means honoring batch mode settings (add, replace, remove), skipping bundles that are not supported in batch mode and ignoring updates
  *		existingRepresentationMap = an array of representation_ids key'ed on file path. If set saveBundlesForScreen() use link the specified representation to the row it is saving rather than processing the uploaded file. saveBundlesForScreen() will build the map as it goes, adding newly uploaded files. If you want it to process a file in a batch situation where it should be processed the first time and linked subsequently then pass an empty array here. saveBundlesForScreen() will use the empty array to build the map.
  */
 public function saveBundlesForScreen($pm_screen, $po_request, &$pa_options)
 {
     $vb_we_set_transaction = false;
     $vs_form_prefix = caGetOption('formName', $pa_options, $po_request->getParameter('_formName', pString));
     $vb_dryrun = caGetOption('dryRun', $pa_options, false);
     $vb_batch = caGetOption('batch', $pa_options, false);
     if (!$this->inTransaction()) {
         $this->setTransaction(new Transaction($this->getDb()));
         $vb_we_set_transaction = true;
     } else {
         if ($vb_dryrun) {
             $this->postError(799, _t('Cannot do dry run save when in transaction. Try again without setting a transaction.'), "BundlableLabelableBaseModelWithAttributes->saveBundlesForScreen()");
             return false;
         }
     }
     $vb_read_only_because_deaccessioned = $this->hasField('is_deaccessioned') && (bool) $this->getAppConfig()->get('deaccession_dont_allow_editing') && (bool) $this->get('is_deaccessioned');
     BaseModel::setChangeLogUnitID();
     // get items on screen
     $t_ui = caGetOption('ui_instance', $pa_options, ca_editor_uis::loadDefaultUI($this->tableName(), $po_request, $this->getTypeID()));
     $va_bundle_lists = $this->getBundleListsForScreen($pm_screen, $po_request, $t_ui, $pa_options);
     //
     // Filter bundles to save if deaccessioned - only allow editing of the ca_objects_deaccession bundle
     //
     if ($vb_read_only_because_deaccessioned) {
         foreach ($va_bundle_lists['bundles'] as $vn_i => $va_bundle) {
             if ($va_bundle['bundle_name'] !== 'ca_objects_deaccession') {
                 unset($va_bundle_lists['bundles'][$vn_i]);
             }
         }
         foreach ($va_bundle_lists['fields_by_type'] as $vs_type => $va_bundles) {
             foreach ($va_bundles as $vs_id => $vs_bundle_name) {
                 if ($vs_bundle_name !== 'ca_objects_deaccession') {
                     unset($va_bundle_lists['fields_by_type'][$vs_type][$vs_id]);
                 }
             }
         }
     }
     $va_bundles = $va_bundle_lists['bundles'];
     $va_fields_by_type = $va_bundle_lists['fields_by_type'];
     // save intrinsic fields
     if (is_array($va_fields_by_type['intrinsic'])) {
         $vs_idno_field = $this->getProperty('ID_NUMBERING_ID_FIELD');
         foreach ($va_fields_by_type['intrinsic'] as $vs_placement_code => $vs_f) {
             if ($vb_batch) {
                 $vs_batch_mode = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_batch_mode", pString);
                 if ($vs_batch_mode == '_disabled_') {
                     continue;
                 }
             }
             if (isset($_FILES["{$vs_placement_code}{$vs_form_prefix}{$vs_f}"]) && $_FILES["{$vs_placement_code}{$vs_form_prefix}{$vs_f}"]) {
                 // media field
                 $this->set($vs_f, $_FILES["{$vs_placement_code}{$vs_form_prefix}{$vs_f}"]['tmp_name'], array('original_filename' => $_FILES["{$vs_placement_code}{$vs_form_prefix}{$vs_f}"]['name']));
             } else {
                 switch ($vs_f) {
                     case 'access':
                         if ((bool) $this->getAppConfig()->get($this->tableName() . '_allow_access_inheritance') && $this->hasField('access_inherit_from_parent')) {
                             $this->set('access_inherit_from_parent', $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}access_inherit_from_parent", pInteger));
                         }
                         if (!(bool) $this->getAppConfig()->get($this->tableName() . '_allow_access_inheritance') || !$this->hasField('access_inherit_from_parent') || !(bool) $this->get('access_inherit_from_parent')) {
                             $this->set('access', $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}access", pString));
                         }
                         break;
                     case $vs_idno_field:
                         if ($this->opo_idno_plugin_instance) {
                             $this->opo_idno_plugin_instance->setDb($this->getDb());
                             $this->set($vs_f, $vs_tmp = $this->opo_idno_plugin_instance->htmlFormValue($vs_idno_field));
                         } else {
                             $this->set($vs_f, $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}{$vs_f}", pString));
                         }
                         break;
                     default:
                         // Look for fully qualified intrinsic
                         if (!strlen($vs_v = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}{$vs_f}", pString))) {
                             // fall back to simple field name intrinsic spec - still used for "mandatory" fields such as type_id and parent_id
                             $vs_v = $po_request->getParameter("{$vs_f}", pString);
                         }
                         $this->set($vs_f, $vs_v);
                         break;
                 }
             }
             if ($this->numErrors() > 0) {
                 foreach ($this->errors() as $o_e) {
                     switch ($o_e->getErrorNumber()) {
                         case 795:
                             // field conflicts
                             foreach ($this->getFieldConflicts() as $vs_conflict_field) {
                                 $po_request->addActionError($o_e, $vs_conflict_field);
                             }
                             break;
                         default:
                             $po_request->addActionError($o_e, $vs_f);
                             break;
                     }
                 }
             }
         }
     }
     // save attributes
     $va_inserted_attributes_by_element = array();
     if (isset($va_fields_by_type['attribute']) && is_array($va_fields_by_type['attribute'])) {
         //
         // name of attribute request parameters are:
         // 	For new attributes
         // 		{$vs_form_prefix}_attribute_{element_set_id}_{element_id|'locale_id'}_new_{n}
         //		ex. ObjectBasicForm_attribute_6_locale_id_new_0 or ObjectBasicForm_attribute_6_desc_type_new_0
         //
         // 	For existing attributes:
         // 		{$vs_form_prefix}_attribute_{element_set_id}_{element_id|'locale_id'}_{attribute_id}
         //
         // look for newly created attributes; look for attributes to delete
         $va_inserted_attributes = array();
         $reserved_elements = array();
         foreach ($va_fields_by_type['attribute'] as $vs_placement_code => $vs_f) {
             $vs_element_set_code = preg_replace("/^ca_attribute_/", "", $vs_f);
             //does the attribute's datatype have a saveElement method - if so, use that instead
             $vs_element = $this->_getElementInstance($vs_element_set_code);
             $vn_element_id = $vs_element->getPrimaryKey();
             $vs_element_datatype = $vs_element->get('datatype');
             $vs_datatype = Attribute::getValueInstance($vs_element_datatype);
             if (method_exists($vs_datatype, 'saveElement')) {
                 $reserved_elements[] = $vs_element;
                 continue;
             }
             $va_attributes_to_insert = array();
             $va_attributes_to_delete = array();
             $va_locales = array();
             $vs_batch_mode = $_REQUEST[$vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_id . '_batch_mode'];
             if ($vb_batch && $vs_batch_mode == '_delete_') {
                 // Remove all attributes and continue
                 $this->removeAttributes($vn_element_id, array('force' => true));
                 continue;
             }
             foreach ($_REQUEST as $vs_key => $vs_val) {
                 // is it a newly created attribute?
                 if (preg_match('/' . $vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_id . '_([\\w\\d\\-_]+)_new_([\\d]+)/', $vs_key, $va_matches)) {
                     if ($vb_batch) {
                         switch ($vs_batch_mode) {
                             case '_disabled_':
                                 // skip
                                 continue 2;
                                 break;
                             case '_add_':
                                 // just try to add attribute as in normal non-batch save
                                 // noop
                                 break;
                             case '_replace_':
                                 // remove all existing attributes before trying to save
                                 $this->removeAttributes($vn_element_id, array('force' => true));
                                 continue;
                                 break;
                         }
                     }
                     $vn_c = intval($va_matches[2]);
                     // yep - grab the locale and value
                     $vn_locale_id = isset($_REQUEST[$vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_id . '_locale_id_new_' . $vn_c]) ? $_REQUEST[$vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_id . '_locale_id_new_' . $vn_c] : null;
                     $va_inserted_attributes_by_element[$vn_element_id][$vn_c]['locale_id'] = $va_attributes_to_insert[$vn_c]['locale_id'] = $vn_locale_id;
                     $va_inserted_attributes_by_element[$vn_element_id][$vn_c][$va_matches[1]] = $va_attributes_to_insert[$vn_c][$va_matches[1]] = $vs_val;
                 } else {
                     // is it a delete key?
                     if (preg_match('/' . $vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_id . '_([\\d]+)_delete/', $vs_key, $va_matches)) {
                         $vn_attribute_id = intval($va_matches[1]);
                         $va_attributes_to_delete[$vn_attribute_id] = true;
                     }
                 }
             }
             // look for uploaded files as attributes
             foreach ($_FILES as $vs_key => $va_val) {
                 if (preg_match('/' . $vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_id . '_locale_id_new_([\\d]+)/', $vs_key, $va_locale_matches)) {
                     $vn_locale_c = intval($va_locale_matches[1]);
                     $va_locales[$vn_locale_c] = $vs_val;
                     continue;
                 }
                 // is it a newly created attribute?
                 if (preg_match('/' . $vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_id . '_([\\w\\d\\-_]+)_new_([\\d]+)/', $vs_key, $va_matches)) {
                     if (!$va_val['size']) {
                         continue;
                     }
                     // skip empty files
                     // yep - grab the value
                     $vn_c = intval($va_matches[2]);
                     $va_inserted_attributes_by_element[$vn_element_id][$vn_c]['locale_id'] = $va_attributes_to_insert[$vn_c]['locale_id'] = $va_locales[$vn_c];
                     $va_val['_uploaded_file'] = true;
                     $va_inserted_attributes_by_element[$vn_element_id][$vn_c][$va_matches[1]] = $va_attributes_to_insert[$vn_c][$va_matches[1]] = $va_val;
                 }
             }
             if (!$vb_batch) {
                 // do deletes
                 $this->clearErrors();
                 foreach ($va_attributes_to_delete as $vn_attribute_id => $vb_tmp) {
                     $this->removeAttribute($vn_attribute_id, $vs_f, array('pending_adds' => $va_attributes_to_insert));
                 }
             }
             // do inserts
             foreach ($va_attributes_to_insert as $va_attribute_to_insert) {
                 $this->clearErrors();
                 $this->addAttribute($va_attribute_to_insert, $vn_element_id, $vs_f);
             }
             if (!$vb_batch) {
                 // check for attributes to update
                 if (is_array($va_attrs = $this->getAttributesByElement($vn_element_id))) {
                     $t_element = new ca_metadata_elements();
                     $va_attrs_update_list = array();
                     foreach ($va_attrs as $o_attr) {
                         $this->clearErrors();
                         $vn_attribute_id = $o_attr->getAttributeID();
                         if (isset($va_inserted_attributes[$vn_attribute_id]) && $va_inserted_attributes[$vn_attribute_id]) {
                             continue;
                         }
                         if (isset($va_attributes_to_delete[$vn_attribute_id]) && $va_attributes_to_delete[$vn_attribute_id]) {
                             continue;
                         }
                         $vn_element_set_id = $o_attr->getElementID();
                         $va_attr_update = array('locale_id' => $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_set_id . '_locale_id_' . $vn_attribute_id, pString));
                         //
                         // Check to see if there are any values in the element set that are not in the  attribute we're editing
                         // If additional sub-elements were added to the set after the attribute we're updating was created
                         // those sub-elements will not have corresponding values returned by $o_attr->getValues() above.
                         // Because we use the element_ids in those values to pull request parameters, if an element_id is missing
                         // it effectively becomes invisible and cannot be set. This is a fairly unusual case but it happens, and when it does
                         // it's really annoying. It would be nice and efficient to simply create the missing values at configuration time, but we wouldn't
                         // know what to set the values to. So what we do is, after setting all of the values present in the attribute from the request, grab
                         // the configuration for the element set and see if there are any elements in the set that we didn't get values for.
                         //
                         $va_sub_elements = $t_element->getElementsInSet($vn_element_set_id);
                         foreach ($va_sub_elements as $vn_i => $va_element_info) {
                             if ($va_element_info['datatype'] == 0) {
                                 continue;
                             }
                             //$vn_element_id = $o_attr_val->getElementID();
                             $vn_element_id = $va_element_info['element_id'];
                             $vs_k = $vs_placement_code . $vs_form_prefix . '_attribute_' . $vn_element_set_id . '_' . $vn_element_id . '_' . $vn_attribute_id;
                             if (isset($_FILES[$vs_k]) && ($va_val = $_FILES[$vs_k])) {
                                 if ($va_val['size'] > 0) {
                                     // is there actually a file?
                                     $va_val['_uploaded_file'] = true;
                                     $va_attr_update[$vn_element_id] = $va_val;
                                     continue;
                                 }
                             }
                             $vs_attr_val = $po_request->getParameter($vs_k, pString);
                             $va_attr_update[$vn_element_id] = $vs_attr_val;
                         }
                         $this->clearErrors();
                         $this->editAttribute($vn_attribute_id, $vn_element_set_id, $va_attr_update, $vs_f);
                     }
                 }
             }
         }
     }
     if (!$vb_batch) {
         // hierarchy moves are not supported in batch mode
         if (is_array($va_fields_by_type['special'])) {
             foreach ($va_fields_by_type['special'] as $vs_placement_code => $vs_bundle) {
                 if ($vs_bundle !== 'hierarchy_location') {
                     continue;
                 }
                 $va_parent_tmp = explode("-", $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_new_parent_id", pString));
                 // Hierarchy browser sets new_parent_id param to "X" if user wants to extract item from hierarchy
                 $vn_parent_id = ($vn_parent_id = array_pop($va_parent_tmp)) == 'X' ? -1 : (int) $vn_parent_id;
                 if (sizeof($va_parent_tmp) > 0) {
                     $vs_parent_table = array_pop($va_parent_tmp);
                 } else {
                     $vs_parent_table = $this->tableName();
                 }
                 if ($this->getPrimaryKey() && $this->HIERARCHY_PARENT_ID_FLD && $vn_parent_id > 0) {
                     if ($vs_parent_table == $this->tableName()) {
                         $this->set($this->HIERARCHY_PARENT_ID_FLD, $vn_parent_id);
                     } else {
                         if ((bool) $this->getAppConfig()->get('ca_objects_x_collections_hierarchy_enabled') && $vs_parent_table == 'ca_collections' && $this->tableName() == 'ca_objects' && ($vs_coll_rel_type = $this->getAppConfig()->get('ca_objects_x_collections_hierarchy_relationship_type'))) {
                             // link object to collection
                             $this->removeRelationships('ca_collections', $vs_coll_rel_type);
                             $this->set($this->HIERARCHY_PARENT_ID_FLD, null);
                             $this->set($this->HIERARCHY_ID_FLD, $this->getPrimaryKey());
                             if (!$this->addRelationship('ca_collections', $vn_parent_id, $vs_coll_rel_type)) {
                                 $this->postError(2510, _t('Could not move object under collection: %1', join("; ", $this->getErrors())), "BundlableLabelableBaseModelWithAttributes->saveBundlesForScreen()");
                             }
                         }
                     }
                 } else {
                     if ($this->getPrimaryKey() && $this->HIERARCHY_PARENT_ID_FLD && $this->HIERARCHY_TYPE == __CA_HIER_TYPE_ADHOC_MONO__ && isset($_REQUEST["{$vs_placement_code}{$vs_form_prefix}_new_parent_id"]) && $vn_parent_id <= 0) {
                         $this->set($this->HIERARCHY_PARENT_ID_FLD, null);
                         $this->set($this->HIERARCHY_ID_FLD, $this->getPrimaryKey());
                         // Support for collection-object cross-table hierarchies
                         if ((bool) $this->getAppConfig()->get('ca_objects_x_collections_hierarchy_enabled') && $this->tableName() == 'ca_objects' && ($vs_coll_rel_type = $this->getAppConfig()->get('ca_objects_x_collections_hierarchy_relationship_type')) && $vn_parent_id == -1) {
                             // -1 = extract from hierarchy
                             $this->removeRelationships('ca_collections', $vs_coll_rel_type);
                         }
                     }
                 }
                 break;
             }
         }
     }
     //
     // Call processBundlesBeforeBaseModelSave() method in sub-class, if it is defined. The method is passed
     // a list of bundles, the form prefix, the current request and the options passed to saveBundlesForScreen() –
     // everything needed to perform custom processing using the incoming form content that is being saved.
     //
     // A processBundlesBeforeBaseModelSave() method is rarely needed, but can be handy when you need to do something model-specific
     // right before the basic database record is committed via insert() (for new records) or update() (for existing records).
     // For example, the media in ca_object_representations is set in a "special" bundle, which provides a specialized media upload UI. Unfortunately "special's"
     // are handled after the basic database record is saved via insert() or update(), while the actual media must be set prior to the save.
     // processBundlesBeforeBaseModelSave() allows special logic in the ca_object_representations model to be invoked to set the media before the insert() or update().
     // The "special" takes care of other functions after the insert()/update()
     //
     if (method_exists($this, "processBundlesBeforeBaseModelSave")) {
         $this->processBundlesBeforeBaseModelSave($va_bundles, $vs_form_prefix, $po_request, $pa_options);
     }
     $this->setMode(ACCESS_WRITE);
     $vb_is_insert = false;
     if ($this->getPrimaryKey()) {
         $this->update();
     } else {
         $this->insert();
         $vb_is_insert = true;
     }
     if ($this->numErrors() > 0) {
         $va_errors = array();
         foreach ($this->errors() as $o_e) {
             switch ($o_e->getErrorNumber()) {
                 case 2010:
                     $po_request->addActionErrors(array($o_e), 'hierarchy_location');
                     break;
                 case 795:
                     // field conflict
                     foreach ($this->getFieldConflicts() as $vs_conflict_field) {
                         $po_request->addActionError($o_e, $vs_conflict_field);
                     }
                     break;
                 case 1100:
                     if ($vs_idno_field = $this->getProperty('ID_NUMBERING_ID_FIELD')) {
                         $po_request->addActionError($o_e, $this->getProperty('ID_NUMBERING_ID_FIELD'));
                     }
                     break;
                 default:
                     $va_errors[] = $o_e;
                     break;
             }
         }
         $po_request->addActionErrors($va_errors);
         if ($vb_is_insert) {
             BaseModel::unsetChangeLogUnitID();
             if ($vb_we_set_transaction) {
                 $this->removeTransaction(false);
             }
             return false;
             // bail on insert error
         }
     }
     if (!$this->getPrimaryKey()) {
         BaseModel::unsetChangeLogUnitID();
         if ($vb_we_set_transaction) {
             $this->removeTransaction(false);
         }
         return false;
     }
     // bail if insert failed
     $this->clearErrors();
     //save reserved elements -  those with a saveElement method
     if (isset($reserved_elements) && is_array($reserved_elements)) {
         foreach ($reserved_elements as $res_element) {
             $res_element_id = $res_element->getPrimaryKey();
             $res_element_datatype = $res_element->get('datatype');
             $res_datatype = Attribute::getValueInstance($res_element_datatype);
             $res_datatype->saveElement($this, $res_element, $vs_form_prefix, $po_request);
         }
     }
     // save preferred labels
     if ($this->getProperty('LABEL_TABLE_NAME')) {
         $vb_check_for_dupe_labels = $this->_CONFIG->get('allow_duplicate_labels_for_' . $this->tableName()) ? false : true;
         $vb_error_inserting_pref_label = false;
         if (is_array($va_fields_by_type['preferred_label'])) {
             foreach ($va_fields_by_type['preferred_label'] as $vs_placement_code => $vs_f) {
                 if (!$vb_batch) {
                     // check for existing labels to update (or delete)
                     $va_preferred_labels = $this->getPreferredLabels(null, false);
                     foreach ($va_preferred_labels as $vn_item_id => $va_labels_by_locale) {
                         foreach ($va_labels_by_locale as $vn_locale_id => $va_label_list) {
                             foreach ($va_label_list as $va_label) {
                                 if ($vn_label_locale_id = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_Pref' . 'locale_id_' . $va_label['label_id'], pString)) {
                                     if (is_array($va_label_values = $this->getLabelUIValuesFromRequest($po_request, $vs_placement_code . $vs_form_prefix, $va_label['label_id'], true))) {
                                         if ($vb_check_for_dupe_labels && $this->checkForDupeLabel($vn_label_locale_id, $va_label_values)) {
                                             $this->postError(1125, _t('Value <em>%1</em> is already used and duplicates are not allowed', join("/", $va_label_values)), "BundlableLabelableBaseModelWithAttributes->saveBundlesForScreen()", $this->tableName() . '.preferred_labels');
                                             $po_request->addActionErrors($this->errors(), 'preferred_labels');
                                             continue;
                                         }
                                         $vn_label_type_id = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_Pref' . 'type_id_' . $va_label['label_id'], pInteger);
                                         $this->editLabel($va_label['label_id'], $va_label_values, $vn_label_locale_id, $vn_label_type_id, true);
                                         if ($this->numErrors()) {
                                             foreach ($this->errors() as $o_e) {
                                                 switch ($o_e->getErrorNumber()) {
                                                     case 795:
                                                         // field conflicts
                                                         $po_request->addActionError($o_e, 'preferred_labels');
                                                         break;
                                                     default:
                                                         $po_request->addActionError($o_e, $vs_f);
                                                         break;
                                                 }
                                             }
                                         }
                                     }
                                 } else {
                                     if ($po_request->getParameter($vs_placement_code . $vs_form_prefix . '_PrefLabel_' . $va_label['label_id'] . '_delete', pString)) {
                                         // delete
                                         $this->removeLabel($va_label['label_id']);
                                     }
                                 }
                             }
                         }
                     }
                 }
                 // check for new labels to add
                 foreach ($_REQUEST as $vs_key => $vs_value) {
                     if (!preg_match('/' . $vs_placement_code . $vs_form_prefix . '_Pref' . 'locale_id_new_([\\d]+)/', $vs_key, $va_matches)) {
                         continue;
                     }
                     if ($vb_batch) {
                         $vs_batch_mode = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_Pref_batch_mode', pString);
                         switch ($vs_batch_mode) {
                             case '_disabled_':
                                 // skip
                                 continue 2;
                                 break;
                             case '_replace_':
                                 // remove all existing preferred labels before trying to save
                                 $this->removeAllLabels(__CA_LABEL_TYPE_PREFERRED__);
                                 continue;
                             case '_delete_':
                                 // remove all existing preferred labels
                                 $this->removeAllLabels(__CA_LABEL_TYPE_PREFERRED__);
                                 continue 2;
                             case '_add_':
                                 break;
                         }
                     }
                     $vn_c = intval($va_matches[1]);
                     if ($vn_new_label_locale_id = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_Pref' . 'locale_id_new_' . $vn_c, pString)) {
                         if (is_array($va_label_values = $this->getLabelUIValuesFromRequest($po_request, $vs_placement_code . $vs_form_prefix, 'new_' . $vn_c, true))) {
                             // make sure we don't add multiple pref labels for one locale in batch mode
                             if ($vb_batch && $vs_batch_mode == '_add_') {
                                 // first remove [BLANK] labels for this locale if there are any, as we are about to add a new one
                                 $va_labels_for_this_locale = $this->getPreferredLabels(array($vn_new_label_locale_id));
                                 if (is_array($va_labels_for_this_locale)) {
                                     foreach ($va_labels_for_this_locale as $vn_id => $va_labels_by_locale) {
                                         foreach ($va_labels_by_locale as $vn_locale_id => $va_labels) {
                                             foreach ($va_labels as $vn_i => $va_label) {
                                                 if (isset($va_label[$this->getLabelDisplayField()]) && $va_label[$this->getLabelDisplayField()] == '[' . _t('BLANK') . ']') {
                                                     $this->removeLabel($va_label['label_id']);
                                                 }
                                             }
                                         }
                                     }
                                 }
                                 // if there are non-[BLANK] labels for this locale, don't add this new one
                                 $va_labels_for_this_locale = $this->getPreferredLabels(array($vn_new_label_locale_id), true, array('forDisplay' => true));
                                 if (is_array($va_labels_for_this_locale) && sizeof($va_labels_for_this_locale) > 0) {
                                     $this->postError(1125, _t('A preferred label for this locale already exists. Only one preferred label per locale is allowed.'), "BundlableLabelableBaseModelWithAttributes->saveBundlesForScreen()", $this->tableName() . '.preferred_labels');
                                     $po_request->addActionErrors($this->errors(), $vs_f);
                                     $vb_error_inserting_pref_label = true;
                                     continue;
                                 }
                             }
                             if ($vb_check_for_dupe_labels && $this->checkForDupeLabel($vn_new_label_locale_id, $va_label_values)) {
                                 $this->postError(1125, _t('Value <em>%1</em> is already used and duplicates are not allowed', join("/", $va_label_values)), "BundlableLabelableBaseModelWithAttributes->saveBundlesForScreen()", $this->tableName() . '.preferred_labels');
                                 $po_request->addActionErrors($this->errors(), 'preferred_labels');
                                 $vb_error_inserting_pref_label = true;
                                 continue;
                             }
                             $vn_label_type_id = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_Pref' . 'type_id_new_' . $vn_c, pInteger);
                             $this->addLabel($va_label_values, $vn_new_label_locale_id, $vn_label_type_id, true);
                             if ($this->numErrors()) {
                                 $po_request->addActionErrors($this->errors(), $vs_f);
                                 $vb_error_inserting_pref_label = true;
                             }
                         }
                     }
                 }
             }
         }
     }
     // Add default label if needed (ie. if the user has failed to set at least one label or if they have deleted all existing labels)
     // This ensures at least one label is present for the record. If no labels are present then the
     // record may not be found in queries
     if ($this->getProperty('LABEL_TABLE_NAME')) {
         if ($vb_error_inserting_pref_label || !$this->addDefaultLabel($vn_new_label_locale_id)) {
             if (!$vb_error_inserting_pref_label) {
                 $po_request->addActionErrors($this->errors(), 'preferred_labels');
             }
             if ($vb_we_set_transaction) {
                 $this->removeTransaction(false);
             }
             if ($vb_is_insert) {
                 $this->_FIELD_VALUES[$this->primaryKey()] = null;
                 // clear primary key, which doesn't actually exist since we rolled back the transaction
                 foreach ($va_inserted_attributes_by_element as $vn_element_id => $va_failed_inserts) {
                     // set attributes as "failed" (but with no error messages) so they stay set
                     $this->setFailedAttributeInserts($vn_element_id, $va_failed_inserts);
                 }
             }
             return false;
         }
     }
     unset($va_inserted_attributes_by_element);
     // save non-preferred labels
     if ($this->getProperty('LABEL_TABLE_NAME') && isset($va_fields_by_type['nonpreferred_label']) && is_array($va_fields_by_type['nonpreferred_label'])) {
         if (!$vb_batch) {
             foreach ($va_fields_by_type['nonpreferred_label'] as $vs_placement_code => $vs_f) {
                 // check for existing labels to update (or delete)
                 $va_nonpreferred_labels = $this->getNonPreferredLabels(null, false);
                 foreach ($va_nonpreferred_labels as $vn_item_id => $va_labels_by_locale) {
                     foreach ($va_labels_by_locale as $vn_locale_id => $va_label_list) {
                         foreach ($va_label_list as $va_label) {
                             if ($vn_label_locale_id = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_NPref' . 'locale_id_' . $va_label['label_id'], pString)) {
                                 if (is_array($va_label_values = $this->getLabelUIValuesFromRequest($po_request, $vs_placement_code . $vs_form_prefix, $va_label['label_id'], false))) {
                                     $vn_label_type_id = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_NPref' . 'type_id_' . $va_label['label_id'], pInteger);
                                     $this->editLabel($va_label['label_id'], $va_label_values, $vn_label_locale_id, $vn_label_type_id, false);
                                     if ($this->numErrors()) {
                                         foreach ($this->errors() as $o_e) {
                                             switch ($o_e->getErrorNumber()) {
                                                 case 795:
                                                     // field conflicts
                                                     $po_request->addActionError($o_e, 'nonpreferred_labels');
                                                     break;
                                                 default:
                                                     $po_request->addActionError($o_e, $vs_f);
                                                     break;
                                             }
                                         }
                                     }
                                 }
                             } else {
                                 if ($po_request->getParameter($vs_placement_code . $vs_form_prefix . '_NPrefLabel_' . $va_label['label_id'] . '_delete', pString)) {
                                     // delete
                                     $this->removeLabel($va_label['label_id']);
                                 }
                             }
                         }
                     }
                 }
             }
         }
         // check for new labels to add
         foreach ($va_fields_by_type['nonpreferred_label'] as $vs_placement_code => $vs_f) {
             if ($vb_batch) {
                 $vs_batch_mode = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_NPref_batch_mode', pString);
                 switch ($vs_batch_mode) {
                     case '_disabled_':
                         // skip
                         continue 2;
                         break;
                     case '_add_':
                         // just try to add attribute as in normal non-batch save
                         // noop
                         break;
                     case '_replace_':
                         // remove all existing nonpreferred labels before trying to save
                         $this->removeAllLabels(__CA_LABEL_TYPE_NONPREFERRED__);
                         continue;
                     case '_delete_':
                         // remove all existing nonpreferred labels
                         $this->removeAllLabels(__CA_LABEL_TYPE_NONPREFERRED__);
                         continue 2;
                         break;
                 }
             }
             foreach ($_REQUEST as $vs_key => $vs_value) {
                 if (!preg_match('/^' . $vs_placement_code . $vs_form_prefix . '_NPref' . 'locale_id_new_([\\d]+)/', $vs_key, $va_matches)) {
                     continue;
                 }
                 $vn_c = intval($va_matches[1]);
                 if ($vn_new_label_locale_id = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_NPref' . 'locale_id_new_' . $vn_c, pString)) {
                     if (is_array($va_label_values = $this->getLabelUIValuesFromRequest($po_request, $vs_placement_code . $vs_form_prefix, 'new_' . $vn_c, false))) {
                         $vn_new_label_type_id = $po_request->getParameter($vs_placement_code . $vs_form_prefix . '_NPref' . 'type_id_new_' . $vn_c, pInteger);
                         $this->addLabel($va_label_values, $vn_new_label_locale_id, $vn_new_label_type_id, false);
                         if ($this->numErrors()) {
                             $po_request->addActionErrors($this->errors(), $vs_f);
                         }
                     }
                 }
             }
         }
     }
     // save data in related tables
     if (isset($va_fields_by_type['related_table']) && is_array($va_fields_by_type['related_table'])) {
         foreach ($va_fields_by_type['related_table'] as $vs_placement_code => $vs_f) {
             $vn_table_num = $this->_DATAMODEL->getTableNum($vs_f);
             // get settings
             $va_bundle_settings = array();
             foreach ($va_bundles as $va_bundle_info) {
                 if ($va_bundle_info['placement_code'] == $vs_placement_code) {
                     $va_bundle_settings = $va_bundle_info['settings'];
                     break;
                 }
             }
             switch ($vs_f) {
                 # -------------------------------------
                 case 'ca_object_representations':
                     // check for existing representations to update (or delete)
                     $vs_prefix_stub = $vs_placement_code . $vs_form_prefix . '_';
                     $vb_allow_fetching_of_urls = (bool) $this->_CONFIG->get('allow_fetching_of_media_from_remote_urls');
                     $va_rep_ids_sorted = $va_rep_sort_order = explode(';', $po_request->getParameter($vs_prefix_stub . 'ObjectRepresentationBundleList', pString));
                     sort($va_rep_ids_sorted, SORT_NUMERIC);
                     $va_reps = $this->getRepresentations();
                     if (!$vb_batch && is_array($va_reps)) {
                         foreach ($va_reps as $vn_i => $va_rep) {
                             $this->clearErrors();
                             if (strlen($po_request->getParameter($vs_prefix_stub . 'access_' . $va_rep['representation_id'], pInteger)) > 0) {
                                 if ($vb_allow_fetching_of_urls && ($vs_path = $_REQUEST[$vs_prefix_stub . 'media_url_' . $va_rep['representation_id']])) {
                                     $va_tmp = explode('/', $vs_path);
                                     $vs_original_name = array_pop($va_tmp);
                                 } else {
                                     $vs_path = $_FILES[$vs_prefix_stub . 'media_' . $va_rep['representation_id']]['tmp_name'];
                                     $vs_original_name = $_FILES[$vs_prefix_stub . 'media_' . $va_rep['representation_id']]['name'];
                                 }
                                 $vn_is_primary = $po_request->getParameter($vs_prefix_stub . 'is_primary_' . $va_rep['representation_id'], pString) != '' ? $po_request->getParameter($vs_prefix_stub . 'is_primary_' . $va_rep['representation_id'], pInteger) : null;
                                 $vn_locale_id = $po_request->getParameter($vs_prefix_stub . 'locale_id_' . $va_rep['representation_id'], pInteger);
                                 $vs_idno = $po_request->getParameter($vs_prefix_stub . 'idno_' . $va_rep['representation_id'], pString);
                                 $vn_access = $po_request->getParameter($vs_prefix_stub . 'access_' . $va_rep['representation_id'], pInteger);
                                 $vn_status = $po_request->getParameter($vs_prefix_stub . 'status_' . $va_rep['representation_id'], pInteger);
                                 $vs_rep_label = trim($po_request->getParameter($vs_prefix_stub . 'rep_label_' . $va_rep['representation_id'], pString));
                                 //$vn_rep_type_id = $po_request->getParameter($vs_prefix_stub.'rep_type_id'.$va_rep['representation_id'], pInteger);
                                 // Get user-specified center point (images only)
                                 $vn_center_x = $po_request->getParameter($vs_prefix_stub . 'center_x_' . $va_rep['representation_id'], pString);
                                 $vn_center_y = $po_request->getParameter($vs_prefix_stub . 'center_y_' . $va_rep['representation_id'], pString);
                                 $vn_rank = null;
                                 if (($vn_rank_index = array_search($va_rep['representation_id'], $va_rep_sort_order)) !== false) {
                                     $vn_rank = $va_rep_ids_sorted[$vn_rank_index];
                                 }
                                 $this->editRepresentation($va_rep['representation_id'], $vs_path, $vn_locale_id, $vn_status, $vn_access, $vn_is_primary, array('idno' => $vs_idno), array('original_filename' => $vs_original_name, 'rank' => $vn_rank, 'centerX' => $vn_center_x, 'centerY' => $vn_center_y));
                                 if ($this->numErrors()) {
                                     //$po_request->addActionErrors($this->errors(), $vs_f, $va_rep['representation_id']);
                                     foreach ($this->errors() as $o_e) {
                                         switch ($o_e->getErrorNumber()) {
                                             case 795:
                                                 // field conflicts
                                                 $po_request->addActionError($o_e, $vs_f, $va_rep['representation_id']);
                                                 break;
                                             default:
                                                 $po_request->addActionError($o_e, $vs_f, $va_rep['representation_id']);
                                                 break;
                                         }
                                     }
                                 }
                                 if ($vs_rep_label) {
                                     //
                                     // Set representation label
                                     //
                                     $t_rep = new ca_object_representations();
                                     if ($this->inTransaction()) {
                                         $t_rep->setTransaction($this->getTransaction());
                                     }
                                     global $g_ui_locale_id;
                                     if ($t_rep->load($va_rep['representation_id'])) {
                                         $t_rep->setMode(ACCESS_WRITE);
                                         $t_rep->replaceLabel(array('name' => $vs_rep_label), $g_ui_locale_id, null, true);
                                         if ($t_rep->numErrors()) {
                                             $po_request->addActionErrors($t_rep->errors(), $vs_f, $va_rep['representation_id']);
                                         }
                                     }
                                 }
                             } else {
                                 // is it a delete key?
                                 $this->clearErrors();
                                 if ($po_request->getParameter($vs_prefix_stub . $va_rep['representation_id'] . '_delete', pInteger) > 0) {
                                     // delete!
                                     $this->removeRepresentation($va_rep['representation_id']);
                                     if ($this->numErrors()) {
                                         $po_request->addActionErrors($this->errors(), $vs_f, $va_rep['representation_id']);
                                     }
                                 }
                             }
                         }
                     }
                     if ($vb_batch) {
                         $vs_batch_mode = $_REQUEST[$vs_prefix_stub . 'batch_mode'];
                         if ($vs_batch_mode == '_disabled_') {
                             break;
                         }
                         if ($vs_batch_mode == '_replace_') {
                             $this->removeAllRepresentations();
                         }
                         if ($vs_batch_mode == '_delete_') {
                             $this->removeAllRepresentations();
                             break;
                         }
                     }
                     // check for new representations to add
                     $va_file_list = $_FILES;
                     foreach ($_REQUEST as $vs_key => $vs_value) {
                         if (!preg_match('/^' . $vs_prefix_stub . 'media_url_new_([\\d]+)$/', $vs_key, $va_matches)) {
                             continue;
                         }
                         $va_file_list[$vs_key] = array('url' => $vs_value);
                     }
                     foreach ($va_file_list as $vs_key => $va_values) {
                         $this->clearErrors();
                         if (!preg_match('/^' . $vs_prefix_stub . 'media_new_([\\d]+)$/', $vs_key, $va_matches) && ($vb_allow_fetching_of_urls && !preg_match('/^' . $vs_prefix_stub . 'media_url_new_([\\d]+)$/', $vs_key, $va_matches) || !$vb_allow_fetching_of_urls)) {
                             continue;
                         }
                         if ($vs_upload_type = $po_request->getParameter($vs_prefix_stub . 'upload_typenew_' . $va_matches[1], pString)) {
                             $po_request->user->setVar('defaultRepresentationUploadType', $vs_upload_type);
                         }
                         $vn_type_id = $po_request->getParameter($vs_prefix_stub . 'type_id_new_' . $va_matches[1], pInteger);
                         if ($vn_existing_rep_id = $po_request->getParameter($vs_prefix_stub . 'idnew_' . $va_matches[1], pInteger)) {
                             $this->addRelationship('ca_object_representations', $vn_existing_rep_id, $vn_type_id);
                         } else {
                             if ($vb_allow_fetching_of_urls && ($vs_path = $va_values['url'])) {
                                 $va_tmp = explode('/', $vs_path);
                                 $vs_original_name = array_pop($va_tmp);
                             } else {
                                 $vs_path = $va_values['tmp_name'];
                                 $vs_original_name = $va_values['name'];
                             }
                             if (!$vs_path) {
                                 continue;
                             }
                             $vn_rep_type_id = $po_request->getParameter($vs_prefix_stub . 'rep_type_id_new_' . $va_matches[1], pInteger);
                             if (!$vn_rep_type_id && !($vn_rep_type_id = caGetDefaultItemID('object_representation_types'))) {
                                 require_once __CA_MODELS_DIR__ . '/ca_lists.php';
                                 $t_list = new ca_lists();
                                 if (is_array($va_rep_type_ids = $t_list->getItemsForList('object_representation_types', array('idsOnly' => true, 'enabledOnly' => true)))) {
                                     $vn_rep_type_id = array_shift($va_rep_type_ids);
                                 }
                             }
                             if (is_array($pa_options['existingRepresentationMap']) && isset($pa_options['existingRepresentationMap'][$vs_path]) && $pa_options['existingRepresentationMap'][$vs_path]) {
                                 $this->addRelationship('ca_object_representations', $pa_options['existingRepresentationMap'][$vs_path], $vn_type_id);
                                 break;
                             }
                             $vs_rep_label = trim($po_request->getParameter($vs_prefix_stub . 'rep_label_new_' . $va_matches[1], pString));
                             $vn_locale_id = $po_request->getParameter($vs_prefix_stub . 'locale_id_new_' . $va_matches[1], pInteger);
                             $vs_idno = $po_request->getParameter($vs_prefix_stub . 'idno_new_' . $va_matches[1], pString);
                             $vn_status = $po_request->getParameter($vs_prefix_stub . 'status_new_' . $va_matches[1], pInteger);
                             $vn_access = $po_request->getParameter($vs_prefix_stub . 'access_new_' . $va_matches[1], pInteger);
                             $vn_is_primary = $po_request->getParameter($vs_prefix_stub . 'is_primary_new_' . $va_matches[1], pInteger);
                             // Get user-specified center point (images only)
                             $vn_center_x = $po_request->getParameter($vs_prefix_stub . 'center_x_new_' . $va_matches[1], pString);
                             $vn_center_y = $po_request->getParameter($vs_prefix_stub . 'center_y_new_' . $va_matches[1], pString);
                             $t_rep = $this->addRepresentation($vs_path, $vn_rep_type_id, $vn_locale_id, $vn_status, $vn_access, $vn_is_primary, array('name' => $vs_rep_label, 'idno' => $vs_idno), array('original_filename' => $vs_original_name, 'returnRepresentation' => true, 'centerX' => $vn_center_x, 'centerY' => $vn_center_y, 'type_id' => $vn_type_id));
                             // $vn_type_id = *relationship* type_id (as opposed to representation type)
                             if ($this->numErrors()) {
                                 $po_request->addActionErrors($this->errors(), $vs_f, 'new_' . $va_matches[1]);
                             } else {
                                 if ($t_rep && is_array($pa_options['existingRepresentationMap'])) {
                                     $pa_options['existingRepresentationMap'][$vs_path] = $t_rep->getPrimaryKey();
                                 }
                             }
                         }
                     }
                     break;
                     # -------------------------------------
                 # -------------------------------------
                 case 'ca_entities':
                 case 'ca_places':
                 case 'ca_objects':
                 case 'ca_collections':
                 case 'ca_occurrences':
                 case 'ca_list_items':
                 case 'ca_object_lots':
                 case 'ca_storage_locations':
                 case 'ca_loans':
                 case 'ca_movements':
                 case 'ca_tour_stops':
                     $this->_processRelated($po_request, $vs_f, $vs_form_prefix, $vs_placement_code, array('batch' => $vb_batch, 'settings' => $va_bundle_settings));
                     break;
                     # -------------------------------------
                 # -------------------------------------
                 case 'ca_representation_annotations':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $this->_processRepresentationAnnotations($po_request, $vs_form_prefix, $vs_placement_code);
                     break;
                     # -------------------------------------
             }
         }
     }
     // save data for "specials"
     if (isset($va_fields_by_type['special']) && is_array($va_fields_by_type['special'])) {
         foreach ($va_fields_by_type['special'] as $vs_placement_code => $vs_f) {
             // get settings
             $va_bundle_settings = array();
             foreach ($va_bundles as $va_bundle_info) {
                 if ('P' . $va_bundle_info['placement_id'] == $vs_placement_code) {
                     $va_bundle_settings = $va_bundle_info['settings'];
                     break;
                 }
             }
             switch ($vs_f) {
                 # -------------------------------------
                 // This bundle is only available when editing objects of type ca_representation_annotations
                 case 'ca_representation_annotation_properties':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     if (!$this->useInEditor()) {
                         break;
                     }
                     foreach ($this->getPropertyList() as $vs_property) {
                         $this->setPropertyValue($vs_property, $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}{$vs_property}", pString));
                     }
                     if (!$this->validatePropertyValues()) {
                         $po_request->addActionErrors($this->errors(), 'ca_representation_annotation_properties', 'general');
                     }
                     $this->update();
                     break;
                     # -------------------------------------
                     // This bundle is only available for types which support set membership
                 # -------------------------------------
                 // This bundle is only available for types which support set membership
                 case 'ca_sets':
                     // check for existing labels to delete (no updating supported)
                     require_once __CA_MODELS_DIR__ . '/ca_sets.php';
                     require_once __CA_MODELS_DIR__ . '/ca_set_items.php';
                     $t_set = new ca_sets();
                     if (!$vb_batch) {
                         $va_sets = caExtractValuesByUserLocale($t_set->getSetsForItem($this->tableNum(), $this->getPrimaryKey(), array('user_id' => $po_request->getUserID())));
                         foreach ($va_sets as $vn_set_id => $va_set_info) {
                             $vn_item_id = $va_set_info['item_id'];
                             if ($po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_set_id_{$vn_item_id}_delete", pString)) {
                                 // delete
                                 $t_set->load($va_set_info['set_id']);
                                 $t_set->removeItem($this->getPrimaryKey(), $po_request->getUserID());
                                 // remove *all* instances of the item in the set, not just the specified id
                                 if ($t_set->numErrors()) {
                                     $po_request->addActionErrors($t_set->errors(), $vs_f);
                                 }
                             }
                         }
                     }
                     if ($vb_batch) {
                         $vs_batch_mode = $_REQUEST["{$vs_placement_code}{$vs_form_prefix}_batch_mode"];
                         if ($vs_batch_mode == '_disabled_') {
                             break;
                         }
                         if ($vs_batch_mode == '_replace_') {
                             $t_set->removeItemFromAllSets($this->tableNum(), $this->getPrimaryKey());
                         }
                         if ($vs_batch_mode == '_delete_') {
                             $t_set->removeItemFromAllSets($this->tableNum(), $this->getPrimaryKey());
                             break;
                         }
                     }
                     foreach ($_REQUEST as $vs_key => $vs_value) {
                         if (!preg_match("/{$vs_placement_code}{$vs_form_prefix}_set_id_new_([\\d]+)/", $vs_key, $va_matches)) {
                             continue;
                         }
                         $vn_c = intval($va_matches[1]);
                         if ($vn_new_set_id = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_set_id_new_{$vn_c}", pString)) {
                             $t_set->load($vn_new_set_id);
                             $t_set->addItem($this->getPrimaryKey(), null, $po_request->getUserID());
                             if ($t_set->numErrors()) {
                                 $po_request->addActionErrors($t_set->errors(), $vs_f);
                             }
                         }
                     }
                     break;
                     # -------------------------------------
                     // This bundle is only available for types which support set membership
                 # -------------------------------------
                 // This bundle is only available for types which support set membership
                 case 'ca_set_items':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     // check for existing labels to delete (no updating supported)
                     require_once __CA_MODELS_DIR__ . '/ca_sets.php';
                     require_once __CA_MODELS_DIR__ . '/ca_set_items.php';
                     $va_rids = explode(';', $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}setRowIDList", pString));
                     $this->reorderItems($va_rids, array('user_id' => $po_request->getUserID(), 'treatRowIDsAsRIDs' => true, 'deleteExcludedItems' => true));
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_search_forms
                 # -------------------------------------
                 // This bundle is only available for ca_search_forms
                 case 'ca_search_form_elements':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     // save settings
                     $va_settings = $this->getAvailableSettings();
                     foreach ($va_settings as $vs_setting => $va_setting_info) {
                         if (isset($_REQUEST['setting_' . $vs_setting])) {
                             $vs_setting_val = $po_request->getParameter('setting_' . $vs_setting, pString);
                             $this->setSetting($vs_setting, $vs_setting_val);
                             $this->update();
                         }
                     }
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_bundle_displays
                 # -------------------------------------
                 // This bundle is only available for ca_bundle_displays
                 case 'ca_bundle_display_placements':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $this->savePlacementsFromHTMLForm($po_request, $vs_form_prefix, $vs_placement_code);
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_bundle_displays
                 # -------------------------------------
                 // This bundle is only available for ca_bundle_displays
                 case 'ca_bundle_display_type_restrictions':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $this->saveTypeRestrictionsFromHTMLForm($po_request, $vs_form_prefix, $vs_placement_code);
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_search_forms
                 # -------------------------------------
                 // This bundle is only available for ca_search_forms
                 case 'ca_search_form_placements':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $this->savePlacementsFromHTMLForm($po_request, $vs_form_prefix, $vs_placement_code);
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_editor_ui
                 # -------------------------------------
                 // This bundle is only available for ca_editor_ui
                 case 'ca_editor_ui_screens':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     global $g_ui_locale_id;
                     require_once __CA_MODELS_DIR__ . '/ca_editor_ui_screens.php';
                     $va_screen_ids = explode(';', $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_ScreenBundleList", pString));
                     foreach ($_REQUEST as $vs_key => $vs_val) {
                         if (is_array($vs_val)) {
                             continue;
                         }
                         if (!($vs_val = trim($vs_val))) {
                             continue;
                         }
                         if (preg_match("!^{$vs_placement_code}{$vs_form_prefix}_name_new_([\\d]+)\$!", $vs_key, $va_matches)) {
                             if (!($t_screen = $this->addScreen($vs_val, $g_ui_locale_id, 'screen_' . $this->getPrimaryKey() . '_' . $va_matches[1]))) {
                                 break;
                             }
                             if ($vn_fkey = array_search("new_" . $va_matches[1], $va_screen_ids)) {
                                 $va_screen_ids[$vn_fkey] = $t_screen->getPrimaryKey();
                             } else {
                                 $va_screen_ids[] = $t_screen->getPrimaryKey();
                             }
                             continue;
                         }
                         if (preg_match("!^{$vs_placement_code}{$vs_form_prefix}_([\\d]+)_delete\$!", $vs_key, $va_matches)) {
                             $this->removeScreen($va_matches[1]);
                             if ($vn_fkey = array_search($va_matches[1], $va_screen_ids)) {
                                 unset($va_screen_ids[$vn_fkey]);
                             }
                         }
                     }
                     $this->reorderScreens($va_screen_ids);
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_editor_ui_screens
                 # -------------------------------------
                 // This bundle is only available for ca_editor_ui_screens
                 case 'ca_editor_ui_bundle_placements':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $this->savePlacementsFromHTMLForm($po_request, $vs_form_prefix, $vs_placement_code);
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_editor_uis
                 # -------------------------------------
                 // This bundle is only available for ca_editor_uis
                 case 'ca_editor_ui_type_restrictions':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $this->saveTypeRestrictionsFromHTMLForm($po_request, $vs_form_prefix, $vs_placement_code);
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_editor_ui_screens
                 # -------------------------------------
                 // This bundle is only available for ca_editor_ui_screens
                 case 'ca_editor_ui_screen_type_restrictions':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $this->saveTypeRestrictionsFromHTMLForm($po_request, $vs_form_prefix, $vs_placement_code);
                     break;
                     # -------------------------------------
                     // This bundle is only available for ca_tours
                 # -------------------------------------
                 // This bundle is only available for ca_tours
                 case 'ca_tour_stops_list':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     global $g_ui_locale_id;
                     require_once __CA_MODELS_DIR__ . '/ca_tour_stops.php';
                     $va_stop_ids = explode(';', $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_StopBundleList", pString));
                     foreach ($_REQUEST as $vs_key => $vs_val) {
                         if (!($vs_val = trim($vs_val))) {
                             continue;
                         }
                         if (preg_match("!^{$vs_placement_code}{$vs_form_prefix}_name_new_([\\d]+)\$!", $vs_key, $va_matches)) {
                             $vn_type_id = $_REQUEST["{$vs_placement_code}{$vs_form_prefix}_type_id_new_" . $va_matches[1]];
                             if (!($t_stop = $this->addStop($vs_val, $vn_type_id, $g_ui_locale_id, mb_substr(preg_replace('![^A-Za-z0-9_]+!', '_', $vs_val), 0, 255)))) {
                                 break;
                             }
                             if ($vn_fkey = array_search("new_" . $va_matches[1], $va_stop_ids)) {
                                 $va_stop_ids[$vn_fkey] = $t_stop->getPrimaryKey();
                             } else {
                                 $va_stop_ids[] = $t_stop->getPrimaryKey();
                             }
                             continue;
                         }
                         if (preg_match("!^{$vs_placement_code}{$vs_form_prefix}_([\\d]+)_delete\$!", $vs_key, $va_matches)) {
                             $this->removeStop($va_matches[1]);
                             if ($vn_fkey = array_search($va_matches[1], $va_stop_ids)) {
                                 unset($va_stop_ids[$vn_fkey]);
                             }
                         }
                     }
                     $this->reorderStops($va_stop_ids);
                     break;
                     # -------------------------------------
                 # -------------------------------------
                 case 'ca_user_groups':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     if (!$po_request->user->canDoAction('is_administrator') && $po_request->getUserID() != $this->get('user_id')) {
                         break;
                     }
                     // don't save if user is not owner
                     require_once __CA_MODELS_DIR__ . '/ca_user_groups.php';
                     $va_groups_to_set = $va_group_effective_dates = array();
                     foreach ($_REQUEST as $vs_key => $vs_val) {
                         if (preg_match("!^{$vs_placement_code}{$vs_form_prefix}_id(.*)\$!", $vs_key, $va_matches)) {
                             $vs_effective_date = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_effective_date_" . $va_matches[1], pString);
                             $vn_group_id = (int) $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_id" . $va_matches[1], pInteger);
                             $vn_access = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_access_" . $va_matches[1], pInteger);
                             if ($vn_access > 0) {
                                 $va_groups_to_set[$vn_group_id] = $vn_access;
                                 $va_group_effective_dates[$vn_group_id] = $vs_effective_date;
                             }
                         }
                     }
                     $this->setUserGroups($va_groups_to_set, $va_group_effective_dates, array('user_id' => $po_request->getUserID()));
                     break;
                     # -------------------------------------
                 # -------------------------------------
                 case 'ca_users':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     if (!$po_request->user->canDoAction('is_administrator') && $po_request->getUserID() != $this->get('user_id')) {
                         break;
                     }
                     // don't save if user is not owner
                     require_once __CA_MODELS_DIR__ . '/ca_users.php';
                     $va_users_to_set = $va_user_effective_dates = array();
                     foreach ($_REQUEST as $vs_key => $vs_val) {
                         if (preg_match("!^{$vs_placement_code}{$vs_form_prefix}_id(.*)\$!", $vs_key, $va_matches)) {
                             $vs_effective_date = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_effective_date_" . $va_matches[1], pString);
                             $vn_user_id = (int) $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_id" . $va_matches[1], pInteger);
                             $vn_access = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_access_" . $va_matches[1], pInteger);
                             if ($vn_access > 0) {
                                 $va_users_to_set[$vn_user_id] = $vn_access;
                                 $va_user_effective_dates[$vn_user_id] = $vs_effective_date;
                             }
                         }
                     }
                     $this->setUsers($va_users_to_set, $va_user_effective_dates);
                     break;
                     # -------------------------------------
                 # -------------------------------------
                 case 'settings':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $this->setSettingsFromHTMLForm($po_request, array('id' => $vs_form_prefix . '_', 'placement_code' => $vs_placement_code));
                     break;
                     # -------------------------------
                     // This bundle is only available when editing objects of type ca_object_representations
                 # -------------------------------
                 // This bundle is only available when editing objects of type ca_object_representations
                 case 'ca_object_representations_media_display':
                     if ($vb_batch) {
                         break;
                     }
                     // not supported in batch mode
                     $va_versions_to_process = null;
                     if ($vb_use_options = (bool) $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_derivative_options_selector", pInteger)) {
                         // update only specified versions
                         $va_versions_to_process = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_set_versions", pArray);
                     }
                     if (!is_array($va_versions_to_process) || !sizeof($va_versions_to_process)) {
                         $va_versions_to_process = array('_all');
                     }
                     if ($vb_use_options && $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_derivative_options_mode", pString) == 'timecode') {
                         // timecode
                         if (!(string) ($vs_timecode = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_derivative_options_mode_timecode_value", pString))) {
                             $vs_timecode = "1s";
                         }
                         //
                         $o_media = new Media();
                         if ($o_media->read($this->getMediaPath('media', 'original'))) {
                             $va_files = $o_media->writePreviews(array('force' => true, 'outputDirectory' => $this->_CONFIG->get("taskqueue_tmp_directory"), 'minNumberOfFrames' => 1, 'maxNumberOfFrames' => 1, 'startAtTime' => $vs_timecode, 'endAtTime' => $vs_timecode, 'width' => 720, 'height' => 540));
                             if (sizeof($va_files)) {
                                 $this->set('media', array_shift($va_files));
                             }
                         }
                     } else {
                         if ($vb_use_options && $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_derivative_options_mode", pString) == 'page') {
                             if (!(int) ($vn_page = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_derivative_options_mode_page_value", pInteger))) {
                                 $vn_page = 1;
                             }
                             //
                             $o_media = new Media();
                             if ($o_media->read($this->getMediaPath('media', 'original'))) {
                                 $va_files = $o_media->writePreviews(array('force' => true, 'outputDirectory' => $this->_CONFIG->get("taskqueue_tmp_directory"), 'numberOfPages' => 1, 'startAtPage' => $vn_page, 'width' => 2048, 'height' => 2048));
                                 if (sizeof($va_files)) {
                                     $this->set('media', array_shift($va_files));
                                 }
                             }
                         } else {
                             // process file as new upload
                             $vs_key = "{$vs_placement_code}{$vs_form_prefix}_url";
                             if (($vs_media_url = trim($po_request->getParameter($vs_key, pString))) && isURL($vs_media_url)) {
                                 $this->set('media', $vs_media_url);
                             } else {
                                 $vs_key = "{$vs_placement_code}{$vs_form_prefix}_media";
                                 if (isset($_FILES[$vs_key])) {
                                     $this->set('media', $_FILES[$vs_key]['tmp_name'], array('original_filename' => $_FILES[$vs_key]['name']));
                                 }
                             }
                         }
                     }
                     if ($this->changed('media')) {
                         $this->update($vs_version != '_all' ? array('updateOnlyMediaVersions' => $va_versions_to_process) : array());
                         if ($this->numErrors()) {
                             $po_request->addActionErrors($this->errors(), 'ca_object_representations_media_display', 'general');
                         }
                     }
                     break;
                     # -------------------------------
                     // This bundle is only available when editing objects of type ca_object_representations
                 # -------------------------------
                 // This bundle is only available when editing objects of type ca_object_representations
                 case 'ca_object_representation_captions':
                     if ($vb_batch) {
                         return null;
                     }
                     // not supported in batch mode
                     $va_users_to_set = array();
                     foreach ($_REQUEST as $vs_key => $vs_val) {
                         if (preg_match("!^{$vs_placement_code}{$vs_form_prefix}_locale_id(.*)\$!", $vs_key, $va_matches)) {
                             $vn_locale_id = (int) $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_locale_id" . $va_matches[1], pInteger);
                             $this->addCaptionFile($_FILES["{$vs_placement_code}{$vs_form_prefix}_caption_file" . $va_matches[1]]['tmp_name'], $vn_locale_id, array('originalFilename' => $_FILES["{$vs_placement_code}{$vs_form_prefix}_captions_caption_file" . $va_matches[1]]['name']));
                         } else {
                             // any to delete?
                             if (preg_match("!^{$vs_placement_code}{$vs_form_prefix}_([\\d]+)_delete\$!", $vs_key, $va_matches)) {
                                 $this->removeCaptionFile((int) $va_matches[1]);
                             }
                         }
                     }
                     break;
                     # -------------------------------
                     // This bundle is only available for relationships that include an object on one end
                 # -------------------------------
                 // This bundle is only available for relationships that include an object on one end
                 case 'ca_object_representation_chooser':
                     if ($vb_batch) {
                         return null;
                     }
                     // not supported in batch mode
                     if (!is_array($va_rep_ids = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}", pArray))) {
                         $va_rep_ids = array();
                     }
                     if ($vs_element_code = caGetOption(array('elementCode', 'element_code'), $va_bundle_settings, null)) {
                         if (!is_array($va_current_rep_ids = $this->get($this->tableName() . "." . $vs_element_code, array('returnAsArray' => true, 'idsOnly' => true)))) {
                             $va_current_rep_ids = $va_current_rep_id_with_structure = array();
                         } else {
                             $va_current_rep_id_with_structure = $this->get($this->tableName() . "." . $vs_element_code, array('returnWithStructure' => true, 'idsOnly' => true));
                         }
                         $va_rep_to_attr_id = array();
                         foreach ($va_rep_ids as $vn_rep_id) {
                             if (in_array($vn_rep_id, $va_current_rep_ids)) {
                                 continue;
                             }
                             $this->addAttribute(array($vs_element_code => $vn_rep_id), $vs_element_code);
                         }
                         foreach ($va_current_rep_id_with_structure as $vn_id => $va_vals_by_attr_id) {
                             foreach ($va_vals_by_attr_id as $vn_attribute_id => $va_val) {
                                 if (!in_array($va_val[$vs_element_code], $va_rep_ids)) {
                                     $this->removeAttribute($vn_attribute_id);
                                 }
                             }
                         }
                         $this->update();
                     }
                     break;
                     # -------------------------------
                     // This bundle is only available for objects
                 # -------------------------------
                 // This bundle is only available for objects
                 case 'ca_objects_location':
                     if ($vb_batch) {
                         return null;
                     }
                     // not supported in batch mode
                     if (!$po_request->user->canDoAction('can_edit_ca_objects')) {
                         break;
                     }
                     if ($vn_location_id = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_location_idnew_0", pInteger)) {
                         if (is_array($va_relationship_types = caGetOption('ca_storage_locations_relationshipType', $va_bundle_settings, null)) && ($vn_relationship_type_id = array_shift($va_relationship_types))) {
                             $this->addRelationship('ca_storage_locations', $vn_location_id, $vn_relationship_type_id, null, null, null, null, array('allowDuplicates' => true));
                             if ($this->numErrors()) {
                                 $po_request->addActionErrors($this->errors(), 'ca_objects_location', 'general');
                             }
                         }
                     }
                     break;
                     # -------------------------------
                     // This bundle is only available for objects
                 # -------------------------------
                 // This bundle is only available for objects
                 case 'ca_objects_history':
                     if ($vb_batch) {
                         return null;
                     }
                     // not supported in batch mode
                     if (!$po_request->user->canDoAction('can_edit_ca_objects')) {
                         break;
                     }
                     // set storage location
                     if ($vn_location_id = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_location_idnew_0", pInteger)) {
                         if (is_array($va_relationship_types = caGetOption('ca_storage_locations_showRelationshipTypes', $va_bundle_settings, null)) && ($vn_relationship_type_id = array_shift($va_relationship_types))) {
                             $this->addRelationship('ca_storage_locations', $vn_location_id, $vn_relationship_type_id, null, null, null, null, array('allowDuplicates' => true));
                             if ($this->numErrors()) {
                                 $po_request->addActionErrors($this->errors(), 'ca_objects_history', 'general');
                             }
                         }
                     }
                     // set loan
                     if ($vn_loan_id = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_loan_idnew_0", pInteger)) {
                         if ($vn_loan_type_id = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}_loan_type_idnew_0", pInteger)) {
                             $this->addRelationship('ca_loans', $vn_loan_id, $vn_loan_type_id);
                             if ($this->numErrors()) {
                                 $po_request->addActionErrors($this->errors(), 'ca_objects_history', 'general');
                             }
                         }
                     }
                     break;
                     # -------------------------------
                     // This bundle is only available for objects
                 # -------------------------------
                 // This bundle is only available for objects
                 case 'ca_objects_deaccession':
                     // object deaccession information
                     if (!$vb_batch && !$this->getPrimaryKey()) {
                         return null;
                     }
                     // not supported for new records
                     if (!$po_request->user->canDoAction('can_edit_ca_objects')) {
                         break;
                     }
                     $this->set('is_deaccessioned', $vb_is_deaccessioned = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}is_deaccessioned", pInteger));
                     $this->set('deaccession_notes', $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}deaccession_notes", pString));
                     $this->set('deaccession_type_id', $x = $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}deaccession_type_id", pString));
                     $this->set('deaccession_date', $po_request->getParameter("{$vs_placement_code}{$vs_form_prefix}deaccession_date", pString));
                     if ($vb_is_deaccessioned && (bool) $this->getAppConfig()->get('deaccession_force_access_private')) {
                         $this->get('access', 0);
                     }
                     // set access to private for accessioned items
                     $this->update();
                     break;
                     # -------------------------------
                     // This bundle is only available for objects
                 # -------------------------------
                 // This bundle is only available for objects
                 case 'ca_object_checkouts':
                     // object checkout information
                     if ($vb_batch) {
                         return null;
                     }
                     // not supported in batch mode
                     if (!$vb_batch && !$this->getPrimaryKey()) {
                         return null;
                     }
                     // not supported for new records
                     if (!$po_request->user->canDoAction('can_edit_ca_objects')) {
                         break;
                     }
                     // NOOP (for now)
                     break;
                     # -------------------------------
             }
         }
     }
     BaseModel::unsetChangeLogUnitID();
     $va_bundle_names = array();
     foreach ($va_bundles as $va_bundle) {
         $vs_bundle_name = str_replace('ca_attribute_', '', $va_bundle['bundle_name']);
         if (!$this->getAppDatamodel()->getInstanceByTableName($vs_bundle_name, true)) {
             $vs_bundle_name = $this->tableName() . '.' . $vs_bundle_name;
         }
         $va_bundle_names[] = $vs_bundle_name;
     }
     // validate metadata dictionary rules
     $va_violations = $this->validateUsingMetadataDictionaryRules(array('bundles' => $va_bundle_names));
     if (sizeof($va_violations)) {
         if ($vb_we_set_transaction && isset($va_violations['ERR']) && is_array($va_violations['ERR']) && sizeof($va_violations['ERR']) > 0) {
             BaseModel::unsetChangeLogUnitID();
             $this->removeTransaction(false);
             $this->_FIELD_VALUES[$this->primaryKey()] = null;
             // clear primary key since transaction has been rolled back
             foreach ($va_violations['ERR'] as $vs_bundle => $va_errs_by_bundle) {
                 foreach ($va_errs_by_bundle as $vn_i => $va_rule) {
                     $vs_bundle = str_replace($this->tableName() . ".", "", $vs_bundle);
                     $po_request->addActionErrors(array(new Error(1100, $va_rule['rule_settings']['violationMessage'], "BundlableLabelableBaseModelWithAttributes->saveBundlesForScreen()", 'MetadataDictionary', false, false)), $vs_bundle, 'general');
                 }
             }
             return false;
         }
     }
     // prepopulate fields
     $vs_prepopulate_cfg = $this->getAppConfig()->get('prepopulate_config');
     $o_prepopulate_conf = Configuration::load($vs_prepopulate_cfg);
     if ($o_prepopulate_conf->get('prepopulate_fields_on_save')) {
         $this->prepopulateFields(array('prepopulateConfig' => $vs_prepopulate_cfg));
     }
     if ($vb_dryrun) {
         $this->removeTransaction(false);
     }
     if ($vb_we_set_transaction) {
         $this->removeTransaction(true);
     }
     return true;
 }
 private function fetchAndImport($pa_item_queue, $po_client, $pa_config, $pa_tables, $ps_code)
 {
     if (!is_array($pa_tables)) {
         $pa_tables = array();
     }
     $t_rel_type = new ca_relationship_types();
     $vs_base_url = $pa_config['baseUrl'];
     $o_dm = Datamodel::load();
     $t_locale = new ca_locales();
     $t_list = new ca_lists();
     $vn_source_id = $t_list->getItemIDFromList('object_sources', $pa_config['code']);
     $pn_rep_type_id = $t_list->getItemIDFromList('object_representation_types', 'front');
     foreach ($pa_item_queue as $vn_i => $va_item) {
         $vs_table = $va_item['table'];
         $va_import_relationships_from = $pa_config['importRelatedFor'][$va_item['table']];
         print "oo";
         print_r($va_import_relationships_from);
         $vn_id = $va_item['id'];
         if (!$vn_id) {
             print "[Notice] SKIP CAUSE NO ID ({$ps_code})\n";
             continue;
         }
         if (isset($this->opa_processed_records[$vs_table . '/' . $vn_id])) {
             continue;
         }
         $vs_idno = trim((string) $va_item['idno']);
         try {
             $o_xml = $po_client->getItem($vs_table, $vn_id)->get();
         } catch (exception $e) {
             print "[ERROR] While trying to get item information: " . $e->getMessage() . "\n";
             continue;
         }
         $o_item = $o_xml->getItem;
         $t_instance = $o_dm->getInstanceByTableName($vs_table, false);
         $t_instance_label = $t_instance->getLabelTableInstance();
         // Look for existing record
         $vb_skip = false;
         $vb_update = false;
         $vs_label_fld = $t_instance->getLabelDisplayField();
         $vs_label = (string) $o_item->preferred_labels->en_US->{$vs_label_fld};
         print "[Notice] Processing [{$vs_table}] {$vs_label} [{$vs_idno}] ({$ps_code})\n";
         $t_instance_label->clear();
         if ($vs_idno && ($vs_table == 'ca_objects' && $t_instance->load(array('idno' => $vs_idno)) || $vs_table != 'ca_objects' && $t_instance->load(array('idno' => $vs_idno)))) {
             if ($t_instance->hasField('deleted') && $t_instance->get('deleted') == 1) {
                 $t_instance->set('deleted', 0);
             }
             //print "[Notice] Update [{$vs_idno}] for {$vs_table} 'cause it already exists ({$ps_code})\n";
             if (!$t_instance->getPrimaryKey()) {
                 $vb_skip = true;
                 print "[ERROR] Could not load instance for [{$vs_idno}]\n";
             }
             $vb_update = true;
             $t_instance->setMode(ACCESS_WRITE);
             // Clear labels
             $t_instance->removeAllLabels();
             if ($t_instance->numErrors()) {
                 print "[ERROR] Could not remove labels for updating: " . join("; ", $t_instance->getErrors()) . "\n";
             }
             // Clear attributes
             $t_instance->removeAttributes(null, array('dontCheckMinMax' => true));
             if ($t_instance->numErrors()) {
                 print "[ERROR] Could not remove attributes for updating: " . join("; ", $t_instance->getErrors()) . "\n";
             }
             // Clear relationships
             if (is_array($va_import_relationships_from)) {
                 foreach ($va_import_relationships_from as $vs_rel_table => $va_table_info) {
                     $t_instance->removeRelationships($vs_rel_table);
                     if ($t_instance->numErrors()) {
                         print "[ERROR] Could not remove {$vs_rel_table} relationships for updating: " . join("; ", $t_instance->getErrors()) . "\n";
                     }
                 }
             }
             if ($t_instance->tableName() == 'ca_objects') {
                 //$t_instance->set('source_id', $vn_source_id);
             }
             $t_instance->update();
             if ($t_instance->numErrors()) {
                 print "[ERROR] Could not clear record for updating: " . join("; ", $t_instance->getErrors()) . "\n";
             }
         }
         // create new one
         if (!$vb_update) {
             $t_instance->clear();
             if ($t_instance->tableName() == 'ca_objects') {
                 //$t_instance->set('source_id', $vn_source_id);
             }
         }
         $t_instance->setMode(ACCESS_WRITE);
         // add intrinsics
         switch ($vs_table) {
             case 'ca_collections':
                 $va_intrinsics = array('status', 'access', 'idno');
                 break;
             case 'ca_occurrences':
                 $va_intrinsics = array('status', 'access', 'idno');
                 break;
             case 'ca_objects':
                 $va_intrinsics = array('status', 'access', 'idno');
                 break;
             case 'ca_entities':
                 $va_intrinsics = array('status', 'access', 'lifespan', 'source_id', 'idno');
                 break;
             case 'ca_object_lots':
                 $va_intrinsics = array('status', 'access', 'idno_stub');
                 break;
             default:
                 $va_intrinsics = array('status', 'access', 'idno');
                 break;
         }
         // TODO: Need to properly handle foreign-key intrinsics when the item they point to doesn't exist
         // eg. source_id fields, various ca_objects and ca_object_lots intrinsics, etc.
         if ($vs_table == 'ca_list_items') {
             // does list exist?
             $vs_list_code = (string) $o_item->{'list_code'};
             $t_list = new ca_lists();
             if (!$t_list->load(array('list_code' => $vs_list_code))) {
                 // create list
                 $t_list->setMode(ACCESS_WRITE);
                 // TODO: should we bother to replicate the is_hierarchical, use_as_vocabulary and default_sort settings via a service?
                 // For now just set reasonable values
                 $t_list->set('list_code', $vs_list_code);
                 $t_list->set('is_hierarchical', 1);
                 $t_list->set('use_as_vocabulary', 1);
                 $t_list->set('default_sort', 0);
                 $t_list->insert();
                 if ($t_list->numErrors()) {
                     print "[ERROR] Could not insert new list '{$vs_list_code}': " . join('; ', $t_list->getErrors()) . "\n";
                 } else {
                     $t_list->addLabel(array('name' => $vs_list_code), $pn_locale_id, null, true);
                     if ($t_list->numErrors()) {
                         print "[ERROR] Could not add label to new list '{$vs_list_code}': " . join('; ', $t_list->getErrors()) . "\n";
                     }
                 }
             }
             $t_instance->set('list_id', $t_list->getPrimaryKey());
         }
         foreach ($va_intrinsics as $vs_f) {
             $t_instance->set($vs_f, $o_item->{$vs_f});
         }
         if (!$vb_update) {
             $vn_type_id = $t_instance->getTypeIDForCode((string) $o_item->type_id);
             if (!$vn_type_id) {
                 print "NO TYPE FOR {$vs_table}/" . $o_item->type_id . "\n";
             }
             $t_instance->set('type_id', $vn_type_id);
             if ($t_instance->tableName() == 'ca_objects') {
                 //$t_instance->set('source_id', $vn_source_id);
             }
             // TODO: add hook onBeforeInsert()
             $t_instance->insert();
             // TODO: add hook onInsert()
             if ($t_instance->numErrors()) {
                 print "[ERROR] Could not insert record: " . join('; ', $t_instance->getErrors()) . "\n";
             }
         }
         // add attributes
         // TODO: make this configurable
         $va_codes = $t_instance->getApplicableElementCodes();
         // $va_codes = array(
         // 				'description',
         // 				'georeference', 'geonames', 'internal_notes',
         // 				'oclc_number', 'file_name',
         // 				'digitized_by', 'digitized_date', 'call_number',
         // 				'other_call_number', 'collection_title', 'collection_number',
         // 				'box_number', 'folder_number', 'volume_number', 'page_number', 'shelf',
         // 				'pulled_digitization', 'pulled_name', 'pulled_date', 'returned_digitization',
         // 				'returned_name', 'returned_date', 'needs_redigitization', 'donor', 'copyright_holder',
         // 				'reproduction_restrictions', 'administrative_notes', 'date_view', 'date_item',
         // 				'view_format', 'item_format', 'dimensions', 'map_scale', 'image_description', 'address',
         // 				'lcsh_terms',  'inscription'
         //
         // 			);
         foreach ($va_codes as $vs_code) {
             $t_element = $t_instance->_getElementInstance($vs_code);
             switch ($t_element->get('datatype')) {
                 case 0:
                     // container
                     $va_elements = $t_element->getElementsInSet();
                     $o_attr = $o_item->{'ca_attribute_' . $vs_code};
                     foreach ($o_attr as $va_tag => $o_tags) {
                         foreach ($o_tags as $vs_locale => $o_values) {
                             if (!($vn_locale_id = $t_locale->localeCodeToID($vs_locale))) {
                                 $vn_locale_id = null;
                             }
                             $va_container_data = array('locale_id' => $vn_locale_id);
                             foreach ($o_values as $o_value) {
                                 foreach ($va_elements as $vn_i => $va_element_info) {
                                     if ($va_element_info['datatype'] == 0) {
                                         continue;
                                     }
                                     if ($vs_value = trim((string) $o_value->{$va_element_info['element_code']})) {
                                         switch ($va_element_info['datatype']) {
                                             case 3:
                                                 //list
                                                 $va_tmp = explode(":", $vs_value);
                                                 //<item_id>:<item_idno>
                                                 //print "CONTAINER LIST CODE=".$va_tmp[1]."/$vs_value/".$va_element_info['list_id']."\n";
                                                 $va_container_data[$va_element_info['element_code']] = $t_list->getItemIDFromList($va_element_info['list_id'], $va_tmp[1]);
                                                 break;
                                             default:
                                                 $va_container_data[$va_element_info['element_code']] = $vs_value;
                                                 break;
                                         }
                                     }
                                 }
                                 $t_instance->replaceAttribute($va_container_data, $vs_code);
                             }
                         }
                     }
                     break;
                 case 3:
                     // list
                     $o_attr = $o_item->{'ca_attribute_' . $vs_code};
                     foreach ($o_attr as $va_tag => $o_tags) {
                         foreach ($o_tags as $vs_locale => $o_values) {
                             if (!($vn_locale_id = $t_locale->localeCodeToID($vs_locale))) {
                                 $vn_locale_id = null;
                             }
                             foreach ($o_values as $o_value) {
                                 if ($vs_value = trim((string) $o_value->{$vs_code})) {
                                     $va_tmp = explode(":", $vs_value);
                                     //<item_id>:<item_idno>
                                     // TODO: create lists and list items if they don't already exist
                                     if ($vn_item_id = $t_list->getItemIDFromList($t_element->get('list_id'), $va_tmp[1])) {
                                         $t_instance->replaceAttribute(array($vs_code => $vn_item_id, 'locale_id' => $vn_locale_id), $vs_code);
                                     }
                                 }
                             }
                         }
                     }
                     break;
                 case 15:
                     // File
                 // File
                 case 16:
                     // Media
                     $t_instance->update();
                     if ($t_instance->numErrors()) {
                         print "[ERROR] Could not update record before media: " . join('; ', $t_instance->getErrors()) . "\n";
                     }
                     // TODO: detect if media has changes and only pull if it has
                     $o_attr = $o_item->{'ca_attribute_' . $vs_code};
                     foreach ($o_attr as $va_tag => $o_tags) {
                         foreach ($o_tags as $vs_locale => $o_values) {
                             if (!($vn_locale_id = $t_locale->localeCodeToID($vs_locale))) {
                                 $vn_locale_id = null;
                             }
                             foreach ($o_values as $o_value) {
                                 if ($vs_value = trim((string) $o_value->{$vs_code})) {
                                     $t_instance->replaceAttribute(array($vs_code => $vs_value, 'locale_id' => $vn_locale_id), $vs_code);
                                 }
                             }
                         }
                     }
                     $t_instance->update();
                     if ($t_instance->numErrors()) {
                         print "[ERROR] Could not update record after media: " . join('; ', $t_instance->getErrors()) . "\n";
                     }
                     break;
                 default:
                     $o_attr = $o_item->{'ca_attribute_' . $vs_code};
                     foreach ($o_attr as $va_tag => $o_tags) {
                         foreach ($o_tags as $vs_locale => $o_values) {
                             if (!($vn_locale_id = $t_locale->localeCodeToID($vs_locale))) {
                                 $vn_locale_id = null;
                             }
                             foreach ($o_values as $o_value) {
                                 if ($vs_value = trim((string) $o_value->{$vs_code})) {
                                     $t_instance->replaceAttribute(array($vs_code => $vs_value, 'locale_id' => $vn_locale_id), $vs_code);
                                 }
                             }
                         }
                     }
                     break;
             }
         }
         $t_instance->update();
         if ($t_instance->numErrors()) {
             print "[ERROR] Could not update [1] record: " . join('; ', $t_instance->getErrors()) . "\n";
         }
         // TODO: add hook onBeforeUpdate()
         $t_instance->update();
         // TODO: add hook onUpdate()
         if ($t_instance->numErrors()) {
             print "[ERROR] Could not update [2] record: " . join('; ', $t_instance->getErrors()) . "\n";
         }
         // get label fields
         $va_label_data = array();
         foreach ($t_instance->getLabelUIFields() as $vs_field) {
             if (!($va_label_data[$vs_field] = $o_item->preferred_labels->en_US->{$vs_field})) {
                 $va_label_data[$vs_field] = $o_item->preferred_labels->en_US->{$vs_field};
             }
         }
         // TODO: add hook onBeforeAddLabel()
         $t_instance->addLabel($va_label_data, 1, null, true);
         // TODO: add hook onAddLabel()
         if ($t_instance->numErrors()) {
             print "ERROR adding label: " . join('; ', $t_instance->getErrors()) . "\n";
         }
         $this->opa_processed_records[$va_item['table'] . '/' . (int) $va_item['id']] = $t_instance->getPrimaryKey();
         if ($vb_skip) {
             continue;
         }
         if (!is_array($va_import_relationships_from)) {
             continue;
         }
         $pa_tables[$va_item['table']] = true;
         // Are there relationships?
         $pb_imported_self_relations = false;
         print_r($va_import_relationships_from);
         foreach ($va_import_relationships_from as $vs_rel_table => $va_table_info) {
             $vb_is_self_relation = $vs_rel_table == $t_instance->tableName() && !$pb_imported_self_relations ? true : false;
             if (!$pa_tables[$vs_rel_table] || $vb_is_self_relation) {
                 // load related records recursively
                 if ($vs_rel_table == $t_instance->tableName()) {
                     $pb_imported_self_relations = true;
                 }
                 if ($o_item->{'related_' . $vs_rel_table}) {
                     $t_rel = $o_dm->getInstanceByTableName($vs_rel_table, false);
                     // TODO: add hook onBeforeAddRelationships()
                     foreach ($o_item->{'related_' . $vs_rel_table} as $vs_tag => $o_related_items) {
                         foreach ($o_related_items as $vs_i => $o_related_item) {
                             if (is_array($pa_config['importRelatedFor'][$va_item['table']][$vs_rel_table])) {
                                 $va_rel_types = array_keys($pa_config['importRelatedFor'][$va_item['table']][$vs_rel_table]);
                                 if (is_array($va_rel_types) && sizeof($va_rel_types) && !in_array((string) $o_related_item->relationship_type_code, $va_rel_types)) {
                                     print "[INFO] Skipped relationship for {$vs_display_name} because type='" . (string) $o_related_item->relationship_type_code . "' is excluded\n";
                                     continue;
                                 }
                             }
                             $vs_pk = $t_rel->primaryKey();
                             $vn_id = (int) $o_related_item->{$vs_pk};
                             $va_queue = array($vs_rel_table . "/" . $vn_id => array('table' => $vs_rel_table, 'id' => $vn_id, 'idno' => (string) $o_related_item->idno));
                             // TODO: Add from/until support
                             $this->fetchAndImport($va_queue, $po_client, $pa_config, $pa_tables, $ps_code);
                             $vn_rel_record_id = $this->opa_processed_records[$vs_rel_table . '/' . (int) $vn_id];
                             $vb_skip = false;
                             if ($vb_is_self_relation) {
                                 if ($this->opa_processed_self_relations[$vs_rel_table][$vn_rel_record_id][$t_instance->getPrimaryKey()][(string) $o_related_item->relationship_type_code] || $this->opa_processed_self_relations[$vs_rel_table][$t_instance->getPrimaryKey()][$vn_rel_record_id][(string) $o_related_item->relationship_type_code]) {
                                     $vb_skip = true;
                                 } else {
                                     $this->opa_processed_self_relations[$vs_rel_table][$t_instance->getPrimaryKey()][$vn_rel_record_id][(string) $o_related_item->relationship_type_code] = $this->opa_processed_self_relations[$vs_rel_table][$vn_rel_record_id][$t_instance->getPrimaryKey()][(string) $o_related_item->relationship_type_code] = true;
                                 }
                             }
                             if (!$vb_skip) {
                                 $t_instance->addRelationship($vs_rel_table, $vn_rel_record_id, (string) $o_related_item->relationship_type_code);
                                 if ($t_instance->numErrors()) {
                                     print "[ERROR] Could not add relationship to {$vs_rel_table} for row_id={$vn_rel_record_id}: " . join('; ', $t_instance->getErrors()) . "\n";
                                 }
                             }
                         }
                     }
                     // TODO: add hook onAddRelationships()
                 }
             }
         }
         // Is there media?
         if ($t_instance->tableName() == 'ca_objects') {
             try {
                 $o_rep_xml = $po_client->getObjectRepresentations((int) $va_item['id'], array('large', 'original'))->get();
             } catch (exception $e) {
                 print "[ERROR] While getting object representations: " . $e->getMessage() . "\n";
             }
             $va_existing_reps = $t_instance->getRepresentations(array('large', 'original'));
             $va_existing_md5s = array();
             $va_rep_ids = array();
             $va_dupe_reps = array();
             foreach ($va_existing_reps as $va_rep) {
                 if ($va_existing_md5s[$va_rep['info']['original']['MD5']] && $va_existing_md5s[$va_rep['info']['large']['MD5']]) {
                     // dupe
                     $va_dupe_reps[] = $va_rep['representation_id'];
                     continue;
                 }
                 $va_existing_md5s[$va_rep['info']['original']['MD5']] = $va_rep['representation_id'];
                 $va_existing_md5s[$va_rep['info']['large']['MD5']] = $va_rep['representation_id'];
                 $va_rep_ids[] = $va_rep['representation_id'];
             }
             if ($o_rep_xml->getObjectRepresentations) {
                 foreach ($o_rep_xml->getObjectRepresentations as $vs_x => $o_reps) {
                     foreach ($o_reps as $vs_key => $o_rep) {
                         if ($vs_url = trim((string) $o_rep->urls->large)) {
                             $vs_remote_original_md5 = (string) $o_rep->info->original->MD5;
                             $vs_remote_large_md5 = (string) $o_rep->info->large->MD5;
                             if (isset($va_existing_md5s[$vs_remote_original_md5]) && $va_existing_md5s[$vs_remote_original_md5] || isset($va_existing_md5s[$vs_remote_large_md5]) && $va_existing_md5s[$vs_remote_large_md5]) {
                                 print "[NOTICE] Skipping representation at {$vs_url} because it already exists (MD5={$vs_remote_original_md5}/{$vs_remote_large_md5}) ({$ps_code})\n";
                                 if (!($vn_kill_rep_id = $va_existing_md5s[$vs_remote_large_md5])) {
                                     $vn_kill_rep_id = $va_existing_md5s[$vs_remote_original_md5];
                                 }
                                 foreach ($va_existing_md5s as $vs_md5 => $vn_rep_id) {
                                     if ($vn_kill_rep_id == $vn_rep_id) {
                                         $t_existing_rep_link = new ca_objects_x_object_representations();
                                         if ($t_existing_rep_link->load(array('object_id' => $t_instance->getPrimaryKey(), 'representation_id' => $vn_rep_id))) {
                                             $t_existing_rep_link->setMode(ACCESS_WRITE);
                                             //	print "update object_id ".$t_instance->getPrimaryKey()."/rep=$vn_rep_id to rank=".$o_rep->rank."/primary=".$o_rep->is_primary."\n";
                                             $t_existing_rep_link->set('is_primary', (int) $o_rep->is_primary);
                                             $t_existing_rep_link->set('rank', (int) $o_rep->rank);
                                             $t_existing_rep_link->update();
                                             if ($t_existing_rep_link->numErrors()) {
                                                 print_r($t_existing_rep_link->getErrors());
                                             }
                                         }
                                         unset($va_existing_md5s[$vs_md5]);
                                     }
                                 }
                                 continue;
                             }
                             print "[Notice] Importing for [{$vs_idno}] media from {$vs_url}: primary=" . (string) $o_rep->is_primary . " ({$ps_code})\n";
                             print "instance has id=" . $t_instance->getPrimaryKey() . "\n";
                             // TODO: add hook onBeforeAddMedia()
                             $vn_link_id = $t_instance->addRepresentation($vs_url, $pn_rep_type_id, 1, (int) $o_rep->status, (int) $o_rep->access, (int) $o_rep->is_primary);
                             // TODO: add hook onAddMedia()
                             if ($t_instance->numErrors()) {
                                 print "[ERROR] Could not load object representation: " . join("; ", $t_instance->getErrors()) . " ({$ps_code})\n";
                             } else {
                                 $t_link = new ca_objects_x_object_representations($vn_link_id);
                                 $t_new_rep = new ca_object_representations($t_link->get('representation_id'));
                                 //unlink($x=$t_new_rep->getMediaPath('media', 'original'));
                             }
                         }
                     }
                 }
             }
             $va_rep_ids = array();
             foreach ($va_existing_md5s as $vs_md5 => $vn_rep_id) {
                 if ($va_rep_ids[$vn_rep_id]) {
                     continue;
                 }
                 $t_obj_x_rep = new ca_objects_x_object_representations();
                 while ($t_obj_x_rep->load(array('object_id' => $t_instance->getPrimaryKey(), 'representation_id' => $vn_rep_id))) {
                     $t_obj_x_rep->setMode(ACCESS_WRITE);
                     $t_obj_x_rep->delete(true);
                     if ($t_obj_x_rep->numErrors()) {
                         print "[ERROR] Could not load remove object-to-representation link: " . join("; ", $t_obj_x_rep->getErrors()) . " ({$ps_code})\n";
                         break;
                     }
                     if (!$t_obj_x_rep->load(array('representation_id' => $vn_rep_id))) {
                         $t_rep = new ca_object_representations();
                         if ($t_rep->load($vn_rep_id)) {
                             $t_rep->setMode(ACCESS_WRITE);
                             $t_rep->delete(true, array('hard' => true));
                             if ($t_rep->numErrors()) {
                                 print "[ERROR] Could not remove representation: " . join("; ", $t_rep->getErrors()) . "\n";
                                 break;
                             }
                         }
                     }
                 }
                 $va_rep_ids[$vn_rep_id] = true;
             }
             foreach ($va_dupe_reps as $vn_dupe_rep_id) {
                 $t_rep = new ca_object_representations();
                 if ($t_rep->load($vn_dupe_rep_id)) {
                     print "[Notice] DELETE DUPE {$vn_dupe_rep_id}\n";
                     $t_rep->setMode(ACCESS_WRITE);
                     $t_rep->delete(true, array('hard' => true));
                     if ($t_rep->numErrors()) {
                         print "[ERROR] Could not remove dupe representation: " . join("; ", $t_rep->getErrors()) . "\n";
                         break;
                     }
                 }
             }
         }
         unset($pa_tables[$va_item['table']]);
     }
 }
Beispiel #4
0
 /**
  * Reindex PDF media by content for in-PDF search
  */
 public static function reindex_pdfs($po_opts = null)
 {
     require_once __CA_LIB_DIR__ . "/core/Db.php";
     require_once __CA_MODELS_DIR__ . "/ca_object_representations.php";
     if (!caPDFMinerInstalled()) {
         CLIUtils::addError(_t("Can't reindex PDFs: PDFMiner is not installed."));
         return false;
     }
     $o_db = new Db();
     $t_rep = new ca_object_representations();
     $t_rep->setMode(ACCESS_WRITE);
     $va_versions = array("original");
     $va_kinds = ($vs_kinds = $po_opts->getOption("kinds")) ? explode(",", $vs_kinds) : array();
     if (!is_array($va_kinds) || !sizeof($va_kinds)) {
         $va_kinds = array('all');
     }
     $va_kinds = array_map('strtolower', $va_kinds);
     if (in_array('all', $va_kinds) || in_array('ca_object_representations', $va_kinds)) {
         if (!($vn_start = (int) $po_opts->getOption('start_id'))) {
             $vn_start = null;
         }
         if (!($vn_end = (int) $po_opts->getOption('end_id'))) {
             $vn_end = null;
         }
         if ($vn_id = (int) $po_opts->getOption('id')) {
             $vn_start = $vn_id;
             $vn_end = $vn_id;
         }
         $va_ids = array();
         if ($vs_ids = (string) $po_opts->getOption('ids')) {
             if (sizeof($va_tmp = explode(",", $vs_ids))) {
                 foreach ($va_tmp as $vn_id) {
                     if ((int) $vn_id > 0) {
                         $va_ids[] = (int) $vn_id;
                     }
                 }
             }
         }
         $vs_sql_where = null;
         $va_params = array();
         if (sizeof($va_ids)) {
             $vs_sql_where = "WHERE representation_id IN (?)";
             $va_params[] = $va_ids;
         } else {
             if ($vn_start > 0 && $vn_end > 0 && $vn_start <= $vn_end || $vn_start > 0 && $vn_end == null) {
                 $vs_sql_where = "WHERE representation_id >= ?";
                 $va_params[] = $vn_start;
                 if ($vn_end) {
                     $vs_sql_where .= " AND representation_id <= ?";
                     $va_params[] = $vn_end;
                 }
             }
         }
         if ($vs_sql_where) {
             $vs_sql_where .= " AND mimetype = 'application/pdf'";
         } else {
             $vs_sql_where = " WHERE mimetype = 'application/pdf'";
         }
         $qr_reps = $o_db->query("\n\t\t\t\t\tSELECT * \n\t\t\t\t\tFROM ca_object_representations \n\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\tORDER BY representation_id\n\t\t\t\t", $va_params);
         print CLIProgressBar::start($qr_reps->numRows(), _t('Reindexing PDF representations'));
         $vn_rep_table_num = $t_rep->tableNum();
         while ($qr_reps->nextRow()) {
             $va_media_info = $qr_reps->getMediaInfo('media');
             $vs_original_filename = $va_media_info['ORIGINAL_FILENAME'];
             print CLIProgressBar::next(1, _t("Reindexing PDF %1", $vs_original_filename ? $vs_original_filename . " (" . $qr_reps->get('representation_id') . ")" : $qr_reps->get('representation_id')));
             $t_rep->load($qr_reps->get('representation_id'));
             $vn_rep_id = $t_rep->getPrimaryKey();
             $m = new Media();
             if ($m->read($vs_path = $t_rep->getMediaPath('media', 'original')) && is_array($va_locs = $m->getExtractedTextLocations())) {
                 MediaContentLocationIndexer::clear($vn_rep_table_num, $vn_rep_id);
                 foreach ($va_locs as $vs_content => $va_loc_list) {
                     foreach ($va_loc_list as $va_loc) {
                         MediaContentLocationIndexer::index($vn_rep_table_num, $vn_rep_id, $vs_content, $va_loc['p'], $va_loc['x1'], $va_loc['y1'], $va_loc['x2'], $va_loc['y2']);
                     }
                 }
                 MediaContentLocationIndexer::write();
             } else {
                 //CLIUtils::addError(_t("[Warning] No content to reindex for PDF representation: %1", $vs_path));
             }
         }
         print CLIProgressBar::finish();
     }
     if (in_array('all', $va_kinds) || in_array('ca_attributes', $va_kinds)) {
         // get all Media elements
         $va_elements = ca_metadata_elements::getElementsAsList(false, null, null, true, false, true, array(16));
         // 16=media
         $qr_c = $o_db->query("\n\t\t\t\t\tSELECT count(*) c \n\t\t\t\t\tFROM ca_attribute_values\n\t\t\t\t\tWHERE\n\t\t\t\t\t\telement_id in (?)\n\t\t\t\t", caExtractValuesFromArrayList($va_elements, 'element_id', array('preserveKeys' => false)));
         if ($qr_c->nextRow()) {
             $vn_count = $qr_c->get('c');
         } else {
             $vn_count = 0;
         }
         $t_attr_val = new ca_attribute_values();
         $vn_attr_table_num = $t_attr_val->tableNum();
         print CLIProgressBar::start($vn_count, _t('Reindexing metadata attribute media'));
         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);
                     $va_media_info = $t_attr_val->getMediaInfo('value_blob');
                     $vs_original_filename = $va_media_info['ORIGINAL_FILENAME'];
                     if (!is_array($va_media_info) || $va_media_info['MIMETYPE'] !== 'application/pdf') {
                         continue;
                     }
                     print CLIProgressBar::next(1, _t("Reindexing %1", $vs_original_filename ? $vs_original_filename . " ({$vn_value_id})" : $vn_value_id));
                     $m = new Media();
                     if ($m->read($vs_path = $t_attr_val->getMediaPath('value_blob', 'original')) && is_array($va_locs = $m->getExtractedTextLocations())) {
                         MediaContentLocationIndexer::clear($vn_attr_table_num, $vn_attr_table_num);
                         foreach ($va_locs as $vs_content => $va_loc_list) {
                             foreach ($va_loc_list as $va_loc) {
                                 MediaContentLocationIndexer::index($vn_attr_table_num, $vn_value_id, $vs_content, $va_loc['p'], $va_loc['x1'], $va_loc['y1'], $va_loc['x2'], $va_loc['y2']);
                             }
                         }
                         MediaContentLocationIndexer::write();
                     } else {
                         //CLIUtils::addError(_t("[Warning] No content to reindex for PDF in metadata attribute: %1", $vs_path));
                     }
                 }
             }
         }
         print CLIProgressBar::finish();
     }
     return true;
 }
 /**
  * Override set() to do idno_stub lookups on lots
  *
  * @param mixed $pm_fields
  * @param mixed $pm_value
  * @param array $pa_options Most options are handled by subclasses. Options defined here include:
  *		assumeIdnoStubForLotID = set to force lookup of lot_id values as ca_object_lots.idno_stub values first not matter what, before consideration as a numeric lot_id. The default is false, in which case integer values are considered lot_ids and non-numeric values possible idno_stubs.
  *		
  * @return int 
  */
 public function set($pm_fields, $pm_value = "", $pa_options = null)
 {
     if (!is_array($pm_fields)) {
         $pm_fields = array($pm_fields => $pm_value);
     }
     $pb_assume_idno_for_representation_id = caGetOption('assumeIdnoForRepresentationID', $pa_options, false);
     foreach ($pm_fields as $vs_fld => $vs_val) {
         if ($vs_fld == 'representation_id' && ($pb_assume_idno_for_representation_id || preg_match("![^\\d]+!", $vs_val))) {
             $t_rep = new ca_object_representations();
             if ($t_rep->load(array('idno' => $vs_val, 'deleted' => 0))) {
                 $vn_representation_id = (int) $t_rep->getPrimaryKey();
                 $pm_fields[$vs_fld] = $vn_representation_id;
                 if ($vn_rc = parent::set($pm_fields, null, $pa_options)) {
                     $this->set('type_code', $vs_type = $this->getAnnotationType());
                 }
                 return $vn_rc;
             }
         }
     }
     return parent::set($pm_fields, null, $pa_options);
 }
		<div class="detailNavBgLeft">
			{{{previousLink}}}{{{resultsLink}}}
		</div><!-- end detailNavBgLeft -->
	</div><!-- end col -->
	<div class='col-xs-10 col-sm-10 col-md-10 col-lg-10'>
		<div class="container">
			<div class="row">
				<div class='col-sm-12 col-md-6 col-lg-6'>
					<H1>{{{<unit relativeTo="ca_collections" delimiter="_➔_"><l>^ca_collections.hierarchy.preferred_labels.name</l></unit><ifcount min="1" code="ca_collections"> ➔ </ifcount>}}}{{{ca_objects.preferred_labels.name}}}</H1>
				</div><!-- end col -->
			</div><!-- end row -->
			<div class="row">
				<div class='col-sm-12 col-md-12 col-lg-12'>
<?php 
if ($vn_audio_rep_id) {
    $t_rep->load($vn_audio_rep_id);
    $va_annotations = $t_rep->getAnnotations(array("checkAccess" => $this->getVar("access_values")));
    #print_r($va_annotations);
    print $t_rep->getMediaTag("media", $va_audio_media_display_info["display_version"], $va_audio_media_display_info, array("id" => "caPlayer"));
}
?>
					<div id="detailTools">						
						<div class="detailTool detailToolRight"><span class="glyphicon glyphicon-share-alt"></span>{{{shareLink}}}</div><!-- end detailTool -->
<?php 
print "<div class='detailTool'>";
if (caObjectsDisplayDownloadLink($this->request) && $vn_audio_rep_id) {
    # -- get version to download configured in media_display.conf
    $va_download_display_info = caGetMediaDisplayInfo('download', $t_rep->getMediaInfo('media', 'INPUT', 'MIMETYPE'));
    $vs_download_version = $va_download_display_info['display_version'];
    print caNavLink($this->request, " <span class='glyphicon glyphicon-download-alt'></span>", '', 'Detail', 'DownloadRepresentation', '', array('representation_id' => $t_rep->getPrimaryKey(), "object_id" => $t_object->get("object_id"), "download" => 1, "version" => $vs_download_version), array("title" => _t("Download"))) . "&nbsp;&nbsp;&nbsp;&nbsp;";
}
Beispiel #7
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;
 }
 /**
  * Remove a single representation from the currently loaded object. Note that the representation will be removed from the database completely, so if it is also linked to other items it will be removed from them as well.
  *
  * @param int $pn_representation_id The representation_id of the representation to remove
  * @param array $pa_options Options are passed through to BaseMode::delete()
  * @return bool True if delete succeeded, false if there was an error. You can get the error messages by calling getErrors() on the instance.
  */
 public function removeRepresentation($pn_representation_id, $pa_options = null)
 {
     if (!$this->getPrimaryKey()) {
         return null;
     }
     $va_path = array_keys($this->getAppDatamodel()->getPath($this->tableName(), 'ca_object_representations'));
     if (is_array($va_path) && sizeof($va_path) == 3) {
         $vs_rel_table = $va_path[1];
         if ($t_rel = $this->getAppDatamodel()->getInstanceByTableName($vs_rel_table)) {
             if ($t_rel->load(array($this->primaryKey() => $this->getPrimaryKey(), 'representation_id' => $pn_representation_id))) {
                 $t_rel->setMode(ACCESS_WRITE);
                 $t_rel->delete();
                 if ($t_rel->numErrors()) {
                     $this->errors = array_merge($this->errors, $t_rel->errors());
                     return false;
                 }
             }
         }
     }
     $t_rep = new ca_object_representations();
     if (!$t_rep->load($pn_representation_id)) {
         $this->postError(750, _t("Representation id=%1 does not exist", $pn_representation_id), "RepresentableBaseModel->removeRepresentation()");
         return false;
     } else {
         if (!($va_rels = $t_rep->hasRelationships()) || !is_array($va_rels) || !sizeof($va_rels)) {
             //
             // Only delete the related representation if nothing else is related to it
             //
             $t_rep->setMode(ACCESS_WRITE);
             $t_rep->delete(false, $pa_options);
             if ($t_rep->numErrors()) {
                 $this->errors = array_merge($this->errors, $t_rep->errors());
                 return false;
             }
         }
         return true;
     }
     return false;
 }
 /**
  * Remove representation from database
  *
  * @param int $representation_id
  * @return boolean
  * @throws SoapFault
  */
 public function removeObjectRepresentation($representation_id)
 {
     require_once __CA_MODELS_DIR__ . "/ca_object_representations.php";
     $t_rep = new ca_object_representations();
     if (!$t_rep->load($representation_id)) {
         throw new SoapFault("Server", "Invalid representation ID");
     }
     $t_rep->delete();
     if ($t_rep->numErrors() == 0) {
         return true;
     } else {
         throw new SoapFault("Server", "There were errors while removing the representation: " . join(";", $t_rep->getErrors()));
     }
 }
Beispiel #10
0
 /**
  * Reprocess media
  */
 public static function reprocess_media($po_opts = null)
 {
     require_once __CA_LIB_DIR__ . "/core/Db.php";
     require_once __CA_MODELS_DIR__ . "/ca_object_representations.php";
     $o_db = new Db();
     $t_rep = new ca_object_representations();
     $t_rep->setMode(ACCESS_WRITE);
     $va_mimetypes = ($vs_mimetypes = $po_opts->getOption("mimetypes")) ? explode(",", $vs_mimetypes) : array();
     $va_versions = ($vs_versions = $po_opts->getOption("versions")) ? explode(",", $vs_versions) : array();
     $va_kinds = ($vs_kinds = $po_opts->getOption("kinds")) ? explode(",", $vs_kinds) : array();
     if (!is_array($va_kinds) || !sizeof($va_kinds)) {
         $va_kinds = array('all');
     }
     $va_kinds = array_map('strtolower', $va_kinds);
     if (in_array('all', $va_kinds) || in_array('ca_object_representations', $va_kinds)) {
         if (!($vn_start = (int) $po_opts->getOption('start_id'))) {
             $vn_start = null;
         }
         if (!($vn_end = (int) $po_opts->getOption('end_id'))) {
             $vn_end = null;
         }
         if ($vn_id = (int) $po_opts->getOption('id')) {
             $vn_start = $vn_id;
             $vn_end = $vn_id;
         }
         $va_ids = array();
         if ($vs_ids = (string) $po_opts->getOption('ids')) {
             if (sizeof($va_tmp = explode(",", $vs_ids))) {
                 foreach ($va_tmp as $vn_id) {
                     if ((int) $vn_id > 0) {
                         $va_ids[] = (int) $vn_id;
                     }
                 }
             }
         }
         $vs_sql_where = null;
         $va_params = array();
         if (sizeof($va_ids)) {
             $vs_sql_where = "WHERE representation_id IN (?)";
             $va_params[] = $va_ids;
         } else {
             if ($vn_start > 0 && $vn_end > 0 && $vn_start <= $vn_end || $vn_start > 0 && $vn_end == null) {
                 $vs_sql_where = "WHERE representation_id >= ?";
                 $va_params[] = $vn_start;
                 if ($vn_end) {
                     $vs_sql_where .= " AND representation_id <= ?";
                     $va_params[] = $vn_end;
                 }
             }
         }
         $qr_reps = $o_db->query("\n\t\t\t\t\tSELECT * \n\t\t\t\t\tFROM ca_object_representations \n\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\tORDER BY representation_id\n\t\t\t\t", $va_params);
         print CLIProgressBar::start($qr_reps->numRows(), _t('Re-processing representation media'));
         while ($qr_reps->nextRow()) {
             $va_media_info = $qr_reps->getMediaInfo('media');
             $vs_original_filename = $va_media_info['ORIGINAL_FILENAME'];
             print CLIProgressBar::next(1, _t("Re-processing %1", $vs_original_filename ? $vs_original_filename . " (" . $qr_reps->get('representation_id') . ")" : $qr_reps->get('representation_id')));
             $vs_mimetype = $qr_reps->getMediaInfo('media', 'original', 'MIMETYPE');
             if (sizeof($va_mimetypes)) {
                 foreach ($va_mimetypes as $vs_mimetype_pattern) {
                     if (!preg_match("!^{$vs_mimetype_pattern}!", $vs_mimetype)) {
                         continue 2;
                     }
                 }
             }
             $t_rep->load($qr_reps->get('representation_id'));
             $t_rep->set('media', $qr_reps->getMediaPath('media', 'original'), array('original_filename' => $vs_original_filename));
             if (sizeof($va_versions)) {
                 $t_rep->update(array('updateOnlyMediaVersions' => $va_versions));
             } else {
                 $t_rep->update();
             }
             if ($t_rep->numErrors()) {
                 CLIUtils::addError(_t("Error processing representation media: %1", join('; ', $t_rep->getErrors())));
             }
         }
         print CLIProgressBar::finish();
     }
     if (in_array('all', $va_kinds) || in_array('ca_attributes', $va_kinds)) {
         // get all Media elements
         $va_elements = ca_metadata_elements::getElementsAsList(false, null, null, true, false, true, array(16));
         // 16=media
         $qr_c = $o_db->query("\n\t\t\t\t\tSELECT count(*) c \n\t\t\t\t\tFROM ca_attribute_values\n\t\t\t\t\tWHERE\n\t\t\t\t\t\telement_id in (?)\n\t\t\t\t", caExtractValuesFromArrayList($va_elements, 'element_id', array('preserveKeys' => false)));
         if ($qr_c->nextRow()) {
             $vn_count = $qr_c->get('c');
         } else {
             $vn_count = 0;
         }
         print CLIProgressBar::start($vn_count, _t('Re-processing attribute media'));
         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);
                     $va_media_info = $t_attr_val->getMediaInfo('value_blob');
                     $vs_original_filename = is_array($va_media_info) ? $va_media_info['ORIGINAL_FILENAME'] : '';
                     print CLIProgressBar::next(1, _t("Re-processing %1", $vs_original_filename ? $vs_original_filename . " ({$vn_value_id})" : $vn_value_id));
                     $t_attr_val->set('value_blob', $t_attr_val->getMediaPath('value_blob', 'original'), array('original_filename' => $vs_original_filename));
                     $t_attr_val->update();
                     if ($t_attr_val->numErrors()) {
                         CLIUtils::addError(_t("Error processing attribute media: %1", join('; ', $t_attr_val->getErrors())));
                     }
                 }
             }
         }
         print CLIProgressBar::finish();
     }
     return true;
 }
 /**
  * Remove a single representation from the currently loaded object. Note that the representation will be removed from the database completely, so if it is also linked to other items it will be removed from them as well.
  *
  * @param int $pn_representation_id The representation_id of the representation to remove
  * @param array $pa_options Options are passed through to BaseMode::delete()
  * @return bool True if delete succeeded, false if there was an error. You can get the error messages by calling getErrors() on the instance.
  */
 public function removeRepresentation($pn_representation_id, $pa_options = null)
 {
     if (!$this->getPrimaryKey()) {
         return null;
     }
     $va_path = array_keys($this->getAppDatamodel()->getPath($this->tableName(), 'ca_object_representations'));
     if (is_array($va_path) && sizeof($va_path) == 3) {
         $vs_rel_table = $va_path[1];
         if ($t_rel = $this->getAppDatamodel()->getInstanceByTableName($vs_rel_table)) {
             if ($this->inTransaction()) {
                 $t_rel->setTransaction($this->getTransaction());
             }
             if ($t_rel->load(array($this->primaryKey() => $this->getPrimaryKey(), 'representation_id' => $pn_representation_id))) {
                 $t_rel->setMode(ACCESS_WRITE);
                 $t_rel->delete();
                 if ($t_rel->numErrors()) {
                     $this->errors = array_merge($this->errors, $t_rel->errors());
                     return false;
                 }
             }
         }
     }
     $t_rep = new ca_object_representations();
     if ($this->inTransaction()) {
         $t_rep->setTransaction($this->getTransaction());
     }
     if (!$t_rep->load($pn_representation_id)) {
         $this->postError(750, _t("Representation id=%1 does not exist", $pn_representation_id), "RepresentableBaseModel->removeRepresentation()");
         return false;
     } else {
         //
         // Only delete the related representation if nothing else is related to it
         //
         $va_rels = $t_rep->hasRelationships();
         if (is_array($va_rels) && isset($va_rels['ca_object_representation_labels'])) {
             // labels don't count as relationships in this case
             unset($va_rels['ca_object_representation_labels']);
         }
         if (is_array($va_rels) && isset($va_rels['ca_objects_x_object_representations']) && $va_rels['ca_objects_x_object_representations'] < 1) {
             unset($va_rels['ca_objects_x_object_representations']);
         }
         if (!is_array($va_rels) || sizeof($va_rels) == 0) {
             $t_rep->setMode(ACCESS_WRITE);
             $t_rep->delete(true, $pa_options);
             if ($t_rep->numErrors()) {
                 $this->errors = array_merge($this->errors, $t_rep->errors());
                 return false;
             }
         }
         // remove any replicated media
         if (is_array($va_replication_targets = $t_rep->getUsedMediaReplicationTargets('media'))) {
             foreach ($va_replication_targets as $vs_target => $va_target_info) {
                 $t_rep->removeMediaReplication('media', $vs_target, $t_rep->getMediaReplicationKey('media', $vs_target));
             }
         }
         return true;
     }
     return false;
 }
 /**
  * 
  */
 public function media()
 {
     if (!is_object($t_entity = $this->_checkEntity())) {
         return $t_entity;
     }
     $vn_id = $t_entity->getPrimaryKey();
     $t_list = new ca_lists();
     $vn_exhibition_audio_type_id = $t_list->getItemIDFromList('object_types', 'MemEx_Audio');
     $vs_filter = $this->opo_request->getParameter('filter', pString);
     if (!in_array($vs_filter, array('video', 'audio', 'image', 'pdf'))) {
         $vs_filter = null;
     }
     $t_object = new ca_objects();
     $va_data = array('id' => $vn_id);
     $from = $this->opo_request->getParameter('from', pString);
     $until = $this->opo_request->getParameter('until', pString);
     if (!$until) {
         $until = date('c');
     }
     $vs_range = $from && $until ? self::utcToDb($from) . ' to ' . self::utcToDb($until) : null;
     $o_tep = new TimeExpressionParser();
     $vb_parsed_date = false;
     if ($vs_range) {
         if ($vb_parsed_date = $o_tep->parse($vs_range)) {
             $va_range = $o_tep->getUnixTimestamps();
         }
     }
     $t_rep = new ca_object_representations();
     $t_list = new ca_lists();
     $va_pub_target_values = $t_list->getItemsForList('object_publication_targets', array('extractValuesByUserLocale' => true));
     $va_audio_target_values = $t_list->getItemsForList('audio_publication_targets', array('extractValuesByUserLocale' => true));
     $vn_memorial_exhibition_audio_type_id = $t_list->getItemIDFromList('object_types', 'MemEx_Audio');
     $vn_publish_annotation_id = $t_list->getItemIDFromList('annotation_publication_targets', 'interactive_tables');
     $vn_publish_rep = $t_list->getItemIDFromList("memex_status", "publish");
     $va_objects = $t_entity->getRelatedItems('ca_objects');
     foreach ($va_objects as $vn_relation_id => $va_object_info) {
         $va_timestamp = $t_object->getLastChangeTimestamp($va_object_info['object_id']);
         if ($vb_parsed_date && ($va_timestamp['timestamp'] <= $va_range['start'] || $va_timestamp['timestamp'] >= $va_range['end'])) {
             continue;
         }
         if ($t_object->load($va_object_info['object_id'])) {
             $va_reps = $t_object->getRepresentations(array("preview", "preview170", "icon", "small", "medium", "large", "large_png", "original", "h264_hi", "mp3"));
             if (!is_array($va_reps) || !sizeof($va_reps)) {
                 continue;
             }
             $va_filtered_reps = array();
             foreach ($va_reps as $vn_i => $va_rep) {
                 $va_tmp = explode('/', $vs_mimetype = $va_rep['info']['original']['MIMETYPE']);
                 if ($vs_filter && ($va_tmp[0] != $vs_filter && $va_tmp[1] != $vs_filter)) {
                     continue;
                 }
                 $vb_is_audio = false;
                 if ($t_object->get('type_id') == $vn_memorial_exhibition_audio_type_id) {
                     $va_pub_targets = $t_object->get('ca_objects.audio_publication_targets', array('returnAsArray' => true, 'convertCodesToDisplayText' => false));
                     $vb_is_audio = true;
                 } else {
                     $va_pub_targets = $t_object->get('ca_objects.object_publication_targets', array('returnAsArray' => true, 'convertCodesToDisplayText' => false));
                 }
                 if (!sizeof($va_pub_targets)) {
                     continue;
                 }
                 if (!$t_rep->load($va_rep['representation_id'])) {
                     continue;
                 }
                 if ($t_rep->get("ca_object_representations.memex_status", array('convertCodesToDisplayText' => false)) != $vn_publish_rep) {
                     continue;
                 }
                 // reset filesize property to reflect size of version, not size of original
                 foreach ($va_reps[$vn_i]['paths'] as $vs_version => $vs_path) {
                     $va_reps[$vn_i]['info'][$vs_version]['PROPERTIES']['filesize'] = @filesize($va_reps[$vn_i]['paths'][$vs_version]);
                 }
                 unset($va_reps[$vn_i]['paths']);
                 unset($va_reps[$vn_i]['tags']);
                 unset($va_reps[$vn_i]['media']);
                 unset($va_reps[$vn_i]['media_metadata']);
                 unset($va_reps[$vn_i]['is_primary']);
                 unset($va_reps[$vn_i]['name']);
                 unset($va_reps[$vn_i]['status']);
                 unset($va_reps[$vn_i]['locale_id']);
                 unset($va_reps[$vn_i]['type_id']);
                 $va_reps[$vn_i]['lastupdate_timestamp'] = date('o-m-N', $va_timestamp['timestamp']) . "T" . date('H:i:s', $va_timestamp['timestamp']) . "Z";
                 //date('c', $va_timestamp['timestamp']);
                 $va_reps[$vn_i]['type_id'] = $vn_type_id = $t_object->get('ca_objects.type_id');
                 $va_reps[$vn_i]['typename'] = $t_object->getTypeName();
                 $va_reps[$vn_i]['typecode'] = $t_object->getTypeCode();
                 $va_targets = array();
                 foreach ($va_pub_targets as $vn_attr_id => $va_value) {
                     $va_targets[] = $va_pub_target_values[$va_value['object_publication_targets']]['idno'] ? $va_pub_target_values[$va_value['object_publication_targets']]['idno'] : $va_audio_target_values[$va_value['audio_publication_targets']]['idno'];
                 }
                 $va_reps[$vn_i]['publication_targets'] = $va_targets;
                 $va_reps[$vn_i]['title'] = $t_object->get('ca_objects.memex_title');
                 $va_reps[$vn_i]['credit'] = $t_object->get('ca_objects.memex_credit_line');
                 $va_reps[$vn_i]['caption'] = $t_object->get('ca_objects.memex_caption');
                 if ($t_object->get('type_id') == $vn_exhibition_audio_type_id) {
                     $va_reps[$vn_i]['transcript'] = $t_object->get('ca_objects.final_text_inner_chamber');
                     $va_reps[$vn_i]['attribution'] = $t_object->get('ca_objects.remembrance_attribution');
                 }
                 if ($va_rep['num_multifiles'] > 0) {
                     $va_pages = $t_rep->getFileList($va_rep['representation_id'], null, null, array('page_preview'));
                     $va_page_urls = array();
                     foreach ($va_pages as $vn_file_id => $va_file_info) {
                         $va_page_urls[] = $va_file_info['page_preview_url'];
                     }
                     $va_reps[$vn_i]['page_images'] = $va_page_urls;
                 }
                 $va_reps[$vn_i]['clips'] = array();
                 if (is_array($va_annotations = $t_rep->getAnnotations()) && sizeof($va_annotations)) {
                     foreach ($va_annotations as $vn_index => $va_annotation) {
                         $vn_annotation_id = $va_annotation['annotation_id'];
                         //if ($va_annotation['access'] == 0) { continue; }
                         $t_annotation = new ca_representation_annotations($vn_annotation_id);
                         if ($vn_publish_annotation_id != $t_annotation->get('annotation_publication_targets')) {
                             continue;
                         }
                         // skip ones not marked for publication
                         unset($va_annotation['props']);
                         $va_annotation['description'] = $t_annotation->get('description');
                         $va_annotation['transcript'] = $t_annotation->get('transcript');
                         //$va_annotation['mp3'] = $t_annotation->getAppConfig()->get('site_host')."/service.php/ns11mmServices/Victim/getClip/id/{$vn_annotation_id}";
                         $va_annotation['mp3'] = $t_annotation->getMediaUrl('ca_representation_annotations.preview', 'original');
                         $va_annotation['md5'] = $t_annotation->getMediaInfo('ca_representation_annotations.preview', 'original', 'MD5');
                         $va_reps[$vn_i]['clips'][] = $va_annotation;
                     }
                 }
                 $va_filtered_reps[] = $va_reps[$vn_i];
             }
             if (sizeof($va_filtered_reps)) {
                 $va_data['media'][$va_object_info['object_id']] = $va_filtered_reps;
             }
         }
     }
     return $this->makeResponse($va_data);
 }
if (sizeof($va_videos)) {
    $va_audio_video_rep = array_shift($va_videos);
    $vn_audio_video_rep_id = $va_audio_video_rep["representation_id"];
    $va_audio_video_media_display_info = caGetMediaDisplayInfo('detail', $va_audio_video_rep["mimetype"]);
} elseif (sizeof($va_audios)) {
    $va_audio_video_rep = array_shift($va_audios);
    $vn_audio_video_rep_id = $va_audio_video_rep["representation_id"];
    $va_audio_video_media_display_info = caGetMediaDisplayInfo('detail', $va_audio_video_rep["mimetype"]);
    if (sizeof($va_images)) {
        $va_image_rep = array_shift($va_images);
        $vn_image_rep_id = $va_image_rep["representation_id"];
        $va_image_media_display_info = caGetMediaDisplayInfo('detail', $va_image_rep["mimetype"]);
    }
}
if ($vn_image_rep_id) {
    $t_rep->load($vn_image_rep_id);
    print "<div id='cont'>" . $t_rep->getMediaTag("media", $va_image_media_display_info["display_version"], $va_image_media_display_info) . "</div>";
}
if ($vn_audio_video_rep_id) {
    $t_rep->load($vn_audio_video_rep_id);
    print $t_rep->getMediaTag("media", $va_audio_video_media_display_info["display_version"], $va_audio_video_media_display_info, array("id" => "caPlayer"));
    # --- get the annotations for this audio/video rep
    $va_annotations = $t_rep->getAnnotations(array("checkAccess" => $this->getVar("access_values")));
}
?>
				</div><!-- end col -->
				<div class='col-sm-6 col-md-6 col-lg-6'>
					<H4>{{{<unit relativeTo="ca_collections" delimiter="<br/>"><l>^ca_collections.preferred_labels.name</l></unit><ifcount min="1" code="ca_collections"> ➔ </ifcount>}}}{{{ca_objects.preferred_labels.name}}}</H4>
					<H6>{{{<unit>^ca_objects.type_id</unit>}}}</H6>
					<HR>
					
?>
<div id="caSetsSlideshowContainer">
	<h1><?php 
print $t_set->getLabelForDisplay();
?>
</h1>
	<div id="caSetsSlideshow">
<?php 
if (is_array($va_items) && sizeof($va_items)) {
    $i = 1;
    $t_set_item = new ca_objects();
    $t_rep = new ca_object_representations();
    foreach ($va_items as $va_item) {
        $t_set_item->load($va_item["row_id"]);
        #print_r($va_item);
        $t_rep->load($t_set_item->getPrimaryRepresentationId());
        $vs_image = $t_rep->getMediaTag("media", $vs_version);
        $va_media_info = $t_rep->getMediaInfo("media", $vs_version);
        # --- pad the top to center vertically
        if ($vn_public_display) {
            $vn_height = 450;
        } else {
            $vn_height = 600;
        }
        $vn_top_padding = round(($vn_height - $va_media_info["HEIGHT"]) / 2) . "px";
        print "<div><div style='width:" . $va_media_info["WIDTH"] . "px; margin: 0px auto 0px auto; position:relative;'>";
        print "<div style='padding-top: " . $vn_top_padding . "'>" . caNavLink($this->request, $vs_image, "", "Detail", "Object", "Show", array("object_id" => $va_item["object_id"])) . "</div>";
        print "<div class='caSetsSlideshowCaption'>(" . $i . "/" . sizeof($va_items) . ")</br>";
        if ($t_rep->get("image_credit_line")) {
            print "<i>" . $t_rep->get("image_credit_line") . "</i>";
        }
 public function downloadCustomWorksheet()
 {
     $o_purifier = new HTMLPurifier();
     $pn_occurrence_id = $this->request->getParameter('occurrence_id', pInteger);
     $pn_relation_id = $this->request->getParameter('relation_id', pInteger);
     $t_objects_x_occurrences = new ca_objects_x_occurrences($pn_relation_id);
     # --- get the images
     $pa_print_rep = $this->request->getParameter('print_reps', pArray);
     $va_images = array();
     if (is_array($pa_print_rep)) {
         $t_rep = new ca_object_representations();
         foreach ($pa_print_rep as $vn_i => $vn_rep_id) {
             $t_rep->load($vn_rep_id);
             $va_media_info = $t_rep->getMediaInfo('media');
             $vn_height = $va_media_info["large"]["HEIGHT"];
             $vn_width = $va_media_info["large"]["WIDTH"];
             if ($vn_height > 900) {
                 $vn_new_width = 900 * $vn_width / $vn_height;
                 $vs_image = "<img src='" . $t_rep->getMediaUrl('media', 'large') . "' style='height:900px; width:" . $vn_new_width . "px;'>";
             } else {
                 $vs_image = $t_rep->getMediaTag("media", "large");
             }
             $va_images[] = $vs_image;
         }
     }
     $this->view->setVar("images", $va_images);
     $t_lists = new ca_lists();
     $vn_original_date = $t_lists->getItemIDFromList("date_types", "dateOriginal");
     $vs_image_info = "<div style='font-size:11px; font-style:italic;'>" . $t_objects_x_occurrences->get("ca_objects.preferred_labels.name");
     if ($va_dates = $t_objects_x_occurrences->get("ca_objects.date", array("returnAsArray" => true))) {
         foreach ($va_dates as $va_date_info) {
             if ($va_date_info["dc_dates_types"] == $vn_original_date) {
                 $vs_image_info .= ", " . $va_date_info["dates_value"];
             }
         }
     }
     if ($t_objects_x_occurrences->get("ca_objects.repository")) {
         $vs_image_info .= ", " . $t_objects_x_occurrences->get("ca_objects.repository", array('delimiter' => ', ', 'convertCodesToDisplayText' => true));
     }
     $vs_image_info .= ", " . $t_objects_x_occurrences->get("ca_objects.idno") . "</div>";
     $this->view->setVar("image_info", $vs_image_info);
     # --- get the attributes the user may have altered
     $va_info = array();
     $va_attributes = $this->opa_worksheet_attributes;
     foreach ($va_attributes as $vs_attribute_code => $vs_title) {
         if ($vs_value = str_replace("\n", "<br/>", $o_purifier->purify($this->request->getParameter($vs_attribute_code, pString)))) {
             if ($vs_attribute_code == "title") {
                 $va_info[$vs_attribute_code] = $vs_value;
             } else {
                 $va_info[$vs_attribute_code] = "<b>" . $vs_title . "</b><br/>" . $vs_value;
             }
         } else {
             $va_info[$vs_attribute_code] = "";
         }
     }
     $this->view->setvar("worksheet_info", $va_info);
     require_once __CA_LIB_DIR__ . '/core/Parsers/dompdf/dompdf_config.inc.php';
     if ($vs_title = $o_purifier->purify($this->request->getParameter($vs_attribute_code, pString))) {
         $vs_output_filename = $vs_title;
     } else {
         $vs_output_filename = "NYSA_Custom_WorkSheet";
     }
     $vs_output_file_name = preg_replace("/[^A-Za-z0-9\\-]+/", '_', $vs_output_filename);
     header("Content-Disposition: attachment; filename=export_results.pdf");
     header("Content-type: application/pdf");
     $vs_content = $this->render($this->ops_theme . '/custom_worksheet_html.php');
     $o_pdf = new DOMPDF();
     // Page sizes: 'letter', 'legal', 'A4'
     // Orientation:  'portrait' or 'landscape'
     $o_pdf->set_paper("letter", "portrait");
     $o_pdf->load_html($vs_content, 'utf-8');
     $o_pdf->render();
     $o_pdf->stream($vs_output_file_name . ".pdf");
     return;
 }