Example #1
0
/**
 * Fetch item_id for item with specified idno in list
 *
 * @param string $ps_list List code or list label
 * @return int list_id of list or null if no matching list was found
 */
function caGetListID($ps_list)
{
    $t_list = new ca_lists();
    if (is_numeric($ps_list)) {
        if ($t_list->load((int) $ps_list)) {
            return $t_list->getPrimaryKey();
        }
    }
    if ($t_list->load(array('list_code' => $ps_list))) {
        return $t_list->getPrimaryKey();
    }
    $t_label = new ca_list_labels();
    if ($t_label->load(array('name' => $ps_list))) {
        return $t_label->get('list_id');
    }
    return null;
}
Example #2
0
function caGetListID($ps_list)
{
    global $g_list_id_cache;
    if (isset($g_list_id_cache[$ps_list])) {
        return $g_list_id_cache[$ps_list];
    }
    $t_list = new ca_lists();
    if (is_numeric($ps_list)) {
        if ($t_list->load((int) $ps_list)) {
            return $g_list_id_cache[$ps_list] = $t_list->getPrimaryKey();
        }
    }
    if ($t_list->load(array('list_code' => $ps_list))) {
        return $g_list_id_cache[$ps_list] = $t_list->getPrimaryKey();
    }
    $t_label = new ca_list_labels();
    if ($t_label->load(array('name' => $ps_list))) {
        return $g_list_id_cache[$ps_list] = $t_label->get('list_id');
    }
    return $g_list_id_cache[$ps_list] = null;
}
 /**
  * Returns string representing the name of the item the browse will return
  *
  * If $ps_mode is 'singular' [default] then the singular version of the name is returned, otherwise the plural is returned
  */
 public function browseName($ps_mode = 'singular')
 {
     $vb_type_restriction_has_changed = false;
     $vn_type_id = $this->opo_result_context->getTypeRestriction($vb_type_restriction_has_changed);
     $t_list = new ca_lists();
     $t_list->load(array('list_code' => 'occurrence_types'));
     $t_list_item = new ca_list_items();
     $t_list_item->load(array('list_id' => $t_list->getPrimaryKey(), 'parent_id' => null));
     $va_hier = caExtractValuesByUserLocale($t_list_item->getHierarchyWithLabels());
     if (!($vs_name = $ps_mode == 'singular' ? $va_hier[$vn_type_id]['name_singular'] : $va_hier[$vn_type_id]['name_plural'])) {
         $vs_name = '???';
     }
     return $vs_name;
 }
Example #4
0
 public function processDisplays()
 {
     require_once __CA_MODELS_DIR__ . "/ca_bundle_displays.php";
     require_once __CA_MODELS_DIR__ . "/ca_bundle_display_placements.php";
     require_once __CA_MODELS_DIR__ . "/ca_bundle_display_type_restrictions.php";
     $o_config = Configuration::load();
     $vo_dm = Datamodel::load();
     if ($this->ops_base_name) {
         // "merge" profile and its base
         $va_displays = array();
         if ($this->opo_base->displays) {
             foreach ($this->opo_base->displays->children() as $vo_display) {
                 $va_displays[self::getAttribute($vo_display, "code")] = $vo_display;
             }
         }
         if ($this->opo_profile->displays) {
             foreach ($this->opo_profile->displays->children() as $vo_display) {
                 $va_displays[self::getAttribute($vo_display, "code")] = $vo_display;
             }
         }
     } else {
         if ($this->opo_profile->displays) {
             foreach ($this->opo_profile->displays->children() as $vo_display) {
                 $va_displays[self::getAttribute($vo_display, "code")] = $vo_display;
             }
         }
     }
     if (!is_array($va_displays) || sizeof($va_displays) == 0) {
         return true;
     }
     foreach ($va_displays as $vo_display) {
         $vs_display_code = self::getAttribute($vo_display, "code");
         $vb_system = self::getAttribute($vo_display, "system");
         $vs_table = self::getAttribute($vo_display, "type");
         if ($o_config->get($vs_table . '_disable')) {
             continue;
         }
         $t_display = $this->opb_updating ? ca_bundle_displays::find(array('code' => $vs_display_code, 'type' => $vs_table), array('returnAs' => 'firstModelInstance')) : false;
         $t_display = $t_display ? $t_display : new ca_bundle_displays();
         $t_display->setMode(ACCESS_WRITE);
         $t_display->set("display_code", $vs_display_code);
         $t_display->set("is_system", $vb_system);
         $t_display->set("table_num", $vo_dm->getTableNum($vs_table));
         $t_display->set("user_id", 1);
         // let administrative user own these
         $this->_processSettings($t_display, $vo_display->settings);
         if ($t_display->getPrimaryKey()) {
             $t_display->update();
         } else {
             $t_display->insert();
         }
         if ($t_display->numErrors()) {
             $this->addError("There was an error while inserting display {$vs_display_code}: " . join(" ", $t_display->getErrors()));
         } else {
             self::addLabelsFromXMLElement($t_display, $vo_display->labels, $this->opa_locales);
             if ($t_display->numErrors()) {
                 $this->addError("There was an error while inserting display label for {$vs_display_code}: " . join(" ", $t_display->getErrors()));
             }
             if (!$this->processDisplayPlacements($t_display, $vo_display->bundlePlacements, null)) {
                 return false;
             }
         }
         if ($vo_display->typeRestrictions) {
             foreach ($vo_display->typeRestrictions->children() as $vo_restriction) {
                 $t_list = new ca_lists();
                 $t_list_item = new ca_list_items();
                 $vs_restriction_code = trim((string) self::getAttribute($vo_restriction, "code"));
                 $vs_type = trim((string) self::getAttribute($vo_restriction, "type"));
                 $t_instance = $vo_dm->getInstanceByTableNum($vn_table_num = $vo_dm->getTableNum($vs_table));
                 $vs_type_list_name = $t_instance->getFieldListCode($t_instance->getTypeFieldName());
                 if ($vs_type) {
                     $t_list->load(array('list_code' => $vs_type_list_name));
                     $t_list_item->load(array('list_id' => $t_list->getPrimaryKey(), 'idno' => $vs_type));
                 }
                 $vn_type_id = $vs_type ? $t_list_item->getPrimaryKey() : null;
                 $t_restriction = $this->opb_updating ? ca_bundle_display_type_restrictions::find(array('table_num' => $vn_table_num, 'type_id' => $vn_type_id), array('returnAs' => 'firstModelInstance')) : false;
                 $t_restriction = $t_restriction ? $t_restriction : new ca_bundle_display_type_restrictions();
                 $t_restriction->setMode(ACCESS_WRITE);
                 $t_restriction->set('table_num', $vn_table_num);
                 $t_restriction->set('include_subtypes', (bool) $vo_restriction->includeSubtypes ? 1 : 0);
                 $t_restriction->set('type_id', $vn_type_id);
                 $t_restriction->set('display_id', $t_display->getPrimaryKey());
                 $this->_processSettings($t_restriction, $vo_restriction->settings);
                 if ($t_restriction->getPrimaryKey()) {
                     $t_restriction->update();
                 } else {
                     $t_restriction->insert();
                 }
                 if ($t_restriction->numErrors()) {
                     $this->addError("There was an error while inserting type restriction {$vs_restriction_code} in display {$vs_display_code}: " . join("; ", $t_restriction->getErrors()));
                 }
             }
         }
         if ($vo_display->userAccess) {
             $t_user = new ca_users();
             $va_display_users = array();
             foreach ($vo_display->userAccess->children() as $vo_permission) {
                 $vs_user = trim((string) self::getAttribute($vo_permission, "user"));
                 $vn_access = $this->_convertUserGroupAccessStringToInt(self::getAttribute($vo_permission, 'access'));
                 if ($vn_access && $t_user->load(array('user_name' => $vs_user))) {
                     $va_display_users[$t_user->getUserID()] = $vn_access;
                 } else {
                     $this->addError("User name or access value invalid for display {$vs_display_code} (permission item with user name '{$vs_user}')");
                 }
             }
             if (sizeof($va_display_users) > 0) {
                 $t_display->addUsers($va_display_users);
             }
         }
         if ($vo_display->groupAccess) {
             $t_group = new ca_user_groups();
             $va_display_groups = array();
             foreach ($vo_display->groupAccess->children() as $vo_permission) {
                 $vs_group = trim((string) self::getAttribute($vo_permission, "group"));
                 $vn_access = $this->_convertUserGroupAccessStringToInt(self::getAttribute($vo_permission, 'access'));
                 if ($vn_access && $t_group->load(array('code' => $vs_group))) {
                     $va_display_groups[$t_group->getPrimaryKey()] = $vn_access;
                 } else {
                     $this->addError("Group code or access value invalid for display {$vs_display_code} (permission item with group code '{$vs_group}')");
                 }
             }
             if (sizeof($va_display_groups) > 0) {
                 $t_display->addUserGroups($va_display_groups);
             }
         }
     }
     return true;
 }
Example #5
0
function caGetListCode($pn_list_id, $pa_options = null)
{
    global $g_ca_get_list_code_cache;
    if (isset($g_ca_get_list_code_cache[$pn_list_id])) {
        return $g_ca_get_list_code_cache[$pn_list_id];
    }
    $t_list = new ca_lists();
    if ($o_trans = caGetOption('transaction', $pa_options, null)) {
        $t_list->setTransaction($o_trans);
    }
    $t_list->load($pn_list_id);
    return $g_ca_get_list_code_cache[$pn_list_id] = $t_list->get('list_code');
}
Example #6
0
 /**
  * Set setting value 
  * (you must call insert() or update() to write the settings to the database)
  */
 public function setSetting($ps_setting, $pm_value)
 {
     if (!$this->isValidSetting($ps_setting)) {
         return null;
     }
     $va_setting_info = $this->getSettingInfo($ps_setting);
     if ($va_setting_info['displayType'] == DT_CHECKBOXES) {
         $pm_value = (int) $pm_value;
     }
     if (isset($va_setting_info['useRelationshipTypeList']) && $va_setting_info['useRelationshipTypeList'] || isset($va_setting_info['useList']) && $va_setting_info['useList'] || isset($va_setting_info['showLists']) && $va_setting_info['showLists'] || isset($va_setting_info['showVocabularies']) && $va_setting_info['showVocabularies']) {
         if (!is_array($pm_value)) {
             $pm_value = array($pm_value);
         }
         foreach ($pm_value as $vn_i => $vm_value) {
             if (trim($vm_value) && !is_numeric($vm_value)) {
                 // need to convert codes to ids
                 if ($vs_t = $va_setting_info['useRelationshipTypeList']) {
                     $t_rel = new ca_relationship_types();
                     $pm_value[$vn_i] = $t_rel->getRelationshipTypeID($vs_t, $vm_value);
                 } else {
                     if ($vs_l = $va_setting_info['useList']) {
                         // is a list
                         $t_list = new ca_lists();
                         $pm_value[$vn_i] = $t_list->getItemIDFromList($vs_l, $vm_value);
                     } else {
                         if ($va_setting_info['showLists'] || $va_setting_info['showVocabularies']) {
                             // is a list
                             $t_list = new ca_lists();
                             $vn_list_id = null;
                             if ($t_list->load(array('list_code' => $vm_value))) {
                                 $vn_list_id = $t_list->getPrimaryKey();
                             } else {
                                 if ($t_list->load((int) $vm_value)) {
                                     $vn_list_id = $t_list->getPrimaryKey();
                                 }
                             }
                             if ($vn_list_id) {
                                 $pm_value[$vn_i] = $vn_list_id;
                             }
                         } else {
                             if ($va_setting_info['showSortableBundlesFor']) {
                             }
                         }
                     }
                 }
             }
         }
     }
     $va_settings = $this->getSettings();
     if ($va_setting_info['formatType'] == FT_NUMBER) {
         $pm_value = (double) $pm_value;
     }
     $va_settings[$ps_setting] = $pm_value;
     $this->o_instance->set($this->ops_settings_field, $va_settings);
     return true;
 }
/**
 * 
 *
 * @return string 
 */
function caLoadULAN($ps_path_to_ulan_data = null, $ps_path_to_ulan_config = null, $pa_options = null)
{
    require_once __CA_LIB_DIR__ . '/core/Db.php';
    require_once __CA_LIB_DIR__ . '/core/Configuration.php';
    require_once __CA_LIB_DIR__ . '/ca/Utils/DataMigrationUtils.php';
    require_once __CA_MODELS_DIR__ . '/ca_locales.php';
    require_once __CA_MODELS_DIR__ . '/ca_entities.php';
    require_once __CA_MODELS_DIR__ . '/ca_entities_x_entities.php';
    require_once __CA_MODELS_DIR__ . '/ca_lists.php';
    require_once __CA_MODELS_DIR__ . '/ca_list_items.php';
    require_once __CA_MODELS_DIR__ . '/ca_list_items_x_list_items.php';
    require_once __CA_MODELS_DIR__ . '/ca_relationship_types.php';
    $t = new Timer();
    $o_log = new KLogger(__CA_APP_DIR__ . '/log', KLogger::INFO);
    $va_parent_child_links = array();
    $va_item_item_links = array();
    $va_ulan_id_to_item_id = array();
    $o_log->logInfo("Starting import of Getty ULAN");
    define('__CA_DONT_DO_SEARCH_INDEXING__', true);
    $_ = new Zend_Translate('gettext', __CA_APP_DIR__ . '/locale/en_US/messages.mo', 'en_US');
    $t_locale = new ca_locales();
    $pn_en_locale_id = $t_locale->loadLocaleByCode('en_US');
    if (!($o_config = Configuration::load($ps_path_to_ulan_config))) {
        $o_log->logError("Could not load ULAN import configuration file");
        die("ERROR: Could not load ULAN import configuration\n");
    }
    $vs_ulan_import_mode = $o_config->get('ulan_import_target');
    $t_list = null;
    if ($vs_ulan_import_mode == 'ca_entities') {
        $va_ulan_types = $o_config->getAssoc('ulan_entity_types');
        $va_mapping = $o_config->getAssoc('ulan_entity_mapping');
    } elseif ($vs_ulan_import_mode == 'ca_list_items') {
        $va_ulan_types = $o_config->getAssoc('ulan_list_item_types');
        if (!($vs_ulan_list_code = $o_config->get('ulan_import_list'))) {
            $vs_ulan_list_code = 'ULAN';
        }
        // create vocabulary list record (if it doesn't exist already)
        $t_list = new ca_lists();
        if (!$t_list->load(array('list_code' => $vs_ulan_list_code))) {
            $t_list->setMode(ACCESS_WRITE);
            $t_list->set('list_code', $vs_ulan_list_code);
            $t_list->set('is_system_list', 0);
            $t_list->set('is_hierarchical', 1);
            $t_list->set('use_as_vocabulary', 1);
            $t_list->insert();
            if ($t_list->numErrors()) {
                $o_log->logError("Could not create list record for ULAN: " . join('; ', $t_list->getErrors()));
                die("ERROR: couldn't create ca_list row for ULAN: " . join('; ', $t_list->getErrors()) . "\n");
            }
            $t_list->addLabel(array('name' => 'Union List of Artist Names'), $pn_en_locale_id, null, true);
        }
        $vn_list_id = $t_list->getPrimaryKey();
        $va_mapping = $o_config->getAssoc('ulan_list_item_mapping');
    } else {
        $o_log->logError("Invalid ULAN import mode {$vs_ulan_import_mode}");
        die("ERROR: invalid ULAN import mode {$vs_ulan_import_mode}\n");
    }
    $vn_last_message_length = 0;
    $vn_term_count = 0;
    $va_subject = array();
    foreach (array('ULAN1.xml', 'ULAN2.xml', 'ULAN3.xml') as $vs_file) {
        if (!$ps_path_to_ulan_data) {
            $ps_path_to_ulan_data = ".";
        }
        if (!file_exists($ps_path_to_ulan_data . "/{$vs_file}")) {
            $o_log->logError("Could not find ULAN data file {$vs_file}");
            print "[ERROR] cannot find ULAN data.\n";
            continue;
        }
        $o_log->logInfo("Processing ULAN file {$vs_file}");
        print "[Notice] Processing ULAN file {$vs_file}\n";
        // load
        $o_xml = new XMLReader();
        $o_xml->open($ps_path_to_ulan_data . '/' . $vs_file);
        while ($o_xml->read()) {
            switch ($o_xml->name) {
                # ---------------------------
                case 'Subject':
                    if ($o_xml->nodeType == XMLReader::END_ELEMENT) {
                        if (in_array($va_subject['subject_id'], array('500000000', '500000001'))) {
                            break;
                        }
                        // skip top-level root
                        $vs_preferred_term = $va_subject['preferred_term'];
                        $pb_is_enabled = false;
                        switch ($va_subject['record_type']) {
                            case 'Person':
                            default:
                                $vn_type_id = $va_ulan_types['Person'];
                                $pb_is_enabled = true;
                                break;
                            case 'Corporate Body':
                                $vn_type_id = $va_ulan_types['Corporate Body'];
                                $pb_is_enabled = true;
                                break;
                        }
                        print str_repeat(chr(8), $vn_last_message_length);
                        $vs_message = "\tIMPORTING #" . ($vn_term_count + 1) . " [" . $va_subject['subject_id'] . "] " . $vs_preferred_term;
                        if (($vn_l = 100 - strlen($vs_message)) < 1) {
                            $vn_l = 1;
                        }
                        $vs_message .= str_repeat(' ', $vn_l);
                        $vn_last_message_length = strlen($vs_message);
                        print $vs_message;
                        if ($vs_ulan_import_mode == 'ca_entities') {
                            $va_np_labels = array();
                            if (is_array($va_subject['non_preferred_terms'])) {
                                for ($vn_i = 0; $vn_i < sizeof($va_subject['non_preferred_terms']); $vn_i++) {
                                    $va_np_labels[] = DataMigrationUtils::splitEntityName(trim(htmlentities($va_subject['non_preferred_terms'][$vn_i])));
                                }
                            }
                            $t_item = DataMigrationUtils::getEntityID(DataMigrationUtils::splitEntityName(trim(htmlentities($vs_preferred_term, ENT_NOQUOTES))), $vn_type_id, $pn_en_locale_id, array('idno' => $va_subject['subject_id']), array('nonPreferredLabels' => $va_np_labels, 'returnInstance' => true));
                            if (!$t_item) {
                                $o_log->logError("Failed to create entity for ULAN artist {$vs_preferred_term}");
                                break;
                            }
                            $t_item->setMode(ACCESS_WRITE);
                            $va_ulan_id_to_item_id[$va_subject['subject_id']] = $t_item->getPrimaryKey();
                        } else {
                            if ($t_item = $t_list->addItem($va_subject['subject_id'], $pb_is_enabled, false, null, $vn_type_id, $va_subject['subject_id'], '', 4, 1)) {
                                $va_ulan_id_to_item_id[$va_subject['subject_id']] = $t_item->getPrimaryKey();
                                if ($va_subject['preferred_parent_subject_id'] != 500000000) {
                                    $va_parent_child_links[$va_subject['subject_id']] = $va_subject['preferred_parent_subject_id'];
                                }
                                // add preferred labels
                                if (!$t_item->addLabel(array('name_singular' => trim(htmlentities($vs_preferred_term, ENT_NOQUOTES)), 'name_plural' => trim(htmlentities($vs_preferred_term, ENT_NOQUOTES)), 'description' => $va_subject['description']), $pn_en_locale_id, null, true)) {
                                    $o_log->logError("Could not add preferred label to ULAN term [" . $va_subject['subject_id'] . "] " . $vs_preferred_term . ": " . join("; ", $t_item->getErrors()));
                                }
                                // add alternate labels
                                if (is_array($va_subject['non_preferred_terms'])) {
                                    for ($vn_i = 0; $vn_i < sizeof($va_subject['non_preferred_terms']); $vn_i++) {
                                        $vs_np_label = $va_subject['non_preferred_terms'][$vn_i];
                                        $vs_np_term_type = $va_subject['non_preferred_term_types'][$vn_i];
                                        switch ($vs_np_term_type) {
                                            case 'Used For Term':
                                                $vn_np_term_type_id = $vn_list_item_label_type_uf;
                                                break;
                                            case 'Alternate Descriptor':
                                                $vn_np_term_type_id = $vn_list_item_label_type_alt;
                                                break;
                                            default:
                                                $vn_np_term_type_id = null;
                                                break;
                                        }
                                        if (!$t_item->addLabel(array('name_singular' => trim(htmlentities($vs_np_label, ENT_NOQUOTES)), 'name_plural' => trim(htmlentities($vs_np_label, ENT_NOQUOTES)), 'description' => ''), $pn_en_locale_id, $vn_np_term_type_id, false)) {
                                            $o_log->logError("Could not add non-preferred label to ULAN term [" . $va_subject['subject_id'] . "] " . $vs_np_label);
                                        }
                                    }
                                }
                            } else {
                                $o_log->logError("Could not import ULAN term [" . $va_subject['subject_id'] . "] " . $vs_preferred_term . ": " . join("; ", $t_list->getErrors()));
                                break;
                            }
                        }
                        // Map content fields
                        foreach ($va_mapping as $vs_dest => $vs_source) {
                            $va_values = array();
                            switch ($vs_source) {
                                case 'biography':
                                    if (!is_array($va_subject['biographies'])) {
                                        break;
                                    }
                                    foreach ($va_subject['biographies'] as $va_bio) {
                                        $va_values[] = $va_bio['text'];
                                    }
                                    break;
                                case 'biography_dates':
                                    if (!is_array($va_subject['biographies'])) {
                                        break;
                                    }
                                    foreach ($va_subject['biographies'] as $va_bio) {
                                        if ($va_bio['birth_date'] == 1000 || $va_bio['birth_date'] < -5000) {
                                            if ($va_bio['death_date'] >= 2050) {
                                                break 2;
                                            } else {
                                                $va_values[] = "before " . $va_bio['death_date'];
                                            }
                                        } elseif ($va_bio['death_date'] >= 2050) {
                                            $va_values[] = "after " . $va_bio['birth_date'];
                                        } else {
                                            $va_values[] = $va_bio['birth_date'] . " - " . $va_bio['death_date'];
                                        }
                                    }
                                    break;
                                case 'sex':
                                    if (!is_array($va_subject['biographies'])) {
                                        break;
                                    }
                                    foreach ($va_subject['biographies'] as $va_bio) {
                                        $va_values[] = $va_bio['sex'];
                                    }
                                    break;
                                case 'nationality_name':
                                    if (!is_array($va_subject['nationalities'])) {
                                        break;
                                    }
                                    foreach ($va_subject['nationalities'] as $va_nationality) {
                                        $va_values[] = $va_nationality['name'];
                                    }
                                    break;
                                case 'nationality_code':
                                    if (!is_array($va_subject['nationalities'])) {
                                        break;
                                    }
                                    foreach ($va_subject['nationalities'] as $va_nationality) {
                                        $va_values[] = $va_nationality['code'];
                                    }
                                    break;
                                case 'role_name':
                                    if (!is_array($va_subject['roles'])) {
                                        break;
                                    }
                                    foreach ($va_subject['roles'] as $va_role) {
                                        $va_values[] = $va_role['name'];
                                    }
                                    break;
                                case 'role_code':
                                    if (!is_array($va_subject['roles'])) {
                                        break;
                                    }
                                    foreach ($va_subject['roles'] as $va_role) {
                                        $va_values[] = $va_role['code'];
                                    }
                                    break;
                            }
                            if (sizeof($va_values)) {
                                $va_dest = explode('.', $vs_dest);
                                $vs_fld = array_pop($va_dest);
                                if ($t_item->hasField($vs_fld)) {
                                    $t_item->set($vs_fld, join("\n", $va_values));
                                } else {
                                    foreach ($va_values as $vs_value) {
                                        $t_item->addAttribute(array('locale_id' => $pn_en_locale_id, $vs_fld => $vs_value), $vs_fld);
                                    }
                                }
                                $t_item->update(array('dontCheckCircularReferences' => true, 'dontSetHierarchicalIndexing' => true));
                                if ($t_item->numErrors()) {
                                    $o_log->logError("Could not update ULAN list item with content values: " . join("; ", $t_item->getErrors()));
                                }
                            }
                        }
                        // record item-item relations
                        if (is_array($va_subject['related_subjects'])) {
                            foreach ($va_subject['related_subjects'] as $vs_rel_subject_id) {
                                $va_item_item_links[$va_subject['subject_id']] = $vs_rel_subject_id;
                            }
                        }
                        $vn_term_count++;
                    } else {
                        $va_subject = array('subject_id' => $o_xml->getAttribute('Subject_ID'));
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'Biographies':
                    while ($o_xml->read()) {
                        switch ($o_xml->name) {
                            case 'Preferred_Biography':
                                $va_bio = array();
                                while ($o_xml->read()) {
                                    switch ($o_xml->name) {
                                        case 'Biography_Text':
                                            switch ($o_xml->nodeType) {
                                                case XMLReader::ELEMENT:
                                                    $o_xml->read();
                                                    $va_bio['text'] = $o_xml->value;
                                                    break;
                                            }
                                            break;
                                        case 'Birth_Date':
                                            switch ($o_xml->nodeType) {
                                                case XMLReader::ELEMENT:
                                                    $o_xml->read();
                                                    $va_bio['birth_date'] = $o_xml->value;
                                                    if ($va_bio['birth_date'] < 0) {
                                                        $va_bio['birth_date'] = abs($va_bio['birth_date']) . " BCE";
                                                    }
                                                    break;
                                            }
                                            break;
                                        case 'Death_Date':
                                            switch ($o_xml->nodeType) {
                                                case XMLReader::ELEMENT:
                                                    $o_xml->read();
                                                    $va_bio['death_date'] = $o_xml->value;
                                                    if ($va_bio['death_date'] < 0) {
                                                        $va_bio['death_date'] = abs($va_bio['death_date']) . " BCE";
                                                    }
                                                    break;
                                            }
                                            break;
                                        case 'Sex':
                                            switch ($o_xml->nodeType) {
                                                case XMLReader::ELEMENT:
                                                    $o_xml->read();
                                                    $va_bio['sex'] = $o_xml->value;
                                                    break;
                                            }
                                            break;
                                        case 'Preferred_Biography':
                                            break 2;
                                    }
                                }
                                $va_subject['biographies'][] = $va_bio;
                                break;
                            case 'Biographies':
                                break 2;
                        }
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'Nationalities':
                    while ($o_xml->read()) {
                        switch ($o_xml->name) {
                            case 'Preferred_Nationality':
                                $va_nationality = array();
                                while ($o_xml->read()) {
                                    switch ($o_xml->name) {
                                        case 'Nationality_Code':
                                            switch ($o_xml->nodeType) {
                                                case XMLReader::ELEMENT:
                                                    $o_xml->read();
                                                    $va_nationality['code'] = $o_xml->value;
                                                    $va_nationality['name'] = array_pop(explode('/', $o_xml->value));
                                                    break;
                                            }
                                            break;
                                        case 'Preferred_Nationality':
                                            break 2;
                                    }
                                }
                                $va_subject['nationalities'][] = $va_nationality;
                                break;
                            case 'Nationalities':
                                break 2;
                        }
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'Roles':
                    while ($o_xml->read()) {
                        switch ($o_xml->name) {
                            case 'Preferred_Role':
                                $va_role = array();
                                while ($o_xml->read()) {
                                    switch ($o_xml->name) {
                                        case 'Role_ID':
                                            switch ($o_xml->nodeType) {
                                                case XMLReader::ELEMENT:
                                                    $o_xml->read();
                                                    $va_role['code'] = $o_xml->value;
                                                    $va_role['name'] = array_pop(explode('/', $o_xml->value));
                                                    break;
                                            }
                                            break;
                                        case 'Preferred_Role':
                                            break 2;
                                    }
                                }
                                $va_subject['roles'][] = $va_role;
                                break;
                            case 'Roles':
                                break 2;
                        }
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'Record_Type':
                    switch ($o_xml->nodeType) {
                        case XMLReader::ELEMENT:
                            $o_xml->read();
                            $va_subject['record_type'] = $o_xml->value;
                            break;
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'Hierarchy':
                    switch ($o_xml->nodeType) {
                        case XMLReader::ELEMENT:
                            $o_xml->read();
                            $va_subject['hierarchy'] = $o_xml->value;
                            break;
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'Parent_Relationships':
                    $vn_parent_id = $vs_historic_flag = null;
                    while ($o_xml->read()) {
                        switch ($o_xml->name) {
                            case 'Preferred_Parent':
                                while ($o_xml->read()) {
                                    switch ($o_xml->name) {
                                        case 'Parent_Subject_ID':
                                            switch ($o_xml->nodeType) {
                                                case XMLReader::ELEMENT:
                                                    $o_xml->read();
                                                    $vn_parent_id = $o_xml->value;
                                                    break;
                                            }
                                            break;
                                        case 'Historic_Flag':
                                            switch ($o_xml->nodeType) {
                                                case XMLReader::ELEMENT:
                                                    $o_xml->read();
                                                    $vs_historic_flag = $o_xml->value;
                                                    break;
                                            }
                                            break;
                                        case 'Preferred_Parent':
                                            $va_subject['preferred_parent_subject_id'] = $vn_parent_id;
                                            break 2;
                                    }
                                }
                                break;
                            case 'Parent_Relationships':
                                break 2;
                        }
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'Preferred_Term':
                    while ($o_xml->read()) {
                        switch ($o_xml->name) {
                            case 'Term_Type':
                                switch ($o_xml->nodeType) {
                                    case XMLReader::ELEMENT:
                                        $o_xml->read();
                                        $va_subject['preferred_term_type'] = $o_xml->value;
                                        break;
                                }
                                break;
                            case 'Term_Text':
                                switch ($o_xml->nodeType) {
                                    case XMLReader::ELEMENT:
                                        $o_xml->read();
                                        $va_subject['preferred_term'] = $o_xml->value;
                                        break;
                                }
                                break;
                            case 'Term_ID':
                                switch ($o_xml->nodeType) {
                                    case XMLReader::ELEMENT:
                                        $o_xml->read();
                                        $va_subject['preferred_term_id'] = $o_xml->value;
                                        break;
                                }
                                break;
                                break;
                            case 'Preferred_Term':
                                break 2;
                        }
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'Non-Preferred_Term':
                    while ($o_xml->read()) {
                        switch ($o_xml->name) {
                            case 'Term_Type':
                                switch ($o_xml->nodeType) {
                                    case XMLReader::ELEMENT:
                                        $o_xml->read();
                                        $va_subject['non_preferred_term_types'][] = $o_xml->value;
                                        break;
                                }
                                break;
                            case 'Term_Text':
                                switch ($o_xml->nodeType) {
                                    case XMLReader::ELEMENT:
                                        $o_xml->read();
                                        $va_subject['non_preferred_terms'][] = $o_xml->value;
                                        break;
                                }
                                break;
                            case 'Term_ID':
                                switch ($o_xml->nodeType) {
                                    case XMLReader::ELEMENT:
                                        $o_xml->read();
                                        $va_subject['non_preferred_term_ids'][] = $o_xml->value;
                                        break;
                                }
                                break;
                            case 'Non-Preferred_Term':
                                break 2;
                        }
                    }
                    break;
                    # ---------------------------
                # ---------------------------
                case 'VP_Subject_ID':
                    switch ($o_xml->nodeType) {
                        case XMLReader::ELEMENT:
                            $o_xml->read();
                            $va_subject['related_subjects'][] = $o_xml->value;
                            break;
                    }
                    break;
                    # ---------------------------
            }
        }
        $o_xml->close();
    }
    $o_log->logInfo("Begin linking ULAN terms in hierarchy");
    print "\n\nLINKING TERMS IN HIERARCHY...\n";
    $vn_last_message_length = 0;
    $t_list = new ca_lists();
    $t_item = new ca_list_items();
    $t_item->setMode(ACCESS_WRITE);
    $vn_list_root_id = $t_list->getRootListItemID($vn_list_id);
    foreach ($va_parent_child_links as $vs_child_id => $vs_parent_id) {
        print str_repeat(chr(8), $vn_last_message_length);
        $vs_message = "\tLINKING {$vs_child_id} to parent {$vs_parent_id}";
        if (($vn_l = 100 - strlen($vs_message)) < 1) {
            $vn_l = 1;
        }
        $vs_message .= str_repeat(' ', $vn_l);
        $vn_last_message_length = strlen($vs_message);
        print $vs_message;
        if (in_array($vs_parent_id, array('500000000', '500000001'))) {
            if (!$t_item->load($vn_child_item_id)) {
                $o_log->logError("Could not load item for {$vs_child_id} (was translated to item_id={$vn_child_item_id})");
                continue;
            }
            $t_item->set('parent_id', $vn_list_root_id);
            $t_item->update(array('dontCheckCircularReferences' => true, 'dontSetHierarchicalIndexing' => true));
            if ($t_item->numErrors()) {
                $o_log->logError("Could not set parent_id for {$vs_child_id} to root): " . join('; ', $t_item->getErrors()));
                continue;
            }
            $va_ulan_id_to_item_id[$vs_parent_id] = $vn_list_root_id;
        }
        if (!($vn_child_item_id = $va_ulan_id_to_item_id[$vs_child_id])) {
            $o_log->logError("No list item id for child_id {$vs_child_id} (were there previous errors?)");
            continue;
        }
        if (!($vn_parent_item_id = $va_ulan_id_to_item_id[$vs_parent_id])) {
            $o_log->logError("No list item id for parent_id {$vs_parent_id} (were there previous errors?)");
            continue;
        }
        if (!$t_item->load($vn_child_item_id)) {
            $o_log->logError("Could not load item for {$vs_child_id} (was translated to item_id={$vn_child_item_id})");
            continue;
        }
        $t_item->set('parent_id', $vn_parent_item_id);
        $t_item->update(array('dontCheckCircularReferences' => true, 'dontSetHierarchicalIndexing' => true));
        if ($t_item->numErrors()) {
            $o_log->logError("Could not set parent_id for {$vs_child_id} (was translated to item_id={$vn_child_item_id}): " . join('; ', $t_item->getErrors()));
        }
    }
    if ($vn_list_item_relation_type_id_related > 0) {
        $o_log->logInfo("Begin adding ULAN related term links");
        $vn_last_message_length = 0;
        $t_item = new ca_list_items();
        $t_link = new ca_list_items_x_list_items();
        $t_link->setMode(ACCESS_WRITE);
        foreach ($va_item_item_links as $vs_left_id => $vs_right_id) {
            print str_repeat(chr(8), $vn_last_message_length);
            $vs_message = "\tLINKING {$vs_left_id} to {$vs_right_id}";
            if (($vn_l = 100 - strlen($vs_message)) < 1) {
                $vn_l = 1;
            }
            $vs_message .= str_repeat(' ', $vn_l);
            $vn_last_message_length = strlen($vs_message);
            print $vs_message;
            if (!($vn_left_item_id = $va_ulan_id_to_item_id[$vs_left_id])) {
                $o_log->logError("No list item id for left_id {$vs_left_id} (were there previous errors?)");
                continue;
            }
            if (!($vn_right_item_id = $va_ulan_id_to_item_id[$vs_right_id])) {
                $o_log->logError("No list item id for right_id {$vs_right_id} (were there previous errors?)");
                continue;
            }
            $t_link->set('term_left_id', $vn_left_item_id);
            $t_link->set('term_right_id', $vn_right_item_id);
            $t_link->set('type_id', $vn_list_item_relation_type_id_related);
            $t_link->insert();
            if ($t_link->numErrors()) {
                $o_log->logError("Could not set link between {$vs_left_id} (was translated to item_id={$vn_left_item_id}) and {$vs_right_id} (was translated to item_id={$vn_right_item_id}): " . join('; ', $t_link->getErrors()));
            }
        }
    } else {
        $o_log->logWarn("Skipped import of term-term relationships because the ca_list_items_x_list_items 'related' relationship type is not defined for your installation");
    }
    $vn_duration = $t->getTime(1);
    $vs_time = caFormatInterval($vn_duration);
    $o_log->logInfo("Rebuilding hierarchical indices...");
    $t_item->rebuildAllHierarchicalIndexes();
    $o_log->logInfo("ULAN import complete. Took {$vs_time} ({$vn_duration})");
    print "\n\nIMPORT COMPLETE. Took {$vs_time} ({$vn_duration})\n";
}
 private function getElementAsDOM($pn_parent_id)
 {
     $t_element = new ca_metadata_elements();
     $t_list = new ca_lists();
     $qr_elements = $this->opo_db->query("SELECT * FROM ca_metadata_elements WHERE parent_id = ? ORDER BY element_id", $pn_parent_id);
     if (!$qr_elements->numRows()) {
         return null;
     }
     $vo_elements = $this->opo_dom->createElement("elements");
     while ($qr_elements->nextRow()) {
         $vo_element = $this->opo_dom->createElement("metadataElement");
         $vo_element->setAttribute("code", $this->makeIDNO($qr_elements->get("element_code")));
         $vo_element->setAttribute("datatype", ca_metadata_elements::getAttributeNameForTypeCode($qr_elements->get("datatype")));
         if ($qr_elements->get("list_id")) {
             $t_list->load($qr_elements->get("list_id"));
             $vo_element->setAttribute("list", $t_list->get("list_code"));
         }
         $vo_labels = $this->opo_dom->createElement("labels");
         $qr_element_labels = $this->opo_db->query("SELECT * FROM ca_metadata_element_labels WHERE element_id=?", $qr_elements->get("element_id"));
         while ($qr_element_labels->nextRow()) {
             $vo_label = $this->opo_dom->createElement("label");
             $vo_label->setAttribute("locale", $this->opt_locale->localeIDToCode($qr_element_labels->get("locale_id")));
             $vo_label->appendChild($this->opo_dom->createElement("name", caEscapeForXML($qr_element_labels->get("name"))));
             if (strlen(trim($qr_element_labels->get("description"))) > 0) {
                 $vo_label->appendChild($this->opo_dom->createElement("description", caEscapeForXML($qr_element_labels->get("description"))));
             }
             $vo_labels->appendChild($vo_label);
         }
         $vo_element->appendChild($vo_labels);
         $t_element->load($qr_elements->get("element_id"));
         $vo_settings = $this->opo_dom->createElement("settings");
         if (is_array($va_settings = $t_element->getSettings())) {
             foreach ($va_settings as $vs_setting => $va_values) {
                 if (is_null($va_values)) {
                     continue;
                 }
                 if (!is_array($va_values)) {
                     $va_values = array($va_values);
                 }
                 foreach ($va_values as $vs_value) {
                     $vo_setting = $this->opo_dom->createElement("setting", $vs_value);
                     $vo_setting->setAttribute("name", $vs_setting);
                     $vo_settings->appendChild($vo_setting);
                 }
             }
         }
         $vo_element->appendChild($vo_settings);
         $vo_sub_elements = $this->getElementAsDOM($qr_elements->get("element_id"));
         if ($vo_sub_elements) {
             $vo_element->appendChild($vo_sub_elements);
         }
         $vo_elements->appendChild($vo_element);
     }
     return $vo_elements;
 }
 /**
  *  Returns or Creates a list item or list item id matching the parameters and options provided
  * @param string/int $pm_list_code_or_id
  * @param string $ps_item_idno
  * @param string/int $pn_type_id
  * @param int $pn_locale_id
  * @param null/array $pa_values
  * @param array $pa_options An optional array of options. See DataMigrationUtils::_getID() for a list.
  * @return bool|ca_list_items|mixed|null
  *
  * @see DataMigrationUtils::_getID()
  */
 static function getListItemID($pm_list_code_or_id, $ps_item_idno, $pn_type_id, $pn_locale_id, $pa_values = null, $pa_options = null)
 {
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     $pb_output_errors = caGetOption('outputErrors', $pa_options, false);
     $pa_match_on = caGetOption('matchOn', $pa_options, array('label', 'idno'), array('castTo' => "array"));
     $vn_parent_id = caGetOption('parent_id', $pa_values, false);
     $vs_singular_label = isset($pa_values['preferred_labels']['name_singular']) && $pa_values['preferred_labels']['name_singular'] ? $pa_values['preferred_labels']['name_singular'] : '';
     if (!$vs_singular_label) {
         $vs_singular_label = isset($pa_values['name_singular']) && $pa_values['name_singular'] ? $pa_values['name_singular'] : str_replace("_", " ", $ps_item_idno);
     }
     $vs_plural_label = isset($pa_values['preferred_labels']['name_plural']) && $pa_values['preferred_labels']['name_plural'] ? $pa_values['preferred_labels']['name_plural'] : '';
     if (!$vs_plural_label) {
         $vs_plural_label = isset($pa_values['name_plural']) && $pa_values['name_plural'] ? $pa_values['name_plural'] : str_replace("_", " ", $ps_item_idno);
     }
     if (!$vs_singular_label) {
         $vs_singular_label = $vs_plural_label;
     }
     if (!$vs_plural_label) {
         $vs_plural_label = $vs_singular_label;
     }
     if (!$ps_item_idno) {
         $ps_item_idno = $vs_plural_label;
     }
     if (!isset($pa_options['cache'])) {
         $pa_options['cache'] = true;
     }
     // Create cache key
     $vs_cache_key = md5($pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id . '/' . $vs_singular_label . '/' . $vs_plural_label . '/' . json_encode($pa_match_on));
     $o_event = isset($pa_options['importEvent']) && $pa_options['importEvent'] instanceof ca_data_import_events ? $pa_options['importEvent'] : null;
     $ps_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;
     if ($pa_options['cache'] && isset(DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key])) {
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             $t_item = new ca_list_items(DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key]);
             if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
                 $t_item->setTransaction($pa_options['transaction']);
             }
             return $t_item;
         }
         if ($o_event) {
             $o_event->beginItem($ps_event_source, 'ca_list_items', 'U');
             $o_event->endItem(DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key], __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
         }
         if ($o_log) {
             $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using idno", $ps_item_idno, $pm_list_code_or_id));
         }
         return DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key];
     }
     if (!($vn_list_id = ca_lists::getListID($pm_list_code_or_id))) {
         if ($pb_output_errors) {
             print "[Error] " . _t("Could not find list with list code %1", $pm_list_code_or_id) . "\n";
         }
         if ($o_log) {
             $o_log->logError(_t("Could not find list with list code %1", $pm_list_code_or_id));
         }
         return DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key] = null;
     }
     if (!$vn_parent_id && $vn_parent_id !== false) {
         $vn_parent_id = caGetListRootID($pm_list_code_or_id);
     }
     $t_list = new ca_lists();
     $t_item = new ca_list_items();
     if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
         $t_list->setTransaction($pa_options['transaction']);
         $t_item->setTransaction($pa_options['transaction']);
         if ($o_event) {
             $o_event->setTransaction($pa_options['transaction']);
         }
     }
     $vn_item_id = null;
     foreach ($pa_match_on as $vs_match_on) {
         switch (strtolower($vs_match_on)) {
             case 'label':
             case 'labels':
                 if (trim($vs_singular_label) || trim($vs_plural_label)) {
                     $va_criteria = array('preferred_labels' => array('name_singular' => $vs_singular_label), 'list_id' => $vn_list_id);
                     if ($vn_parent_id !== false) {
                         $va_criteria['parent_id'] = $vn_parent_id;
                     }
                     if ($vn_item_id = ca_list_items::find($va_criteria, array('returnAs' => 'firstId', 'purifyWithFallback' => true, 'transaction' => $pa_options['transaction']))) {
                         if ($o_log) {
                             $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using singular label %3", $ps_item_idno, $pm_list_code_or_id, $vs_singular_label));
                         }
                         break 2;
                     } else {
                         $va_criteria['preferred_labels'] = array('name_plural' => $vs_plural_label);
                         if ($vn_item_id = ca_list_items::find($va_criteria, array('returnAs' => 'firstId', 'purifyWithFallback' => true, 'transaction' => $pa_options['transaction']))) {
                             if ($o_log) {
                                 $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using plural label %3", $ps_item_idno, $pm_list_code_or_id, $vs_plural_label));
                             }
                             break 2;
                         }
                     }
                     break;
                 }
             case 'idno':
                 if ($ps_item_idno == '%') {
                     break;
                 }
                 // don't try to match on an unreplaced idno placeholder
                 $va_criteria = array('idno' => $ps_item_idno ? $ps_item_idno : $vs_plural_label, 'list_id' => $vn_list_id);
                 if ($vn_parent_id !== false) {
                     $va_criteria['parent_id'] = $vn_parent_id;
                 }
                 if ($vn_item_id = ca_list_items::find($va_criteria, array('returnAs' => 'firstId', 'purifyWithFallback' => true, 'transaction' => $pa_options['transaction']))) {
                     if ($o_log) {
                         $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using idno with %3", $ps_item_idno, $pm_list_code_or_id, $ps_item_idno));
                     }
                     break 2;
                 }
                 break;
         }
     }
     if ($vn_item_id) {
         DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key] = $vn_item_id;
         if ($o_event) {
             $o_event->beginItem($ps_event_source, 'ca_list_items', 'U');
             $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
         }
         if (($vb_force_update = caGetOption('forceUpdate', $pa_options, false)) || ($vb_return_instance = caGetOption('returnInstance', $pa_options, false))) {
             $vb_has_attr = false;
             if ($vb_force_update) {
                 foreach ($pa_values as $vs_element => $va_values) {
                     if ($t_item->hasElement($vs_element)) {
                         $vb_has_attr = true;
                         break;
                     }
                 }
             }
             if ($vb_return_instance || $vb_force_update && $vb_has_attr) {
                 $t_item = new ca_list_items($vn_item_id);
                 if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
                     $t_item->setTransaction($pa_options['transaction']);
                 }
             }
             $vb_attr_errors = false;
             if ($vb_force_update && $vb_has_attr) {
                 $vb_attr_errors = !DataMigrationUtils::_setAttributes($t_item, $pn_locale_id, $pa_values, $pa_options);
             }
             if ($o_event) {
                 if ($vb_attr_errors) {
                     $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_PARTIAL_SUCCESS__, _t("Errors setting field values: %1", join('; ', $t_item->getErrors())));
                 } else {
                     $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
                 }
             }
             if ($vb_return_instance) {
                 return $t_item;
             }
         }
         return $vn_item_id;
     }
     if (isset($pa_options['dontCreate']) && $pa_options['dontCreate']) {
         return false;
     }
     //
     // Need to create list item
     //
     if (!$t_list->load($vn_list_id)) {
         if ($o_log) {
             $o_log->logError(_t("Could not find list with list id %1", $vn_list_id));
         }
         return null;
     }
     if ($o_event) {
         $o_event->beginItem($ps_event_source, 'ca_list_items', 'I');
     }
     if ($t_item = $t_list->addItem($ps_item_idno, $pa_values['is_enabled'], $pa_values['is_default'], $vn_parent_id, $pn_type_id, $ps_item_idno, '', (int) $pa_values['status'], (int) $pa_values['access'], $pa_values['rank'])) {
         $vb_label_errors = false;
         $t_item->addLabel(array('name_singular' => $vs_singular_label, 'name_plural' => $vs_plural_label), $pn_locale_id, null, true);
         if ($t_item->numErrors()) {
             if ($pb_output_errors) {
                 print "[Error] " . _t("Could not set preferred label for list item %1: %2", "{$vs_singular_label}/{$vs_plural_label}/{$ps_item_idno}", join('; ', $t_item->getErrors())) . "\n";
             }
             if ($o_log) {
                 $o_log->logError(_t("Could not set preferred label for list item %1: %2", "{$vs_singular_label}/{$vs_plural_label}/{$ps_item_idno}", join('; ', $t_item->getErrors())));
             }
             $vb_label_errors = true;
         }
         unset($pa_values['access']);
         unset($pa_values['status']);
         unset($pa_values['idno']);
         unset($pa_values['source_id']);
         $vb_attr_errors = !DataMigrationUtils::_setAttributes($t_item, $pn_locale_id, $pa_values, $pa_options);
         DataMigrationUtils::_setNonPreferredLabels($t_item, $pn_locale_id, $pa_options);
         DataMigrationUtils::_setIdno($t_item, $ps_item_idno, $pa_options);
         $vn_item_id = DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key] = $t_item->getPrimaryKey();
         if ($o_event) {
             if ($vb_attr_errors || $vb_label_errors) {
                 $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_PARTIAL_SUCCESS__, _t("Errors setting field values: %1", join('; ', $t_item->getErrors())));
             } else {
                 $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
             }
         }
         if ($o_log) {
             $o_log->logInfo(_t("Created new list item %1 in list %2", "{$vs_singular_label}/{$vs_plural_label}/{$ps_item_idno}", $pm_list_code_or_id));
         }
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             return $t_item;
         }
         return $vn_item_id;
     } else {
         if ($o_log) {
             $o_log->logError(_t("Could not find add item to list: %1", join("; ", $t_list->getErrors())));
         }
     }
     return null;
 }
Example #10
0
 /**
  * Does bounds checks specified for field $field on value $value.
  * Returns 0 and throws an exception is it fails, returns 1 on success.
  * 
  * @access public
  * @param string $field field name
  * @param string $value value 
  */
 public function verifyFieldValue($field, $value, &$pb_need_reload)
 {
     $pb_need_reload = false;
     $va_attr = $this->FIELDS[$field];
     if (!$va_attr) {
         $this->postError(716, _t("%1 does not exist", $field), "BaseModel->verifyFieldValue()", $this->tableName() . '.' . $field);
         return false;
     }
     $data_type = $this->_getFieldTypeType($field);
     $field_type = $this->getFieldInfo($field, "FIELD_TYPE");
     if (isset($va_attr["FILTER"]) && ($filter = $va_attr["FILTER"])) {
         if (!preg_match($filter, $value)) {
             $this->postError(1102, _t("%1 is invalid", $va_attr["LABEL"]), "BaseModel->verifyFieldValue()", $this->tableName() . '.' . $field);
             return false;
         }
     }
     if ($data_type == 0) {
         # number; check value
         if (isset($va_attr["BOUNDS_VALUE"][0])) {
             $min_value = $va_attr["BOUNDS_VALUE"][0];
         }
         if (isset($va_attr["BOUNDS_VALUE"][1])) {
             $max_value = $va_attr["BOUNDS_VALUE"][1];
         }
         if (!($va_attr["IS_NULL"] && !$value)) {
             if (isset($min_value) && $value < $min_value) {
                 $this->postError(1101, _t("%1 must not be less than %2", $va_attr["LABEL"], $min_value), "BaseModel->verifyFieldValue()", $this->tableName() . '.' . $field);
                 return false;
             }
             if (isset($max_value) && $value > $max_value) {
                 $this->postError(1101, _t("%1 must not be greater than %2", $va_attr["LABEL"], $max_value), "BaseModel->verifyFieldValue()", $this->tableName() . '.' . $field);
                 return false;
             }
         }
     }
     if (!isset($va_attr["IS_NULL"])) {
         $va_attr["IS_NULL"] = 0;
     }
     if (!($va_attr["IS_NULL"] && !$value)) {
         # check length
         if (isset($va_attr["BOUNDS_LENGTH"]) && is_array($va_attr["BOUNDS_LENGTH"])) {
             $min_length = $va_attr["BOUNDS_LENGTH"][0];
             $max_length = $va_attr["BOUNDS_LENGTH"][1];
         }
         if (isset($min_length) && strlen($value) < $min_length) {
             $this->postError(1102, _t("%1 must be at least %2 characters", $va_attr["LABEL"], $min_length), "BaseModel->verifyFieldValue()", $this->tableName() . '.' . $field);
             return false;
         }
         if (isset($max_length) && strlen($value) > $max_length) {
             $this->postError(1102, _t("%1 must not be more than %2 characters long", $va_attr["LABEL"], $max_length), "BaseModel->verifyFieldValue()", $this->tableName() . '.' . $field);
             return false;
         }
         $va_list = isset($va_attr["BOUNDS_CHOICE_LIST"]) ? $va_attr["BOUNDS_CHOICE_LIST"] : null;
         if (isset($va_attr['LIST']) && $va_attr['LIST']) {
             $t_list = new ca_lists();
             if ($t_list->load(array('list_code' => $va_attr['LIST']))) {
                 $va_items = caExtractValuesByUserLocale($t_list->getItemsForList($va_attr['LIST']));
                 $va_list = array();
                 $vs_list_default = null;
                 foreach ($va_items as $vn_item_id => $va_item_info) {
                     if (is_null($vs_list_default) || isset($va_item_info['is_default']) && $va_item_info['is_default']) {
                         $vs_list_default = $va_item_info['item_value'];
                     }
                     $va_list[$va_item_info['name_singular']] = $va_item_info['item_value'];
                 }
                 $va_attr['DEFAULT'] = $vs_list_default;
             }
         }
         if (in_array($data_type, array(FT_NUMBER, FT_TEXT)) && isset($va_list) && is_array($va_list) && count($va_list) > 0) {
             # string; check choice list
             if (isset($va_attr['DEFAULT']) && !strlen($value)) {
                 $value = $va_attr['DEFAULT'];
                 if (strlen($value)) {
                     $this->set($field, $value);
                     $pb_need_reload = true;
                 }
             }
             // force default value if nothing is set
             if (!is_array($value)) {
                 $value = explode(":", $value);
             }
             if (!isset($va_attr['LIST_MULTIPLE_DELIMITER']) || !($vs_list_multiple_delimiter = $va_attr['LIST_MULTIPLE_DELIMITER'])) {
                 $vs_list_multiple_delimiter = ';';
             }
             foreach ($value as $v) {
                 if (sizeof($value) > 1 && !$v) {
                     continue;
                 }
                 if ($va_attr['DISPLAY_TYPE'] == DT_LIST_MULTIPLE) {
                     $va_tmp = explode($vs_list_multiple_delimiter, $v);
                     foreach ($va_tmp as $vs_mult_item) {
                         if (!in_array($vs_mult_item, $va_list)) {
                             $this->postError(1103, _t("'%1' is not valid choice for %2", $v, $va_attr["LABEL"]), "BaseModel->verifyFieldValue()", $this->tableName() . '.' . $field);
                             return false;
                         }
                     }
                 } else {
                     if (!in_array($v, $va_list)) {
                         $this->postError(1103, _t("'%1' is not valid choice for %2", $v, $va_attr["LABEL"]), "BaseModel->verifyFieldValue()", $this->tableName() . '.' . $field);
                         return false;
                     }
                 }
             }
         }
     }
     return true;
 }
Example #11
0
 private function fetchAndImport($pa_item_queue, $po_client, $pa_config, $pa_tables, $ps_code)
 {
     if (!is_array($pa_tables)) {
         $pa_tables = array();
     }
     $t_rel_type = new ca_relationship_types();
     $vs_base_url = $pa_config['baseUrl'];
     $o_dm = Datamodel::load();
     $t_locale = new ca_locales();
     $t_list = new ca_lists();
     $vn_source_id = $t_list->getItemIDFromList('object_sources', $pa_config['code']);
     $pn_rep_type_id = $t_list->getItemIDFromList('object_representation_types', 'front');
     foreach ($pa_item_queue as $vn_i => $va_item) {
         $vs_table = $va_item['table'];
         $va_import_relationships_from = $pa_config['importRelatedFor'][$va_item['table']];
         print "oo";
         print_r($va_import_relationships_from);
         $vn_id = $va_item['id'];
         if (!$vn_id) {
             print "[Notice] SKIP CAUSE NO ID ({$ps_code})\n";
             continue;
         }
         if (isset($this->opa_processed_records[$vs_table . '/' . $vn_id])) {
             continue;
         }
         $vs_idno = trim((string) $va_item['idno']);
         try {
             $o_xml = $po_client->getItem($vs_table, $vn_id)->get();
         } catch (exception $e) {
             print "[ERROR] While trying to get item information: " . $e->getMessage() . "\n";
             continue;
         }
         $o_item = $o_xml->getItem;
         $t_instance = $o_dm->getInstanceByTableName($vs_table, false);
         $t_instance_label = $t_instance->getLabelTableInstance();
         // Look for existing record
         $vb_skip = false;
         $vb_update = false;
         $vs_label_fld = $t_instance->getLabelDisplayField();
         $vs_label = (string) $o_item->preferred_labels->en_US->{$vs_label_fld};
         print "[Notice] Processing [{$vs_table}] {$vs_label} [{$vs_idno}] ({$ps_code})\n";
         $t_instance_label->clear();
         if ($vs_idno && ($vs_table == 'ca_objects' && $t_instance->load(array('idno' => $vs_idno)) || $vs_table != 'ca_objects' && $t_instance->load(array('idno' => $vs_idno)))) {
             if ($t_instance->hasField('deleted') && $t_instance->get('deleted') == 1) {
                 $t_instance->set('deleted', 0);
             }
             //print "[Notice] Update [{$vs_idno}] for {$vs_table} 'cause it already exists ({$ps_code})\n";
             if (!$t_instance->getPrimaryKey()) {
                 $vb_skip = true;
                 print "[ERROR] Could not load instance for [{$vs_idno}]\n";
             }
             $vb_update = true;
             $t_instance->setMode(ACCESS_WRITE);
             // Clear labels
             $t_instance->removeAllLabels();
             if ($t_instance->numErrors()) {
                 print "[ERROR] Could not remove labels for updating: " . join("; ", $t_instance->getErrors()) . "\n";
             }
             // Clear attributes
             $t_instance->removeAttributes(null, array('dontCheckMinMax' => true));
             if ($t_instance->numErrors()) {
                 print "[ERROR] Could not remove attributes for updating: " . join("; ", $t_instance->getErrors()) . "\n";
             }
             // Clear relationships
             if (is_array($va_import_relationships_from)) {
                 foreach ($va_import_relationships_from as $vs_rel_table => $va_table_info) {
                     $t_instance->removeRelationships($vs_rel_table);
                     if ($t_instance->numErrors()) {
                         print "[ERROR] Could not remove {$vs_rel_table} relationships for updating: " . join("; ", $t_instance->getErrors()) . "\n";
                     }
                 }
             }
             if ($t_instance->tableName() == 'ca_objects') {
                 //$t_instance->set('source_id', $vn_source_id);
             }
             $t_instance->update();
             if ($t_instance->numErrors()) {
                 print "[ERROR] Could not clear record for updating: " . join("; ", $t_instance->getErrors()) . "\n";
             }
         }
         // create new one
         if (!$vb_update) {
             $t_instance->clear();
             if ($t_instance->tableName() == 'ca_objects') {
                 //$t_instance->set('source_id', $vn_source_id);
             }
         }
         $t_instance->setMode(ACCESS_WRITE);
         // add intrinsics
         switch ($vs_table) {
             case 'ca_collections':
                 $va_intrinsics = array('status', 'access', 'idno');
                 break;
             case 'ca_occurrences':
                 $va_intrinsics = array('status', 'access', 'idno');
                 break;
             case 'ca_objects':
                 $va_intrinsics = array('status', 'access', 'idno');
                 break;
             case 'ca_entities':
                 $va_intrinsics = array('status', 'access', 'lifespan', 'source_id', 'idno');
                 break;
             case 'ca_object_lots':
                 $va_intrinsics = array('status', 'access', 'idno_stub');
                 break;
             default:
                 $va_intrinsics = array('status', 'access', 'idno');
                 break;
         }
         // TODO: Need to properly handle foreign-key intrinsics when the item they point to doesn't exist
         // eg. source_id fields, various ca_objects and ca_object_lots intrinsics, etc.
         if ($vs_table == 'ca_list_items') {
             // does list exist?
             $vs_list_code = (string) $o_item->{'list_code'};
             $t_list = new ca_lists();
             if (!$t_list->load(array('list_code' => $vs_list_code))) {
                 // create list
                 $t_list->setMode(ACCESS_WRITE);
                 // TODO: should we bother to replicate the is_hierarchical, use_as_vocabulary and default_sort settings via a service?
                 // For now just set reasonable values
                 $t_list->set('list_code', $vs_list_code);
                 $t_list->set('is_hierarchical', 1);
                 $t_list->set('use_as_vocabulary', 1);
                 $t_list->set('default_sort', 0);
                 $t_list->insert();
                 if ($t_list->numErrors()) {
                     print "[ERROR] Could not insert new list '{$vs_list_code}': " . join('; ', $t_list->getErrors()) . "\n";
                 } else {
                     $t_list->addLabel(array('name' => $vs_list_code), $pn_locale_id, null, true);
                     if ($t_list->numErrors()) {
                         print "[ERROR] Could not add label to new list '{$vs_list_code}': " . join('; ', $t_list->getErrors()) . "\n";
                     }
                 }
             }
             $t_instance->set('list_id', $t_list->getPrimaryKey());
         }
         foreach ($va_intrinsics as $vs_f) {
             $t_instance->set($vs_f, $o_item->{$vs_f});
         }
         if (!$vb_update) {
             $vn_type_id = $t_instance->getTypeIDForCode((string) $o_item->type_id);
             if (!$vn_type_id) {
                 print "NO TYPE FOR {$vs_table}/" . $o_item->type_id . "\n";
             }
             $t_instance->set('type_id', $vn_type_id);
             if ($t_instance->tableName() == 'ca_objects') {
                 //$t_instance->set('source_id', $vn_source_id);
             }
             // TODO: add hook onBeforeInsert()
             $t_instance->insert();
             // TODO: add hook onInsert()
             if ($t_instance->numErrors()) {
                 print "[ERROR] Could not insert record: " . join('; ', $t_instance->getErrors()) . "\n";
             }
         }
         // add attributes
         // TODO: make this configurable
         $va_codes = $t_instance->getApplicableElementCodes();
         // $va_codes = array(
         // 				'description',
         // 				'georeference', 'geonames', 'internal_notes',
         // 				'oclc_number', 'file_name',
         // 				'digitized_by', 'digitized_date', 'call_number',
         // 				'other_call_number', 'collection_title', 'collection_number',
         // 				'box_number', 'folder_number', 'volume_number', 'page_number', 'shelf',
         // 				'pulled_digitization', 'pulled_name', 'pulled_date', 'returned_digitization',
         // 				'returned_name', 'returned_date', 'needs_redigitization', 'donor', 'copyright_holder',
         // 				'reproduction_restrictions', 'administrative_notes', 'date_view', 'date_item',
         // 				'view_format', 'item_format', 'dimensions', 'map_scale', 'image_description', 'address',
         // 				'lcsh_terms',  'inscription'
         //
         // 			);
         foreach ($va_codes as $vs_code) {
             $t_element = $t_instance->_getElementInstance($vs_code);
             switch ($t_element->get('datatype')) {
                 case 0:
                     // container
                     $va_elements = $t_element->getElementsInSet();
                     $o_attr = $o_item->{'ca_attribute_' . $vs_code};
                     foreach ($o_attr as $va_tag => $o_tags) {
                         foreach ($o_tags as $vs_locale => $o_values) {
                             if (!($vn_locale_id = $t_locale->localeCodeToID($vs_locale))) {
                                 $vn_locale_id = null;
                             }
                             $va_container_data = array('locale_id' => $vn_locale_id);
                             foreach ($o_values as $o_value) {
                                 foreach ($va_elements as $vn_i => $va_element_info) {
                                     if ($va_element_info['datatype'] == 0) {
                                         continue;
                                     }
                                     if ($vs_value = trim((string) $o_value->{$va_element_info['element_code']})) {
                                         switch ($va_element_info['datatype']) {
                                             case 3:
                                                 //list
                                                 $va_tmp = explode(":", $vs_value);
                                                 //<item_id>:<item_idno>
                                                 //print "CONTAINER LIST CODE=".$va_tmp[1]."/$vs_value/".$va_element_info['list_id']."\n";
                                                 $va_container_data[$va_element_info['element_code']] = $t_list->getItemIDFromList($va_element_info['list_id'], $va_tmp[1]);
                                                 break;
                                             default:
                                                 $va_container_data[$va_element_info['element_code']] = $vs_value;
                                                 break;
                                         }
                                     }
                                 }
                                 $t_instance->replaceAttribute($va_container_data, $vs_code);
                             }
                         }
                     }
                     break;
                 case 3:
                     // list
                     $o_attr = $o_item->{'ca_attribute_' . $vs_code};
                     foreach ($o_attr as $va_tag => $o_tags) {
                         foreach ($o_tags as $vs_locale => $o_values) {
                             if (!($vn_locale_id = $t_locale->localeCodeToID($vs_locale))) {
                                 $vn_locale_id = null;
                             }
                             foreach ($o_values as $o_value) {
                                 if ($vs_value = trim((string) $o_value->{$vs_code})) {
                                     $va_tmp = explode(":", $vs_value);
                                     //<item_id>:<item_idno>
                                     // TODO: create lists and list items if they don't already exist
                                     if ($vn_item_id = $t_list->getItemIDFromList($t_element->get('list_id'), $va_tmp[1])) {
                                         $t_instance->replaceAttribute(array($vs_code => $vn_item_id, 'locale_id' => $vn_locale_id), $vs_code);
                                     }
                                 }
                             }
                         }
                     }
                     break;
                 case 15:
                     // File
                 // File
                 case 16:
                     // Media
                     $t_instance->update();
                     if ($t_instance->numErrors()) {
                         print "[ERROR] Could not update record before media: " . join('; ', $t_instance->getErrors()) . "\n";
                     }
                     // TODO: detect if media has changes and only pull if it has
                     $o_attr = $o_item->{'ca_attribute_' . $vs_code};
                     foreach ($o_attr as $va_tag => $o_tags) {
                         foreach ($o_tags as $vs_locale => $o_values) {
                             if (!($vn_locale_id = $t_locale->localeCodeToID($vs_locale))) {
                                 $vn_locale_id = null;
                             }
                             foreach ($o_values as $o_value) {
                                 if ($vs_value = trim((string) $o_value->{$vs_code})) {
                                     $t_instance->replaceAttribute(array($vs_code => $vs_value, 'locale_id' => $vn_locale_id), $vs_code);
                                 }
                             }
                         }
                     }
                     $t_instance->update();
                     if ($t_instance->numErrors()) {
                         print "[ERROR] Could not update record after media: " . join('; ', $t_instance->getErrors()) . "\n";
                     }
                     break;
                 default:
                     $o_attr = $o_item->{'ca_attribute_' . $vs_code};
                     foreach ($o_attr as $va_tag => $o_tags) {
                         foreach ($o_tags as $vs_locale => $o_values) {
                             if (!($vn_locale_id = $t_locale->localeCodeToID($vs_locale))) {
                                 $vn_locale_id = null;
                             }
                             foreach ($o_values as $o_value) {
                                 if ($vs_value = trim((string) $o_value->{$vs_code})) {
                                     $t_instance->replaceAttribute(array($vs_code => $vs_value, 'locale_id' => $vn_locale_id), $vs_code);
                                 }
                             }
                         }
                     }
                     break;
             }
         }
         $t_instance->update();
         if ($t_instance->numErrors()) {
             print "[ERROR] Could not update [1] record: " . join('; ', $t_instance->getErrors()) . "\n";
         }
         // TODO: add hook onBeforeUpdate()
         $t_instance->update();
         // TODO: add hook onUpdate()
         if ($t_instance->numErrors()) {
             print "[ERROR] Could not update [2] record: " . join('; ', $t_instance->getErrors()) . "\n";
         }
         // get label fields
         $va_label_data = array();
         foreach ($t_instance->getLabelUIFields() as $vs_field) {
             if (!($va_label_data[$vs_field] = $o_item->preferred_labels->en_US->{$vs_field})) {
                 $va_label_data[$vs_field] = $o_item->preferred_labels->en_US->{$vs_field};
             }
         }
         // TODO: add hook onBeforeAddLabel()
         $t_instance->addLabel($va_label_data, 1, null, true);
         // TODO: add hook onAddLabel()
         if ($t_instance->numErrors()) {
             print "ERROR adding label: " . join('; ', $t_instance->getErrors()) . "\n";
         }
         $this->opa_processed_records[$va_item['table'] . '/' . (int) $va_item['id']] = $t_instance->getPrimaryKey();
         if ($vb_skip) {
             continue;
         }
         if (!is_array($va_import_relationships_from)) {
             continue;
         }
         $pa_tables[$va_item['table']] = true;
         // Are there relationships?
         $pb_imported_self_relations = false;
         print_r($va_import_relationships_from);
         foreach ($va_import_relationships_from as $vs_rel_table => $va_table_info) {
             $vb_is_self_relation = $vs_rel_table == $t_instance->tableName() && !$pb_imported_self_relations ? true : false;
             if (!$pa_tables[$vs_rel_table] || $vb_is_self_relation) {
                 // load related records recursively
                 if ($vs_rel_table == $t_instance->tableName()) {
                     $pb_imported_self_relations = true;
                 }
                 if ($o_item->{'related_' . $vs_rel_table}) {
                     $t_rel = $o_dm->getInstanceByTableName($vs_rel_table, false);
                     // TODO: add hook onBeforeAddRelationships()
                     foreach ($o_item->{'related_' . $vs_rel_table} as $vs_tag => $o_related_items) {
                         foreach ($o_related_items as $vs_i => $o_related_item) {
                             if (is_array($pa_config['importRelatedFor'][$va_item['table']][$vs_rel_table])) {
                                 $va_rel_types = array_keys($pa_config['importRelatedFor'][$va_item['table']][$vs_rel_table]);
                                 if (is_array($va_rel_types) && sizeof($va_rel_types) && !in_array((string) $o_related_item->relationship_type_code, $va_rel_types)) {
                                     print "[INFO] Skipped relationship for {$vs_display_name} because type='" . (string) $o_related_item->relationship_type_code . "' is excluded\n";
                                     continue;
                                 }
                             }
                             $vs_pk = $t_rel->primaryKey();
                             $vn_id = (int) $o_related_item->{$vs_pk};
                             $va_queue = array($vs_rel_table . "/" . $vn_id => array('table' => $vs_rel_table, 'id' => $vn_id, 'idno' => (string) $o_related_item->idno));
                             // TODO: Add from/until support
                             $this->fetchAndImport($va_queue, $po_client, $pa_config, $pa_tables, $ps_code);
                             $vn_rel_record_id = $this->opa_processed_records[$vs_rel_table . '/' . (int) $vn_id];
                             $vb_skip = false;
                             if ($vb_is_self_relation) {
                                 if ($this->opa_processed_self_relations[$vs_rel_table][$vn_rel_record_id][$t_instance->getPrimaryKey()][(string) $o_related_item->relationship_type_code] || $this->opa_processed_self_relations[$vs_rel_table][$t_instance->getPrimaryKey()][$vn_rel_record_id][(string) $o_related_item->relationship_type_code]) {
                                     $vb_skip = true;
                                 } else {
                                     $this->opa_processed_self_relations[$vs_rel_table][$t_instance->getPrimaryKey()][$vn_rel_record_id][(string) $o_related_item->relationship_type_code] = $this->opa_processed_self_relations[$vs_rel_table][$vn_rel_record_id][$t_instance->getPrimaryKey()][(string) $o_related_item->relationship_type_code] = true;
                                 }
                             }
                             if (!$vb_skip) {
                                 $t_instance->addRelationship($vs_rel_table, $vn_rel_record_id, (string) $o_related_item->relationship_type_code);
                                 if ($t_instance->numErrors()) {
                                     print "[ERROR] Could not add relationship to {$vs_rel_table} for row_id={$vn_rel_record_id}: " . join('; ', $t_instance->getErrors()) . "\n";
                                 }
                             }
                         }
                     }
                     // TODO: add hook onAddRelationships()
                 }
             }
         }
         // Is there media?
         if ($t_instance->tableName() == 'ca_objects') {
             try {
                 $o_rep_xml = $po_client->getObjectRepresentations((int) $va_item['id'], array('large', 'original'))->get();
             } catch (exception $e) {
                 print "[ERROR] While getting object representations: " . $e->getMessage() . "\n";
             }
             $va_existing_reps = $t_instance->getRepresentations(array('large', 'original'));
             $va_existing_md5s = array();
             $va_rep_ids = array();
             $va_dupe_reps = array();
             foreach ($va_existing_reps as $va_rep) {
                 if ($va_existing_md5s[$va_rep['info']['original']['MD5']] && $va_existing_md5s[$va_rep['info']['large']['MD5']]) {
                     // dupe
                     $va_dupe_reps[] = $va_rep['representation_id'];
                     continue;
                 }
                 $va_existing_md5s[$va_rep['info']['original']['MD5']] = $va_rep['representation_id'];
                 $va_existing_md5s[$va_rep['info']['large']['MD5']] = $va_rep['representation_id'];
                 $va_rep_ids[] = $va_rep['representation_id'];
             }
             if ($o_rep_xml->getObjectRepresentations) {
                 foreach ($o_rep_xml->getObjectRepresentations as $vs_x => $o_reps) {
                     foreach ($o_reps as $vs_key => $o_rep) {
                         if ($vs_url = trim((string) $o_rep->urls->large)) {
                             $vs_remote_original_md5 = (string) $o_rep->info->original->MD5;
                             $vs_remote_large_md5 = (string) $o_rep->info->large->MD5;
                             if (isset($va_existing_md5s[$vs_remote_original_md5]) && $va_existing_md5s[$vs_remote_original_md5] || isset($va_existing_md5s[$vs_remote_large_md5]) && $va_existing_md5s[$vs_remote_large_md5]) {
                                 print "[NOTICE] Skipping representation at {$vs_url} because it already exists (MD5={$vs_remote_original_md5}/{$vs_remote_large_md5}) ({$ps_code})\n";
                                 if (!($vn_kill_rep_id = $va_existing_md5s[$vs_remote_large_md5])) {
                                     $vn_kill_rep_id = $va_existing_md5s[$vs_remote_original_md5];
                                 }
                                 foreach ($va_existing_md5s as $vs_md5 => $vn_rep_id) {
                                     if ($vn_kill_rep_id == $vn_rep_id) {
                                         $t_existing_rep_link = new ca_objects_x_object_representations();
                                         if ($t_existing_rep_link->load(array('object_id' => $t_instance->getPrimaryKey(), 'representation_id' => $vn_rep_id))) {
                                             $t_existing_rep_link->setMode(ACCESS_WRITE);
                                             //	print "update object_id ".$t_instance->getPrimaryKey()."/rep=$vn_rep_id to rank=".$o_rep->rank."/primary=".$o_rep->is_primary."\n";
                                             $t_existing_rep_link->set('is_primary', (int) $o_rep->is_primary);
                                             $t_existing_rep_link->set('rank', (int) $o_rep->rank);
                                             $t_existing_rep_link->update();
                                             if ($t_existing_rep_link->numErrors()) {
                                                 print_r($t_existing_rep_link->getErrors());
                                             }
                                         }
                                         unset($va_existing_md5s[$vs_md5]);
                                     }
                                 }
                                 continue;
                             }
                             print "[Notice] Importing for [{$vs_idno}] media from {$vs_url}: primary=" . (string) $o_rep->is_primary . " ({$ps_code})\n";
                             print "instance has id=" . $t_instance->getPrimaryKey() . "\n";
                             // TODO: add hook onBeforeAddMedia()
                             $vn_link_id = $t_instance->addRepresentation($vs_url, $pn_rep_type_id, 1, (int) $o_rep->status, (int) $o_rep->access, (int) $o_rep->is_primary);
                             // TODO: add hook onAddMedia()
                             if ($t_instance->numErrors()) {
                                 print "[ERROR] Could not load object representation: " . join("; ", $t_instance->getErrors()) . " ({$ps_code})\n";
                             } else {
                                 $t_link = new ca_objects_x_object_representations($vn_link_id);
                                 $t_new_rep = new ca_object_representations($t_link->get('representation_id'));
                                 //unlink($x=$t_new_rep->getMediaPath('media', 'original'));
                             }
                         }
                     }
                 }
             }
             $va_rep_ids = array();
             foreach ($va_existing_md5s as $vs_md5 => $vn_rep_id) {
                 if ($va_rep_ids[$vn_rep_id]) {
                     continue;
                 }
                 $t_obj_x_rep = new ca_objects_x_object_representations();
                 while ($t_obj_x_rep->load(array('object_id' => $t_instance->getPrimaryKey(), 'representation_id' => $vn_rep_id))) {
                     $t_obj_x_rep->setMode(ACCESS_WRITE);
                     $t_obj_x_rep->delete(true);
                     if ($t_obj_x_rep->numErrors()) {
                         print "[ERROR] Could not load remove object-to-representation link: " . join("; ", $t_obj_x_rep->getErrors()) . " ({$ps_code})\n";
                         break;
                     }
                     if (!$t_obj_x_rep->load(array('representation_id' => $vn_rep_id))) {
                         $t_rep = new ca_object_representations();
                         if ($t_rep->load($vn_rep_id)) {
                             $t_rep->setMode(ACCESS_WRITE);
                             $t_rep->delete(true, array('hard' => true));
                             if ($t_rep->numErrors()) {
                                 print "[ERROR] Could not remove representation: " . join("; ", $t_rep->getErrors()) . "\n";
                                 break;
                             }
                         }
                     }
                 }
                 $va_rep_ids[$vn_rep_id] = true;
             }
             foreach ($va_dupe_reps as $vn_dupe_rep_id) {
                 $t_rep = new ca_object_representations();
                 if ($t_rep->load($vn_dupe_rep_id)) {
                     print "[Notice] DELETE DUPE {$vn_dupe_rep_id}\n";
                     $t_rep->setMode(ACCESS_WRITE);
                     $t_rep->delete(true, array('hard' => true));
                     if ($t_rep->numErrors()) {
                         print "[ERROR] Could not remove dupe representation: " . join("; ", $t_rep->getErrors()) . "\n";
                         break;
                     }
                 }
             }
         }
         unset($pa_tables[$va_item['table']]);
     }
 }
 /**
  *
  */
 private function _getChangeLogFromRawData($pa_data, $pn_table_num, $pa_options = null)
 {
     //print "<pre>".print_r($pa_data, true)."</pre>\n";
     $va_log_output = array();
     $vs_blank_placeholder = '&lt;' . _t('BLANK') . '&gt;';
     if (!$pa_options) {
         $pa_options = array();
     }
     if (sizeof($pa_data)) {
         //
         // Init
         //
         $o_datamodel = Datamodel::load();
         $va_change_types = array('I' => _t('Added'), 'U' => _t('Edited'), 'D' => _t('Deleted'));
         $vs_label_table_name = $vs_label_display_name = '';
         $t_item = $o_datamodel->getInstanceByTableNum($pn_table_num, true);
         $vs_label_table_name = $vn_label_table_num = $vs_label_display_name = null;
         if (method_exists($t_item, 'getLabelTableName')) {
             $t_item_label = $t_item->getLabelTableInstance();
             $vs_label_table_name = $t_item->getLabelTableName();
             $vn_label_table_num = $t_item_label->tableNum();
             $vs_label_display_name = $t_item_label->getProperty('NAME_SINGULAR');
         }
         //
         // Group data by unit
         //
         $va_grouped_data = array();
         foreach ($pa_data as $va_log_entry) {
             $va_grouped_data[$va_log_entry['unit_id']]['ca_table_num_' . $va_log_entry['logged_table_num']][] = $va_log_entry;
         }
         //
         // Process units
         //
         $va_attributes = array();
         foreach ($va_grouped_data as $vn_unit_id => $va_log_entries_by_table) {
             foreach ($va_log_entries_by_table as $vs_table_key => $va_log_entries) {
                 foreach ($va_log_entries as $va_log_entry) {
                     $va_changes = array();
                     if (!is_array($va_log_entry['snapshot'])) {
                         $va_log_entry['snapshot'] = array();
                     }
                     //
                     // Get date/time stamp for display
                     //
                     $vs_datetime = date("n/d/Y@g:i:sa T", $va_log_entry['log_datetime']);
                     //
                     // Get user name
                     //
                     $vs_user = $va_log_entry['fname'] . ' ' . $va_log_entry['lname'];
                     $vs_email = $va_log_entry['email'];
                     // The "logged" table/row is the row to which the change was actually applied
                     // The "subject" table/row is the row to which the change is considered to have been made for workflow purposes.
                     //
                     // For example: if an entity is related to an object, strictly speaking the logging occurs on the ca_objects_x_entities
                     // row (ca_objects_x_entities is the "logged" table), but the subject is ca_objects since it's only in the context of the
                     // object (and probably the ca_entities row as well) that you can about the change.
                     //
                     $t_obj = $o_datamodel->getInstanceByTableNum($va_log_entry['logged_table_num'], true);
                     // get instance for logged table
                     if (!$t_obj) {
                         continue;
                     }
                     $vs_subject_display_name = '???';
                     $vn_subject_row_id = null;
                     $vn_subject_table_num = null;
                     if (isset($pa_options['return_item_names']) && $pa_options['return_item_names']) {
                         if (!($vn_subject_table_num = $va_log_entry['subject_table_num'])) {
                             $vn_subject_table_num = $va_log_entry['logged_table_num'];
                             $vn_subject_row_id = $va_log_entry['logged_row_id'];
                         } else {
                             $vn_subject_row_id = $va_log_entry['subject_row_id'];
                         }
                         if ($t_subject = $o_datamodel->getInstanceByTableNum($vn_subject_table_num, true)) {
                             if ($t_subject->load($vn_subject_row_id)) {
                                 if (method_exists($t_subject, 'getLabelForDisplay')) {
                                     $vs_subject_display_name = $t_subject->getLabelForDisplay(false);
                                 } else {
                                     if ($vs_idno_field = $t_subject->getProperty('ID_NUMBERING_ID_FIELD')) {
                                         $vs_subject_display_name = $t_subject->getProperty('NAME_SINGULAR') . ' [' . $t_subject->get($vs_idno_field) . ']';
                                     } else {
                                         $vs_subject_display_name = $t_subject->getProperty('NAME_SINGULAR') . ' [' . $vn_subject_row_id . ']';
                                     }
                                 }
                             }
                         }
                     }
                     //
                     // Get item changes
                     //
                     // ---------------------------------------------------------------
                     // is this an intrinsic field?
                     if ($pn_table_num == $va_log_entry['logged_table_num']) {
                         foreach ($va_log_entry['snapshot'] as $vs_field => $vs_value) {
                             $va_field_info = $t_obj->getFieldInfo($vs_field);
                             if (isset($va_field_info['IDENTITY']) && $va_field_info['IDENTITY']) {
                                 continue;
                             }
                             if (isset($va_field_info['DISPLAY_TYPE']) && $va_field_info['DISPLAY_TYPE'] == DT_OMIT) {
                                 continue;
                             }
                             if (isset($va_field_info['DISPLAY_FIELD']) && is_array($va_field_info['DISPLAY_FIELD']) && ($va_disp_fields = $va_field_info['DISPLAY_FIELD'])) {
                                 //
                                 // Lookup value in related table
                                 //
                                 if (!$vs_value) {
                                     continue;
                                 }
                                 if (sizeof($va_disp_fields)) {
                                     $va_rel = $o_datamodel->getManyToOneRelations($t_obj->tableName(), $vs_field);
                                     $va_rel_values = array();
                                     if ($t_rel_obj = $o_datamodel->getTableInstance($va_rel['one_table'], true)) {
                                         $t_rel_obj->load($vs_value);
                                         foreach ($va_disp_fields as $vs_display_field) {
                                             $va_tmp = explode('.', $vs_display_field);
                                             if (($vs_tmp = $t_rel_obj->get($va_tmp[1])) !== '') {
                                                 $va_rel_values[] = $vs_tmp;
                                             }
                                         }
                                     }
                                     $vs_proc_val = join(', ', $va_rel_values);
                                 }
                             } else {
                                 // Is field a foreign key?
                                 $va_keys = $o_datamodel->getManyToOneRelations($t_obj->tableName(), $vs_field);
                                 if (sizeof($va_keys)) {
                                     // yep, it's a foreign key
                                     $va_rel_values = array();
                                     if ($t_rel_obj = $o_datamodel->getTableInstance($va_keys['one_table'], true)) {
                                         if ($t_rel_obj->load($vs_value)) {
                                             if (method_exists($t_rel_obj, 'getLabelForDisplay')) {
                                                 $vs_proc_val = $t_rel_obj->getLabelForDisplay(false);
                                             } else {
                                                 $va_disp_fields = $t_rel_obj->getProperty('LIST_FIELDS');
                                                 foreach ($va_disp_fields as $vs_display_field) {
                                                     if (($vs_tmp = $t_rel_obj->get($vs_display_field)) !== '') {
                                                         $va_rel_values[] = $vs_tmp;
                                                     }
                                                 }
                                                 $vs_proc_val = join(' ', $va_rel_values);
                                             }
                                             if (!$vs_proc_val) {
                                                 $vs_proc_val = '???';
                                             }
                                         } else {
                                             $vs_proc_val = _t("Not set");
                                         }
                                     } else {
                                         $vs_proc_val = _t('Non-existent');
                                     }
                                 } else {
                                     // Adjust display of value for different field types
                                     switch ($va_field_info['FIELD_TYPE']) {
                                         case FT_BIT:
                                             $vs_proc_val = $vs_value ? 'Yes' : 'No';
                                             break;
                                         default:
                                             $vs_proc_val = $vs_value;
                                             break;
                                     }
                                     // Adjust display of value for lists
                                     if ($va_field_info['LIST']) {
                                         $t_list = new ca_lists();
                                         if ($t_list->load(array('list_code' => $va_field_info['LIST']))) {
                                             $vn_list_id = $t_list->getPrimaryKey();
                                             $t_list_item = new ca_list_items();
                                             if ($t_list_item->load(array('list_id' => $vn_list_id, 'item_value' => $vs_value))) {
                                                 $vs_proc_val = $t_list_item->getLabelForDisplay();
                                             }
                                         }
                                     } else {
                                         if ($va_field_info['BOUNDS_CHOICE_LIST']) {
                                             // TODO
                                         }
                                     }
                                 }
                             }
                             $va_changes[] = array('label' => $va_field_info['LABEL'], 'description' => strlen((string) $vs_proc_val) ? $vs_proc_val : $vs_blank_placeholder, 'value' => $vs_value);
                         }
                     }
                     // ---------------------------------------------------------------
                     // is this a label row?
                     if ($va_log_entry['logged_table_num'] == $vn_label_table_num) {
                         foreach ($va_log_entry['snapshot'] as $vs_field => $vs_value) {
                             $va_changes[] = array('label' => $t_item_label->getFieldInfo($vs_field, 'LABEL'), 'description' => $vs_value);
                         }
                     }
                     // ---------------------------------------------------------------
                     // is this an attribute?
                     if ($va_log_entry['logged_table_num'] == 3) {
                         // attribute_values
                         if ($t_element = ca_attributes::getElementInstance($va_log_entry['snapshot']['element_id'])) {
                             if ($o_attr_val = Attribute::getValueInstance($t_element->get('datatype'))) {
                                 $o_attr_val->loadValueFromRow($va_log_entry['snapshot']);
                                 $vs_attr_val = $o_attr_val->getDisplayValue();
                             } else {
                                 $vs_attr_val = '?';
                             }
                             // Convert list-based attributes to text
                             if ($vn_list_id = $t_element->get('list_id')) {
                                 $t_list = new ca_lists();
                                 $vs_attr_val = $t_list->getItemFromListForDisplayByItemID($vn_list_id, $vs_attr_val, true);
                             }
                             if (!$vs_attr_val) {
                                 $vs_attr_val = $vs_blank_placeholder;
                             }
                             $vs_label = $t_element->getLabelForDisplay();
                             $va_attributes[$va_log_entry['snapshot']['attribute_id']]['values'][] = array('label' => $vs_label, 'value' => $vs_attr_val);
                             $va_changes[] = array('label' => $vs_label, 'description' => $vs_attr_val);
                         }
                     }
                     // ---------------------------------------------------------------
                     // is this a related (many-many) row?
                     $va_keys = $o_datamodel->getOneToManyRelations($t_item->tableName(), $t_obj->tableName());
                     if (sizeof($va_keys) > 0) {
                         if (method_exists($t_obj, 'getLeftTableNum')) {
                             if ($t_obj->getLeftTableNum() == $t_item->tableNum()) {
                                 // other side of rel is on right
                                 $t_related_table = $o_datamodel->getInstanceByTableNum($t_obj->getRightTableNum(), true);
                                 $t_related_table->load($va_log_entry['snapshot'][$t_obj->getRightTableFieldName()]);
                             } else {
                                 // other side of rel is on left
                                 $t_related_table = $o_datamodel->getInstanceByTableNum($t_obj->getLeftTableNum(), true);
                                 $t_related_table->load($va_log_entry['snapshot'][$t_obj->getLeftTableFieldName()]);
                             }
                             $t_rel = $o_datamodel->getInstanceByTableNum($t_obj->tableNum(), true);
                             $va_changes[] = array('label' => caUcFirstUTF8Safe($t_related_table->getProperty('NAME_SINGULAR')), 'idno' => ($vs_idno_field = $t_related_table->getProperty('ID_NUMBERING_ID_FIELD')) ? $t_related_table->get($vs_idno_field) : null, 'description' => $t_related_table->getLabelForDisplay(), 'table_name' => $t_related_table->tableName(), 'table_num' => $t_related_table->tableNum(), 'row_id' => $t_related_table->getPrimaryKey(), 'rel_type_id' => $va_log_entry['snapshot']['type_id'], 'rel_typename' => $t_rel->getRelationshipTypename('ltor', $va_log_entry['snapshot']['type_id']));
                         }
                     }
                     // ---------------------------------------------------------------
                     // record log line
                     if (sizeof($va_changes)) {
                         $va_log_output[$vn_unit_id][] = array('datetime' => $vs_datetime, 'user_fullname' => $vs_user, 'user_email' => $vs_email, 'user' => $vs_user . ' (' . $vs_email . ')', 'changetype_display' => $va_change_types[$va_log_entry['changetype']], 'changetype' => $va_log_entry['changetype'], 'changes' => $va_changes, 'subject' => $vs_subject_display_name, 'subject_id' => $vn_subject_row_id, 'subject_table_num' => $vn_subject_table_num, 'logged_table_num' => $va_log_entry['logged_table_num'], 'logged_table' => $t_obj->tableName(), 'logged_row_id' => $va_log_entry['logged_row_id']);
                     }
                 }
             }
         }
     }
     return $va_log_output;
 }
 /**
  *
  */
 public function refine(&$pa_destination_data, $pa_group, $pa_item, $pa_source_data, $pa_options = null)
 {
     global $g_ui_locale_id;
     $vs_delimiter = caGetOption('delimiter', $pa_options, null);
     if (!($pn_locale_id = ca_locales::getDefaultCataloguingLocaleID())) {
         $pn_locale_id = $g_ui_locale_id;
     }
     $o_log = isset($pa_options['log']) && is_object($pa_options['log']) ? $pa_options['log'] : null;
     $t_mapping = caGetOption('mapping', $pa_options, null);
     if ($t_mapping) {
         $o_dm = Datamodel::load();
         if ($t_mapping->get('table_num') != $o_dm->getTableNum('ca_list_items')) {
             if ($o_log) {
                 $o_log->logError(_t("listItemIndentedHierarchyBuilder refinery may only be used in imports to ca_list_items"));
             }
             return null;
         }
     }
     $va_group_dest = explode(".", $pa_group['destination']);
     $vs_terminal = array_pop($va_group_dest);
     $pm_value = $pa_source_data[$pa_item['source']];
     // Get list of fields to insert
     if (!is_array($va_levels = $pa_item['settings']['listItemIndentedHierarchyBuilder_levels'])) {
         if ($o_log) {
             $o_log->logError(_t("listItemIndentedHierarchyBuilder requires levels option be set to a list of data source placeholders"));
         }
         return null;
     } else {
         $va_level_types = $pa_item['settings']['listItemIndentedHierarchyBuilder_levelTypes'];
     }
     // Get list, or create if it doesn't already exist
     if (!($vs_list_code = $pa_item['settings']['listItemIndentedHierarchyBuilder_list'])) {
         if ($o_log) {
             $o_log->logError(_t("listItemIndentedHierarchyBuilder requires list option be set"));
         }
         return null;
     }
     $t_list = new ca_lists();
     if (!$t_list->load(array('list_code' => $vs_list_code))) {
         // create list
         $t_list->set('list_code', $vs_list_code);
         $t_list->setMode(ACCESS_WRITE);
         $t_list->insert();
         if ($t_list->numErrors()) {
             if ($o_log) {
                 $o_log->logError(_t("listItemIndentedHierarchyBuilder could not create list %1: %2", $vs_list_code, join("; ", $t_list->getErrors())));
             }
             return null;
         }
         $t_list->addLabel(array('name' => caUcFirstUTF8Safe($vs_list_code)), $pn_locale_id, null, true);
         if ($t_list->numErrors()) {
             if ($o_log) {
                 $o_log->logError(_t("listItemIndentedHierarchyBuilder could not create list label %1: %2", $vs_list_code, join("; ", $t_list->getErrors())));
             }
             return null;
         }
     }
     // Handle each level
     if (!is_array($va_level_values = listItemIndentedHierarchyBuilderRefinery::$opa_level_values)) {
         $va_level_values = $va_level_value_ids = array();
     }
     $va_level_value_ids = listItemIndentedHierarchyBuilderRefinery::$opa_level_value_ids;
     $vn_max_level = 0;
     $vn_parent_id = null;
     foreach ($va_levels as $vn_i => $vs_level_placeholder) {
         $vs_level_value = null;
         if (strlen($vs_level_placeholder)) {
             if ($vs_level_value = BaseRefinery::parsePlaceholder($vs_level_placeholder, $pa_source_data, $pa_item, 0, array('reader' => caGetOption('reader', $pa_options, null), 'returnAsString' => true))) {
                 if (!$vn_parent_id && isset(listItemIndentedHierarchyBuilderRefinery::$opa_level_value_ids[$vn_i - 1])) {
                     $vn_parent_id = listItemIndentedHierarchyBuilderRefinery::$opa_level_value_ids[$vn_i - 1];
                 }
                 $vs_type = isset($va_level_types[$vn_i]) ? $va_level_types[$vn_i] : null;
                 if ($vn_item_id = DataMigrationUtils::getListItemID($vs_list_code, preg_replace("![^A-Za-z0-9_]+!", "_", $vs_level_value), $vs_type, $pn_locale_id, array('is_enabled' => 1, 'parent_id' => $vn_parent_id, 'preferred_labels' => array('name_singular' => $vs_level_value, 'name_plural' => $vs_level_value)), array('matchOnIdno' => true, 'log' => $o_log, 'transaction' => caGetOption('transaction', $pa_options, null), 'importEvent' => caGetOption('event', $pa_options, null), 'importEventSource' => 'listItemIndentedHierarchyBuilder'))) {
                     $vn_parent_id = $vn_item_id;
                     $va_level_values[$vn_i] = $vs_level_value;
                     $va_level_value_ids[$vn_i] = $vn_item_id;
                     $vn_max_level = $vn_i;
                 }
             }
         }
     }
     listItemIndentedHierarchyBuilderRefinery::$opa_level_values = array_slice($va_level_values, 0, $vn_max_level + 1);
     listItemIndentedHierarchyBuilderRefinery::$opa_level_value_ids = array_slice($va_level_value_ids, 0, $vn_max_level + 1);
     if ($pa_item['settings']['listItemIndentedHierarchyBuilder_list'] == 'returnData') {
         return $vn_parent_id;
     }
     return null;
 }
 /**
  * Returns navigation fragment for types and subtypes of a given primary item type (Eg. ca_objects). Used to generate dynamic type menus 
  * from database by AppNavigation class. 
  *
  * @param array $pa_params Array of parameters used to generate menu
  * @return array List of types with subtypes ready for inclusion in a menu spec
  */
 public function _genTypeNav($pa_params)
 {
     $t_subject = $this->opo_datamodel->getInstanceByTableName($this->ops_table_name, true);
     $t_list = new ca_lists();
     $t_list->load(array('list_code' => $t_subject->getTypeListCode()));
     $t_list_item = new ca_list_items();
     $t_list_item->load(array('list_id' => $t_list->getPrimaryKey(), 'parent_id' => null));
     $va_hier = caExtractValuesByUserLocale($t_list_item->getHierarchyWithLabels());
     $vn_sort_type = $t_list->get('default_sort');
     $va_restrict_to_types = null;
     if ($t_subject->getAppConfig()->get('perform_type_access_checking')) {
         $va_restrict_to_types = caGetTypeRestrictionsForUser($this->ops_table_name, array('access' => __CA_BUNDLE_ACCESS_EDIT__));
     }
     $va_types = array();
     if (is_array($va_hier)) {
         $va_types_by_parent_id = array();
         $vn_root_id = $t_list->getRootItemIDForList($t_subject->getTypeListCode());
         foreach ($va_hier as $vn_item_id => $va_item) {
             if ($vn_item_id == $vn_root_id) {
                 continue;
             }
             // skip root
             $va_types_by_parent_id[$va_item['parent_id']][] = $va_item;
         }
         foreach ($va_hier as $vn_item_id => $va_item) {
             if (is_array($va_restrict_to_types) && !in_array($vn_item_id, $va_restrict_to_types)) {
                 continue;
             }
             if ($va_item['parent_id'] != $vn_root_id) {
                 continue;
             }
             // does this item have sub-items?
             $va_subtypes = array();
             if (!(bool) $this->getRequest()->config->get($this->ops_table_name . '_navigation_new_menu_shows_top_level_types_only') && !(bool) $this->getRequest()->config->get($this->ops_table_name . '_enforce_strict_type_hierarchy')) {
                 if (isset($va_item['item_id']) && isset($va_types_by_parent_id[$va_item['item_id']]) && is_array($va_types_by_parent_id[$va_item['item_id']])) {
                     $va_subtypes = $this->_getSubTypes($va_types_by_parent_id[$va_item['item_id']], $va_types_by_parent_id, $vn_sort_type, $va_restrict_to_types);
                 }
             }
             switch ($vn_sort_type) {
                 case 0:
                     // label
                 // label
                 default:
                     $vs_key = $va_item['name_singular'];
                     break;
                 case 1:
                     // rank
                     $vs_key = sprintf("%08d", (int) $va_item['rank']);
                     break;
                 case 2:
                     // value
                     $vs_key = $va_item['item_value'];
                     break;
                 case 3:
                     // identifier
                     $vs_key = $va_item['idno_sort'];
                     break;
             }
             $va_types[$vs_key][] = array('displayName' => $va_item['name_singular'], 'parameters' => array('type_id' => $va_item['item_id']), 'is_enabled' => $va_item['is_enabled'], 'navigation' => $va_subtypes);
         }
         ksort($va_types);
     }
     $va_types_proc = array();
     foreach ($va_types as $vs_sort_key => $va_items) {
         foreach ($va_items as $vn_i => $va_item) {
             $va_types_proc[] = $va_item;
         }
     }
     return $va_types_proc;
 }
Example #15
0
 /**
  * Return list of items from the specified table that are related to the current browse set. This is the method that actually
  * pulls the facet content, regardless of whether the facet is cached yet or not. If you want to use the facet cache, call
  * BrowseEngine::getFacet()
  *
  * @see BrowseEngine::getFacet()
  * Options:
  *		checkAccess = array of access values to filter facets that have an 'access' field by
  *		checkAvailabilityOnly = if true then content is not actually fetch - only the availablility of content is verified
  *		user_id = If set item level access control is performed relative to specified user_id, otherwise defaults to logged in user
  */
 public function getFacetContent($ps_facet_name, $pa_options = null)
 {
     global $AUTH_CURRENT_USER_ID;
     $vs_browse_table_name = $this->ops_browse_table_name;
     $vs_browse_table_num = $this->opn_browse_table_num;
     $vn_user_id = isset($pa_options['user_id']) && (int) $pa_options['user_id'] ? (int) $pa_options['user_id'] : (int) $AUTH_CURRENT_USER_ID;
     $vb_show_if_no_acl = (bool) ($this->opo_config->get('default_item_access_level') > __CA_ACL_NO_ACCESS__);
     $t_user = new ca_users($vn_user_id);
     if (is_array($va_groups = $t_user->getUserGroups()) && sizeof($va_groups)) {
         $va_group_ids = array_keys($va_groups);
     } else {
         $va_group_ids = array();
     }
     if (!is_array($this->opa_browse_settings)) {
         return null;
     }
     if (!isset($this->opa_browse_settings['facets'][$ps_facet_name])) {
         return null;
     }
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     $vb_check_availability_only = isset($pa_options['checkAvailabilityOnly']) ? (bool) $pa_options['checkAvailabilityOnly'] : false;
     $va_all_criteria = $this->getCriteria();
     $va_criteria = $this->getCriteria($ps_facet_name);
     $va_facet_info = $this->opa_browse_settings['facets'][$ps_facet_name];
     $t_subject = $this->getSubjectInstance();
     if ($va_facet_info['relative_to']) {
         $vs_browse_table_name = $va_facet_info['relative_to'];
         $vs_browse_table_num = $this->opo_datamodel->getTableNum($vs_browse_table_name);
     }
     $vs_browse_type_limit_sql = '';
     if (($va_browse_type_ids = $this->getTypeRestrictionList()) && sizeof($va_browse_type_ids)) {
         // type restrictions
         $vs_browse_type_limit_sql = '(' . $t_subject->tableName() . '.' . $t_subject->getTypeFieldName() . ' IN (' . join(', ', $va_browse_type_ids) . ')' . ($t_subject->getFieldInfo('type_id', 'IS_NULL') ? " OR (" . $this->ops_browse_table_name . '.' . $t_subject->getTypeFieldName() . " IS NULL)" : '') . ')';
         if (is_array($va_facet_info['type_restrictions'])) {
             // facet type restrictions bind a facet to specific types; we check them here
             $va_restrict_to_types = $this->_convertTypeCodesToIDs($va_facet_info['type_restrictions']);
             $vb_is_ok_to_browse = false;
             foreach ($va_browse_type_ids as $vn_type_id) {
                 if (in_array($vn_type_id, $va_restrict_to_types)) {
                     $vb_is_ok_to_browse = true;
                     break;
                 }
             }
             if (!$vb_is_ok_to_browse) {
                 return array();
             }
         }
     }
     // Values to exclude from list attributes and authorities; can be idnos or ids
     $va_exclude_values = caGetOption('exclude_values', $va_facet_info, array(), array('castTo' => 'array'));
     $va_results = $this->opo_ca_browse_cache->getResults();
     $vb_single_value_is_present = false;
     $vs_single_value = isset($va_facet_info['single_value']) ? $va_facet_info['single_value'] : null;
     $va_wheres = array();
     switch ($va_facet_info['type']) {
         # -----------------------------------------------------
         case 'has':
             $vn_state = null;
             if (isset($va_all_criteria[$ps_facet_name])) {
                 break;
             }
             // only one instance of this facet allowed per browse
             if (!($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true))) {
                 break;
             }
             $vs_yes_text = isset($va_facet_info['label_yes']) && $va_facet_info['label_yes'] ? $va_facet_info['label_yes'] : _t('Yes');
             $vs_no_text = isset($va_facet_info['label_no']) && $va_facet_info['label_no'] ? $va_facet_info['label_no'] : _t('No');
             $va_facet_values = array('yes' => array('id' => 1, 'label' => $vs_yes_text), 'no' => array('id' => 0, 'label' => $vs_no_text));
             // Actually check that both yes and no values will result in something
             if ($va_facet_info['element_code']) {
                 $t_element = new ca_metadata_elements();
                 if (!$t_element->load(array('element_code' => $va_facet_info['element_code']))) {
                     break;
                 }
                 $vs_element_code = $va_facet_info['element_code'];
                 $va_facet = array();
                 $va_counts = array();
                 foreach ($va_facet_values as $vs_state_name => $va_state_info) {
                     $va_wheres = array();
                     $va_joins = array();
                     if (!(bool) $va_state_info['id']) {
                         // no option
                         $va_wheres[] = $this->ops_browse_table_name . '.' . $t_item->primaryKey() . " NOT IN (select row_id from ca_attributes where table_num = " . $t_item->tableNum() . " AND element_id = " . $t_element->getPrimaryKey() . ")";
                     } else {
                         // yes option
                         $va_joins[] = "LEFT JOIN ca_attributes AS caa ON  " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . " = caa.row_id AND " . $t_item->tableNum() . " = caa.table_num";
                         $va_wheres[] = "caa.element_id = " . $t_element->getPrimaryKey();
                     }
                     if ($t_item->hasField('deleted')) {
                         $va_wheres[] = "(" . $t_item->tableName() . ".deleted = 0)";
                     }
                     if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                         $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
                     }
                     if (sizeof($va_results)) {
                         $va_wheres[] = $vs_browse_table_name . "." . $t_item->primaryKey() . " IN (" . join(",", $va_results) . ")";
                     }
                     if ($va_facet_info['relative_to']) {
                         if ($t_subject->hasField('deleted')) {
                             $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                         }
                         if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                             $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                             $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                         }
                     }
                     if ($this->opo_config->get('perform_item_level_access_checking')) {
                         if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                             // Join to limit what browse table items are used to generate facet
                             $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                             $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t\t)";
                         }
                     }
                     $vs_join_sql = join("\n", $va_joins);
                     $vs_where_sql = '';
                     if (sizeof($va_wheres) > 0) {
                         $vs_where_sql = ' WHERE ' . join(' AND ', $va_wheres);
                     }
                     if ($vb_check_availability_only) {
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 2\n\t\t\t\t\t\t\t\t";
                         //print "$vs_sql<hr>";
                         $qr_res = $this->opo_db->query($vs_sql);
                         if ($qr_res->nextRow()) {
                             $va_counts[$vs_state_name] = (int) $qr_res->numRows();
                         }
                     } else {
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT " . $vs_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t";
                         //print "$vs_sql<hr>";
                         $qr_res = $this->opo_db->query($vs_sql);
                         if ($qr_res->numRows() > 0) {
                             $va_facet[$vs_state_name] = $va_state_info;
                         } else {
                             return array();
                             // if either option in a "has" facet fails then don't show the facet
                         }
                     }
                 }
             } else {
                 $vs_rel_table_name = $va_facet_info['table'];
                 if (!is_array($va_restrict_to_relationship_types = $va_facet_info['restrict_to_relationship_types'])) {
                     $va_restrict_to_relationship_types = array();
                 }
                 $va_restrict_to_relationship_types = $this->_getRelationshipTypeIDs($va_restrict_to_relationship_types, $va_facet_info['relationship_table']);
                 if (!is_array($va_exclude_relationship_types = $va_facet_info['exclude_relationship_types'])) {
                     $va_exclude_relationship_types = array();
                 }
                 $va_exclude_relationship_types = $this->_getRelationshipTypeIDs($va_exclude_relationship_types, $va_facet_info['relationship_table']);
                 $vn_table_num = $this->opo_datamodel->getTableNum($vs_rel_table_name);
                 $vs_rel_table_pk = $this->opo_datamodel->getTablePrimaryKeyName($vn_table_num);
                 switch (sizeof($va_path = array_keys($this->opo_datamodel->getPath($vs_browse_table_name, $vs_rel_table_name)))) {
                     case 3:
                         $t_item_rel = $this->opo_datamodel->getInstanceByTableName($va_path[1], true);
                         $t_rel_item = $this->opo_datamodel->getInstanceByTableName($va_path[2], true);
                         $vs_key = 'relation_id';
                         break;
                     case 2:
                         $t_item_rel = null;
                         $t_rel_item = $this->opo_datamodel->getInstanceByTableName($va_path[1], true);
                         $vs_key = $t_rel_item->primaryKey();
                         break;
                     default:
                         // bad related table
                         return null;
                         break;
                 }
                 $vs_cur_table = array_shift($va_path);
                 $va_joins_init = array();
                 foreach ($va_path as $vs_join_table) {
                     $va_rel_info = $this->opo_datamodel->getRelationships($vs_cur_table, $vs_join_table);
                     $va_joins_init[] = ($vn_state ? 'INNER' : 'LEFT') . ' JOIN ' . $vs_join_table . ' ON ' . $vs_cur_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][0] . ' = ' . $vs_join_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][1] . "\n";
                     $vs_cur_table = $vs_join_table;
                 }
                 $va_facet = array();
                 $va_counts = array();
                 foreach ($va_facet_values as $vs_state_name => $va_state_info) {
                     $va_wheres = array();
                     $va_joins = $va_joins_init;
                     if (!(bool) $va_state_info['id']) {
                         // no option
                         $va_wheres[] = "(" . $t_rel_item->tableName() . "." . $t_rel_item->primaryKey() . " IS NULL)";
                         if ($t_rel_item->hasField('deleted')) {
                             $va_wheres[] = "((" . $t_rel_item->tableName() . ".deleted = 0) OR (" . $t_rel_item->tableName() . ".deleted IS NULL))";
                         }
                         if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access')) {
                             $va_wheres[] = "((" . $t_rel_item->tableName() . ".access NOT IN (" . join(',', $pa_options['checkAccess']) . ")) OR (" . $t_rel_item->tableName() . ".access IS NULL))";
                         }
                         if (sizeof($va_restrict_to_relationship_types) > 0 && is_object($t_item_rel)) {
                             $va_wheres[] = "((" . $t_item_rel->tableName() . ".type_id NOT IN (" . join(',', $va_restrict_to_relationship_types) . ")) OR (" . $t_item_rel->tableName() . ".type_id IS NULL))";
                         }
                         if (sizeof($va_exclude_relationship_types) > 0 && is_object($t_item_rel)) {
                             $va_wheres[] = "(" . $t_item_rel->tableName() . ".type_id IN (" . join(',', $va_exclude_relationship_types) . "))";
                         }
                     } else {
                         // yes option
                         $va_wheres[] = "(" . $t_rel_item->tableName() . "." . $t_rel_item->primaryKey() . " IS NOT NULL)";
                         if ($t_rel_item->hasField('deleted')) {
                             $va_wheres[] = "(" . $t_rel_item->tableName() . ".deleted = 0)";
                         }
                         if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access')) {
                             $va_wheres[] = "(" . $t_rel_item->tableName() . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
                         }
                         if (sizeof($va_restrict_to_relationship_types) > 0 && is_object($t_item_rel)) {
                             $va_wheres[] = "(" . $t_item_rel->tableName() . ".type_id IN (" . join(',', $va_restrict_to_relationship_types) . "))";
                         }
                         if (sizeof($va_exclude_relationship_types) > 0 && is_object($t_item_rel)) {
                             $va_wheres[] = "(" . $t_item_rel->tableName() . ".type_id NOT IN (" . join(',', $va_exclude_relationship_types) . "))";
                         }
                     }
                     if ($t_item->hasField('deleted')) {
                         $va_wheres[] = "(" . $t_item->tableName() . ".deleted = 0)";
                     }
                     if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                         $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
                     }
                     if (sizeof($va_results)) {
                         $va_wheres[] = $vs_browse_table_name . "." . $t_item->primaryKey() . " IN (" . join(",", $va_results) . ")";
                     }
                     if ($va_facet_info['relative_to']) {
                         if ($t_subject->hasField('deleted')) {
                             $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                         }
                         if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                             $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                             $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                         }
                     }
                     if ($this->opo_config->get('perform_item_level_access_checking')) {
                         if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                             // Join to limit what browse table items are used to generate facet
                             $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                             $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t\t)";
                         }
                     }
                     $vs_join_sql = join("\n", $va_joins);
                     $vs_where_sql = '';
                     if (sizeof($va_wheres) > 0) {
                         $vs_where_sql = ' WHERE ' . join(' AND ', $va_wheres);
                     }
                     if ($vb_check_availability_only) {
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 2\n\t\t\t\t\t\t\t\t";
                         //print "$vs_sql<hr>";
                         $qr_res = $this->opo_db->query($vs_sql);
                         if ($qr_res->nextRow()) {
                             $va_counts[$vs_state_name] = (int) $qr_res->numRows();
                         }
                     } else {
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT " . $vs_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t";
                         //print "$vs_sql<hr>";
                         $qr_res = $this->opo_db->query($vs_sql);
                         if ($qr_res->numRows() > 0) {
                             $va_facet[$vs_state_name] = $va_state_info;
                         } else {
                             return array();
                             // if either option in a "has" facet fails then don't show the facet
                         }
                     }
                 }
             }
             if ($vb_check_availability_only) {
                 return sizeof($va_counts) > 1 ? true : false;
             }
             return $va_facet;
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'label':
             if (!($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true))) {
                 break;
             }
             if (!($t_label = $t_item->getLabelTableInstance())) {
                 break;
             }
             if (!is_array($va_restrict_to_types = $va_facet_info['restrict_to_types'])) {
                 $va_restrict_to_types = array();
             }
             $vs_item_pk = $t_item->primaryKey();
             $vs_label_table_name = $t_label->tableName();
             $vs_label_pk = $t_label->primaryKey();
             $vs_label_display_field = $t_item->getLabelDisplayField();
             $vs_label_sort_field = $t_item->getLabelSortField();
             $vs_where_sql = $vs_join_sql = '';
             $vb_needs_join = false;
             $va_where_sql = array();
             $va_joins = array();
             if ($vs_browse_type_limit_sql) {
                 $va_where_sql[] = $vs_browse_type_limit_sql;
             }
             if (isset($va_facet_info['preferred_labels_only']) && $va_facet_info['preferred_labels_only'] && $t_label->hasField('is_preferred')) {
                 $va_where_sql[] = "l.is_preferred = 1";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_where_sql[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ($t_item->hasField('deleted')) {
                 $va_where_sql[] = "(" . $vs_browse_table_name . ".deleted = 0)";
                 $vb_needs_join = true;
             }
             if (sizeof($va_restrict_to_types)) {
                 $va_restrict_to_type_ids = caMakeTypeIDList($vs_browse_table_name, $va_restrict_to_types, array('dont_include_subtypes_in_type_restriction' => true));
                 if (sizeof($va_restrict_to_type_ids)) {
                     $va_where_sql[] = "(" . $vs_browse_table_name . "." . $t_item->getTypeFieldName() . " IN (" . join(", ", $va_restrict_to_type_ids) . ")" . ($t_item->getFieldInfo('type_id', 'IS_NULL') ? " OR (" . $vs_browse_table_name . '.' . $t_item->getTypeFieldName() . " IS NULL)" : '') . ")";
                     $vb_needs_join = true;
                 }
             }
             if (sizeof($va_exclude_types)) {
                 $va_exclude_type_ids = caMakeTypeIDList($vs_browse_table_name, $va_exclude_types, array('dont_include_subtypes_in_type_restriction' => true));
                 if (sizeof($va_exclude_type_ids)) {
                     $va_where_sql[] = "(" . $vs_browse_table_name . "." . $t_item->getTypeFieldName() . " NOT IN (" . join(", ", $va_exclude_type_ids) . ")" . ($t_item->getFieldInfo('type_id', 'IS_NULL') ? " OR (" . $vs_browse_table_name . '.' . $t_item->getTypeFieldName() . " IS NULL)" : '') . ")";
                     $vb_needs_join = true;
                 }
             }
             if ($vb_needs_join) {
                 $va_joins[] = "INNER JOIN " . $vs_browse_table_name . " ON " . $vs_browse_table_name . "." . $t_item->primaryKey() . " = l." . $t_item->primaryKey();
             }
             if ($va_facet_info['relative_to']) {
                 if ($t_subject->hasField('deleted')) {
                     $va_where_sql[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                     $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                     $va_where_sql = array_merge($va_where_sql, $va_relative_sql_data['wheres']);
                 }
             }
             if (sizeof($va_results)) {
                 if ($va_facet_info['relative_to']) {
                     $va_where_sql[] = $this->ops_browse_table_name . "." . $t_subject->primaryKey() . " IN (" . join(",", $va_results) . ")";
                 } else {
                     $va_where_sql[] = "l.{$vs_item_pk} IN (" . join(",", $va_results) . ")";
                 }
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_where_sql[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             $vs_join_sql = join("\n", $va_joins);
             if (sizeof($va_where_sql)) {
                 $vs_where_sql = "WHERE " . join(" AND ", $va_where_sql);
             }
             if ($vb_check_availability_only) {
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM {$vs_label_table_name} l\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t\t";
                 $qr_res = $this->opo_db->query($vs_sql);
                 return (int) $qr_res->numRows() > 0 ? true : false;
             } else {
                 $vs_parent_fld = $t_item->getProperty('HIERARCHY_PARENT_ID_FLD');
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT  l.* " . ($vs_parent_fld ? ", " . $vs_browse_table_name . "." . $vs_parent_fld : '') . "\n\t\t\t\t\t\t\tFROM {$vs_label_table_name} l\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tORDER BY l.{$vs_label_display_field}\n\t\t\t\t\t\t";
                 $qr_res = $this->opo_db->query($vs_sql);
                 $va_values = array();
                 $va_child_counts = array();
                 $vn_parent_id = null;
                 $va_unique_values = array();
                 while ($qr_res->nextRow()) {
                     $vn_id = $qr_res->get($t_item->primaryKey());
                     if ($vs_parent_fld) {
                         $vn_parent_id = $qr_res->get($vs_parent_fld);
                         if ($vn_parent_id) {
                             $va_child_counts[$vn_parent_id]++;
                         }
                     }
                     $vs_label = trim($qr_res->get($vs_label_display_field));
                     if (isset($va_unique_values[$vs_label])) {
                         continue;
                     }
                     $va_unique_values[$vs_label] = true;
                     $va_values[$vn_id][$qr_res->get('locale_id')] = array_merge($qr_res->getRow(), array('id' => $vn_id, 'parent_id' => $vn_parent_id, 'label' => $vs_label));
                     if (!is_null($vs_single_value) && $vn_id == $vs_single_value) {
                         $vb_single_value_is_present = true;
                     }
                 }
                 if ($vs_parent_fld) {
                     foreach ($va_values as $vn_id => $va_values_by_locale) {
                         foreach ($va_values_by_locale as $vn_locale_id => $va_value) {
                             $va_values[$vn_id][$vn_locale_id]['child_count'] = (int) $va_child_counts[$vn_id];
                         }
                     }
                 }
                 if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                     return array();
                 }
                 $va_values = caExtractValuesByUserLocale($va_values);
                 return $va_values;
             }
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'attribute':
             $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true);
             $t_element = new ca_metadata_elements();
             if (!$t_element->load(array('element_code' => $va_facet_info['element_code']))) {
                 return array();
             }
             $vn_element_type = $t_element->get('datatype');
             $vn_element_id = $t_element->getPrimaryKey();
             $va_joins = array('INNER JOIN ca_attribute_values ON ca_attributes.attribute_id = ca_attribute_values.attribute_id', 'INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_attributes.row_id AND ca_attributes.table_num = ' . intval($vs_browse_table_num));
             $va_wheres = array();
             if (sizeof($va_results) && $this->numCriteria() > 0) {
                 $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ($vs_browse_type_limit_sql) {
                 $va_wheres[] = $vs_browse_type_limit_sql;
             }
             if ($t_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)";
             }
             if ($va_facet_info['relative_to']) {
                 if ($t_subject->hasField('deleted')) {
                     $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                     $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                     $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                 }
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             $vs_join_sql = join("\n", $va_joins);
             if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                 $vs_where_sql = ' AND (' . $vs_where_sql . ')';
             }
             if ($vb_check_availability_only) {
                 // exclude criteria values
                 $vs_criteria_exclude_sql = '';
                 if (is_array($va_criteria) && sizeof($va_criteria)) {
                     $vs_criteria_exclude_sql = ' AND (ca_attribute_values.value_longtext1 NOT IN (' . join(", ", caQuoteList(array_keys($va_criteria))) . ')) ';
                 }
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM ca_attributes\n\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t(ca_attribute_values.element_id = ?) {$vs_criteria_exclude_sql} {$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 2";
                 //print $vs_sql;
                 $qr_res = $this->opo_db->query($vs_sql, $vn_element_id);
                 return (int) $qr_res->numRows() > 1 ? true : false;
             } else {
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT value_longtext1, value_decimal1, value_longtext2, value_integer1\n\t\t\t\t\t\t\tFROM ca_attributes\n\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\tca_attribute_values.element_id = ? {$vs_where_sql}";
                 $qr_res = $this->opo_db->query($vs_sql, $vn_element_id);
                 $va_values = array();
                 $va_list_items = null;
                 $va_suppress_values = null;
                 if ($va_facet_info['suppress'] && !is_array($va_facet_info['suppress'])) {
                     $va_facet_info['suppress'] = array($va_facet_info['suppress']);
                 }
                 if (!is_array($va_suppress_values = caGetOption('suppress', $va_facet_info, null))) {
                     $va_suppress_values = caGetOption('exclude_values', $va_facet_info, null);
                 }
                 switch ($vn_element_type) {
                     case __CA_ATTRIBUTE_VALUE_LIST__:
                         $va_values = $qr_res->getAllFieldValues('value_longtext1');
                         $qr_res->seek(0);
                         $t_list_item = new ca_list_items();
                         $va_list_item_cache = $t_list_item->getFieldValuesForIDs($va_values, array('idno', 'item_value', 'parent_id', 'access'));
                         $va_list_child_count_cache = array();
                         if (is_array($va_list_item_cache)) {
                             foreach ($va_list_item_cache as $vn_id => $va_item) {
                                 if (!($vn_parent_id = $va_item['parent_id'])) {
                                     continue;
                                 }
                                 if (is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && !in_array($va_item['access'], $pa_options['checkAccess'])) {
                                     continue;
                                 }
                                 $va_list_child_count_cache[$vn_parent_id]++;
                             }
                         }
                         $va_list_label_cache = $t_list_item->getPreferredDisplayLabelsForIDs($va_values);
                         // Translate value idnos to ids
                         if (is_array($va_suppress_values)) {
                             $va_suppress_values = ca_lists::getItemIDsFromList($t_element->get('list_id'), $va_suppress_values);
                         }
                         $va_facet_list = array();
                         foreach ($va_values as $vn_val) {
                             if (!$vn_val) {
                                 continue;
                             }
                             if (is_array($va_suppress_values) && in_array($vn_val, $va_suppress_values)) {
                                 continue;
                             }
                             if (is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && !in_array($va_list_item_cache[$vn_val]['access'], $pa_options['checkAccess'])) {
                                 continue;
                             }
                             if ($va_criteria[$vn_val]) {
                                 continue;
                             }
                             // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                             $vn_child_count = isset($va_list_child_count_cache[$vn_val]) ? $va_list_child_count_cache[$vn_val] : 0;
                             $va_facet_list[$vn_val] = array('id' => $vn_val, 'label' => ($vs_label = html_entity_decode($va_list_label_cache[$vn_val])) ? $vs_label : _t('[BLANK]'), 'parent_id' => isset($va_list_item_cache[$vn_val]['parent_id']) ? $va_list_item_cache[$vn_val]['parent_id'] : null, 'child_count' => $vn_child_count);
                         }
                         if (!isset($va_facet_info['dont_expand_hierarchically']) || !$va_facet_info['dont_expand_hierarchically']) {
                             $t_rel_item = new ca_list_items();
                             $qr_res->seek(0);
                             $va_ids = $qr_res->getAllFieldValues($vs_rel_pk);
                             $qr_ancestors = call_user_func($t_rel_item->tableName() . '::getHierarchyAncestorsForIDs', $va_values, array('returnAs' => 'SearchResult'));
                             $vs_rel_table = $t_rel_item->tableName();
                             $vs_rel_pk = $t_rel_item->primaryKey();
                             $vb_check_ancestor_access = (bool) (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access'));
                             if ($qr_ancestors) {
                                 while ($qr_ancestors->nextHit()) {
                                     $vn_parent_type_id = $qr_ancestors->get('type_id');
                                     if (sizeof($va_exclude_types) > 0 && in_array($vn_parent_type_id, $va_exclude_types)) {
                                         continue;
                                     }
                                     if (sizeof($va_restrict_to_types) > 0 && !in_array($vn_parent_type_id, $va_restrict_to_types)) {
                                         continue;
                                     }
                                     if ($vb_check_ancestor_access && !in_array($qr_ancestors->get('access'), $pa_options['checkAccess'])) {
                                         continue;
                                     }
                                     if (!($vn_parent_id = $qr_ancestors->get("parent_id"))) {
                                         continue;
                                     }
                                     $va_facet_list[$vn_ancestor_id = (int) $qr_ancestors->get("{$vs_rel_pk}")] = array('id' => $vn_ancestor_id, 'label' => ($vs_label = $qr_ancestors->get('ca_list_items.preferred_labels.name_plural')) ? $vs_label : _t('[BLANK]'), 'parent_id' => $vn_parent_id, 'hierarchy_id' => $qr_ancestors->get('list_id'), 'child_count' => 1);
                                 }
                             }
                         }
                         // preserve order of list
                         return caSortArrayByKeyInValue($va_facet_list, array('label'));
                         break;
                     case __CA_ATTRIBUTE_VALUE_OBJECTS__:
                     case __CA_ATTRIBUTE_VALUE_ENTITIES__:
                     case __CA_ATTRIBUTE_VALUE_PLACES__:
                     case __CA_ATTRIBUTE_VALUE_OCCURRENCES__:
                     case __CA_ATTRIBUTE_VALUE_COLLECTIONS__:
                     case __CA_ATTRIBUTE_VALUE_LOANS__:
                     case __CA_ATTRIBUTE_VALUE_MOVEMENTS__:
                     case __CA_ATTRIBUTE_VALUE_STORAGELOCATIONS__:
                     case __CA_ATTRIBUTE_VALUE_OBJECTLOTS__:
                         if ($t_rel_item = AuthorityAttributeValue::elementTypeToInstance($vn_element_type)) {
                             $va_ids = $qr_res->getAllFieldValues('value_integer1');
                             $va_auth_items = $t_rel_item->getPreferredDisplayLabelsForIDs($va_ids);
                             $qr_res->seek(0);
                         }
                         break;
                     default:
                         if (isset($va_facet_info['suppress']) && is_array($va_facet_info['suppress'])) {
                             $va_suppress_values = $va_facet_info['suppress'];
                         }
                         break;
                 }
                 while ($qr_res->nextRow()) {
                     $o_attr = Attribute::getValueInstance($vn_element_type, $qr_res->getRow(), true);
                     if (!($vs_val = trim($o_attr->getDisplayValue()))) {
                         continue;
                     }
                     if (is_array($va_suppress_values) && in_array($vs_val, $va_suppress_values)) {
                         continue;
                     }
                     if ($va_criteria[$vs_val]) {
                         continue;
                     }
                     // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                     switch ($vn_element_type) {
                         case __CA_ATTRIBUTE_VALUE_LIST__:
                             $vn_child_count = 0;
                             if ($va_list_parent_ids[$vs_val]) {
                                 $vn_child_count++;
                             }
                             $va_values[$vs_val] = array('id' => str_replace('/', '&#47;', $vs_val), 'label' => html_entity_decode($va_list_items[$vs_val]['name_plural'] ? $va_list_items[$vs_val]['name_plural'] : $va_list_items[$vs_val]['item_value']), 'parent_id' => $va_list_items[$vs_val]['parent_id'], 'child_count' => $vn_child_count);
                             break;
                         case __CA_ATTRIBUTE_VALUE_OBJECTS__:
                         case __CA_ATTRIBUTE_VALUE_ENTITIES__:
                         case __CA_ATTRIBUTE_VALUE_PLACES__:
                         case __CA_ATTRIBUTE_VALUE_OCCURRENCES__:
                         case __CA_ATTRIBUTE_VALUE_COLLECTIONS__:
                         case __CA_ATTRIBUTE_VALUE_LOANS__:
                         case __CA_ATTRIBUTE_VALUE_MOVEMENTS__:
                         case __CA_ATTRIBUTE_VALUE_STORAGELOCATIONS__:
                         case __CA_ATTRIBUTE_VALUE_OBJECTLOTS__:
                             $vn_id = $qr_res->get('value_integer1');
                             $va_values[$vs_val] = array('id' => $vn_id, 'label' => html_entity_decode($va_auth_items[$vn_id] ? $va_auth_items[$vn_id] : $vs_val));
                             break;
                         case __CA_ATTRIBUTE_VALUE_LCSH__:
                             $va_values[$vs_val] = array('id' => str_replace('/', '&#47;', $vs_val), 'label' => preg_replace('![ ]*\\[[^\\]]*\\]!', '', $vs_val));
                             break;
                         case __CA_ATTRIBUTE_VALUE_CURRENCY__:
                             $va_values[sprintf("%014.2f", preg_replace("![\\D]+!", "", $vs_val))] = array('id' => str_replace('/', '&#47;', $vs_val), 'label' => $vs_val);
                             break;
                         default:
                             $va_values[$vs_val] = array('id' => str_replace('/', '&#47;', $vs_val), 'label' => $vs_val);
                             break;
                     }
                     if (!is_null($vs_single_value) && $vs_val == $vs_single_value) {
                         $vb_single_value_is_present = true;
                     }
                 }
                 if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                     return array();
                 }
                 ksort($va_values);
                 return $va_values;
             }
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'location':
             $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true);
             $vs_sort_field = null;
             if ($t_item->getProperty('ID_NUMBERING_ID_FIELD') == $vs_field_name) {
                 $vs_sort_field = $t_item->getProperty('ID_NUMBERING_SORT_FIELD');
             }
             $va_joins = array();
             $va_wheres = array();
             $vs_where_sql = '';
             $va_wheres[] = "({$vs_browse_table_name}.current_loc_class IS NOT NULL)";
             if (sizeof($va_results) && $this->numCriteria() > 0) {
                 $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ($vs_browse_type_limit_sql) {
                 $va_wheres[] = $vs_browse_type_limit_sql;
             }
             if ($t_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)";
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             $vs_join_sql = join("\n", $va_joins);
             if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                 $vs_where_sql = '(' . $vs_where_sql . ')';
             }
             if ($vb_check_availability_only) {
                 if (sizeof($va_criteria) > 0) {
                     return false;
                 }
                 // only one current location criteria allowed
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 2";
                 $qr_res = $this->opo_db->query($vs_sql);
                 if ($qr_res->nextRow()) {
                     return (int) $qr_res->numRows() > 0 ? true : false;
                 }
                 return false;
             } else {
                 if (sizeof($va_criteria) > 0) {
                     return array();
                 }
                 // only one current location criteria allowed
                 $vs_pk = $t_item->primaryKey();
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT {$vs_browse_table_name}.current_loc_class, {$vs_browse_table_name}.current_loc_subclass, {$vs_browse_table_name}.current_loc_id\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}";
                 if ($vs_sort_field) {
                     $vs_sql .= " ORDER BY {$vs_sort_field}";
                 }
                 $qr_res = $this->opo_db->query($vs_sql);
                 $va_collapse_map = $this->getCollapseMapForLocationFacet($va_facet_info);
                 $va_values = $va_values_by_table = array();
                 while ($qr_res->nextRow()) {
                     if (!($vs_loc_class = trim($qr_res->get('current_loc_class')))) {
                         continue;
                     }
                     if (!($vs_loc_subclass = trim($qr_res->get('current_loc_subclass')))) {
                         continue;
                     }
                     if (!($vs_loc_id = trim($qr_res->get('current_loc_id')))) {
                         continue;
                     }
                     $vs_val = "{$vs_loc_class}:{$vs_loc_subclass}:{$vs_loc_id}";
                     if ($va_criteria[$vs_val]) {
                         continue;
                     }
                     // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                     $va_values_by_table[$vs_loc_class][$vs_loc_subclass][$vs_loc_id] = true;
                 }
                 foreach ($va_values_by_table as $vs_loc_class => $va_loc_id_by_subclass) {
                     foreach ($va_loc_id_by_subclass as $vs_loc_subclass => $va_loc_ids) {
                         if (sizeof($va_tmp = array_keys($va_loc_ids))) {
                             $vs_loc_table_name = $this->opo_datamodel->getTableName($vs_loc_class);
                             if (($vs_table_name = $vs_loc_table_name) == 'ca_objects_x_storage_locations') {
                                 $vs_table_name = 'ca_storage_locations';
                             }
                             $qr_res = caMakeSearchResult($vs_table_name, $va_tmp);
                             if (isset($va_collapse_map[$vs_table_name]) && isset($va_collapse_map[$vs_table_name]['*']) && $va_collapse_map[$vs_table_name]['*']) {
                                 $va_values[$vs_id = "{$vs_loc_class}"] = array('id' => $vs_id, 'label' => $va_collapse_map[$vs_table_name]['*']);
                                 continue;
                             }
                             while ($qr_res->nextHit()) {
                                 $vn_id = $qr_res->getPrimaryKey();
                                 $va_config = ca_objects::getConfigurationForCurrentLocationType($vs_table_name, $vs_loc_subclass, array('facet' => isset($va_facet_info['display']) ? $va_facet_info['display'] : null));
                                 $vs_template = isset($va_config['template']) ? $va_config['template'] : "^{$vs_table_name}.preferred_labels";
                                 if (isset($va_collapse_map[$vs_table_name]) && isset($va_collapse_map[$vs_table_name][$vs_loc_subclass]) && $va_collapse_map[$vs_table_name][$vs_loc_subclass]) {
                                     $va_values[$vs_id = "{$vs_loc_class}:{$vs_loc_subclass}"] = array('id' => $vs_id, 'label' => $va_collapse_map[$vs_table_name][$vs_loc_subclass]);
                                     continue;
                                 }
                                 $va_values[$vs_id = "{$vs_loc_class}:{$vs_loc_subclass}:{$vn_id}"] = array('id' => $vs_id, 'label' => $qr_res->getWithTemplate($vs_template, $va_config));
                             }
                         }
                     }
                 }
                 if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                     return array();
                 }
                 return caSortArrayByKeyInValue($va_values, array('label'));
             }
             return array();
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'fieldList':
             $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true);
             $vs_field_name = $va_facet_info['field'];
             $va_field_info = $t_item->getFieldInfo($vs_field_name);
             $t_list = new ca_lists();
             $t_list_item = new ca_list_items();
             $va_joins = array();
             $va_wheres = array();
             $vs_where_sql = '';
             if (isset($va_field_info['LIST_CODE']) && ($vs_list_name = $va_field_info['LIST_CODE'])) {
                 // Handle fields containing ca_list_item.item_id's
                 $va_joins = array('INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $vs_field_name . ' = li.item_id', 'INNER JOIN ca_lists ON ca_lists.list_id = li.list_id');
                 if (sizeof($va_results) && $this->numCriteria() > 0) {
                     $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
                 }
                 if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                     $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
                     $va_wheres[] = "(li.access IN (" . join(',', $pa_options['checkAccess']) . "))";
                 }
                 if ($vs_browse_type_limit_sql) {
                     $va_wheres[] = $vs_browse_type_limit_sql;
                 }
                 if ($t_subject->hasField('deleted')) {
                     $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_facet_info['relative_to']) {
                     if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                         $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                         $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                     }
                 }
                 if (is_array($va_criteria) && sizeof($va_criteria)) {
                     $va_wheres[] = "(li.item_id NOT IN (" . join(",", caQuoteList(array_keys($va_criteria))) . "))";
                 }
                 if ($this->opo_config->get('perform_item_level_access_checking')) {
                     if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                         // Join to limit what browse table items are used to generate facet
                         $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                         $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t)";
                     }
                 }
                 $vs_join_sql = join("\n", $va_joins);
                 if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                     $vs_where_sql = ' AND (' . $vs_where_sql . ')';
                 }
                 if ($vb_check_availability_only) {
                     $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\tFROM ca_list_items li\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\tca_lists.list_code = ? {$vs_where_sql}\n\t\t\t\t\t\t\t\tLIMIT 2";
                     $qr_res = $this->opo_db->query($vs_sql, $vs_list_name);
                     return (int) $qr_res->numRows() > 1 ? true : false;
                 } else {
                     $va_orderbys = array();
                     // Get label ordering fields
                     if (isset($va_facet_info['order_by_label_fields']) && is_array($va_facet_info['order_by_label_fields']) && sizeof($va_facet_info['order_by_label_fields'])) {
                         $t_rel_item_label = new ca_list_item_labels();
                         foreach ($va_facet_info['order_by_label_fields'] as $vs_sort_by_field) {
                             if (!$t_rel_item_label->hasField($vs_sort_by_field)) {
                                 continue;
                             }
                             $va_orderbys[] = $va_label_selects[] = 'lil.' . $vs_sort_by_field;
                         }
                     } else {
                         $t_list->load(array('list_code' => $vs_list_name));
                         $vn_sort = $t_list->get('default_sort');
                         switch ($vn_sort) {
                             default:
                             case __CA_LISTS_SORT_BY_LABEL__:
                                 // by label
                                 $va_orderbys[] = 'lil.name_plural';
                                 break;
                             case __CA_LISTS_SORT_BY_RANK__:
                                 // by rank
                                 $va_orderbys[] = 'li.rank';
                                 break;
                             case __CA_LISTS_SORT_BY_VALUE__:
                                 // by value
                                 $va_orderbys[] = 'li.item_value';
                                 break;
                             case __CA_LISTS_SORT_BY_IDENTIFIER__:
                                 // by identifier
                                 $va_orderbys[] = 'li.idno_sort';
                                 break;
                         }
                     }
                     $vs_order_by = sizeof($va_orderbys) ? "ORDER BY " . join(', ', $va_orderbys) : '';
                     $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT DISTINCT lil.item_id, lil.name_singular, lil.name_plural, lil.locale_id\n\t\t\t\t\t\t\t\tFROM ca_list_items li\n\t\t\t\t\t\t\t\tINNER JOIN ca_list_item_labels AS lil ON lil.item_id = li.item_id\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\tca_lists.list_code = ?  AND lil.is_preferred = 1 {$vs_where_sql} {$vs_order_by}";
                     //print $vs_sql." [$vs_list_name]";
                     $qr_res = $this->opo_db->query($vs_sql, $vs_list_name);
                     $va_values = array();
                     while ($qr_res->nextRow()) {
                         $vn_id = $qr_res->get('item_id');
                         if ($va_criteria[$vn_id]) {
                             continue;
                         }
                         // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                         $va_values[$vn_id][$qr_res->get('locale_id')] = array('id' => $vn_id, 'label' => $qr_res->get('name_plural'));
                         if (!is_null($vs_single_value) && $vn_id == $vs_single_value) {
                             $vb_single_value_is_present = true;
                         }
                     }
                     if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                         return array();
                     }
                     return caExtractValuesByUserLocale($va_values);
                 }
             } else {
                 if ($vs_list_name = $va_field_info['LIST']) {
                     $va_list_items_by_value = array();
                     // fields with values set according to ca_list_items (not a foreign key ref)
                     if ($va_list_items = caExtractValuesByUserLocale($t_list->getItemsForList($vs_list_name))) {
                         foreach ($va_list_items as $vn_id => $va_list_item) {
                             $va_list_items_by_value[$va_list_item['item_value']] = $va_list_item['name_plural'];
                         }
                     } else {
                         foreach ($va_field_info['BOUNDS_CHOICE_LIST'] as $vs_val => $vn_id) {
                             $va_list_items_by_value[$vn_id] = $vs_val;
                         }
                     }
                     if (sizeof($va_results) && $this->numCriteria() > 0) {
                         $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
                     }
                     if ($vs_browse_type_limit_sql) {
                         $va_wheres[] = $vs_browse_type_limit_sql;
                     }
                     if ($t_subject->hasField('deleted')) {
                         $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                     }
                     if ($va_facet_info['relative_to']) {
                         if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                             $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                             $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                         }
                     }
                     if ($this->opo_config->get('perform_item_level_access_checking')) {
                         if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                             // Join to limit what browse table items are used to generate facet
                             $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                             $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t\t)";
                         }
                     }
                     if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                         $vs_where_sql = '(' . $vs_where_sql . ')';
                     }
                     $vs_join_sql = join("\n", $va_joins);
                     if ($vb_check_availability_only) {
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t" . ($vs_where_sql ? 'WHERE' : '') . "\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 2";
                         $qr_res = $this->opo_db->query($vs_sql);
                         return (int) $qr_res->numRows() > 1 ? true : false;
                     } else {
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT DISTINCT " . $vs_browse_table_name . '.' . $vs_field_name . "\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t" . ($vs_where_sql ? 'WHERE' : '') . "\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}";
                         //print $vs_sql." [$vs_list_name]";
                         $qr_res = $this->opo_db->query($vs_sql);
                         $va_values = array();
                         while ($qr_res->nextRow()) {
                             $vn_id = $qr_res->get($vs_field_name);
                             if ($va_criteria[$vn_id]) {
                                 continue;
                             }
                             // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                             if (isset($va_list_items_by_value[$vn_id])) {
                                 $va_values[$vn_id] = array('id' => $vn_id, 'label' => $va_list_items_by_value[$vn_id]);
                                 if (!is_null($vs_single_value) && $vn_id == $vs_single_value) {
                                     $vb_single_value_is_present = true;
                                 }
                             }
                         }
                         if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                             return array();
                         }
                         return $va_values;
                     }
                 } else {
                     if ($t_browse_table = $this->opo_datamodel->getInstanceByTableName($vs_facet_table = $va_facet_info['table'], true)) {
                         // Handle fields containing ca_list_item.item_id's
                         $va_joins = array('INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $vs_field_name . ' = ' . $vs_facet_table . '.' . $t_browse_table->primaryKey());
                         $vs_display_field_name = null;
                         if (method_exists($t_browse_table, 'getLabelTableInstance')) {
                             $t_label_instance = $t_browse_table->getLabelTableInstance();
                             $vs_display_field_name = isset($va_facet_info['display']) && $va_facet_info['display'] ? $va_facet_info['display'] : $t_label_instance->getDisplayField();
                             $va_joins[] = 'INNER JOIN ' . $t_label_instance->tableName() . " AS lab ON lab." . $t_browse_table->primaryKey() . ' = ' . $t_browse_table->tableName() . '.' . $t_browse_table->primaryKey();
                         }
                         if (sizeof($va_results) && $this->numCriteria() > 0) {
                             $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
                         }
                         if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                             $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
                         }
                         if ($vs_browse_type_limit_sql) {
                             $va_wheres[] = $vs_browse_type_limit_sql;
                         }
                         if ($va_facet_info['relative_to']) {
                             if ($t_subject->hasField('deleted')) {
                                 $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                             }
                             if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                                 $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                                 $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                             }
                         }
                         if ($this->opo_config->get('perform_item_level_access_checking')) {
                             if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                                 // Join to limit what browse table items are used to generate facet
                                 $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                                 $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t\t\t)";
                             }
                         }
                         $vs_join_sql = join("\n", $va_joins);
                         if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                             $vs_where_sql = 'WHERE (' . $vs_where_sql . ')';
                         }
                         if ($vb_check_availability_only) {
                             $vs_sql = "\n\t\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\t\tFROM {$vs_facet_table}\n\n\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\t\tLIMIT 1";
                             $qr_res = $this->opo_db->query($vs_sql);
                             return (int) $qr_res->numRows() > 0 ? true : false;
                         } else {
                             $vs_sql = "\n\t\t\t\t\t\t\t\t\t\tSELECT DISTINCT *\n\t\t\t\t\t\t\t\t\t\tFROM {$vs_facet_table}\n\n\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}";
                             //print $vs_sql;
                             $qr_res = $this->opo_db->query($vs_sql);
                             $va_values = array();
                             $vs_pk = $t_browse_table->primaryKey();
                             while ($qr_res->nextRow()) {
                                 $vn_id = $qr_res->get($vs_pk);
                                 if ($va_criteria[$vn_id]) {
                                     continue;
                                 }
                                 // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                                 $va_values[$vn_id][$qr_res->get('locale_id')] = array('id' => $vn_id, 'label' => $qr_res->get($vs_display_field_name));
                                 if (!is_null($vs_single_value) && $vn_id == $vs_single_value) {
                                     $vb_single_value_is_present = true;
                                 }
                             }
                             if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                                 return array();
                             }
                             return caExtractValuesByUserLocale($va_values);
                         }
                     }
                 }
             }
             return array();
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'field':
             $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true);
             if (!is_array($va_restrict_to_types = $va_facet_info['restrict_to_types'])) {
                 $va_restrict_to_types = array();
             }
             if (!is_array($va_restrict_to_types = $this->_convertTypeCodesToIDs($va_restrict_to_types, array('instance' => $t_item, 'dontExpandHierarchically' => true)))) {
                 $va_restrict_to_types = array();
             }
             $va_restrict_to_types_expanded = $this->_convertTypeCodesToIDs($va_restrict_to_types, array('instance' => $t_item));
             $vs_field_name = $va_facet_info['field'];
             $va_field_info = $t_item->getFieldInfo($vs_field_name);
             $vs_sort_field = null;
             if ($t_item->getProperty('ID_NUMBERING_ID_FIELD') == $vs_field_name) {
                 $vs_sort_field = $vs_browse_table_name . '.' . $t_item->getProperty('ID_NUMBERING_SORT_FIELD');
             }
             $t_list = new ca_lists();
             $t_list_item = new ca_list_items();
             $va_joins = array();
             $va_wheres = array();
             $vs_where_sql = '';
             $va_facet_values = null;
             if ($vb_is_bit = $va_field_info['FIELD_TYPE'] == FT_BIT) {
                 $vs_yes_text = caGetOption('label_yes', $va_facet_info, _t('Yes'));
                 $vs_no_text = caGetOption('label_no', $va_facet_info, _t('No'));
                 $va_facet_values = array(1 => array('id' => 1, 'label' => $vs_yes_text), 0 => array('id' => 0, 'label' => $vs_no_text));
             }
             if (is_array($va_restrict_to_types) && sizeof($va_restrict_to_types) > 0 && method_exists($t_rel_item, "getTypeList")) {
                 $va_wheres[] = "{$va_restrict_to_types_expanded}.type_id IN (" . join(',', caGetOption('dont_include_subtypes', $va_facet_info, false) ? $va_restrict_to_types : $va_restrict_to_types_expanded) . ")";
                 $va_selects[] = "{$va_restrict_to_types_expanded}.type_id";
             }
             if (sizeof($va_results) && $this->numCriteria() > 0) {
                 $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ($vs_browse_type_limit_sql) {
                 $va_wheres[] = $vs_browse_type_limit_sql;
             }
             if ($t_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)";
             }
             if ($va_facet_info['relative_to']) {
                 if ($t_subject->hasField('deleted')) {
                     $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                     $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                     $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                 }
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             $vs_join_sql = join("\n", $va_joins);
             if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                 $vs_where_sql = '(' . $vs_where_sql . ')';
             }
             if ($vb_check_availability_only) {
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT {$vs_browse_table_name}.{$vs_field_name}\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 2";
                 $qr_res = $this->opo_db->query($vs_sql);
                 if ($qr_res->numRows() > 1) {
                     return true;
                 }
                 return false;
             } else {
                 $vs_pk = $t_item->primaryKey();
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT {$vs_browse_table_name}.{$vs_field_name}\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}";
                 if ($vs_sort_field) {
                     $vs_sql .= " ORDER BY {$vs_sort_field}";
                 }
                 $qr_res = $this->opo_db->query($vs_sql);
                 $va_values = array();
                 while ($qr_res->nextRow()) {
                     if (!($vs_val = trim($qr_res->get($vs_field_name))) && !$vb_is_bit) {
                         continue;
                     }
                     if ($va_criteria[$vs_val]) {
                         continue;
                     }
                     // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                     if ($vb_is_bit && isset($va_facet_values[$vs_val])) {
                         $va_values[$vs_val] = $va_facet_values[$vs_val];
                     } else {
                         $va_values[$vs_val] = array('id' => str_replace('/', '&#47;', $vs_val), 'label' => $vs_val);
                     }
                     if (!is_null($vs_single_value) && $vs_val == $vs_single_value) {
                         $vb_single_value_is_present = true;
                     }
                 }
                 if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                     return array();
                 }
                 return $va_values;
             }
             return array();
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'violations':
             $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true);
             $vs_field_name = $va_facet_info['field'];
             $va_field_info = $t_item->getFieldInfo($vs_field_name);
             $va_joins = array();
             $va_wheres = array();
             $vs_where_sql = '';
             $va_facet_values = null;
             if (sizeof($va_results) && $this->numCriteria() > 0) {
                 $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ($vs_browse_type_limit_sql) {
                 $va_wheres[] = $vs_browse_type_limit_sql;
             }
             if ($t_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)";
             }
             if ($va_facet_info['relative_to']) {
                 if ($t_subject->hasField('deleted')) {
                     $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                     $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                     $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                 }
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             $vs_join_sql = join("\n", $va_joins);
             if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                 $vs_where_sql = '(' . $vs_where_sql . ')';
             }
             if ($vb_check_availability_only) {
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\tINNER JOIN ca_metadata_dictionary_rule_violations ON ca_metadata_dictionary_rule_violations.row_id = {$vs_browse_table_name}." . $t_item->primaryKey() . " AND ca_metadata_dictionary_rule_violations.table_num = {$vs_browse_table_num}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 2";
                 $qr_res = $this->opo_db->query($vs_sql);
                 if ($qr_res->nextRow()) {
                     return (int) $qr_res->numRows() > 0 ? true : false;
                 }
                 return false;
             } else {
                 $vs_pk = $t_item->primaryKey();
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT ca_metadata_dictionary_rules.rule_id\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\tINNER JOIN ca_metadata_dictionary_rule_violations ON ca_metadata_dictionary_rule_violations.row_id = {$vs_browse_table_name}." . $t_item->primaryKey() . " AND ca_metadata_dictionary_rule_violations.table_num = {$vs_browse_table_num}\n\t\t\t\t\t\t\tINNER JOIN ca_metadata_dictionary_rules ON ca_metadata_dictionary_rules.rule_id = ca_metadata_dictionary_rule_violations.rule_id\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}";
                 $qr_res = $this->opo_db->query($vs_sql);
                 $va_values = array();
                 $t_rule = new ca_metadata_dictionary_rules();
                 while ($qr_res->nextRow()) {
                     if ($t_rule->load($qr_res->get('rule_id'))) {
                         if (!($vs_val = trim($t_rule->getSetting('label')))) {
                             continue;
                         }
                         $vs_code = $t_rule->get('rule_code');
                         if ($va_criteria[$vs_val]) {
                             continue;
                         }
                         // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                         if (isset($va_facet_values[$vs_code])) {
                             $va_values[$vs_code] = $va_facet_values[$vs_code];
                         } else {
                             $va_values[$vs_code] = array('id' => $vs_code, 'label' => $vs_val);
                         }
                         if (!is_null($vs_single_value) && $vs_code == $vs_single_value) {
                             $vb_single_value_is_present = true;
                         }
                     }
                 }
                 if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                     return array();
                 }
                 return $va_values;
             }
             return array();
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'checkouts':
             if ($vs_browse_table_name != 'ca_objects') {
                 return array();
             }
             $t_item = new ca_objects();
             $va_joins = array();
             $va_wheres = array();
             $vs_where_sql = '';
             $va_facet_values = null;
             if (sizeof($va_results) && $this->numCriteria() > 0) {
                 $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ($vs_browse_type_limit_sql) {
                 $va_wheres[] = $vs_browse_type_limit_sql;
             }
             if ($t_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)";
             }
             if ($va_facet_info['relative_to']) {
                 if ($t_subject->hasField('deleted')) {
                     $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                     $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                     $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                 }
             }
             $vs_checkout_join_sql = "INNER JOIN ca_object_checkouts ON ca_object_checkouts.object_id = ca_objects.object_id";
             $vn_current_time = time();
             switch ($va_facet_info['status']) {
                 case 'overdue':
                     $va_wheres[] = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL) AND (ca_object_checkouts.due_date <= {$vn_current_time}))";
                     break;
                 case 'reserved':
                     $va_wheres[] = "((ca_object_checkouts.checkout_date IS NULL) AND (ca_object_checkouts.return_date IS NULL))";
                     break;
                 case 'available':
                     $vs_checkout_join_sql = '';
                     $va_wheres[] = "(ca_objects.object_id NOT IN (SELECT object_id FROM ca_object_checkouts WHERE (ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL)))";
                     break;
                 default:
                 case 'out':
                     $va_wheres[] = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL))";
                     break;
             }
             if ($vs_checkout_join_sql) {
                 $va_joins[] = $vs_checkout_join_sql;
                 $va_joins[] = "INNER JOIN ca_users ON ca_object_checkouts.user_id = ca_users.user_id";
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             $vs_join_sql = join("\n", $va_joins);
             if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                 $vs_where_sql = '(' . $vs_where_sql . ')';
             }
             if ($vb_check_availability_only) {
                 switch ($va_facet_info['mode']) {
                     case 'user':
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM ca_objects\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql} AND ca_objects.deleted = 0\n\t\t\t\t\t\t\t\t\tLIMIT 2";
                         break;
                     default:
                     case 'all':
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM ca_objects\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\tca_objects.deleted = 0 " . (sizeof($va_results) ? "AND (" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tLIMIT 2";
                         break;
                 }
                 $qr_res = $this->opo_db->query($vs_sql);
                 if ($qr_res->nextRow()) {
                     return (int) $qr_res->numRows() > 0 ? true : false;
                 }
                 return false;
             } else {
                 $va_values = array();
                 $vs_pk = $t_item->primaryKey();
                 switch ($va_facet_info['mode']) {
                     case 'user':
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT DISTINCT ca_object_checkouts.user_id, ca_users.fname, ca_users.lname, ca_users.email\n\t\t\t\t\t\t\t\t\tFROM ca_objects\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql} " . (sizeof($va_results) ? " AND (" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))" : "");
                         $qr_res = $this->opo_db->query($vs_sql);
                         while ($qr_res->nextRow()) {
                             $vn_user_id = $qr_res->get('user_id');
                             $vs_val = $qr_res->get('fname') . ' ' . $qr_res->get('lname') . (($vs_email = $qr_res->get('email')) ? "({$vs_email})" : '');
                             if ($va_criteria[$vs_val]) {
                                 continue;
                             }
                             // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                             if (isset($va_facet_values[$vn_user_id])) {
                                 $va_values[$vn_user_id] = $va_facet_values[$vn_user_id];
                             } else {
                                 $va_values[$vn_user_id] = array('id' => $vn_user_id, 'label' => $vs_val);
                             }
                             if (!is_null($vs_single_value) && $vn_user_id == $vs_single_value) {
                                 $vb_single_value_is_present = true;
                             }
                         }
                         break;
                     case 'all':
                     default:
                         foreach (array(_t('Available') => 'available', _t('Out') => 'out', _t('Reserved') => 'reserved', _t('Overdue') => 'overdue') as $vs_status_text => $vs_status) {
                             $vs_join_sql = "INNER JOIN ca_object_checkouts ON ca_object_checkouts.object_id = ca_objects.object_id";
                             switch ($vs_status) {
                                 case 'overdue':
                                     $vs_where = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL) AND (ca_object_checkouts.due_date <= {$vn_current_time}))";
                                     break;
                                 case 'reserved':
                                     $vs_where = "((ca_object_checkouts.checkout_date IS NULL) AND (ca_object_checkouts.return_date IS NULL))";
                                     break;
                                 case 'available':
                                     $vs_join_sql = '';
                                     $vs_where = "(ca_objects.object_id NOT IN (SELECT object_id FROM ca_object_checkouts WHERE (ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL)))";
                                     break;
                                 default:
                                 case 'out':
                                     $vs_where = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL))";
                                     break;
                             }
                             if (sizeof($va_results) && $this->numCriteria() > 0) {
                                 $vs_where .= " AND (" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
                             }
                             $vs_sql = "\n\t\t\t\t\t\t\t\t\t\tSELECT count(*) c\n\t\t\t\t\t\t\t\t\t\tFROM ca_objects\n\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t{$vs_where}\n\t\t\t\t\t\t\t\t\t";
                             $qr_res = $this->opo_db->query($vs_sql);
                             $qr_res->nextRow();
                             if (!$qr_res->get('c')) {
                                 continue;
                             }
                             $va_values[$vs_status] = array('id' => $vs_status, 'label' => $vs_status_text);
                             if (!is_null($vs_single_value) && $vs_status == $vs_single_value) {
                                 $vb_single_value_is_present = true;
                             }
                         }
                         break;
                 }
                 if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                     return array();
                 }
                 return $va_values;
             }
             return array();
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'normalizedDates':
             $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true);
             $t_element = new ca_metadata_elements();
             $vb_is_element = $vb_is_field = false;
             if (!($vb_is_element = $t_element->load(array('element_code' => $va_facet_info['element_code']))) && !($vb_is_field = $t_item->hasField($va_facet_info['element_code']) && $t_item->getFieldInfo($va_facet_info['element_code'], 'FIELD_TYPE') === FT_HISTORIC_DATERANGE)) {
                 return array();
             }
             if ($vb_is_element) {
                 $va_joins = array('INNER JOIN ca_attribute_values ON ca_attributes.attribute_id = ca_attribute_values.attribute_id', 'INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_attributes.row_id AND ca_attributes.table_num = ' . intval($vs_browse_table_num));
             } else {
                 $va_joins = array();
             }
             $va_wheres = array();
             $vs_normalization = $va_facet_info['normalization'];
             // how do we construct the date ranges presented to uses. In other words - how do we want to allow users to browse dates? By year, decade, century?
             if (sizeof($va_results) && $this->numCriteria() > 0) {
                 $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ($vs_browse_type_limit_sql) {
                 $va_wheres[] = $vs_browse_type_limit_sql;
             }
             if ($t_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)";
             }
             if ($va_facet_info['relative_to']) {
                 if ($t_subject->hasField('deleted')) {
                     $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                     $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                     $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                 }
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             $vs_where_sql = '';
             if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                 $vs_where_sql = ' AND (' . $vs_where_sql . ')';
             }
             $vs_join_sql = join("\n", $va_joins);
             if ($vb_is_element) {
                 $vn_element_id = $t_element->getPrimaryKey();
                 $vs_dir = strtoupper($va_facet_info['sort']) === 'DESC' ? "DESC" : "ASC";
                 $o_tep = new TimeExpressionParser();
                 $vn_min_date = $vn_max_date = null;
                 $vs_min_sql = $vs_max_sql = '';
                 if (isset($va_facet_info['minimum_date'])) {
                     if ($o_tep->parse($va_facet_info['minimum_date'])) {
                         $va_tmp = $o_tep->getHistoricTimestamps();
                         $vn_min_date = (double) $va_tmp['start'];
                         $vs_min_sql = " AND (ca_attribute_values.value_decimal1 >= {$vn_min_date})";
                     }
                 }
                 if (isset($va_facet_info['maximum_date'])) {
                     if ($o_tep->parse($va_facet_info['maximum_date'])) {
                         $va_tmp = $o_tep->getHistoricTimestamps();
                         $vn_max_date = (double) $va_tmp['end'];
                         $vs_max_sql = " AND (ca_attribute_values.value_decimal2 <= {$vn_max_date})";
                     }
                 }
                 if ($vb_check_availability_only) {
                     $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\tca_attribute_values.element_id = ?\n\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 1";
                     //print $vs_sql;
                     $qr_res = $this->opo_db->query($vs_sql, $vn_element_id);
                     return (int) $qr_res->numRows() > 0 ? true : false;
                 } else {
                     $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT DISTINCT ca_attribute_values.value_decimal1, ca_attribute_values.value_decimal2\n\t\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\tca_attribute_values.element_id = ?\n\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t";
                     //print $vs_sql;
                     $qr_res = $this->opo_db->query($vs_sql, $vn_element_id);
                     $vn_current_year = (int) date("Y");
                     $va_values = array();
                     $vb_include_unknown = (bool) caGetOption('include_unknown', $va_facet_info, false);
                     $vb_unknown_is_set = false;
                     while ($qr_res->nextRow()) {
                         $vn_start = $qr_res->get('value_decimal1');
                         $vn_end = $qr_res->get('value_decimal2');
                         if (!($vn_start && $vn_end)) {
                             if ($vb_include_unknown) {
                                 $vb_unknown_is_set = true;
                             }
                             continue;
                         }
                         if ($vn_end > $vn_current_year + 50) {
                             continue;
                         }
                         // bad years can make for large facets that cause timeouts so cut it off 50 years into the future
                         $va_normalized_values = $o_tep->normalizeDateRange($vn_start, $vn_end, $vs_normalization);
                         foreach ($va_normalized_values as $vn_sort_value => $vs_normalized_value) {
                             if ($va_criteria[$vs_normalized_value]) {
                                 continue;
                             }
                             // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                             if (is_numeric($vs_normalized_value) && (int) $vs_normalized_value === 0) {
                                 continue;
                             }
                             // don't include year=0
                             $va_values[$vn_sort_value][$vs_normalized_value] = array('id' => $vs_normalized_value, 'label' => $vs_normalized_value);
                             if (!is_null($vs_single_value) && $vs_normalized_value == $vs_single_value) {
                                 $vb_single_value_is_present = true;
                             }
                         }
                     }
                     if ($vb_include_unknown && !$vb_unknown_is_set) {
                         // Check for rows where no data is set at all as opposed to null dates
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT DISTINCT ca_attributes.row_id\n\t\t\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\tca_attribute_values.element_id = ?\n\t\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t";
                         //print $vs_sql;
                         $qr_res = $this->opo_db->query($vs_sql, $vn_element_id);
                         if ($qr_res->numRows() < sizeof($va_results)) {
                             $vb_unknown_is_set = true;
                         }
                     }
                     if ($vb_unknown_is_set && sizeof($va_values) > 0) {
                         $va_values['999999999'][_t('Date unknown')] = array('id' => 'null', 'label' => _t('Date unknown'));
                     }
                     if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                         return array();
                     }
                     ksort($va_values);
                     if ($vs_dir == 'DESC') {
                         $va_values = array_reverse($va_values);
                     }
                     $va_sorted_values = array();
                     foreach ($va_values as $vn_sort_value => $va_values_for_sort_value) {
                         $va_sorted_values = array_merge($va_sorted_values, $va_values_for_sort_value);
                     }
                     return $va_sorted_values;
                 }
             } else {
                 // is intrinsic
                 $vs_dir = strtoupper($va_facet_info['sort']) === 'DESC' ? "DESC" : "ASC";
                 $vs_browse_start_fld = $t_item->getFieldInfo($va_facet_info['element_code'], 'START');
                 $vs_browse_end_fld = $t_item->getFieldInfo($va_facet_info['element_code'], 'END');
                 $o_tep = new TimeExpressionParser();
                 $vn_min_date = $vn_max_date = null;
                 $vs_min_sql = $vs_max_sql = '';
                 if (isset($va_facet_info['minimum_date'])) {
                     if ($o_tep->parse($va_facet_info['minimum_date'])) {
                         $va_tmp = $o_tep->getHistoricTimestamps();
                         $vn_min_date = (double) $va_tmp['start'];
                         $vs_min_sql = " AND ({$vs_browse_table_name}.{$vs_browse_start_fld} >= {$vn_min_date})";
                     }
                 }
                 if (isset($va_facet_info['maximum_date'])) {
                     if ($o_tep->parse($va_facet_info['maximum_date'])) {
                         $va_tmp = $o_tep->getHistoricTimestamps();
                         $vn_max_date = (double) $va_tmp['end'];
                         $vs_max_sql = " AND ({$vs_browse_table_name}.{$vs_browse_end_fld} <= {$vn_max_date})";
                     }
                 }
                 if ($vb_check_availability_only) {
                     $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t1 = 1\n\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 1";
                     //print $vs_sql;
                     $qr_res = $this->opo_db->query($vs_sql);
                     return (int) $qr_res->numRows() > 0 ? true : false;
                 } else {
                     $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT DISTINCT {$vs_browse_table_name}.{$vs_browse_start_fld}, {$vs_browse_table_name}.{$vs_browse_end_fld}\n\t\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t1 = 1\n\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t";
                     //print $vs_sql;
                     $qr_res = $this->opo_db->query($vs_sql);
                     $va_values = array();
                     while ($qr_res->nextRow()) {
                         $vn_start = $qr_res->get($vs_browse_start_fld);
                         $vn_end = $qr_res->get($vs_browse_end_fld);
                         if (!($vn_start && $vn_end)) {
                             continue;
                         }
                         $va_normalized_values = $o_tep->normalizeDateRange($vn_start, $vn_end, $vs_normalization);
                         foreach ($va_normalized_values as $vn_sort_value => $vs_normalized_value) {
                             if ($va_criteria[$vs_normalized_value]) {
                                 continue;
                             }
                             // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                             if (is_numeric($vs_normalized_value) && (int) $vs_normalized_value === 0) {
                                 continue;
                             }
                             // don't include year=0
                             $va_values[$vn_sort_value][$vs_normalized_value] = array('id' => $vs_normalized_value, 'label' => $vs_normalized_value);
                             if (!is_null($vs_single_value) && $vs_normalized_value == $vs_single_value) {
                                 $vb_single_value_is_present = true;
                             }
                         }
                     }
                     if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                         return array();
                     }
                     ksort($va_values);
                     if ($vs_dir == 'DESC') {
                         $va_values = array_reverse($va_values);
                     }
                     $va_sorted_values = array();
                     foreach ($va_values as $vn_sort_value => $va_values_for_sort_value) {
                         $va_sorted_values = array_merge($va_sorted_values, $va_values_for_sort_value);
                     }
                     return $va_sorted_values;
                 }
             }
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'normalizedLength':
             $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true);
             $t_element = new ca_metadata_elements();
             $vb_is_element = $vb_is_field = false;
             if (!($vb_is_element = $t_element->load(array('element_code' => $va_facet_info['element_code']))) && !($vb_is_field = $t_item->hasField($va_facet_info['element_code']) && $t_item->getFieldInfo($va_facet_info['element_code'], 'FIELD_TYPE') === FT_HISTORIC_DATERANGE)) {
                 return array();
             }
             if ($vb_is_element) {
                 $va_joins = array('INNER JOIN ca_attribute_values ON ca_attributes.attribute_id = ca_attribute_values.attribute_id', 'INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_attributes.row_id AND ca_attributes.table_num = ' . intval($vs_browse_table_num));
             } else {
                 $va_joins = array();
             }
             $va_wheres = array();
             $vs_normalization = $va_facet_info['normalization'];
             // how do we construct the dimensions ranges presented to users. In other words - what increments do we can to use to  browse measurments?
             if (sizeof($va_results) && $this->numCriteria() > 0) {
                 $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ($vs_browse_type_limit_sql) {
                 $va_wheres[] = $vs_browse_type_limit_sql;
             }
             if ($t_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)";
             }
             if ($va_facet_info['relative_to']) {
                 if ($t_subject->hasField('deleted')) {
                     $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                     $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                     $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                 }
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             $vs_where_sql = '';
             if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) {
                 $vs_where_sql = ' AND (' . $vs_where_sql . ')';
             }
             $vs_join_sql = join("\n", $va_joins);
             $vn_element_id = $t_element->getPrimaryKey();
             $vs_dir = strtoupper($va_facet_info['sort']) === 'DESC' ? "DESC" : "ASC";
             $vs_min_sql = $vs_max_sql = '';
             $vo_minimum_dimension = caParseLengthDimension(caGetOption('minimum_dimension', $va_facet_info, "0 in"));
             $vo_maximum_dimension = caParseLengthDimension(caGetOption('maximum_dimension', $va_facet_info, "0 in"));
             if ($vo_minimum_dimension) {
                 $vn_tmp = (double) $vo_minimum_dimension->convertTo('METER', 6, 'en_US');
                 $vs_min_sql = " AND (ca_attribute_values.value_decimal1 >= {$vn_tmp})";
             }
             if (caGetOption('maximum_dimension', $va_facet_info, null) && $vo_maximum_dimension) {
                 $vn_tmp = (double) $vo_maximum_dimension->convertTo('METER', 6, 'en_US');
                 $vs_max_sql = " AND (ca_attribute_values.value_decimal1 <= {$vn_tmp})";
             }
             if ($vb_check_availability_only) {
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\tca_attribute_values.element_id = ?\n\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\tLIMIT 1";
                 //print $vs_sql;
                 $qr_res = $this->opo_db->query($vs_sql, $vn_element_id);
                 return (int) $qr_res->numRows() > 0 ? true : false;
             } else {
                 $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT ca_attribute_values.value_decimal1, ca_attribute_values.value_decimal2, ca_attribute_values.value_longtext1, ca_attribute_values.value_longtext2\n\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\tca_attribute_values.element_id = ?\n\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t";
                 //print $vs_sql;
                 $qr_res = $this->opo_db->query($vs_sql, $vn_element_id);
                 $va_values = array();
                 if (!($vs_output_units = caGetLengthUnitType($vs_units = caGetOption('units', $va_facet_info, 'm')))) {
                     $vs_output_units = Zend_Measure_Length::METER;
                 }
                 $vs_increment = caGetOption('increment', $va_facet_info, '1 m');
                 $vo_increment = caParseLengthDimension($vs_increment);
                 $vn_increment_in_current_units = (double) $vo_increment->convertTo($vs_output_units, 6, 'en_US');
                 while ($qr_res->nextRow()) {
                     $vn_meters = $qr_res->get('value_decimal1');
                     // measurement in meters
                     // convert to target dimensions
                     // normalize
                     $vo_dim = new Zend_Measure_Length($vn_meters, Zend_Measure_Length::METER, 'en_US');
                     $vs_dim = $vo_dim->convertTo($vs_output_units, 6, 'en_US');
                     $vn_dim = (double) $vs_dim;
                     $vn_normalized = floor($vn_dim / $vn_increment_in_current_units) * $vn_increment_in_current_units;
                     if (isset($va_criteria[$vn_normalized])) {
                         continue;
                     }
                     $vs_normalized_range_with_units = "{$vn_normalized} {$vs_units} - " . ($vn_normalized + $vn_increment_in_current_units) . " {$vs_units}";
                     $va_values[$vn_normalized][$vn_normalized] = array('id' => $vn_normalized, 'label' => $vs_normalized_range_with_units);
                     if (!is_null($vs_single_value) && $vn_normalized == $vs_single_value) {
                         $vb_single_value_is_present = true;
                     }
                 }
                 if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                     return array();
                 }
                 ksort($va_values);
                 if ($vs_dir == 'DESC') {
                     $va_values = array_reverse($va_values);
                 }
                 $va_sorted_values = array();
                 foreach ($va_values as $vn_sort_value => $va_values_for_sort_value) {
                     $va_sorted_values = array_merge($va_sorted_values, $va_values_for_sort_value);
                 }
                 return $va_sorted_values;
             }
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         case 'authority':
             $vs_rel_table_name = $va_facet_info['table'];
             $va_params = $this->opo_ca_browse_cache->getParameters();
             // Make sure we honor type restrictions for the related authority
             $va_user_type_restrictions = caGetTypeRestrictionsForUser($vs_rel_table_name);
             $va_restrict_to_types = $va_facet_info['restrict_to_types'];
             if (is_array($va_user_type_restrictions)) {
                 if (!is_array($va_restrict_to_types)) {
                     $va_restrict_to_types = $va_user_type_restrictions;
                 } else {
                     $va_restrict_to_types = array_intersect($va_restrict_to_types, $va_user_type_restrictions);
                 }
             }
             if (!is_array($va_exclude_types = $va_facet_info['exclude_types'])) {
                 $va_exclude_types = array();
             }
             if (!is_array($va_restrict_to_relationship_types = $va_facet_info['restrict_to_relationship_types'])) {
                 $va_restrict_to_relationship_types = array();
             }
             if (!is_array($va_exclude_relationship_types = $va_facet_info['exclude_relationship_types'])) {
                 $va_exclude_relationship_types = array();
             }
             $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true);
             if ($vs_browse_table_name == $vs_rel_table_name) {
                 // browsing on self-relations not supported
                 break;
             } else {
                 switch (sizeof($va_path = array_keys($this->opo_datamodel->getPath($vs_browse_table_name, $vs_rel_table_name)))) {
                     case __CA_ATTRIBUTE_VALUE_LIST__:
                         $t_item_rel = $this->opo_datamodel->getInstanceByTableName($va_path[1], true);
                         $t_rel_item = $this->opo_datamodel->getInstanceByTableName($va_path[2], true);
                         $vs_key = 'relation_id';
                         break;
                     case __CA_ATTRIBUTE_VALUE_DATERANGE__:
                         $t_item_rel = null;
                         $t_rel_item = $this->opo_datamodel->getInstanceByTableName($va_path[1], true);
                         $vs_key = $t_rel_item->primaryKey();
                         break;
                     default:
                         // bad related table
                         return null;
                         break;
                 }
             }
             $vb_rel_is_hierarchical = (bool) $t_rel_item->isHierarchical();
             //
             // Convert related item type_code specs in restrict_to_types and exclude_types lists to numeric type_ids we need for the query
             //
             if (!is_array($va_restrict_to_types = $this->_convertTypeCodesToIDs($va_restrict_to_types, array('instance' => $t_rel_item, 'dontExpandHierarchically' => true)))) {
                 $va_restrict_to_types = array();
             }
             if (!is_array($va_exclude_types = $this->_convertTypeCodesToIDs($va_exclude_types, array('instance' => $t_rel_item, 'dontExpandHierarchically' => true)))) {
                 $va_exclude_types = array();
             }
             $va_restrict_to_types_expanded = $this->_convertTypeCodesToIDs($va_restrict_to_types, array('instance' => $t_rel_item));
             $va_exclude_types_expanded = $this->_convertTypeCodesToIDs($va_exclude_types, array('instance' => $t_rel_item));
             // look up relationship type restrictions
             $va_restrict_to_relationship_types = $this->_getRelationshipTypeIDs($va_restrict_to_relationship_types, $va_facet_info['relationship_table']);
             $va_exclude_relationship_types = $this->_getRelationshipTypeIDs($va_exclude_relationship_types, $va_facet_info['relationship_table']);
             $va_joins = array();
             $va_selects = array();
             $va_wheres = array();
             $va_orderbys = array();
             if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) {
                 $vs_cur_table = array_shift($va_path);
                 foreach ($va_path as $vs_join_table) {
                     $va_rel_info = $this->opo_datamodel->getRelationships($vs_cur_table, $vs_join_table);
                     $va_joins[] = 'INNER JOIN ' . $vs_join_table . ' ON ' . $vs_cur_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][0] . ' = ' . $vs_join_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][1] . "\n";
                     $vs_cur_table = $vs_join_table;
                 }
             } else {
                 if ($va_facet_info['show_all_when_first_facet']) {
                     $va_path = array_reverse($va_path);
                     // in "show_all" mode we turn the browse on it's head and grab records by the "subject" table, rather than the browse table
                     $vs_cur_table = array_shift($va_path);
                     $vs_join_table = $va_path[0];
                     $va_rel_info = $this->opo_datamodel->getRelationships($vs_cur_table, $vs_join_table);
                     $va_joins[] = 'LEFT JOIN ' . $vs_join_table . ' ON ' . $vs_cur_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][0] . ' = ' . $vs_join_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][1] . "\n";
                 }
             }
             if (sizeof($va_results) && $this->numCriteria() > 0) {
                 $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))";
             }
             if (!is_array($va_restrict_to_lists = $va_facet_info['restrict_to_lists'])) {
                 $va_restrict_to_lists = array();
             }
             if (is_array($va_restrict_to_lists) && sizeof($va_restrict_to_lists) > 0 && $t_rel_item->tableName() == 'ca_list_items') {
                 $va_list_ids = array();
                 foreach ($va_restrict_to_lists as $vm_list) {
                     if (is_numeric($vm_list)) {
                         $vn_list_id = (int) $vm_list;
                     } else {
                         $vn_list_id = (int) ca_lists::getListID($vm_list);
                     }
                     if ($vn_list_id) {
                         $va_list_ids[] = $vn_list_id;
                     }
                 }
                 if (sizeof($va_list_ids) > 0) {
                     $va_wheres[] = "{$vs_rel_table_name}.list_id IN (" . join(',', $va_list_ids) . ")";
                 }
             }
             if (is_array($va_restrict_to_types) && sizeof($va_restrict_to_types) > 0 && method_exists($t_rel_item, "getTypeList")) {
                 $va_wheres[] = "{$vs_rel_table_name}.type_id IN (" . join(',', caGetOption('dont_include_subtypes', $va_facet_info, false) ? $va_restrict_to_types : $va_restrict_to_types_expanded) . ")" . ($t_rel_item->getFieldInfo('type_id', 'IS_NULL') ? " OR ({$vs_rel_table_name}.type_id IS NULL)" : '');
                 $va_selects[] = "{$vs_rel_table_name}.type_id";
             }
             if (is_array($va_exclude_types) && sizeof($va_exclude_types) > 0 && method_exists($t_rel_item, "getTypeList")) {
                 $va_wheres[] = "{$vs_rel_table_name}.type_id NOT IN (" . join(',', caGetOption('dont_include_subtypes', $va_facet_info, false) ? $va_exclude_types : $va_exclude_types_expanded) . ")";
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access')) {
                 $va_wheres[] = "(" . $t_rel_item->tableName() . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
                 // exclude non-accessible authority items
                 if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) {
                     $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
                     // exclude non-accessible browse items
                 }
             }
             if ($t_item->hasField('deleted') && !$va_facet_info['show_all_when_first_facet']) {
                 $va_wheres[] = "(" . $t_item->tableName() . ".deleted = 0)";
             }
             if ($t_rel_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $t_rel_item->tableName() . ".deleted = 0)";
             }
             $vs_rel_pk = $t_rel_item->primaryKey();
             $va_rel_attr_elements = $t_rel_item->getApplicableElementCodes(null, true, false);
             $va_attrs_to_fetch = array();
             if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) {
                 //$va_selects[] = $t_item->tableName().'.'.$t_item->primaryKey();			// get primary key of subject
             }
             $va_selects[] = $t_rel_item->tableName() . '.' . $vs_rel_pk;
             // get primary key of related
             $vs_hier_parent_id_fld = $vs_hier_id_fld = null;
             if ($vb_rel_is_hierarchical) {
                 $vs_hier_parent_id_fld = $t_rel_item->getProperty('HIERARCHY_PARENT_ID_FLD');
                 $va_selects[] = $t_rel_item->tableName() . '.' . $vs_hier_parent_id_fld;
                 if ($vs_hier_id_fld = $t_rel_item->getProperty('HIERARCHY_ID_FLD')) {
                     $va_selects[] = $t_rel_item->tableName() . '.' . $vs_hier_id_fld;
                 }
             }
             // analyze group_fields (if defined) and add them to the query
             $va_groupings_to_fetch = array();
             if (isset($va_facet_info['groupings']) && is_array($va_facet_info['groupings']) && sizeof($va_facet_info['groupings'])) {
                 foreach ($va_facet_info['groupings'] as $vs_grouping => $vs_grouping_name) {
                     // is grouping type_id?
                     if ($vs_grouping === 'type' && $t_rel_item->hasField('type_id')) {
                         $va_selects[] = $t_rel_item->tableName() . '.type_id';
                         $va_groupings_to_fetch[] = 'type_id';
                     }
                     // is group field a relationship type?
                     if ($vs_grouping === 'relationship_types') {
                         $va_selects[] = $va_facet_info['relationship_table'] . '.type_id rel_type_id';
                         $va_groupings_to_fetch[] = 'rel_type_id';
                     }
                     // is group field an attribute?
                     if (preg_match('!^ca_attribute_([^:]*)!', $vs_grouping, $va_matches)) {
                         if ($vn_element_id = array_search($va_matches[1], $va_rel_attr_elements)) {
                             $va_attrs_to_fetch[] = $vn_element_id;
                         }
                     }
                 }
             }
             if ($va_facet_info['relative_to']) {
                 // TODO: do this everywhere
                 $va_restrict_to_relationship_types = array();
                 $vs_browse_type_limit_sql = '';
                 if ($t_subject->hasField('deleted')) {
                     $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)";
                 }
                 if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) {
                     $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']);
                     $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']);
                 }
             }
             if (sizeof($va_restrict_to_relationship_types) > 0 && is_object($t_item_rel)) {
                 $va_wheres[] = $t_item_rel->tableName() . ".type_id IN (" . join(',', $va_restrict_to_relationship_types) . ")";
             }
             if (sizeof($va_exclude_relationship_types) > 0 && is_object($t_item_rel)) {
                 $va_wheres[] = $t_item_rel->tableName() . ".type_id NOT IN (" . join(',', $va_exclude_relationship_types) . ")";
             }
             if ($vs_browse_type_limit_sql) {
                 $va_wheres[] = $vs_browse_type_limit_sql;
             }
             if ($this->opo_config->get('perform_item_level_access_checking')) {
                 if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) {
                     // Join to limit what browse table items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                     // Join to limit what related items are used to generate facet
                     $va_joins[] = 'LEFT JOIN ca_acl AS rel_acl ON ' . $t_rel_item->tableName() . '.' . $t_rel_item->primaryKey() . ' = rel_acl.row_id AND rel_acl.table_num = ' . $t_rel_item->tableNum() . "\n";
                     $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(rel_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(rel_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(rel_acl.user_id IS NULL and rel_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND rel_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR rel_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)";
                 }
             }
             if (sizeof($va_criteria) > 0) {
                 $va_wheres[] = "(" . $t_rel_item->tableName() . "." . $t_rel_item->primaryKey() . " NOT IN (" . join(",", caQuoteList(array_map(intval, array_keys($va_criteria)))) . "))";
             }
             $vs_join_sql = join("\n", $va_joins);
             if ($vb_check_availability_only) {
                 if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) {
                     $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t" . (sizeof($va_wheres) ? ' WHERE ' : '') . join(" AND ", $va_wheres) . " LIMIT 1";
                 } else {
                     $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM " . $t_rel_item->tableName() . "\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t" . (sizeof($va_wheres) ? ' WHERE ' : '') . join(" AND ", $va_wheres) . " LIMIT 1";
                 }
                 $qr_res = $this->opo_db->query($vs_sql);
                 //print "<hr>$vs_sql<hr>\n";
                 return (int) $qr_res->numRows() > 0 ? true : false;
             } else {
                 if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) {
                     $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT " . join(', ', $va_selects) . "\n\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t" . (sizeof($va_wheres) ? ' WHERE ' : '') . join(" AND ", $va_wheres) . "\n\t\t\t\t\t\t\t\t" . (sizeof($va_orderbys) ? "ORDER BY " . join(', ', $va_orderbys) : '');
                 } else {
                     $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT " . join(', ', $va_selects) . "\n\t\t\t\t\t\t\tFROM " . $t_rel_item->tableName() . "\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t" . (sizeof($va_wheres) ? ' WHERE ' : '') . join(" AND ", $va_wheres) . "\n\t\t\t\t\t\t\t\t" . (sizeof($va_orderbys) ? "ORDER BY " . join(', ', $va_orderbys) : '');
                 }
                 //print "<hr>$vs_sql<hr>\n";
                 $qr_res = $this->opo_db->query($vs_sql);
                 $va_facet = $va_facet_items = array();
                 $vs_rel_pk = $t_rel_item->primaryKey();
                 // First get related ids with type and relationship type values
                 // (You could get all of the data we need for the facet in a single query but it turns out to be faster for very large facets to
                 // do it in separate queries, one for the primary ids and another for the labels; a third is done if attributes need to be fetched.
                 // There appears to be a significant [~10%] performance for smaller facets and a larger one [~20-25%] for very large facets)
                 $vn_max_level = caGetOption('maximum_levels', $va_facet_info, null);
                 while ($qr_res->nextRow()) {
                     $va_fetched_row = $qr_res->getRow();
                     $vn_id = $va_fetched_row[$vs_rel_pk];
                     //if (isset($va_facet_items[$vn_id])) { continue; } --- we can't do this as then we don't detect items that have multiple rel_type_ids... argh.
                     if (isset($va_criteria[$vn_id])) {
                         continue;
                     }
                     // skip items that are used as browse critera - don't want to browse on something you're already browsing on
                     if (!$va_facet_items[$va_fetched_row[$vs_rel_pk]]) {
                         // if(!is_null($vn_max_level)) {
                         // 									if (sizeof($va_ancestors) + 1 > $vn_max_level) {
                         // 										if ($va_tmp = $va_ancestors[sizeof($va_ancestors) - $vn_max_level]) {
                         // 											$va_ancestors = array();
                         // 											$va_fetched_row = $va_tmp['NODE'];
                         // 										}
                         // 									}
                         // 								}
                         if (is_array($va_restrict_to_types) && sizeof($va_restrict_to_types) && $va_fetched_row['type_id'] && !in_array($va_fetched_row['type_id'], $va_restrict_to_types)) {
                             continue;
                         }
                         $va_facet_items[$va_fetched_row[$vs_rel_pk]] = array('id' => $va_fetched_row[$vs_rel_pk], 'type_id' => array(), 'parent_id' => $vb_rel_is_hierarchical ? $va_fetched_row[$vs_hier_parent_id_fld] : null, 'hierarchy_id' => $vb_rel_is_hierarchical ? $va_fetched_row[$vs_hier_id_fld] : null, 'rel_type_id' => array(), 'child_count' => 0);
                         if (!is_null($vs_single_value) && $va_fetched_row[$vs_rel_pk] == $vs_single_value) {
                             $vb_single_value_is_present = true;
                         }
                     }
                     if ($va_fetched_row['type_id']) {
                         $va_facet_items[$va_fetched_row[$vs_rel_pk]]['type_id'][] = $va_fetched_row['type_id'];
                     }
                     if ($va_fetched_row['rel_type_id']) {
                         $va_facet_items[$va_fetched_row[$vs_rel_pk]]['rel_type_id'][] = $va_fetched_row['rel_type_id'];
                     }
                 }
                 if (!isset($va_facet_info['dont_expand_hierarchically']) || !$va_facet_info['dont_expand_hierarchically']) {
                     $qr_res->seek(0);
                     $va_ids = $qr_res->getAllFieldValues($vs_rel_pk);
                     $qr_ancestors = call_user_func($t_rel_item->tableName() . '::getHierarchyAncestorsForIDs', $va_ids, array('returnAs' => 'SearchResult'));
                     $vs_rel_table = $t_rel_item->tableName();
                     $vs_rel_pk = $t_rel_item->primaryKey();
                     $vb_check_ancestor_access = (bool) (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access'));
                     if ($qr_ancestors) {
                         while ($qr_ancestors->nextHit()) {
                             $vn_parent_type_id = $qr_ancestors->get('type_id');
                             if (sizeof($va_exclude_types) > 0 && in_array($vn_parent_type_id, $va_exclude_types)) {
                                 continue;
                             }
                             if (sizeof($va_restrict_to_types) > 0 && !in_array($vn_parent_type_id, $va_restrict_to_types)) {
                                 continue;
                             }
                             if ($vb_check_ancestor_access && !in_array($qr_ancestors->get('access'), $pa_options['checkAccess'])) {
                                 continue;
                             }
                             $va_facet_items[$vn_ancestor_id = (int) $qr_ancestors->get("{$vs_rel_pk}")] = array('id' => $vn_ancestor_id, 'type_id' => array(), 'parent_id' => $vb_rel_is_hierarchical ? $qr_ancestors->get("{$vs_hier_parent_id_fld}") : null, 'hierarchy_id' => $vb_rel_is_hierarchical && $vs_hier_id_fld ? $qr_ancestors->get($vs_hier_id_fld) : null, 'rel_type_id' => array(), 'child_count' => 0);
                         }
                     }
                 }
                 // Set child counts
                 foreach ($va_facet_items as $vn_i => $va_item) {
                     if ($va_item['parent_id'] && isset($va_facet_items[$va_item['parent_id']])) {
                         $va_facet_items[$va_item['parent_id']]['child_count']++;
                     }
                 }
                 // Get labels for facet items
                 if (sizeof($va_row_ids = array_keys($va_facet_items))) {
                     if ($vs_label_table_name = $t_rel_item->getLabelTableName()) {
                         $t_rel_item_label = $this->opo_datamodel->getInstanceByTableName($vs_label_table_name, true);
                         $vs_label_display_field = $t_rel_item_label->getDisplayField();
                         $vs_rel_pk = $t_rel_item->primaryKey();
                         $va_label_wheres = array();
                         if ($t_rel_item_label->hasField('is_preferred')) {
                             $va_label_wheres[] = "({$vs_label_table_name}.is_preferred = 1)";
                         }
                         $va_label_wheres[] = "({$vs_label_table_name}.{$vs_rel_pk} IN (" . join(",", $va_row_ids) . "))";
                         $va_label_selects[] = "{$vs_label_table_name}.{$vs_rel_pk}";
                         $va_label_selects[] = "{$vs_label_table_name}.locale_id";
                         $va_label_fields = $t_rel_item->getLabelUIFields();
                         foreach ($va_label_fields as $vs_label_field) {
                             $va_label_selects[] = "{$vs_label_table_name}.{$vs_label_field}";
                         }
                         // Get label ordering fields
                         $va_ordering_fields_to_fetch = isset($va_facet_info['order_by_label_fields']) && is_array($va_facet_info['order_by_label_fields']) ? $va_facet_info['order_by_label_fields'] : array();
                         $va_orderbys = array();
                         foreach ($va_ordering_fields_to_fetch as $vs_sort_by_field) {
                             if (!$t_rel_item_label->hasField($vs_sort_by_field)) {
                                 continue;
                             }
                             $va_orderbys[] = $va_label_selects[] = $vs_label_table_name . '.' . $vs_sort_by_field;
                         }
                         // get labels
                         $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT " . join(', ', $va_label_selects) . "\n\t\t\t\t\t\t\t\t\tFROM " . $vs_label_table_name . "\n\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_label_wheres) ? ' WHERE ' : '') . join(" AND ", $va_label_wheres) . "\n\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_orderbys) ? "ORDER BY " . join(', ', $va_orderbys) : '') . "";
                         //print $vs_sql;
                         $qr_labels = $this->opo_db->query($vs_sql);
                         while ($qr_labels->nextRow()) {
                             $va_fetched_row = $qr_labels->getRow();
                             $va_facet_item = array_merge($va_facet_items[$va_fetched_row[$vs_rel_pk]], array('label' => $va_fetched_row[$vs_label_display_field]));
                             foreach ($va_ordering_fields_to_fetch as $vs_to_fetch) {
                                 $va_facet_item[$vs_to_fetch] = $va_fetched_row[$vs_to_fetch];
                             }
                             $va_facet[$va_fetched_row[$vs_rel_pk]][$va_fetched_row['locale_id']] = $va_facet_item;
                         }
                     }
                     // get attributes for facet items
                     if (sizeof($va_attrs_to_fetch)) {
                         $qr_attrs = $this->opo_db->query("\n\t\t\t\t\t\t\t\t\tSELECT c_av.*, c_a.locale_id, c_a.row_id\n\t\t\t\t\t\t\t\t\tFROM ca_attributes c_a\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values c_av ON c_a.attribute_id = c_av.attribute_id\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\tc_av.element_id IN (" . join(',', $va_attrs_to_fetch) . ")\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\tc_a.table_num = ?\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\tc_a.row_id IN (" . join(',', $va_row_ids) . ")\n\t\t\t\t\t\t\t\t", $t_rel_item->tableNum());
                         while ($qr_attrs->nextRow()) {
                             $va_fetched_row = $qr_attrs->getRow();
                             $vn_id = $va_fetched_row['row_id'];
                             // if no locale is set for the attribute default it to whatever the locale for the item is
                             if (!($vn_locale_id = $va_fetched_row['locale_id'])) {
                                 $va_tmp = array_keys($va_facet[$vn_id]);
                                 $vn_locale_id = $va_tmp[0];
                             }
                             $va_facet[$vn_id][$vn_locale_id]['ca_attribute_' . $va_fetched_row['element_id']][] = $va_fetched_row;
                         }
                     }
                 }
                 if (!is_null($vs_single_value) && !$vb_single_value_is_present) {
                     return array();
                 }
                 return caExtractValuesByUserLocale($va_facet);
             }
             break;
             # -----------------------------------------------------
         # -----------------------------------------------------
         default:
             return null;
             break;
             # -----------------------------------------------------
     }
 }
Example #16
0
 /**
  *  Returns or Creates a list item or list item id matching the parameters and options provided
  * @param string/int $pm_list_code_or_id
  * @param string $ps_item_idno
  * @param string/int $pn_type_id
  * @param int $pn_locale_id
  * @param null/array $pa_values
  * @param array $pa_options An optional array of options, which include:
  *                outputErrors - if true, errors will be printed to console [default=false]
  *                dontCreate - if true then new list items will not be created [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.
  *                cache = cache item_ids of previously created/loaded items [default=true]
  *                returnInstance = return ca_occurrences instance rather than occurrence_id. Default is false.
  *                importEvent = if ca_data_import_events instance is passed then the insert/update of the list item 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 list items. Each label in the array is an array with required list item label values.
  *                log = if KLogger instance is passed then actions will be logged
  * @return bool|\ca_list_items|mixed|null
  */
 static function getListItemID($pm_list_code_or_id, $ps_item_idno, $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;
     }
     $pa_match_on = caGetOption('matchOn', $pa_options, array('label', 'idno'), array('castTo' => "array"));
     $vn_parent_id = caGetOption('parent_id', $pa_values, null);
     $vs_singular_label = isset($pa_values['preferred_labels']['name_singular']) && $pa_values['preferred_labels']['name_singular'] ? $pa_values['preferred_labels']['name_singular'] : '';
     if (!$vs_singular_label) {
         $vs_singular_label = isset($pa_values['name_singular']) && $pa_values['name_singular'] ? $pa_values['name_singular'] : str_replace("_", " ", $ps_item_idno);
     }
     $vs_plural_label = isset($pa_values['preferred_labels']['name_plural']) && $pa_values['preferred_labels']['name_plural'] ? $pa_values['preferred_labels']['name_plural'] : '';
     if (!$vs_plural_label) {
         $vs_plural_label = isset($pa_values['name_plural']) && $pa_values['name_plural'] ? $pa_values['name_plural'] : str_replace("_", " ", $ps_item_idno);
     }
     if (!$vs_singular_label) {
         $vs_singular_label = $vs_plural_label;
     }
     if (!$vs_plural_label) {
         $vs_plural_label = $vs_singular_label;
     }
     if (!$ps_item_idno) {
         $ps_item_idno = $vs_plural_label;
     }
     if (!isset($pa_options['cache'])) {
         $pa_options['cache'] = true;
     }
     // Create a cache key and compress it to save memory
     $vs_cache_key = md5($pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id . '/' . $vs_singular_label . '/' . $vs_plural_label . '/' . json_encode($pa_match_on));
     $o_event = isset($pa_options['importEvent']) && $pa_options['importEvent'] instanceof ca_data_import_events ? $pa_options['importEvent'] : null;
     $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;
     if ($pa_options['cache'] && isset(DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key])) {
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             $t_item = new ca_list_items(DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key]);
             if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
                 $t_item->setTransaction($pa_options['transaction']);
             }
             return $t_item;
         }
         if ($o_event) {
             $o_event->beginItem($vs_event_source, 'ca_list_items', 'U');
             $o_event->endItem(DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key], __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
         }
         if ($o_log) {
             $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using idno", $ps_item_idno, $pm_list_code_or_id));
         }
         return DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key];
     }
     if (!($vn_list_id = ca_lists::getListID($pm_list_code_or_id))) {
         if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
             print "[Error] " . _t("Could not find list with list code %1", $pm_list_code_or_id) . "\n";
         }
         if ($o_log) {
             $o_log->logError(_t("Could not find list with list code %1", $pm_list_code_or_id));
         }
         return DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key] = null;
     }
     if (!$vn_parent_id) {
         $vn_parent_id = caGetListRootID($pm_list_code_or_id);
     }
     $t_list = new ca_lists();
     $t_item = new ca_list_items();
     if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
         $t_list->setTransaction($pa_options['transaction']);
         $t_item->setTransaction($pa_options['transaction']);
         if ($o_event) {
             $o_event->setTransaction($pa_options['transaction']);
         }
     }
     $vn_item_id = null;
     foreach ($pa_match_on as $vs_match_on) {
         switch (strtolower($vs_match_on)) {
             case 'label':
             case 'labels':
                 if (trim($vs_singular_label) || trim($vs_plural_label)) {
                     if ($vn_item_id = ca_list_items::find(array('preferred_labels' => array('name_singular' => $vs_singular_label), 'parent_id' => $vn_parent_id, 'list_id' => $vn_list_id), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction']))) {
                         if ($o_log) {
                             $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using singular label %3", $ps_item_idno, $pm_list_code_or_id, $vs_singular_label));
                         }
                         break 2;
                     } else {
                         if ($vn_item_id = ca_list_items::find(array('preferred_labels' => array('name_plural' => $vs_plural_label), 'parent_id' => $vn_parent_id, 'list_id' => $vn_list_id), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction']))) {
                             if ($o_log) {
                                 $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using plural label %3", $ps_item_idno, $pm_list_code_or_id, $vs_plural_label));
                             }
                             break 2;
                         }
                     }
                     break;
                 }
             case 'idno':
                 if ($ps_item_idno == '%') {
                     break;
                 }
                 // don't try to match on an unreplaced idno placeholder
                 if ($vn_item_id = ca_list_items::find(array('idno' => $ps_item_idno ? $ps_item_idno : $vs_plural_label, 'list_id' => $vn_list_id, 'parent_id' => $vn_parent_id), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction']))) {
                     if ($o_log) {
                         $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using idno with %3", $ps_item_idno, $pm_list_code_or_id, $ps_item_idno));
                     }
                     break 2;
                 }
                 break;
         }
     }
     if ($vn_item_id) {
         DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key] = $vn_item_id;
         if ($o_event) {
             $o_event->beginItem($vs_event_source, 'ca_list_items', 'U');
             $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
         }
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             $t_item = new ca_list_items($vn_item_id);
             if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
                 $t_item->setTransaction($pa_options['transaction']);
             }
             return $t_item;
         }
         return $vn_item_id;
     }
     if (isset($pa_options['dontCreate']) && $pa_options['dontCreate']) {
         return false;
     }
     //
     // Need to create list item
     //
     if (!$t_list->load($vn_list_id)) {
         if ($o_log) {
             $o_log->logError(_t("Could not find list with list id %1", $vn_list_id));
         }
         return null;
     }
     if ($o_event) {
         $o_event->beginItem($vs_event_source, 'ca_list_items', 'I');
     }
     if ($t_item = $t_list->addItem($ps_item_idno, $pa_values['is_enabled'], $pa_values['is_default'], $vn_parent_id, $pn_type_id, $ps_item_idno, '', (int) $pa_values['status'], (int) $pa_values['access'], $pa_values['rank'])) {
         $vb_label_errors = false;
         $t_item->addLabel(array('name_singular' => $vs_singular_label, 'name_plural' => $vs_plural_label), $pn_locale_id, null, true);
         if ($t_item->numErrors()) {
             if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                 print "[Error] " . _t("Could not set preferred label for list item %1: %2", "{$vs_singular_label}/{$vs_plural_label}/{$ps_item_idno}", join('; ', $t_item->getErrors())) . "\n";
             }
             if ($o_log) {
                 $o_log->logError(_t("Could not set preferred label for list item %1: %2", "{$vs_singular_label}/{$vs_plural_label}/{$ps_item_idno}", join('; ', $t_item->getErrors())));
             }
             $vb_label_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_item->addLabel($va_label, $pn_locale_id, null, false);
                 if ($t_item->numErrors()) {
                     if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                         print "[Error] " . _t("Could not set non-preferred label for list item %1: %2", "{$vs_singular_label}/{$vs_plural_label}/{$ps_item_idno}", join('; ', $t_item->getErrors())) . "\n";
                     }
                     if ($o_log) {
                         $o_log->logError(_t("Could not set non-preferred label for list item %1: %2", "{$vs_singular_label}/{$vs_plural_label}/{$ps_item_idno}", join('; ', $t_item->getErrors())));
                     }
                 }
             }
         }
         /** @var IIDNumbering $o_idno */
         if ($o_idno = $t_item->getIDNoPlugInInstance()) {
             $va_values = $o_idno->htmlFormValuesAsArray('idno', $ps_item_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 != $ps_item_idno) {
                 $t_item->set('idno', $vs_proc_idno);
                 $t_item->update();
                 if ($t_item->numErrors()) {
                     if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                         print "[Error] " . _t("Could not update idno for %1: %2", $vs_plural_label, join('; ', $t_item->getErrors())) . "\n";
                     }
                     if ($o_log) {
                         $o_log->logError(_t("Could not idno for %1: %2", $vs_plural_label, join('; ', $t_item->getErrors())));
                     }
                     return null;
                 }
             }
         }
         $vn_item_id = DataMigrationUtils::$s_cached_list_item_ids[$vs_cache_key] = $t_item->getPrimaryKey();
         if ($o_event) {
             if ($vb_label_errors) {
                 $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_PARTIAL_SUCCESS__, _t("Errors setting preferred labels: %1", join('; ', $t_item->getErrors())));
             } else {
                 $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
             }
         }
         if ($o_log) {
             $o_log->logInfo(_t("Created new list item %1 in list %2", "{$vs_singular_label}/{$vs_plural_label}/{$ps_item_idno}", $pm_list_code_or_id));
         }
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             return $t_item;
         }
         return $vn_item_id;
     } else {
         if ($o_log) {
             $o_log->logError(_t("Could not find add item to list: %1", join("; ", $t_list->getErrors())));
         }
     }
     return null;
 }
Example #17
0
             }
             if (is_array($va_list) && sizeof($va_list)) {
                 print $va_setting_info['label'] . " = " . join("; ", $va_list) . "<br/>\n";
             }
             break;
         case 'relationship_type':
         case 'restrict_to_relationship_types':
             if (!is_array($vs_setting_value)) {
                 $vs_setting_value = array($vs_setting_value);
             }
             if (is_array($va_list = $t_rel->relationshipTypeListToTypeCodes($t_relationship->tableName(), $vs_setting_value)) && sizeof($va_list)) {
                 print $va_setting_info['label'] . " = " . join("; ", $va_list) . "<br/>\n";
             }
             break;
         case 'list':
             if ($t_list->load($vs_setting_value)) {
                 print $va_setting_info['label'] . " = " . $t_list->getLabelForDisplay() . " [" . $t_list->get('list_code') . "]<br/>\n";
             }
             break;
         default:
             if (is_array($vs_setting_value) && sizeof($vs_setting_value)) {
                 print $va_setting_info['label'] . " = " . join("; ", $vs_setting_value) . "<br/>\n";
             } else {
                 if (strlen($vs_setting_value)) {
                     print $va_setting_info['label'] . " = " . $vs_setting_value . "<br/>\n";
                 }
             }
             break;
     }
 }
 ?>
Example #18
0
 public function insert($pa_options = null)
 {
     if (!$this->inTransaction()) {
         $this->setTransaction(new Transaction());
     }
     if ($this->get('is_default')) {
         $this->getDb()->query("\n\t\t\t\tUPDATE ca_list_items \n\t\t\t\tSET is_default = 0 \n\t\t\t\tWHERE list_id = ?\n\t\t\t", (int) $this->get('list_id'));
     }
     $vn_rc = parent::insert($pa_options);
     if ($this->getPrimaryKey()) {
         $t_list = new ca_lists();
         $o_trans = $this->getTransaction();
         $t_list->setTransaction($o_trans);
         if ($t_list->load($this->get('list_id')) && $t_list->get('list_code') == 'place_hierarchies' && $this->get('parent_id')) {
             // insert root or place hierarchy when creating non-root items in 'place_hierarchies' list
             $t_locale = new ca_locales();
             $va_locales = $this->getAppConfig()->getList('locale_defaults');
             $vn_locale_id = $t_locale->localeCodeToID($va_locales[0]);
             // create root in ca_places
             $t_place = new ca_places();
             $t_place->setTransaction($o_trans);
             $t_place->setMode(ACCESS_WRITE);
             $t_place->set('hierarchy_id', $this->getPrimaryKey());
             $t_place->set('locale_id', $vn_locale_id);
             $t_place->set('type_id', null);
             $t_place->set('parent_id', null);
             $t_place->set('idno', 'Root node for ' . $this->get('idno'));
             $t_place->insert();
             if ($t_place->numErrors()) {
                 $this->delete();
                 $this->errors = array_merge($this->errors, $t_place->errors);
                 return false;
             }
             $t_place->addLabel(array('name' => 'Root node for ' . $this->get('idno')), $vn_locale_id, null, true);
         }
     }
     if ($this->numErrors()) {
         $this->getTransaction()->rollback();
     } else {
         $this->getTransaction()->commit();
         $this->_setSettingsForList();
     }
     return $vn_rc;
 }
Example #19
0
 /** 
  *
  * @param array $pa_options An optional array of options, which include:
  *				outputErrors - if true, errors will be printed to console [default=false]
  *				dontCreate - if true then new items will not be created [default=false]
  *				matchOnLabel =  if true then list items are looked up exclusively using labels [default=false]
  *				matchOnIdno - try to match on idno if name match fails [default=false]
  *				cache = cache item_ids of previously created/loaded items [default=true]
  *				returnInstance = return ca_occurrences instance rather than occurrence_id. Default is false. 
  *				importEvent = if ca_data_import_events instance is passed then the insert/update of the list item 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
  *				log = if KLogger instance is passed then actions will be logged
  */
 static function getListItemID($pm_list_code_or_id, $ps_item_idno, $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;
     }
     $pb_match_on_label = caGetOption('matchOnLabel', $pa_options, false);
     $pb_match_on_idno = caGetOption('matchOnIdno', $pa_options, false);
     $vn_parent_id = caGetOption('parent_id', $pa_values, null);
     if (!isset($pa_options['cache'])) {
         $pa_options['cache'] = true;
     }
     $o_event = isset($pa_options['importEvent']) && $pa_options['importEvent'] instanceof ca_data_import_events ? $pa_options['importEvent'] : null;
     $vs_event_source = isset($pa_options['importEventSource']) && $pa_options['importEventSource'] ? $pa_options['importEventSource'] : "?";
     $o_log = isset($pa_options['log']) && $pa_options['log'] instanceof KLogger ? $pa_options['log'] : null;
     if ($pa_options['cache'] && isset(DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id])) {
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             return new ca_list_items(DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id]);
         }
         if ($o_event) {
             $o_event->beginItem($vs_event_source, 'ca_list_items', 'U');
             $o_event->endItem(DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id], __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
         }
         if ($o_log) {
             $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using idno", $ps_item_idno, $pm_list_code_or_id));
         }
         return DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id];
     }
     if (!($vn_list_id = ca_lists::getListID($pm_list_code_or_id))) {
         if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
             print "[Error] " . _t("Could not find list with list code %1", $pm_list_code_or_id) . "\n";
         }
         if ($o_log) {
             $o_log->logError(_t("Could not find list with list code %1", $pm_list_code_or_id));
         }
         return DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id] = null;
     }
     $t_list = new ca_lists();
     $t_item = new ca_list_items();
     if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
         $t_list->setTransaction($pa_options['transaction']);
         $t_item->setTransaction($pa_options['transaction']);
     }
     $va_find_arr = array('list_id' => $vn_list_id);
     if ($vn_parent_id) {
         $va_find_arr['parent_id'] = $vn_parent_id;
     }
     $vn_item_id = null;
     if ($pb_match_on_label) {
         if (!($vn_item_id = ca_list_items::find(array_merge(array('preferred_labels' => array('name_singular' => $ps_item_idno)), $va_find_arr), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction'])))) {
             $vn_item_id = ca_list_items::find(array_merge(array('preferred_labels' => array('name_plural' => $ps_item_idno)), $va_find_arr), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction']));
         }
         if ($vn_item_id) {
             DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id] = $vn_item_id;
             if ($o_event) {
                 $o_event->beginItem($vs_event_source, 'ca_list_items', 'U');
                 $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
             }
             if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
                 return new ca_list_items($vn_item_id);
             }
             if ($o_log) {
                 $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using label %3 and %4", $ps_item_idno, $pm_list_code_or_id, $vs_label, print_R($va_find_arr, true)));
             }
             return DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id];
         }
     }
     if (!$pb_match_on_label || $pb_match_on_idno) {
         if ($vn_item_id = ca_list_items::find(array_merge(array('idno' => $vs_idno), $va_find_arr), array('returnAs' => 'firstId', 'transaction' => $pa_options['transaction']))) {
             DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id] = $vn_item_id;
             if ($o_event) {
                 $o_event->beginItem($vs_event_source, 'ca_list_items', 'U');
                 $o_event->endItem(DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id], __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
             }
             if ($o_log) {
                 $o_log->logDebug(_t("Found existing list item %1 (member of list %2) in DataMigrationUtils::getListItemID() using idno with %3", $ps_item_idno, $pm_list_code_or_id, print_R($va_find_arr, true)));
             }
             if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
                 return $t_item;
             }
             return DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id];
         }
     }
     if (isset($pa_options['dontCreate']) && $pa_options['dontCreate']) {
         return false;
     }
     //
     // Need to create list item
     //
     if (!$t_list->load($vn_list_id)) {
         if ($o_log) {
             $o_log->logError(_t("Could not find list with list id %1", $vn_list_id));
         }
         return null;
     }
     if ($o_event) {
         $o_event->beginItem($vs_event_source, 'ca_list_items', 'I');
     }
     if ($t_item = $t_list->addItem($ps_item_idno, $pa_values['is_enabled'], $pa_values['is_default'], $vn_parent_id, $pn_type_id, $ps_item_idno, '', (int) $pa_values['status'], (int) $pa_values['access'], $pa_values['rank'])) {
         $vb_label_errors = false;
         $t_item->addLabel(array('name_singular' => $pa_values['name_singular'] ? $pa_values['name_singular'] : $ps_item_idno, 'name_plural' => $pa_values['name_plural'] ? $pa_values['name_plural'] : $ps_item_idno), $pn_locale_id, null, true);
         if ($t_item->numErrors()) {
             if (isset($pa_options['outputErrors']) && $pa_options['outputErrors']) {
                 print "[Error] " . _t("Could not set preferred label for list item %1: %2", $pa_values['name_singular'] . "/" . $pa_values['name_plural'] . "/{$ps_item_idno}", join('; ', $t_item->getErrors())) . "\n";
             }
             if ($o_log) {
                 $o_log->logError(_t("Could not set preferred label for list item %1: %2", $pa_values['name_singular'] . "/" . $pa_values['name_plural'] . "/{$ps_item_idno}", join('; ', $t_item->getErrors())));
             }
             $vb_label_errors = true;
         }
         $vn_item_id = DataMigrationUtils::$s_cached_list_item_ids[$pm_list_code_or_id . '/' . $ps_item_idno . '/' . $vn_parent_id] = $t_item->getPrimaryKey();
         if ($o_event) {
             if ($vb_label_errors) {
                 $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_PARTIAL_SUCCESS__, _t("Errors setting preferred labels: %1", join('; ', $t_item->getErrors())));
             } else {
                 $o_event->endItem($vn_item_id, __CA_DATA_IMPORT_ITEM_SUCCESS__, '');
             }
         }
         if ($o_log) {
             $o_log->logInfo(_t("Created new list item %1 in list %2", $pa_values['name_singular'] . "/" . $pa_values['name_plural'] . "/{$ps_item_idno}", $pm_list_code_or_id));
         }
         if (isset($pa_options['returnInstance']) && $pa_options['returnInstance']) {
             return $t_item;
         }
         return $vn_item_id;
     } else {
         if ($o_log) {
             $o_log->logError(_t("Could not find add litem to list: %1", join("; ", $t_list->getErrors())));
         }
     }
     return null;
 }
 /**
  *
  */
 public function getTypeMenu()
 {
     $t_list = new ca_lists();
     $t_list->load(array('list_code' => $this->getTypeListCode()));
     $t_list_item = new ca_list_items();
     $t_list_item->load(array('list_id' => $t_list->getPrimaryKey(), 'parent_id' => null));
     $va_hierarchy = caExtractValuesByUserLocale($t_list_item->getHierarchyWithLabels());
     $va_types = array();
     if (is_array($va_hierarchy)) {
         $va_types_by_parent_id = array();
         $vn_root_id = null;
         foreach ($va_hierarchy as $vn_item_id => $va_item) {
             if (!$vn_root_id) {
                 $vn_root_id = $va_item['parent_id'];
                 continue;
             }
             $va_types_by_parent_id[$va_item['parent_id']][] = $va_item;
         }
         foreach ($va_hierarchy as $vn_item_id => $va_item) {
             if ($va_item['parent_id'] != $vn_root_id) {
                 continue;
             }
             // does this item have sub-items?
             if (isset($va_types_by_parent_id[$va_item['item_id']]) && is_array($va_types_by_parent_id[$va_item['item_id']])) {
                 $va_subtypes = $this->_getSubTypes($va_types_by_parent_id[$va_item['item_id']], $va_types_by_parent_id);
             } else {
                 $va_subtypes = array();
             }
             $va_types[] = array('displayName' => $va_item['name_singular'], 'parameters' => array('type_id' => $va_item['item_id']), 'navigation' => $va_subtypes);
         }
     }
     return $va_types;
 }
Example #21
0
 /**
  * Returns HTML <select> element containing the specified list, or portion of the list.
  *
  * @param mixed $pm_list_name_or_id
  * @param string $ps_name
  * @param array $pa_attributes 
  * @param array $pa_options Array of options. Valid options include:
  * 	childrenOnlyForItemID = if set only items below item_id in the list item hierarchy are returned. Default (null) is to return all items in the list.
  * 	directChildrenOnly = if set only items with item_id=childrenOnlyForItemID as parent in the list item hierarchy are returned. Default (null) is to return all items in the list.
  *  nullOption = if set then a "null" (no value) option is available labeled with the value passed in this option
  *  additionalOptions = an optional array of options that will be passed through to caHTMLSelect; keys are display labels and values are used as option values
  *  value = if set, the <select> will have default selection set to the item whose *value* matches the option value. If none is set then the first item in the list will be selected
  *  key = ca_list_item field to be used as value for the <select> element list; can be set to either item_id or item_value; default is item_id
  *	width = the display width of the list in characters or pixels
  *  limitToItemsWithID = An optional array of list item_ids. Item_ids not in the array will be omitted from the returned list.
  *  omitItemsWithID = An optional array of list item_ids. Item_ids in the array will be omitted from the returned list.
  *  disableItemsWithID = An optional array of list item_ids. Item_ids in the array will be disabled in the returned list.	
  *
  *	limitToItemsRelatedToCollections = an array of collection_ids or collection idno's; returned items will be restricted to those attached to the specified collections
  *	limitToItemsRelatedToCollectionWithRelationshipTypes = array of collection type names or type_ids; returned items will be restricted to those attached to the specified collectionss with the specified relationship type
  *	limitToListIDs = array of list_ids to restrict returned items to when using "limitToItemsRelatedToCollections"
  *
  *  indentForHierarchy = indicate hierarchy with indentation. [Default is true]
  * 	transaction = transaction to perform database operations within. [Default is null]
  * 
  * @return string - HTML code for the <select> element; empty string if the list is empty
  */
 public static function getListAsHTMLFormElement($pm_list_name_or_id, $ps_name, $pa_attributes = null, $pa_options = null)
 {
     $t_list = new ca_lists();
     if ($o_trans = caGetOption('transaction', $pa_options, null)) {
         $t_list->setTransaction($o_trans);
     }
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     if (!(isset($pa_options['limitToItemsRelatedToCollection']) && is_array($pa_options['limitToItemsRelatedToCollections']))) {
         $vn_list_id = $t_list->_getListID($pm_list_name_or_id);
         $t_list->load($vn_list_id);
     }
     $vn_root_id = isset($pa_options['childrenOnlyForItemID']) && $pa_options['childrenOnlyForItemID'] ? $pa_options['childrenOnlyForItemID'] : null;
     $va_disabled_item_ids = caGetOption('disableItemsWithID', $pa_options, null);
     $vs_render_as = isset($pa_options['render']) ? $pa_options['render'] : '';
     $vn_sort_type = $t_list->get('default_sort');
     if ($vs_render_as == 'yes_no_checkboxes' && $vn_sort_type == __CA_LISTS_SORT_BY_LABEL__) {
         $vn_sort_type = __CA_LISTS_SORT_BY_IDENTIFIER__;
         // never allow sort-by-label when rendering as yes/no checkbox
     }
     if (!in_array($vs_render_as, array('lookup', 'horiz_hierbrowser', 'vert_hierbrowser'))) {
         if (isset($pa_options['limitToItemsRelatedToCollections']) && is_array($pa_options['limitToItemsRelatedToCollections'])) {
             $t_collection = new ca_collections();
             $va_collection_ids = array();
             foreach ($pa_options['limitToItemsRelatedToCollections'] as $vn_collection_id) {
                 if ($vn_collection_id && !is_numeric($vn_collection_id)) {
                     if ($vn_collection_id = $t_collection->load(array('idno' => $vn_collection_id))) {
                         $va_collection_ids[] = $vn_collection_id;
                     }
                 } else {
                     if ($vn_collection_id) {
                         $va_collection_ids[] = $vn_collection_id;
                     }
                 }
             }
             if (sizeof($va_collection_ids)) {
                 $qr_collections = $t_list->makeSearchResult('ca_collections', $va_collection_ids, array('restrictToRelationshipTypes' => isset($pa_options['limitToItemsRelatedToCollectionWithRelationshipTypes']) ? $pa_options['limitToItemsRelatedToCollectionWithRelationshipTypes'] : null));
                 $va_item_ids = array();
                 while ($qr_collections->nextHit()) {
                     $va_list_items = $qr_collections->get('ca_list_items', array('returnAsArray' => true));
                     foreach ($va_list_items as $vn_rel_id => $va_list_item) {
                         $va_item_ids[$vn_rel_id] = $va_list_item['item_id'];
                     }
                 }
                 if ($va_limit_to_listIDs = isset($pa_options['limitToListIDs']) && is_array($pa_options['limitToListIDs']) ? $pa_options['limitToListIDs'] : null) {
                     // for some reason the option comes back as array(0 => null) if no list is selected in UI
                     // -> have to make sure to catch this case here
                     if (sizeof($va_limit_to_listIDs) == 1 && empty($va_limit_to_listIDs[0])) {
                         $va_limit_to_listIDs = null;
                     }
                 }
                 if (is_array($va_limit_to_listIDs) && sizeof($va_item_ids)) {
                     // filter out items from tables we don't want
                     $qr_list_items = $t_list->makeSearchResult("ca_list_items", array_values($va_item_ids));
                     while ($qr_list_items->nextHit()) {
                         if (!in_array($qr_list_items->get('ca_list_items.list_id'), $va_limit_to_listIDs)) {
                             if (is_array($va_k = array_keys($va_item_ids, $qr_list_items->get('ca_list_items.item_id')))) {
                                 foreach ($va_k as $vs_k) {
                                     unset($va_list_items[$vs_k]);
                                 }
                             }
                         }
                     }
                 }
             }
         } else {
             $va_list_items = $t_list->getItemsForList($pm_list_name_or_id, array_merge($pa_options, array('returnHierarchyLevels' => caGetOption('indentForHierarchy', $pa_options, true), 'item_id' => $vn_root_id, 'extractValuesByUserLocale' => true, 'sort' => $vn_sort_type)));
         }
     }
     if (!is_array($va_list_items)) {
         $va_list_items = array();
     }
     $va_options = array();
     $va_disabled_options = array();
     if (!isset($pa_options['value'])) {
         $pa_options['value'] = null;
     }
     if (!isset($pa_options['key'])) {
         $pa_options['key'] = 'item_id';
     }
     if (!in_array($pa_options['key'], array('item_id', 'item_value'))) {
         $pa_options['key'] = 'item_id';
     }
     if (!isset($pa_options['limitToItemsWithID']) || !is_array($pa_options['limitToItemsWithID']) || !sizeof($pa_options['limitToItemsWithID'])) {
         $pa_options['limitToItemsWithID'] = null;
     }
     if (!isset($pa_options['omitItemsWithID']) || !is_array($pa_options['omitItemsWithID']) || !sizeof($pa_options['omitItemsWithID'])) {
         $pa_options['omitItemsWithID'] = null;
     }
     if (isset($pa_options['nullOption']) && $pa_options['nullOption'] && $vs_render_as != 'checklist') {
         $va_options[''] = $pa_options['nullOption'];
     }
     $va_colors = array();
     $vn_default_val = null;
     foreach ($va_list_items as $vn_item_id => $va_item) {
         if (is_array($pa_options['limitToItemsWithID']) && !in_array($vn_item_id, $pa_options['limitToItemsWithID'])) {
             continue;
         }
         if (is_array($pa_options['omitItemsWithID']) && in_array($vn_item_id, $pa_options['omitItemsWithID'])) {
             continue;
         }
         $va_options[$va_item[$pa_options['key']]] = str_repeat('&nbsp;', intval($va_item['LEVEL']) * 3) . ' ' . $va_item['name_singular'];
         if (!$va_item['is_enabled'] || is_array($va_disabled_item_ids) && in_array($vn_item_id, $va_disabled_item_ids)) {
             $va_disabled_options[$va_item[$pa_options['key']]] = true;
         }
         $va_colors[$vn_item_id] = $va_item['color'];
         if ($va_item['is_default']) {
             $vn_default_val = $va_item[$pa_options['key']];
         }
         // get default value
         if ($va_item['is_default'] && !isset($pa_options['nullOption'])) {
             // set default if needed, but only if there's not a null option set
             if (!is_array($pa_options['value']) && (!isset($pa_options['value']) || !strlen($pa_options['value']))) {
                 $pa_options['value'] = $vn_default_val;
             } else {
                 if (is_array($pa_options['value']) && !sizeof($pa_options['value'])) {
                     $pa_options['value'] = array(0 => $vn_default_val);
                 }
             }
         }
     }
     if (isset($pa_options['additionalOptions']) && is_array($pa_options['additionalOptions'])) {
         $va_options = array_merge($va_options, array_flip($pa_options['additionalOptions']));
     }
     $pa_options['disabledOptions'] = $va_disabled_options;
     switch ($vs_render_as) {
         case 'radio_buttons':
             if (!sizeof($va_options)) {
                 return '';
             }
             // return empty string if list has no values
             $vn_c = 0;
             $vn_i = 0;
             $vs_buf = "<table>\n";
             foreach ($va_options as $vm_value => $vs_label) {
                 if ($vn_c == 0) {
                     $vs_buf .= "<tr>";
                 }
                 $va_attributes = array('value' => $vm_value);
                 if (isset($va_disabled_options[$vm_value]) && $va_disabled_options[$vm_value]) {
                     $va_attributes['disabled'] = 1;
                 }
                 $va_attributes['value'] = $vm_value;
                 $va_attributes['id'] = $ps_name . '_' . $vn_i;
                 if ($pa_options['value'] == $vm_value) {
                     $va_attributes['checked'] = '1';
                 }
                 if (isset($pa_options['readonly']) && $pa_options['readonly']) {
                     $va_attributes['disabled'] = 1;
                 }
                 $vs_buf .= "<td>" . caHTMLRadioButtonInput($ps_name, $va_attributes, $pa_options) . " {$vs_label}</td>";
                 $vn_c++;
                 if ($vn_c >= $pa_options['maxColumns']) {
                     $vn_c = 0;
                     $vs_buf .= "</tr>\n";
                 }
                 $vn_i++;
             }
             if ($vn_c != 0) {
                 $vs_buf .= "</tr>\n";
             }
             $vs_buf .= "</table>";
             return $vs_buf;
             break;
         case 'yes_no_checkboxes':
             if (!sizeof($va_options)) {
                 return '';
             }
             // return empty string if list has no values
             $vn_c = 0;
             $vb_is_checked = false;
             if (!$pa_options['value']) {
                 $pa_options['value'] = (string) $vn_default_val;
             }
             foreach ($va_options as $vm_value => $vs_label) {
                 if (strlen($vm_value) == 0) {
                     continue;
                 }
                 // don't count null values when calculating the first value for the yes/no
                 switch ($vn_c) {
                     case 0:
                         if ($pa_options['value'] === (string) $vm_value) {
                             $vb_is_checked = true;
                         }
                         $pa_attributes['value'] = $pa_options['value'] = $vm_value;
                         $pa_options['label'] = $vs_label;
                         break;
                     case 1:
                         $pa_options['returnValueIfUnchecked'] = $vm_value;
                         break;
                     default:
                         // exit
                         break 2;
                 }
                 $vn_c++;
             }
             if ($vb_is_checked) {
                 $pa_attributes['checked'] = 1;
             }
             if (isset($pa_options['readonly']) && $pa_options['readonly']) {
                 $pa_attributes['disabled'] = 1;
             }
             return caHTMLCheckboxInput($ps_name, $pa_attributes, $pa_options);
             break;
         case 'checklist':
             if (!sizeof($va_options)) {
                 return '';
             }
             // return empty string if list has no values
             $vn_c = 0;
             $vs_buf = "<table>\n";
             foreach ($va_options as $vm_value => $vs_label) {
                 if ($vn_c == 0) {
                     $vs_buf .= "<tr>";
                 }
                 $va_attributes = array('value' => $vm_value);
                 if (isset($va_disabled_options[$vm_value]) && $va_disabled_options[$vm_value]) {
                     $va_attributes['disabled'] = 1;
                 }
                 if (isset($pa_options['readonly']) && $pa_options['readonly']) {
                     $va_attributes['disabled'] = 1;
                 }
                 if (is_array($pa_options['value']) && in_array($vm_value, $pa_options['value'])) {
                     $va_attributes['checked'] = '1';
                 }
                 $vs_buf .= "<td>" . caHTMLCheckboxInput($ps_name . '_' . $vm_value, $va_attributes, $pa_options) . " {$vs_label}</td>";
                 $vn_c++;
                 if ($vn_c >= $pa_options['maxColumns']) {
                     $vn_c = 0;
                     $vs_buf .= "</tr>\n";
                 }
             }
             if ($vn_c != 0) {
                 $vs_buf .= "</tr>\n";
             }
             $vs_buf .= "</table>";
             return $vs_buf;
             break;
         case 'lookup':
             $vs_value = $vs_hidden_value = "";
             if (caGetOption('forSearch', $pa_options)) {
                 if ($vs_val_id = caGetOption('value', $pa_options)) {
                     $vs_value = $t_list->getItemFromListForDisplayByItemID($pm_list_name_or_id, $vs_val_id);
                     $vs_hidden_value = $vs_val_id;
                 }
             } else {
                 $vs_value = "{" . $pa_options['element_id'] . "_label}";
                 $vs_hidden_value = "{" . $pa_options['element_id'] . "}";
             }
             $vs_buf = caHTMLTextInput($ps_name . '_autocomplete', array('width' => isset($pa_options['width']) && $pa_options['width'] > 0 ? $pa_options['width'] : 300, 'height' => isset($pa_options['height']) && $pa_options['height'] > 0 ? $pa_options['height'] : 1, 'value' => $vs_value, 'maxlength' => 512, 'id' => $ps_name . "_autocomplete", 'class' => 'lookupBg')) . caHTMLHiddenInput($ps_name, array('value' => $vs_hidden_value, 'id' => $ps_name));
             if ($pa_options['request']) {
                 $vs_url = caNavUrl($pa_options['request'], 'lookup', 'ListItem', 'Get', array('list' => ca_lists::getListCode($vn_list_id), 'noInline' => 1, 'noSymbols' => 1, 'max' => 100));
             } else {
                 // hardcoded default for testing.
                 $vs_url = '/index.php/lookup/ListItem/Get';
             }
             $vs_buf .= '</div>';
             $vs_buf .= "\n\t\t\t\t\t<script type='text/javascript'>\n\t\t\t\t\t\tjQuery(document).ready(function() {\n\t\t\t\t\t\t\tjQuery('#{$ps_name}_autocomplete').autocomplete({\n\t\t\t\t\t\t\t\t\tsource: '{$vs_url}', minLength: 3, delay: 800, html: true,\n\t\t\t\t\t\t\t\t\tselect: function(event, ui) {\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif (parseInt(ui.item.id) > 0) {\n\t\t\t\t\t\t\t\t\t\t\tjQuery('#{$ps_name}').val(ui.item.id);\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\tjQuery('#{$ps_name}_autocomplete').val('');\n\t\t\t\t\t\t\t\t\t\t\tjQuery('#{$ps_name}').val('');\n\t\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t</script>\n\t\t\t\t";
             return $vs_buf;
             break;
         case 'horiz_hierbrowser':
         case 'horiz_hierbrowser_with_search':
         case 'vert_hierbrowser':
             $va_width = caParseFormElementDimension($pa_options['width'] ? $pa_options['width'] : $pa_options['width']);
             if ($va_width['type'] != 'pixels' && $va_width['dimension'] < 250) {
                 $va_width['dimension'] = 500;
             }
             $vn_width = $va_width['dimension'] . 'px';
             $va_height = caParseFormElementDimension($pa_options['height']);
             if ($va_height['type'] != 'pixels' && $va_height['dimension'] < 100) {
                 $va_height['dimension'] = 200;
             }
             $vn_height = $va_height['dimension'] . 'px';
             $t_root_item = new ca_list_items();
             $t_root_item->load(array('list_id' => $vn_list_id, 'parent_id' => null));
             JavascriptLoadManager::register("hierBrowser");
             $vs_buf = "<div style='width: {$vn_width}; height: {$vn_height};'><div id='{$ps_name}_hierarchyBrowser{n}' style='width: 100%; height: 100%;' class='" . ($vs_render_as == 'vert_hierbrowser' ? 'hierarchyBrowserVertical' : 'hierarchyBrowser') . "'>\n\t\t\t\t\t<!-- Content for hierarchy browser is dynamically inserted here by ca.hierbrowser -->\n\t\t\t\t</div><!-- end hierarchyBrowser -->\t</div>";
             $vs_buf .= "\t<script type='text/javascript'>\n\t\tjQuery(document).ready(function() { \n\t\t\tvar oHierBrowser = caUI.initHierBrowser('{$ps_name}_hierarchyBrowser{n}', {\n\t\t\t\tuiStyle: '" . ($vs_render_as == 'vert_hierbrowser' ? 'vertical' : 'horizontal') . "',\n\t\t\t\tlevelDataUrl: '" . caNavUrl($pa_options['request'], 'lookup', 'ListItem', 'GetHierarchyLevel', array('noSymbols' => 1)) . "',\n\t\t\t\tinitDataUrl: '" . caNavUrl($pa_options['request'], 'lookup', 'ListItem', 'GetHierarchyAncestorList') . "',\n\t\t\t\t\n\t\t\t\tselectOnLoad : true,\n\t\t\t\tbrowserWidth: " . (int) $va_width['dimension'] . ",\n\t\t\t\t\n\t\t\t\tclassName: '" . ($vs_render_as == 'vert_hierbrowser' ? 'hierarchyBrowserLevelVertical' : 'hierarchyBrowserLevel') . "',\n\t\t\t\tclassNameContainer: '" . ($vs_render_as == 'vert_hierbrowser' ? 'hierarchyBrowserContainerVertical' : 'hierarchyBrowserContainer') . "',\n\t\t\t\t\n\t\t\t\teditButtonIcon: \"" . caNavIcon($pa_options['request'], __CA_NAV_BUTTON_RIGHT_ARROW__) . "\",\n\t\t\t\tdisabledButtonIcon: \"" . caNavIcon($pa_options['request'], __CA_NAV_BUTTON_DOT__) . "\",\n\t\t\t\tinitItemID: '{" . $pa_options['element_id'] . "}',\n\t\t\t\tdefaultItemID: '" . $t_list->getDefaultItemID() . "',\n\t\t\t\tuseAsRootID: '" . $t_root_item->getPrimaryKey() . "',\n\t\t\t\tindicatorUrl: '" . $pa_options['request']->getThemeUrlPath() . "/graphics/icons/indicator.gif',\n\t\t\t\t\n\t\t\t\tcurrentSelectionDisplayID: '{$ps_name}_browseCurrentSelectionText{n}',\n\t\t\t\tonSelection: function(item_id, parent_id, name, display) {\n\t\t\t\t\tjQuery('#{$ps_name}').val(item_id);\n\t\t\t\t}\n\t\t\t});";
             if ($vs_render_as == 'horiz_hierbrowser_with_search') {
                 $vs_buf .= "jQuery('#{$ps_name}_hierarchyBrowserSearch{n}').autocomplete(\n\t\t\t\t\t{\n\t\t\t\t\t\tsource: '" . caNavUrl($pa_options['request'], 'lookup', 'ListItem', 'Get', array('list' => ca_lists::getListCode($vn_list_id), 'noSymbols' => 1)) . "', \n\t\t\t\t\t\tminLength: 3, delay: 800,\n\t\t\t\t\t\tselect: function(event, ui) {\n\t\t\t\t\t\t\toHierBrowser.setUpHierarchy(ui.item.id);\t// jump browser to selected item\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);";
             }
             $vs_buf .= "});\n\t</script>";
             if ($vs_render_as == 'horiz_hierbrowser_with_search') {
                 $vs_buf .= "<div class='hierarchyBrowserSearchBar'>" . _t('Search') . ": <input type='text' id='{$ps_name}_hierarchyBrowserSearch{n}' class='hierarchyBrowserSearchBar' name='search' value='' size='20'/></div>";
             }
             if ($vs_render_as != 'vert_hierbrowser') {
                 $vs_buf .= "<div id='{$ps_name}_browseCurrentSelection{n}' class='hierarchyBrowserCurrentSelection'>" . _t("Current selection") . ": <span id='{$ps_name}_browseCurrentSelectionText{n}' class='hierarchyBrowserCurrentSelectionText'>?</span></div>";
             }
             $vs_buf .= caHTMLHiddenInput($ps_name, array('value' => "{" . $pa_options['element_id'] . "}", 'id' => $ps_name));
             return $vs_buf;
             break;
         case 'text':
             return caHTMLTextInput($ps_name, $pa_attributes, $pa_options);
             break;
         case 'options':
             return $va_options;
             break;
         default:
             if (!sizeof($va_options)) {
                 return '';
             }
             // return empty string if list has no values
             if (isset($pa_options['readonly']) && $pa_options['readonly']) {
                 $pa_attributes['disabled'] = 1;
             }
             return caHTMLSelect($ps_name, $va_options, $pa_attributes, array_merge($pa_options, array('contentArrayUsesKeysForValues' => true, 'colors' => $va_colors, 'height' => null)));
             break;
     }
 }
 public function _genTypeNav($pa_params)
 {
     $t_subject = $this->opo_datamodel->getInstanceByTableName($this->ops_tablename, true);
     $t_list = new ca_lists();
     $t_list->load(array('list_code' => $t_subject->getTypeListCode()));
     $t_list_item = new ca_list_items();
     $t_list_item->load(array('list_id' => $t_list->getPrimaryKey(), 'parent_id' => null));
     $va_hier = caExtractValuesByUserLocale($t_list_item->getHierarchyWithLabels());
     $va_restrict_to_types = null;
     if ($t_subject->getAppConfig()->get('perform_type_access_checking')) {
         $va_restrict_to_types = caGetTypeRestrictionsForUser($this->ops_tablename, array('access' => __CA_BUNDLE_ACCESS_READONLY__));
     }
     $va_types = array();
     if (is_array($va_hier)) {
         $va_types_by_parent_id = array();
         $vn_root_id = $t_list->getRootItemIDForList($t_subject->getTypeListCode());
         // organize items by parent id, exclude root
         foreach ($va_hier as $vn_item_id => $va_item) {
             if ($vn_item_id == $vn_root_id) {
                 continue;
             }
             // skip root
             if (is_array($va_restrict_to_types) && !in_array($vn_item_id, $va_restrict_to_types)) {
                 continue;
             }
             $va_types_by_parent_id[$va_item['parent_id']][] = $va_item;
         }
         foreach ($va_hier as $vn_item_id => $va_item) {
             if (is_array($va_restrict_to_types) && !in_array($vn_item_id, $va_restrict_to_types)) {
                 continue;
             }
             if ($va_item['parent_id'] != $vn_root_id) {
                 continue;
             }
             // does this item have sub-items?
             if (isset($va_item['item_id']) && isset($va_types_by_parent_id[$va_item['item_id']]) && is_array($va_types_by_parent_id[$va_item['item_id']])) {
                 $va_subtypes = $this->_getSubTypes($va_types_by_parent_id[$va_item['item_id']], $va_types_by_parent_id, $va_restrict_to_types);
             } else {
                 $va_subtypes = array();
             }
             $va_types[] = array('displayName' => $va_item['name_plural'], 'parameters' => array('type_id' => $va_item['item_id']), 'is_enabled' => $va_item['is_enabled'], 'navigation' => $va_subtypes);
         }
     }
     return $va_types;
 }
Example #23
0
        die;
    }
    $t_list->addLabel(array('name' => 'Place hierarchies'), $pn_en_locale_id, null, true);
}
$vn_list_id = $t_list->getPrimaryKey();
// create place hierarchy
if (!($vn_tgn_id = caGetListItemID('place_hierarchies', 'tgn'))) {
    $t_tgn = $t_list->addItem('tgn', true, false, null, null, 'tgn');
    $t_tgn->addLabel(array('name_singular' => 'Thesaurus of Geographic Names', 'name_plural' => 'Thesaurus of Geographic Names'), $pn_en_locale_id, null, true);
    $vn_tgn_id = $t_tgn->getPrimaryKey();
} else {
    $t_tgn = new ca_list_items($vn_tgn_id);
}
// Create list for place types (if it doesn't exist already)
$t_place_types = new ca_lists();
if (!$t_place_types->load(array('list_code' => 'tgn_place_types'))) {
    $t_place_types->setMode(ACCESS_WRITE);
    $t_place_types->set('list_code', 'tgn_place_types');
    $t_place_types->set('is_system_list', 1);
    $t_place_types->set('is_hierarchical', 1);
    $t_place_types->set('use_as_vocabulary', 1);
    $t_place_types->insert();
    if ($t_place_types->numErrors()) {
        print "[Error] couldn't create ca_list row for place types: " . join('; ', $t_place_types->getErrors()) . "\n";
        die;
    }
    $t_place_types->addLabel(array('name' => 'Getty TGN place types'), $pn_en_locale_id, null, true);
}
$vn_place_type_list_id = $t_place_types->getPrimaryKey();
// load places
$o_xml = new XMLReader();
Example #24
0
require_once __CA_MODELS_DIR__ . '/ca_lists.php';
require_once __CA_MODELS_DIR__ . '/ca_list_items.php';
require_once __CA_MODELS_DIR__ . '/ca_list_items_x_list_items.php';
require_once __CA_MODELS_DIR__ . '/ca_relationship_types.php';
$_ = new Zend_Translate('gettext', __CA_APP_DIR__ . '/locale/en_US/messages.mo', 'en_US');
$t_locale = new ca_locales();
$pn_en_locale_id = $t_locale->loadLocaleByCode('en_US');
if (!($pn_nl_locale_id = $t_locale->loadLocaleByCode('nl_NL'))) {
    $pn_nl_locale_id = $t_locale->loadLocaleByCode('nl_BE');
}
if (!$pn_nl_locale_id) {
    die("ERROR: You can only import the Dutch-language AAT into an installation configured to support the nl_NL (Netherlands) or nl_BE (Vlaams Belgium) locale. Add one of these locales to your system and try again.\n");
}
// create vocabulary list record (if it doesn't exist already)
$t_list = new ca_lists();
if (!$t_list->load(array('list_code' => 'aat_nl'))) {
    $t_list->setMode(ACCESS_WRITE);
    $t_list->set('list_code', 'aat_nl');
    $t_list->set('is_system_list', 0);
    $t_list->set('is_hierarchical', 1);
    $t_list->set('use_as_vocabulary', 1);
    $t_list->insert();
    if ($t_list->numErrors()) {
        print "ERROR: couldn't create ca_list row for AAT: " . join('; ', $t_list->getErrors()) . "\n";
        die;
    }
    $t_list->addLabel(array('name' => 'Art & Architecture Thesaurus [Nederlands]'), $pn_en_locale_id, null, true);
}
$vn_list_id = $t_list->getPrimaryKey();
// get list item types (should be defined by base installation profile [base.profile])
// if your installation didn't use a profile inheriting from base.profile then you should make sure
Example #25
0
/**
 * 
 *
 * @return string 
 */
function caLoadAAT($ps_path_to_aat_data = null, $pa_options = null)
{
    if (!$ps_path_to_aat_data) {
        $ps_path_to_aat_data = "./AAT.xml";
    }
    if (!file_exists($ps_path_to_aat_data)) {
        die("ERROR: cannot find AAT data.\n");
    }
    require_once __CA_LIB_DIR__ . '/core/Db.php';
    require_once __CA_MODELS_DIR__ . '/ca_locales.php';
    require_once __CA_MODELS_DIR__ . '/ca_lists.php';
    require_once __CA_MODELS_DIR__ . '/ca_list_items.php';
    require_once __CA_MODELS_DIR__ . '/ca_list_items_x_list_items.php';
    require_once __CA_MODELS_DIR__ . '/ca_relationship_types.php';
    $_ = new Zend_Translate('gettext', __CA_APP_DIR__ . '/locale/en_US/messages.mo', 'en_US');
    $t_locale = new ca_locales();
    $pn_en_locale_id = $t_locale->loadLocaleByCode('en_US');
    // create vocabulary list record (if it doesn't exist already)
    $t_list = new ca_lists();
    if (!$t_list->load(array('list_code' => 'aat'))) {
        $t_list->setMode(ACCESS_WRITE);
        $t_list->set('list_code', 'aat');
        $t_list->set('is_system_list', 0);
        $t_list->set('is_hierarchical', 1);
        $t_list->set('use_as_vocabulary', 1);
        $t_list->insert();
        if ($t_list->numErrors()) {
            print "ERROR: couldn't create ca_list row for AAT: " . join('; ', $t_list->getErrors()) . "\n";
            die;
        }
        $t_list->addLabel(array('name' => 'Art & Architecture Thesaurus'), $pn_en_locale_id, null, true);
    }
    $vn_list_id = $t_list->getPrimaryKey();
    // get list item types (should be defined by base installation profile [base.profile])
    // if your installation didn't use a profile inheriting from base.profile then you should make sure
    // that a list with code='list_item_types' is defined and the following four item codes are defined.
    // If these are not defined then the AAT will still import, but without any distinction between
    // terms, facets and guide terms
    $vn_list_item_type_concept = $t_list->getItemIDFromList('list_item_types', 'concept');
    $vn_list_item_type_facet = $t_list->getItemIDFromList('list_item_types', 'facet');
    $vn_list_item_type_guide_term = $t_list->getItemIDFromList('list_item_types', 'guide_term');
    $vn_list_item_type_hierarchy_name = $t_list->getItemIDFromList('list_item_types', 'hierarchy_name');
    // get list item label types (should be defined by base installation profile [base.profile])
    // if your installation didn't use a profile inheriting from base.profile then you should make sure
    // that a list with code='list_item_label_types' is defined and the following four item codes are defined.
    // If these are not defined then the AAT will still import, but without any distinction between
    // terms, facets and guide terms
    $vn_list_item_label_type_uf = $t_list->getItemIDFromList('list_item_label_types', 'uf');
    $vn_list_item_label_type_alt = $t_list->getItemIDFromList('list_item_label_types', 'alt');
    // get list item-to-item relationship type (should be defined by base installation profile [base.profile])
    // if your installation didn't use a profile inheriting from base.profile then you should make sure
    // that a ca_list_items_x_list_items relationship type with code='related' is defined. Otherwise import of term-to-term
    // relationships will fail.
    $t_rel_types = new ca_relationship_types();
    $vn_list_item_relation_type_id_related = $t_rel_types->getRelationshipTypeID('ca_list_items_x_list_items', 'related');
    // load voc_terms
    $o_xml = new XMLReader();
    $o_xml->open($ps_path_to_aat_data);
    print "READING AAT TERMS...\n";
    $va_parent_child_links = array();
    $va_item_item_links = array();
    $va_aat_id_to_item_id = array();
    $vn_last_message_length = 0;
    $va_subject = array();
    $vn_term_count = 0;
    while ($o_xml->read()) {
        switch ($o_xml->name) {
            # ---------------------------
            case 'Subject':
                if ($o_xml->nodeType == XMLReader::END_ELEMENT) {
                    if ($va_subject['subject_id'] == '300000000') {
                        break;
                    }
                    // skip top-level root
                    $vs_preferred_term = $va_subject['preferred_term'];
                    switch ($va_subject['record_type']) {
                        case 'Concept':
                            $vn_type_id = $vn_list_item_type_hierarchy_name;
                            $pb_is_enabled = true;
                            break;
                        case 'Facet':
                            $vn_type_id = $vn_list_item_type_facet;
                            $vs_preferred_term = '<' . $vs_preferred_term . '>';
                            $pb_is_enabled = false;
                            break;
                        case 'Guide Term':
                            $vn_type_id = $vn_list_item_type_guide_term;
                            $vs_preferred_term = '<' . $vs_preferred_term . '>';
                            $pb_is_enabled = false;
                            break;
                        case 'Hierarchy Name':
                            $vn_type_id = $vn_list_item_type_hierarchy_name;
                            $pb_is_enabled = false;
                            break;
                        default:
                            $vn_type_id = null;
                            $pb_is_enabled = true;
                            break;
                    }
                    print str_repeat(chr(8), $vn_last_message_length);
                    $vs_message = "\tIMPORTING #" . ($vn_term_count + 1) . " [" . $va_subject['subject_id'] . "] " . $vs_preferred_term;
                    if (($vn_l = 100 - strlen($vs_message)) < 1) {
                        $vn_l = 1;
                    }
                    $vs_message .= str_repeat(' ', $vn_l);
                    $vn_last_message_length = strlen($vs_message);
                    print $vs_message;
                    if ($t_item = $t_list->addItem($va_subject['subject_id'], $pb_is_enabled, false, null, $vn_type_id, $va_subject['subject_id'], '', 4, 1)) {
                        $va_aat_id_to_item_id[$va_subject['subject_id']] = $t_item->getPrimaryKey();
                        if ($va_subject['preferred_parent_subject_id'] != 300000000) {
                            $va_parent_child_links[$va_subject['subject_id']] = $va_subject['preferred_parent_subject_id'];
                        }
                        // add preferred labels
                        if (!$t_item->addLabel(array('name_singular' => trim(htmlentities($vs_preferred_term, ENT_NOQUOTES)), 'name_plural' => trim(htmlentities($vs_preferred_term, ENT_NOQUOTES)), 'description' => $va_subject['description']), $pn_en_locale_id, null, true)) {
                            print "ERROR: Could not add preferred label to AAT term [" . $va_subject['subject_id'] . "] " . $vs_preferred_term . ": " . join("; ", $t_item->getErrors()) . "\n";
                        }
                        // add alternate labels
                        if (is_array($va_subject['non_preferred_terms'])) {
                            for ($vn_i = 0; $vn_i < sizeof($va_subject['non_preferred_terms']); $vn_i++) {
                                $vs_np_label = $va_subject['non_preferred_terms'][$vn_i];
                                $vs_np_term_type = $va_subject['non_preferred_term_types'][$vn_i];
                                switch ($vs_np_term_type) {
                                    case 'Used For Term':
                                        $vn_np_term_type_id = $vn_list_item_label_type_uf;
                                        break;
                                    case 'Alternate Descriptor':
                                        $vn_np_term_type_id = $vn_list_item_label_type_alt;
                                        break;
                                    default:
                                        $vn_np_term_type_id = null;
                                        break;
                                }
                                if (!$t_item->addLabel(array('name_singular' => trim(htmlentities($vs_np_label, ENT_NOQUOTES)), 'name_plural' => trim(htmlentities($vs_np_label, ENT_NOQUOTES)), 'description' => ''), $pn_en_locale_id, $vn_np_term_type_id, false)) {
                                    print "ERROR: Could not add non-preferred label to AAT term [" . $va_subject['subject_id'] . "] " . $vs_np_label . "\n";
                                    //: ".join("; ", $t_item->getErrors())."\n";
                                }
                            }
                        }
                        // record item-item relations
                        if (is_array($va_subject['related_subjects'])) {
                            foreach ($va_subject['related_subjects'] as $vs_rel_subject_id) {
                                $va_item_item_links[$va_subject['subject_id']] = $vs_rel_subject_id;
                            }
                        }
                        $vn_term_count++;
                    } else {
                        print "ERROR: Could not import AAT term [" . $va_subject['subject_id'] . "] " . $vs_preferred_term . ": " . join("; ", $t_list->getErrors()) . "\n";
                    }
                } else {
                    $va_subject = array('subject_id' => $o_xml->getAttribute('Subject_ID'));
                }
                break;
                # ---------------------------
            # ---------------------------
            case 'Descriptive_Note':
                while ($o_xml->read()) {
                    switch ($o_xml->name) {
                        case 'Note_Text':
                            switch ($o_xml->nodeType) {
                                case XMLReader::ELEMENT:
                                    $o_xml->read();
                                    $va_subject['description'] = $o_xml->value;
                                    break;
                            }
                            break;
                        case 'Descriptive_Note':
                            break 2;
                    }
                }
                break;
                # ---------------------------
            # ---------------------------
            case 'Record_Type':
                switch ($o_xml->nodeType) {
                    case XMLReader::ELEMENT:
                        $o_xml->read();
                        $va_subject['record_type'] = $o_xml->value;
                        break;
                }
                break;
                # ---------------------------
            # ---------------------------
            case 'Facet_Code':
                switch ($o_xml->nodeType) {
                    case XMLReader::ELEMENT:
                        $o_xml->read();
                        $va_subject['facet_code'] = $o_xml->value;
                        break;
                }
                break;
                # ---------------------------
            # ---------------------------
            case 'Parent_Relationships':
                $vn_parent_id = $vs_historic_flag = null;
                while ($o_xml->read()) {
                    switch ($o_xml->name) {
                        case 'Preferred_Parent':
                            while ($o_xml->read()) {
                                switch ($o_xml->name) {
                                    case 'Parent_Subject_ID':
                                        switch ($o_xml->nodeType) {
                                            case XMLReader::ELEMENT:
                                                $o_xml->read();
                                                $vn_parent_id = $o_xml->value;
                                                break;
                                        }
                                        break;
                                    case 'Historic_Flag':
                                        switch ($o_xml->nodeType) {
                                            case XMLReader::ELEMENT:
                                                $o_xml->read();
                                                $vs_historic_flag = $o_xml->value;
                                                break;
                                        }
                                        break;
                                    case 'Preferred_Parent':
                                        $va_subject['preferred_parent_subject_id'] = $vn_parent_id;
                                        break 2;
                                }
                            }
                            break;
                        case 'Parent_Relationships':
                            break 2;
                    }
                }
                break;
                # ---------------------------
            # ---------------------------
            case 'Preferred_Term':
                while ($o_xml->read()) {
                    switch ($o_xml->name) {
                        case 'Term_Type':
                            switch ($o_xml->nodeType) {
                                case XMLReader::ELEMENT:
                                    $o_xml->read();
                                    $va_subject['preferred_term_type'] = $o_xml->value;
                                    break;
                            }
                            break;
                        case 'Term_Text':
                            switch ($o_xml->nodeType) {
                                case XMLReader::ELEMENT:
                                    $o_xml->read();
                                    $va_subject['preferred_term'] = $o_xml->value;
                                    break;
                            }
                            break;
                        case 'Term_ID':
                            switch ($o_xml->nodeType) {
                                case XMLReader::ELEMENT:
                                    $o_xml->read();
                                    $va_subject['preferred_term_id'] = $o_xml->value;
                                    break;
                            }
                            break;
                            break;
                        case 'Preferred_Term':
                            break 2;
                    }
                }
                break;
                # ---------------------------
            # ---------------------------
            case 'Non-Preferred_Term':
                while ($o_xml->read()) {
                    switch ($o_xml->name) {
                        case 'Term_Type':
                            switch ($o_xml->nodeType) {
                                case XMLReader::ELEMENT:
                                    $o_xml->read();
                                    $va_subject['non_preferred_term_types'][] = $o_xml->value;
                                    break;
                            }
                            break;
                        case 'Term_Text':
                            switch ($o_xml->nodeType) {
                                case XMLReader::ELEMENT:
                                    $o_xml->read();
                                    $va_subject['non_preferred_terms'][] = $o_xml->value;
                                    break;
                            }
                            break;
                        case 'Term_ID':
                            switch ($o_xml->nodeType) {
                                case XMLReader::ELEMENT:
                                    $o_xml->read();
                                    $va_subject['non_preferred_term_ids'][] = $o_xml->value;
                                    break;
                            }
                            break;
                        case 'Non-Preferred_Term':
                            break 2;
                    }
                }
                break;
                # ---------------------------
            # ---------------------------
            case 'VP_Subject_ID':
                switch ($o_xml->nodeType) {
                    case XMLReader::ELEMENT:
                        $o_xml->read();
                        $va_subject['related_subjects'][] = $o_xml->value;
                        break;
                }
                break;
                # ---------------------------
        }
    }
    $o_xml->close();
    print "\n\nLINKING TERMS IN HIERARCHY...\n";
    $vn_last_message_length = 0;
    $t_item = new ca_list_items();
    $t_item->setMode(ACCESS_WRITE);
    foreach ($va_parent_child_links as $vs_child_id => $vs_parent_id) {
        print str_repeat(chr(8), $vn_last_message_length);
        $vs_message = "\tLINKING {$vs_child_id} to parent {$vs_parent_id}";
        if (($vn_l = 100 - strlen($vs_message)) < 1) {
            $vn_l = 1;
        }
        $vs_message .= str_repeat(' ', $vn_l);
        $vn_last_message_length = strlen($vs_message);
        print $vs_message;
        if (!($vn_child_item_id = $va_aat_id_to_item_id[$vs_child_id])) {
            print "ERROR: no list item id for child_id {$vs_child_id} (were there previous errors?)\n";
            continue;
        }
        if (!($vn_parent_item_id = $va_aat_id_to_item_id[$vs_parent_id])) {
            print "ERROR: no list item id for parent_id {$vs_child_id} (were there previous errors?)\n";
            continue;
        }
        if (!$t_item->load($vn_child_item_id)) {
            print "ERROR: could not load item for {$vs_child_id} (was translated to item_id={$vn_child_item_id})\n";
            continue;
        }
        $t_item->set('parent_id', $vn_parent_item_id);
        $t_item->update();
        if ($t_item->numErrors()) {
            print "ERROR: could not set parent_id for {$vs_child_id} (was translated to item_id={$vn_child_item_id}): " . join('; ', $t_item->getErrors()) . "\n";
        }
    }
    if ($vn_list_item_relation_type_id_related > 0) {
        print "\n\nADDING RELATED TERM LINKS...\n";
        $vn_last_message_length = 0;
        $t_item = new ca_list_items();
        $t_link = new ca_list_items_x_list_items();
        $t_link->setMode(ACCESS_WRITE);
        foreach ($va_item_item_links as $vs_left_id => $vs_right_id) {
            print str_repeat(chr(8), $vn_last_message_length);
            $vs_message = "\tLINKING {$vs_left_id} to {$vs_right_id}";
            if (($vn_l = 100 - strlen($vs_message)) < 1) {
                $vn_l = 1;
            }
            $vs_message .= str_repeat(' ', $vn_l);
            $vn_last_message_length = strlen($vs_message);
            print $vs_message;
            if (!($vn_left_item_id = $va_aat_id_to_item_id[$vs_left_id])) {
                print "ERROR: no list item id for left_id {$vs_left_id} (were there previous errors?)\n";
                continue;
            }
            if (!($vn_right_item_id = $va_aat_id_to_item_id[$vs_right_id])) {
                print "ERROR: no list item id for right_id {$vs_right_id} (were there previous errors?)\n";
                continue;
            }
            $t_link->set('term_left_id', $vn_left_item_id);
            $t_link->set('term_right_id', $vn_right_item_id);
            $t_link->set('type_id', $vn_list_item_relation_type_id_related);
            $t_link->insert();
            if ($t_link->numErrors()) {
                print "ERROR: could not set link between {$vs_left_id} (was translated to item_id={$vn_left_item_id}) and {$vs_right_id} (was translated to item_id={$vn_right_item_id}): " . join('; ', $t_link->getErrors()) . "\n";
            }
        }
    } else {
        print "WARNING: Skipped import of term-term relationships because the ca_list_items_x_list_items 'related' relationship type is not defined for your installation\n";
    }
    print "\n\nIMPORT COMPLETE.\n";
}