/**
  * 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;
 }
 /**
  * Returns all available bundle display placements - those data bundles that can be displayed for the given content type, in other words.
  * The returned value is a list of arrays; each array contains a 'bundle' specifier than can be passed got Model::get() or SearchResult::get() and a display name
  *
  * @param mixed $pm_table_name_or_num The table name or number specifying the content type to fetch bundles for. If omitted the content table of the currently loaded display will be used.
  * @param array $pa_options Support options are
  *		no_cache = if set caching of underlying data required to generate list is disabled. This is required in certain situations such as during installation. Only set this if you suspect stale data is being used to generate the list. Eg. if you've been changing metadata attributes in the same request in which you call this method. Default is false.
  *		no_tooltips = if set no tooltips for available bundles will be emitted. Default is false - tooltips will be emitted.
  *		format = specifies label format for bundles. Valid values are "simple" (just the name of the element) or "full" (name of element, name of type of item element pertains to and alternate label, if defined). Default is "full"
  * @return array And array of bundles keyed on display label. Each value is an array with these keys:
  *		bundle = The bundle name (eg. ca_objects.idno)
  *		display = Display label for each available bundle
  *		description = Description of bundle
  * 
  * Will return null if table name or number is invalid.
  */
 public function getAvailableBundles($pm_table_name_or_num = null, $pa_options = null)
 {
     if (!$pm_table_name_or_num) {
         $pm_table_name_or_num = $this->get('table_num');
     }
     $pm_table_name_or_num = $this->getAppDatamodel()->getTableNum($pm_table_name_or_num);
     if (!$pm_table_name_or_num) {
         return null;
     }
     $vb_show_tooltips = isset($pa_options['no_tooltips']) && (bool) $pa_options['no_tooltips'] ? false : true;
     $vs_format = isset($pa_options['format']) && in_array($pa_options['format'], array('simple', 'full')) ? $pa_options['format'] : 'full';
     $t_instance = $this->getAppDatamodel()->getInstanceByTableNum($pm_table_name_or_num, false);
     $vs_table = $t_instance->tableName();
     $vs_table_display_name = $t_instance->getProperty('NAME_PLURAL');
     $va_available_bundles = array();
     $t_placement = new ca_bundle_display_placements(null, array());
     if ($this->inTransaction()) {
         $t_placement->setTransaction($this->getTransaction());
     }
     // get intrinsic fields
     $va_additional_settings = array('maximum_length' => array('formatType' => FT_NUMBER, 'displayType' => DT_FIELD, 'width' => 6, 'height' => 1, 'takesLocale' => false, 'default' => 100, 'label' => _t('Maximum length'), 'description' => _t('Maximum length, in characters, of displayed information.')));
     foreach ($t_instance->getFormFields() as $vs_f => $va_info) {
         if (isset($va_info['DONT_USE_AS_BUNDLE']) && $va_info['DONT_USE_AS_BUNDLE']) {
             continue;
         }
         if ($t_instance->getFieldInfo($vs_f, 'ALLOW_BUNDLE_ACCESS_CHECK')) {
             if (caGetBundleAccessLevel($vs_table, $vs_f) == __CA_BUNDLE_ACCESS_NONE__) {
                 continue;
             }
         }
         $vs_bundle = $vs_table . '.' . $vs_f;
         $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_table}_{$vs_f}'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_instance->getProperty('NAME_SINGULAR')) . "</span> " . ($vs_label = $t_instance->getDisplayLabel($vs_bundle)) . "</div>";
         $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description = $t_instance->getDisplayDescription($vs_bundle), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
         if ($vb_show_tooltips) {
             TooltipManager::add("#bundleDisplayEditorBundle_{$vs_table}_{$vs_f}", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
         }
     }
     // get attributes
     $va_element_codes = $t_instance->getApplicableElementCodes(null, false, $pa_options['no_cache']);
     $t_md = new ca_metadata_elements();
     if ($this->inTransaction()) {
         $t_md->setTransaction($this->getTransaction());
     }
     $va_all_elements = $t_md->getElementsAsList();
     $va_additional_settings = array('format' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 5, 'takesLocale' => false, 'default' => '', 'label' => _t('Display format'), 'description' => _t('Template used to format output.'), 'helpText' => ''), 'delimiter' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 1, 'takesLocale' => false, 'default' => '', 'label' => _t('Delimiter'), 'description' => _t('Text to place in-between repeating values.')), 'maximum_length' => array('formatType' => FT_NUMBER, 'displayType' => DT_FIELD, 'width' => 6, 'height' => 1, 'takesLocale' => false, 'default' => 2048, 'label' => _t('Maximum length'), 'description' => _t('Maximum length, in characters, of displayed information.')), 'filter' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 5, 'takesLocale' => false, 'default' => '', 'label' => _t('Filter using expression'), 'description' => _t('Expression to filter values with. Leave blank if you do not wish to filter values.')));
     foreach ($va_element_codes as $vn_element_id => $vs_element_code) {
         if (!is_null($va_all_elements[$vn_element_id]['settings']['canBeUsedInDisplay']) && !$va_all_elements[$vn_element_id]['settings']['canBeUsedInDisplay']) {
             continue;
         }
         $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
         if ($this->inTransaction()) {
             $t_placement->setTransaction($this->getTransaction());
         }
         if (caGetBundleAccessLevel($vs_table, $vs_element_code) == __CA_BUNDLE_ACCESS_NONE__) {
             continue;
         }
         switch ($va_all_elements[$vn_element_id]['datatype']) {
             case 3:
                 // list
                 $va_even_more_settings = array('sense' => array('formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'width' => 20, 'height' => 1, 'takesLocale' => false, 'default' => 'singular', 'options' => array(_t('Singular') => 'singular', _t('Plural') => 'plural'), 'label' => _t('Sense'), 'description' => _t('Determines if value used is singular or plural version.')));
                 break;
             case 0:
                 // container (allows sub-elements to be summarized)
             // container (allows sub-elements to be summarized)
             case 6:
                 // Currency
             // Currency
             case 8:
                 // Length
             // Length
             case 9:
                 // Weight
             // Weight
             case 10:
                 // Timecode
             // Timecode
             case 11:
                 // Integer
             // Integer
             case 12:
                 // Numeric (decimal)
                 $va_even_more_settings = array('bottom_line' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 5, 'takesLocale' => false, 'default' => '', 'label' => _t('Bottom line format'), 'description' => _t('Template to format aggregate data for display under this column. The template can include these aggregate data tags: ^PAGEAVG, ^AVG, ^PAGESUM, ^SUM, ^PAGEMin, ^MIN, ^PAGEMAX, ^MAX. For containers follow the tag with the element code of the subelement to aggregate. Ex. ^SUM:dimensions_width')));
                 if ($va_all_elements[$vn_element_id]['datatype'] == 6) {
                     $va_even_more_settings['display_currency_conversion'] = array('formatType' => FT_NUMBER, 'displayType' => DT_CHECKBOXES, 'width' => 10, 'height' => 1, 'takesLocale' => false, 'default' => '0', 'label' => _t('Display currency conversion?'), 'description' => _t('Check this option if you want your currency values to be displayed in both the specified and local currency.'));
                 }
                 break;
             default:
                 $va_even_more_settings = array();
                 break;
         }
         $vs_bundle = $vs_table . '.' . $vs_element_code;
         $va_even_more_settings['format'] = $va_additional_settings['format'];
         //$va_even_more_settings['format']['helpText'] = $this->getTemplatePlaceholderDisplayListForBundle($vs_bundle);
         $t_placement = new ca_bundle_display_placements(null, array_merge($va_additional_settings, $va_even_more_settings));
         if ($this->inTransaction()) {
             $t_placement->setTransaction($this->getTransaction());
         }
         $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_table}_{$vs_element_code}'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_instance->getProperty('NAME_SINGULAR')) . "</span> " . ($vs_label = $t_instance->getDisplayLabel($vs_bundle)) . "</div>";
         $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description = $t_instance->getDisplayDescription($vs_bundle), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => array_merge($va_additional_settings, $va_even_more_settings));
         if ($vb_show_tooltips) {
             TooltipManager::add("#bundleDisplayEditorBundle_{$vs_table}_{$vs_element_code}", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
         }
     }
     if (caGetBundleAccessLevel($vs_table, "preferred_labels") != __CA_BUNDLE_ACCESS_NONE__) {
         // get preferred labels for this table
         $va_additional_settings = array('format' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 5, 'takesLocale' => false, 'default' => '', 'label' => _t('Display format'), 'description' => _t('Template used to format output.')), 'delimiter' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 1, 'takesLocale' => false, 'default' => '', 'label' => _t('Delimiter'), 'description' => _t('Text to place in-between repeating values.')), 'maximum_length' => array('formatType' => FT_NUMBER, 'displayType' => DT_FIELD, 'width' => 6, 'height' => 1, 'takesLocale' => false, 'default' => 100, 'label' => _t('Maximum length'), 'description' => _t('Maximum length, in characters, of displayed information.')));
         $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
         if ($this->inTransaction()) {
             $t_placement->setTransaction($this->getTransaction());
         }
         $vs_bundle = $vs_table . '.preferred_labels';
         $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_table}_preferred_labels'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_instance->getProperty('NAME_SINGULAR')) . "</span> " . ($vs_label = $t_instance->getDisplayLabel($vs_bundle)) . "</div>";
         $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description = $t_instance->getDisplayDescription($vs_bundle), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
         if ($vb_show_tooltips) {
             TooltipManager::add("#bundleDisplayEditorBundle_{$vs_table}_preferred_labels", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
         }
     }
     if (caGetBundleAccessLevel($vs_table, "nonpreferred_labels") != __CA_BUNDLE_ACCESS_NONE__) {
         // get non-preferred labels for this table
         $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
         if ($this->inTransaction()) {
             $t_placement->setTransaction($this->getTransaction());
         }
         $vs_bundle = $vs_table . '.nonpreferred_labels';
         $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_table}_nonpreferred_labels'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_instance->getProperty('NAME_SINGULAR')) . "</span> " . ($vs_label = $t_instance->getDisplayLabel($vs_bundle)) . "</div>";
         $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description = $t_instance->getDisplayDescription($vs_bundle), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
         if ($vb_show_tooltips) {
             TooltipManager::add("#bundleDisplayEditorBundle_{$vs_table}_nonpreferred_labels", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
         }
     }
     // get library checkout and commerce order history bundle (objects only, of course)
     if ($vs_table == 'ca_objects') {
         $va_additional_settings = array('order_type' => array('formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'width' => 35, 'height' => 1, 'takesLocale' => false, 'default' => '', 'options' => array(_t('Sales order') => 'O', _t('Loan') => 'L'), 'label' => _t('Type of order'), 'description' => _t('Determines which type of order is displayed.')));
         $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
         if ($this->inTransaction()) {
             $t_placement->setTransaction($this->getTransaction());
         }
         $vs_bundle = 'ca_commerce_order_history';
         $vs_label = _t('Order history');
         $vs_display = _t('Order history');
         $vs_description = _t('List of orders (loans or sales) that include this object');
         $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description, 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
         if ($vb_show_tooltips) {
             TooltipManager::add("#bundleDisplayEditorBundle_ca_commerce_order_history", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
         }
         $va_additional_settings = array('format' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 5, 'takesLocale' => false, 'default' => '', 'label' => _t('Display format'), 'description' => _t('Template used to format output.')));
         $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
         if ($this->inTransaction()) {
             $t_placement->setTransaction($this->getTransaction());
         }
         $vs_bundle = 'ca_object_checkouts';
         $vs_label = _t('Library checkouts');
         $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_table}_preferred_labels'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_instance->getProperty('NAME_SINGULAR')) . "</span> " . _t('Library checkouts') . "</div>";
         $vs_description = _t('List of library checkouts that include this object');
         $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description, 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
         if ($vb_show_tooltips) {
             TooltipManager::add("#bundleDisplayEditorBundle_ca_object_checkouts", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
         }
         $va_additional_settings = array();
         $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
         if ($this->inTransaction()) {
             $t_placement->setTransaction($this->getTransaction());
         }
         $vs_bundle = $vs_table . '.ca_objects_location';
         $vs_label = _t('Current location');
         $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_table}_ca_objects_location'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_instance->getProperty('NAME_SINGULAR')) . "</span> " . _t('Current location') . "</div>";
         $vs_description = _t('Current location of object');
         $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description, 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
         if ($vb_show_tooltips) {
             TooltipManager::add("#bundleDisplayEditorBundle_ca_objects_location", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
         }
     }
     if (caGetBundleAccessLevel($vs_table, "ca_object_representations") != __CA_BUNDLE_ACCESS_NONE__) {
         // get object representations (objects only, of course)
         if ($vs_table == 'ca_objects') {
             $va_additional_settings = array('display_mode' => array('formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'width' => 35, 'height' => 1, 'takesLocale' => false, 'default' => '', 'options' => array(_t('Media') => 'media', _t('URL') => 'url'), 'label' => _t('Output mode'), 'description' => _t('Determines if value used is URL of media or the media itself.')));
             $o_media_settings = new MediaProcessingSettings('ca_object_representations', 'media');
             $va_versions = $o_media_settings->getMediaTypeVersions('*');
             foreach ($va_versions as $vs_version => $va_version_info) {
                 $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
                 if ($this->inTransaction()) {
                     $t_placement->setTransaction($this->getTransaction());
                 }
                 $vs_bundle = 'ca_object_representations.media.' . $vs_version;
                 $vs_display = "<div id='bundleDisplayEditorBundle_ca_object_representations_media_{$vs_version}'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_instance->getProperty('NAME_SINGULAR')) . "</span> " . ($vs_label = $t_instance->getDisplayLabel($vs_bundle)) . "</div>";
                 $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description = $t_instance->getDisplayDescription($vs_bundle), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
                 if ($vb_show_tooltips) {
                     TooltipManager::add("#bundleDisplayEditorBundle_ca_object_representations_media_{$vs_version}", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
                 }
             }
             $t_rep = new ca_object_representations();
             if ($this->inTransaction()) {
                 $t_rep->setTransaction($this->getTransaction());
             }
             foreach (array('mimetype', 'md5', 'original_filename') as $vs_rep_field) {
                 $vs_bundle = 'ca_object_representations.' . $vs_rep_field;
                 $vs_display = "<div id='bundleDisplayEditorBundle_ca_object_representations_{$vs_rep_field}'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_rep->getProperty('NAME_SINGULAR')) . "</span> " . ($vs_label = $t_rep->getDisplayLabel($vs_bundle)) . "</div>";
                 $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description = $t_rep->getDisplayDescription($vs_bundle), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => array());
             }
         }
     }
     // get related items
     $o_dm = $this->getAppDatamodel();
     foreach (array('ca_objects', 'ca_object_lots', 'ca_entities', 'ca_places', 'ca_occurrences', 'ca_collections', 'ca_storage_locations', 'ca_loans', 'ca_movements', 'ca_list_items', 'ca_object_representations') as $vs_related_table) {
         if ($this->getAppConfig()->get($vs_related_table . '_disable') && !($vs_related_table == 'ca_object_representations' && !$this->getAppConfig()->get('ca_objects_disable'))) {
             continue;
         }
         if (caGetBundleAccessLevel($vs_table, $vs_related_table) == __CA_BUNDLE_ACCESS_NONE__) {
             continue;
         }
         if ($vs_related_table === $vs_table) {
             $vs_bundle = $vs_related_table . '.related';
         } else {
             $vs_bundle = $vs_related_table;
         }
         $t_rel_instance = $o_dm->getInstanceByTableName($vs_related_table, true);
         $vs_table_name = $o_dm->getTableName($this->get('table_num'));
         $va_path = array_keys($o_dm->getPath($vs_table_name, $vs_related_table));
         if (sizeof($va_path) < 2 || sizeof($va_path) > 3) {
             continue;
         }
         // only use direct relationships (one-many or many-many)
         $va_additional_settings = array('format' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 5, 'takesLocale' => false, 'default' => '', 'label' => _t('Display format'), 'description' => _t('Template used to format output.')), 'restrict_to_relationship_types' => array('formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'useRelationshipTypeList' => $va_path[1], 'width' => 35, 'height' => 5, 'takesLocale' => false, 'default' => '', 'label' => _t('Restrict to relationship types'), 'description' => _t('Restricts display to items related using the specified relationship type(s). Leave all unchecked for no restriction.')), 'restrict_to_types' => array('formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'useList' => $t_rel_instance->getTypeListCode(), 'width' => 35, 'height' => 5, 'takesLocale' => false, 'default' => '', 'label' => _t('Restrict to types'), 'description' => _t('Restricts display to items of the specified type(s). Leave all unchecked for no restriction.')), 'delimiter' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 1, 'takesLocale' => false, 'default' => '', 'label' => _t('Delimiter'), 'description' => _t('Text to place in-between repeating values.')));
         if ($t_rel_instance->isHierarchical()) {
             $va_additional_settings += array('show_hierarchy' => array('formatType' => FT_NUMBER, 'displayType' => DT_CHECKBOXES, 'width' => 10, 'height' => 1, 'hideOnSelect' => array('format'), 'takesLocale' => false, 'default' => '0', 'label' => _t('Show hierarchy?'), 'description' => _t('If checked the full hierarchical path will be shown.')), 'remove_first_items' => array('formatType' => FT_NUMBER, 'displayType' => DT_FIELD, 'width' => 10, 'height' => 1, 'takesLocale' => false, 'default' => '0', 'label' => _t('Remove first items from hierarchy?'), 'description' => _t('If set to a non-zero value, the specified number of items at the top of the hierarchy will be omitted. For example, if set to 2, the root and first child of the hierarchy will be omitted.')), 'hierarchy_order' => array('formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'options' => array(_t('top first') => 'ASC', _t('bottom first') => 'DESC'), 'width' => 35, 'height' => 1, 'takesLocale' => false, 'default' => '', 'label' => _t('Order hierarchy'), 'description' => _t('Determines order in which hierarchy is displayed.')), 'hierarchy_limit' => array('formatType' => FT_NUMBER, 'displayType' => DT_FIELD, 'width' => 10, 'height' => 1, 'takesLocale' => false, 'default' => '', 'label' => _t('Maximum length of hierarchy'), 'description' => _t('Maximum number of items to show in the hierarchy. Leave blank to show the unabridged hierarchy.')), 'hierarchical_delimiter' => array('formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => 35, 'height' => 1, 'takesLocale' => false, 'default' => ' ➔ ', 'label' => _t('Hierarchical delimiter'), 'description' => _t('Text to place in-between elements of a hierarchical value.')));
         }
         if ($vs_table === 'ca_objects' && $vs_related_table === 'ca_storage_locations' || $vs_table === 'ca_storage_locations' && $vs_related_table === 'ca_objects' || $vs_table === 'ca_objects' && $vs_related_table === 'ca_movements' || $vs_table === 'ca_movements' && $vs_related_table === 'ca_objects' || $vs_table === 'ca_storage_locations' && $vs_related_table === 'ca_movements' || $vs_table === 'ca_movements' && $vs_related_table === 'ca_storage_locations') {
             $va_additional_settings['showCurrentOnly'] = array('formatType' => FT_TEXT, 'displayType' => DT_CHECKBOXES, 'width' => "10", 'height' => "1", 'takesLocale' => false, 'default' => '0', 'label' => _t('Show current only?'), 'description' => _t('If checked only current objects are displayed.'));
         }
         //$va_additional_settings['format']['helpText'] = $this->getTemplatePlaceholderDisplayListForBundle($vs_bundle);
         $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
         if ($this->inTransaction()) {
             $t_placement->setTransaction($this->getTransaction());
         }
         $vs_id_suffix = "bundleDisplayEditorBundle_" . str_replace(".", "_", $vs_bundle);
         $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_id_suffix}'><span class='bundleDisplayEditorPlacementListItemTitle'>" . caUcFirstUTF8Safe($t_rel_instance->getProperty('NAME_SINGULAR')) . "</span> " . ($vs_label = $t_rel_instance->getDisplayLabel($vs_bundle)) . "</div>";
         $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description = $t_rel_instance->getDisplayDescription($vs_bundle), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
         if ($vb_show_tooltips) {
             TooltipManager::add("#bundleDisplayEditorBundle_{$vs_id_suffix}", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
         }
     }
     // created and modified
     $va_additional_settings = array('dateFormat' => array('formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'width' => 40, 'height' => 1, 'takesLocale' => false, 'default' => 'iso8601', 'options' => array('ISO-8601' => 'iso8601', 'Text' => 'text'), 'label' => _t('Date format'), 'description' => _t('Sets format for output of date when exporting.')));
     $t_placement = new ca_bundle_display_placements(null, $va_additional_settings);
     if ($this->inTransaction()) {
         $t_placement->setTransaction($this->getTransaction());
     }
     $vs_bundle = "{$vs_table}.created";
     $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_table}_created'><span class='bundleDisplayEditorPlacementListItemTitle'>" . _t('General') . "</span> " . ($vs_label = $t_instance->getDisplayLabel($vs_bundle)) . "</div>";
     $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_format == 'simple' ? $vs_label : $vs_display, 'description' => $vs_description = _t('Date and time item was created'), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
     if ($vb_show_tooltips) {
         TooltipManager::add("#bundleDisplayEditorBundle_{$vs_table}_created", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
     }
     $vs_bundle = "{$vs_table}.lastModified";
     $vs_display = "<div id='bundleDisplayEditorBundle_{$vs_table}_lastModified'><span class='bundleDisplayEditorPlacementListItemTitle'>" . _t('General') . "</span> " . ($vs_label = $t_instance->getDisplayLabel($vs_bundle)) . "</div>";
     $va_available_bundles[strip_tags($vs_display)][$vs_bundle] = array('bundle' => $vs_bundle, 'display' => $vs_display, 'description' => $vs_description = _t('Date and time item was last modified'), 'settingsForm' => $t_placement->getHTMLSettingForm(array('id' => $vs_bundle . '_0')), 'settings' => $va_additional_settings);
     if ($vb_show_tooltips) {
         TooltipManager::add("#bundleDisplayEditorBundle_{$vs_table}_lastModified", $this->_formatBundleTooltip($vs_label, $vs_bundle, $vs_description));
     }
     ksort($va_available_bundles);
     $va_sorted_bundles = array();
     foreach ($va_available_bundles as $vs_k => $va_val) {
         foreach ($va_val as $vs_real_key => $va_info) {
             $va_sorted_bundles[$vs_real_key] = $va_info;
         }
     }
     return $va_sorted_bundles;
 }
Exemplo n.º 3
0
 /**
  * Convenience method to edit a representation instance. Allows to you edit a linked representation from an instance.
  * 
  * @param int representation_id
  * @param string $ps_media_path
  * @param int $pn_locale_id
  * @param int $pn_status
  * @param int $pn_access
  * @param bool $pb_is_primary Sets 'primaryness' of representation. If you wish to leave the primary setting to its current value set this null or omit the parameter.
  * @param array $pa_values
  * @param array $pa_options
  *
  * @return bool True on success, false on failure, null if no row has been loaded into the object model 
  */
 public function editRepresentation($pn_representation_id, $ps_media_path, $pn_locale_id, $pn_status, $pn_access, $pb_is_primary = null, $pa_values = null, $pa_options = null)
 {
     if (!($vn_id = $this->getPrimaryKey())) {
         return null;
     }
     $t_rep = new ca_object_representations();
     if ($this->inTransaction()) {
         $o_trans = $this->getTransaction();
         $t_rep->setTransaction($o_trans);
     }
     if (!$t_rep->load(array('representation_id' => $pn_representation_id))) {
         $this->postError(750, _t("Representation id=%1 does not exist", $pn_representation_id), "RepresentableBaseModel->editRepresentation()");
         return false;
     } else {
         $t_rep->setMode(ACCESS_WRITE);
         $t_rep->set('locale_id', $pn_locale_id);
         $t_rep->set('status', $pn_status);
         $t_rep->set('access', $pn_access);
         if ($ps_media_path) {
             $t_rep->set('media', $ps_media_path, $pa_options);
         }
         if (is_array($pa_values)) {
             if (isset($pa_values['idno'])) {
                 $t_rep->set('idno', $pa_values['idno']);
             }
             foreach ($pa_values as $vs_element => $va_value) {
                 if (is_array($va_value)) {
                     // array of values (complex multi-valued attribute)
                     $t_rep->replaceAttribute(array_merge($va_value, array('locale_id' => $pn_locale_id)), $vs_element);
                 } else {
                     // scalar value (simple single value attribute)
                     if ($va_value) {
                         $t_rep->replaceAttribute(array('locale_id' => $pn_locale_id, $vs_element => $va_value), $vs_element);
                     }
                 }
             }
         }
         $t_rep->update();
         if ($t_rep->numErrors()) {
             $this->errors = array_merge($this->errors, $t_rep->errors());
             return false;
         }
         if (!($t_oxor = $this->_getRepresentationRelationshipTableInstance())) {
             return null;
         }
         $vs_pk = $this->primaryKey();
         if (!$t_oxor->load(array($vs_pk => $vn_id, 'representation_id' => $pn_representation_id))) {
             $this->postError(750, _t("Representation id=%1 is not related to %3 id=%2", $pn_representation_id, $vn_id, $this->getProperty('NAME_SINGULAR')), "RepresentableBaseModel->editRepresentation()");
             return false;
         } else {
             $t_oxor->setMode(ACCESS_WRITE);
             if (!is_null($pb_is_primary)) {
                 $t_oxor->set('is_primary', (bool) $pb_is_primary ? 1 : 0);
             }
             if (isset($pa_options['rank']) && ($vn_rank = (int) $pa_options['rank'])) {
                 $t_oxor->set('rank', $vn_rank);
             }
             $t_oxor->update();
             if ($t_oxor->numErrors()) {
                 $this->errors = array_merge($this->errors, $t_oxor->errors());
                 return false;
             }
         }
         return true;
     }
     return false;
 }
Exemplo n.º 4
0
 /**
  * Returns representation_id for the object representation with the specified name (and type) or idno (regardless of specified type.) If the object does
  * not already exist then it will be created with the specified name, type and locale, as well as with any specified values in the $pa_values array.
  * $pa_values keys should be either valid object fields or attributes.
  *
  * @param string $ps_representation_name Object label name
  * @param int $pn_type_id The type_id of the object type to use if the representation needs to be created
  * @param int $pn_locale_id The locale_id to use if the representation needs to be created (will be used for both the object locale as well as the label locale)
  * @param array $pa_values An optional array of additional values to populate newly created representation records with. These values are *only* used for newly created representation; they will not be applied if the representation named already exists. The array keys should be names of ca_object_representations fields or valid representation attributes. Values should be either a scalar (for single-value attributes) or an array of values for (multi-valued attributes)
  * @param array $pa_options An optional array of options, which include:
  *                outputErrors - if true, errors will be printed to console [default=false]
  *                matchOn = optional list indicating sequence of checks for an existing record; values of array can be "label" and "idno". Ex. array("idno", "label") will first try to match on idno and then label if the first match fails.
  *                dontCreate - if true then new representations will not be created [default=false]
  *                transaction - if Transaction object is passed, use it for all Db-related tasks [default=null]
  *                returnInstance = return ca_object_representations instance rather than representation_id. Default is false.
  *                generateIdnoWithTemplate = A template to use when setting the idno. The template is a value with automatically-set SERIAL values replaced with % characters. Eg. 2012.% will set the created row's idno value to 2012.121 (assuming that 121 is the next number in the serial sequence.) The template is NOT used if idno is passed explicitly as a value in $pa_values.
  *                importEvent = if ca_data_import_events instance is passed then the insert/update of the representation will be logged as part of the import
  *                importEventSource = if importEvent is passed, then the value set for importEventSource is used in the import event log as the data source. If omitted a default value of "?" is used
  *                nonPreferredLabels = an optional array of nonpreferred labels to add to any newly created representations. Each label in the array is an array with required representation label values.
  *                log = if KLogger instance is passed then actions will be logged
  *				  matchMediaFilesWithoutExtension = if media path is invalid, attempt to find media in referenced directory and sub-directories that has a matching name, regardless of file extension. [default=false] 
  * @return bool|ca_object_representations|mixed|null
  */
 static function getObjectRepresentationID($ps_representation_name, $pn_type_id, $pn_locale_id, $pa_values = null, $pa_options = null)
 {
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     if (!isset($pa_options['outputErrors'])) {
         $pa_options['outputErrors'] = false;
     }
     $vb_match_media_without_extension = caGetOption('matchMediaFilesWithoutExtension', $pa_options, false);
     $pa_match_on = caGetOption('matchOn', $pa_options, array('label', 'idno'), array('castTo' => "array"));
     /** @var ca_data_import_events $o_event */
     $o_event = isset($pa_options['importEvent']) && $pa_options['importEvent'] instanceof ca_data_import_events ? $pa_options['importEvent'] : null;
     $t_rep = new ca_object_representations();
     if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
         $t_rep->setTransaction($pa_options['transaction']);
         if ($o_event) {
             $o_event->setTransaction($pa_options['transaction']);
         }
     }
     $vs_event_source = isset($pa_options['importEventSource']) && $pa_options['importEventSource'] ? $pa_options['importEventSource'] : "?";
     /** @var KLogger $o_log */
     $o_log = isset($pa_options['log']) && $pa_options['log'] instanceof KLogger ? $pa_options['log'] : null;
     $vs_idno = isset($pa_values['idno']) ? (string) $pa_values['idno'] : null;
     if (preg_match('!\\%!', $vs_idno)) {
         $pa_options['generateIdnoWithTemplate'] = $vs_idno;
         $vs_idno = null;
     }
     if (!$vs_idno) {
         if (isset($pa_options['generateIdnoWithTemplate']) && $pa_options['generateIdnoWithTemplate']) {
             $vs_idno = $t_rep->setIdnoWithTemplate($pa_options['generateIdnoWithTemplate'], array('dontSetValue' => true));
         }
     }
     $va_regex_list = caBatchGetMediaFilenameToIdnoRegexList(array('log' => $o_log));
     // Get list of replacements that user can use to transform file names to match object idnos
     $va_replacements_list = caBatchGetMediaFilenameReplacementRegexList(array('log' => $o_log));
     $vn_id = null;
     foreach ($pa_match_on as $vs_match_on) {
         switch (strtolower($vs_match_on)) {
             case 'label':
             case 'labels':
                 if (trim($ps_representation_name)) {
                     if ($vn_id = ca_object_representations::find(array('preferred_labels' => array('name' => $ps_representation_name), 'type_id' => $pn_type_id), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction']))) {
                         break 2;
                     }
                 }
                 break;
             case 'idno':
                 if (!$vs_idno) {
                     break;
                 }
                 if ($vs_idno == '%') {
                     break;
                 }
                 // don't try to match on an unreplaced idno placeholder
                 $va_idnos_to_match = array($vs_idno);
                 if (is_array($va_replacements_list)) {
                     foreach ($va_replacements_list as $vs_replacement_code => $va_replacement) {
                         if (isset($va_replacement['search']) && is_array($va_replacement['search'])) {
                             $va_replace = caGetOption('replace', $va_replacement);
                             $va_search = array();
                             foreach ($va_replacement['search'] as $vs_search) {
                                 $va_search[] = '!' . $vs_search . '!';
                             }
                             if ($vs_idno_proc = @preg_replace($va_search, $va_replace, $vs_idno)) {
                                 $va_idnos_to_match[] = $vs_idno_proc;
                             }
                         }
                     }
                 }
                 if (is_array($va_regex_list) && sizeof($va_regex_list)) {
                     foreach ($va_regex_list as $vs_regex_name => $va_regex_info) {
                         foreach ($va_regex_info['regexes'] as $vs_regex) {
                             foreach ($va_idnos_to_match as $vs_idno_match) {
                                 if (!$vs_idno_match) {
                                     continue;
                                 }
                                 if (preg_match('!' . $vs_regex . '!', $vs_idno_match, $va_matches)) {
                                     if ($vn_id = ca_object_representations::find(array('idno' => $va_matches[1]), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction']))) {
                                         break 5;
                                     }
                                 }
                             }
                         }
                     }
                 } else {
                     foreach ($va_idnos_to_match as $vs_idno_match) {
                         if (!$vs_idno_match) {
                             continue;
                         }
                         if ($vn_id = ca_object_representations::find(array('idno' => $vs_idno_match), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction']))) {
                             break 3;
                         }
                     }
                 }
                 break;
         }
     }
     if (!$vn_id) {
         if (isset($pa_options['dontCreate']) && $pa_options['dontCreate']) {
             return false;
         }
         if ($o_event) {
             $o_event->beginItem($vs_event_source, 'ca_object_representations', 'I');
         }
         $t_rep->setMode(ACCESS_WRITE);
         $t_rep->set('locale_id', $pn_locale_id);
         $t_rep->set('type_id', $pn_type_id);
         $t_rep->set('source_id', isset($pa_values['source_id']) ? $pa_values['source_id'] : null);
         $t_rep->set('access', isset($pa_values['access']) ? $pa_values['access'] : 0);
         $t_rep->set('status', isset($pa_values['status']) ? $pa_values['status'] : 0);
         if (isset($pa_values['media']) && $pa_values['media']) {
             if ($vb_match_media_without_extension && !isURL($pa_values['media']) && !file_exists($pa_values['media'])) {
                 $vs_dirname = pathinfo($pa_values['media'], PATHINFO_DIRNAME);
                 $vs_filename = preg_replace('!\\.[A-Za-z0-9]{1,4}$!', '', pathinfo($pa_values['media'], PATHINFO_BASENAME));
                 $vs_original_path = $pa_values['media'];
                 $pa_values['media'] = null;
                 $va_files_in_dir = caGetDirectoryContentsAsList($vs_dirname, true, false, false, false);
                 foreach ($va_files_in_dir as $vs_filepath) {
                     if ($o_log) {
                         $o_log->logDebug(_t("Trying media %1 in place of %2/%3", $vs_filepath, $vs_original_path, $vs_filename));
                     }
                     if (pathinfo($vs_filepath, PATHINFO_FILENAME) == $vs_filename) {
                         if ($o_log) {
                             $o_log->logNotice(_t("Found media %1 for %2/%3", $vs_filepath, $vs_original_path, $vs_filename));
                         }
                         $pa_values['media'] = $vs_filepath;
                         break;
                     }
                 }
             }
             $t_rep->set('media', $pa_values['media']);
         }
         $t_rep->set('idno', $vs_idno);
         $t_rep->insert();
         if ($t_rep->numErrors()) {
             if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                 print "[Error] " . _t("Could not insert object %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())) . "\n";
             }
             if ($o_log) {
                 $o_log->logError(_t("Could not insert object %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())));
             }
             return null;
         }
         $vb_label_errors = false;
         $t_rep->addLabel(array('name' => $ps_representation_name), $pn_locale_id, null, true);
         if ($t_rep->numErrors()) {
             if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                 print "[Error] " . _t("Could not set preferred label for object %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())) . "\n";
             }
             if ($o_log) {
                 $o_log->logError(_t("Could not set preferred label for object %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())));
             }
             $vb_label_errors = true;
         }
         /** @var IIDNumbering $o_idno */
         if ($o_idno = $t_rep->getIDNoPlugInInstance()) {
             $va_values = $o_idno->htmlFormValuesAsArray('idno', $vs_idno);
             if (!is_array($va_values)) {
                 $va_values = array($va_values);
             }
             if (!($vs_sep = $o_idno->getSeparator())) {
                 $vs_sep = '';
             }
             if (($vs_proc_idno = join($vs_sep, $va_values)) && $vs_proc_idno != $vs_idno) {
                 $t_rep->set('idno', $vs_proc_idno);
                 $t_rep->update();
                 if ($t_rep->numErrors()) {
                     if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                         print "[Error] " . _t("Could not update idno for %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())) . "\n";
                     }
                     if ($o_log) {
                         $o_log->logError(_t("Could not object idno for %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())));
                     }
                     return null;
                 }
             }
         }
         unset($pa_values['access']);
         unset($pa_values['status']);
         unset($pa_values['idno']);
         unset($pa_values['source_id']);
         $vb_attr_errors = false;
         if (is_array($pa_values)) {
             foreach ($pa_values as $vs_element => $va_values) {
                 if (!caIsIndexedArray($va_values)) {
                     $va_values = array($va_values);
                 }
                 foreach ($va_values as $va_value) {
                     if (is_array($va_value)) {
                         // array of values (complex multi-valued attribute)
                         $t_rep->addAttribute(array_merge($va_value, array('locale_id' => $pn_locale_id)), $vs_element);
                     } else {
                         // scalar value (simple single value attribute)
                         if ($va_value) {
                             $t_rep->addAttribute(array('locale_id' => $pn_locale_id, $vs_element => $va_value), $vs_element);
                         }
                     }
                 }
             }
             $t_rep->update();
             if ($t_rep->numErrors()) {
                 if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                     print "[Error] " . _t("Could not set values for representation %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())) . "\n";
                 }
                 if ($o_log) {
                     $o_log->logError(_t("Could not set values for representation %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())));
                 }
                 $vb_attr_errors = true;
             }
         }
         if (is_array($va_nonpreferred_labels = caGetOption("nonPreferredLabels", $pa_options, null))) {
             if (caIsAssociativeArray($va_nonpreferred_labels)) {
                 // single non-preferred label
                 $va_labels = array($va_nonpreferred_labels);
             } else {
                 // list of non-preferred labels
                 $va_labels = $va_nonpreferred_labels;
             }
             foreach ($va_labels as $va_label) {
                 $t_rep->addLabel($va_label, $pn_locale_id, null, false);
                 if ($t_rep->numErrors()) {
                     if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                         print "[Error] " . _t("Could not set non-preferred label for representation %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())) . "\n";
                     }
                     if ($o_log) {
                         $o_log->logError(_t("Could not set non-preferred label for representation %1: %2", $ps_representation_name, join('; ', $t_rep->getErrors())));
                     }
                 }
             }
         }
         $vn_representation_id = $t_rep->getPrimaryKey();
         if ($o_event) {
             if ($vb_attr_errors || $vb_label_errors) {
                 $o_event->endItem($vn_representation_id, __CA_DATA_IMPORT_ITEM_PARTIAL_SUCCESS__, _t("Errors setting field values: %1", join('; ', $t_rep->getErrors())));
             } else {
                 $o_event->endItem($vn_representation_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
             }
         }
         if ($o_log) {
             $o_log->logInfo(_t("Created new representation %1", $ps_representation_name));
         }
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             return $t_rep;
         }
     } else {
         if ($o_event) {
             $o_event->beginItem($vs_event_source, 'ca_object_representations', 'U');
         }
         $vn_representation_id = $vn_id;
         if ($o_event) {
             $o_event->endItem($vn_representation_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
         }
         if ($o_log) {
             $o_log->logDebug(_t("Found existing representation %1 in DataMigrationUtils::getObjectRepresentationID()", $ps_representation_name));
         }
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             $t_rep = new ca_object_representations($vn_representation_id);
             if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
                 $t_rep->setTransaction($pa_options['transaction']);
             }
             return $t_rep;
         }
     }
     return $vn_representation_id;
 }
 /**
  * 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;
 }
 /**
  * Returns annotation type code for currently loaded representation
  * Type codes are based upon the mimetype of the representation's media as defined in the annotation_types.conf file
  * 
  * If you pass the options $pn_representation_id parameter then the returned type is for the specified representation rather
  * than the currently loaded one.
  */
 public function getAnnotationType($pn_representation_id = null)
 {
     if (!$pn_representation_id) {
         $t_rep = $this;
     } else {
         $t_rep = new ca_object_representations($pn_representation_id);
         if ($this->inTransaction()) {
             $t_rep->setTransaction($this->getTransaction());
         }
     }
     $va_media_info = $t_rep->getMediaInfo('media');
     if (!isset($va_media_info['INPUT'])) {
         return null;
     }
     if (!isset($va_media_info['INPUT']['MIMETYPE'])) {
         return null;
     }
     $vs_mimetype = $va_media_info['INPUT']['MIMETYPE'];
     $o_type_config = Configuration::load($this->getAppConfig()->get('annotation_type_config'));
     $va_mappings = $o_type_config->getAssoc('mappings');
     return $va_mappings[$vs_mimetype];
 }