/**
 * Converts the given list of source names or source_ids into an expanded list of numeric source_ids suitable for enforcing source restrictions. Processing
 * includes expansion of sources to include subsources and conversion of any source codes to source_ids.
 *
 * @param mixed $pm_table_name_or_num Table name or number to which sources apply
 * @param array $pa_sources List of source codes and/or source_ids that are the basis of the list
 * @param array $pa_options Array of options:
 * 		dont_include_subsources_in_source_restriction = if set, returned list is not expanded to include subsources
 *		dontIncludeSubsourcesInSourceRestriction = synonym for dont_include_subsources_in_source_restriction
 *
 * @return array List of numeric source_ids
 */
function caMakeSourceIDList($pm_table_name_or_num, $pa_sources, $pa_options = null)
{
    $o_dm = Datamodel::load();
    if (isset($pa_options['dontIncludeSubsourcesInSourceRestriction']) && (!isset($pa_options['dont_include_subsources_in_source_restriction']) || !$pa_options['dont_include_subsources_in_source_restriction'])) {
        $pa_options['dont_include_subsources_in_source_restriction'] = $pa_options['dontIncludeSubsourcesInSourceRestriction'];
    }
    if (isset($pa_options['dont_include_subsources_in_source_restriction']) && $pa_options['dont_include_subsources_in_source_restriction']) {
        $pa_options['noChildren'] = true;
    }
    if (is_numeric($pm_table_name_or_num)) {
        $vs_table_name = $o_dm->getTableName($pm_table_name_or_num);
    } else {
        $vs_table_name = $pm_table_name_or_num;
    }
    $t_instance = $o_dm->getInstanceByTableName($vs_table_name, true);
    if (!$t_instance) {
        return null;
    }
    // bad table
    if (!($vs_source_list_code = $t_instance->getSourceListCode())) {
        return null;
    }
    // table doesn't use sources
    $va_source_ids = array();
    $t_list = new ca_lists();
    $t_item = new ca_list_items();
    $vs_list_code = $t_instance->getSourceListCode();
    foreach ($pa_sources as $vm_source) {
        if (!$vm_source) {
            continue;
        }
        $vn_source_id = null;
        if (is_numeric($vm_source)) {
            $vn_source_id = (int) $vm_source;
        } else {
            $vn_source_id = (int) $t_list->getItemIDFromList($vs_source_list_code, $vm_source);
        }
        if ($vn_source_id && !(isset($pa_options['noChildren']) || $pa_options['noChildren'])) {
            if ($qr_children = $t_item->getHierarchy($vn_source_id, array())) {
                while ($qr_children->nextRow()) {
                    $va_source_ids[$qr_children->get('item_id')] = true;
                }
            }
        } else {
            if ($vn_source_id) {
                $va_source_ids[$vn_source_id] = true;
            }
        }
    }
    return array_keys($va_source_ids);
}
Exemple #2
0
 /**
  *
  *
  * @param array $pa_type_codes_or_ids List of type codes or ids 
  * @param array $pa_options Options include
  *		dontExpandHierarchically =
  * @return array List of type_ids
  */
 private function _convertTypeCodesToIDs($pa_type_codes_or_ids, $pa_options = null)
 {
     $vs_md5 = caMakeCacheKeyFromOptions($pa_type_codes_or_ids);
     if (isset(BrowseEngine::$s_type_id_cache[$vs_md5])) {
         return BrowseEngine::$s_type_id_cache[$vs_md5];
     }
     if (isset($pa_options['instance']) && is_object($pa_options['instance'])) {
         $t_instance = $pa_options['instance'];
     } else {
         $t_instance = $this->getSubjectInstance();
     }
     $va_type_ids = array();
     if (!$pa_type_codes_or_ids) {
         return false;
     }
     if (is_array($pa_type_codes_or_ids) && !sizeof($pa_type_codes_or_ids)) {
         return false;
     }
     if (!is_array($pa_type_codes_or_ids)) {
         $pa_type_codes_or_ids = array($pa_type_codes_or_ids);
     }
     $t_list = new ca_lists();
     if (!method_exists($t_instance, 'getTypeListCode')) {
         return false;
     }
     if (!($vs_list_name = $t_instance->getTypeListCode())) {
         return false;
     }
     $va_type_list = $t_instance->getTypeList();
     foreach ($pa_type_codes_or_ids as $vs_code_or_id) {
         if (!trim($vs_code_or_id)) {
             continue;
         }
         if (!is_numeric($vs_code_or_id)) {
             $vn_type_id = $t_list->getItemIDFromList($vs_list_name, $vs_code_or_id);
         } else {
             $vn_type_id = (int) $vs_code_or_id;
         }
         if (!$vn_type_id) {
             return false;
         }
         if (isset($va_type_list[$vn_type_id]) && $va_type_list[$vn_type_id]) {
             // is valid type for this subject
             // See if there are any child types
             if (!caGetOption('dontExpandHierarchically', $pa_options, false) && !$this->opb_dont_expand_type_restrictions) {
                 $t_item = new ca_list_items();
                 $va_ids = $t_item->getHierarchy($vn_type_id, array('idsOnly' => true));
             }
             $va_ids[] = $vn_type_id;
             $va_type_ids = array_merge($va_type_ids, $va_ids);
         }
     }
     $va_type_ids = array_keys(array_flip($va_type_ids));
     BrowseEngine::$s_type_id_cache[$vs_md5] = $va_type_ids;
     return $va_type_ids;
 }
Exemple #3
0
 /**
  * Converts the given list of list item idnos or item_ids into an expanded list of numeric item_ids. Processing
  * includes expansion of items to include sub-items and conversion of any idnos to item_ids.
  *
  * @param mixed $pm_table_name_or_num Table name or number to which types apply
  * @param array $pa_types List of item idnos and/or item_ids that are the basis of the list
  * @param array $pa_options Array of options:
  * 		dont_include_sub_items = if set, returned list is not expanded to include sub-items
  *		dontIncludeSubItems = synonym for dont_include_sub_items
  * 		transaction = transaction to perform database operations within. [Default is null]
  *
  * @return array List of numeric item_ids
  */
 public static function getItemIDsFromList($pm_list_name_or_id, $pa_idnos, $pa_options = null)
 {
     if (isset($pa_options['dontIncludeSubItems']) && (!isset($pa_options['dont_include_sub_items']) || !$pa_options['dont_include_sub_items'])) {
         $pa_options['dont_include_sub_items'] = $pa_options['dontIncludeSubItems'];
     }
     if (isset($pa_options['dont_include_sub_items']) && $pa_options['dont_include_sub_items']) {
         $pa_options['noChildren'] = true;
     }
     $t_list = new ca_lists();
     $t_item = new ca_list_items();
     if ($o_trans = caGetOption('transaction', $pa_options, null)) {
         $t_list->setTransaction($o_trans);
         $t_item->setTransaction($o_trans);
     }
     $va_tmp = $va_item_ids = array();
     foreach ($pa_idnos as $vs_idno) {
         $vn_item_id = null;
         if (is_numeric($vs_idno)) {
             $va_tmp = array((int) $vs_idno);
         } else {
             $va_tmp = ca_list_items::find(array('idno' => $vs_idno, 'deleted' => 0), array('returnAs' => 'ids', 'transaction' => $o_trans));
         }
         if (sizeof($va_tmp) && !(isset($pa_options['noChildren']) || $pa_options['noChildren'])) {
             foreach ($va_tmp as $vn_item_id) {
                 if ($qr_children = $t_item->getHierarchy($vn_item_id, array())) {
                     while ($qr_children->nextRow()) {
                         $va_item_ids[$qr_children->get('item_id')] = true;
                     }
                 }
             }
         } else {
             foreach ($va_tmp as $vn_item_id) {
                 $va_item_ids[$vn_item_id] = true;
             }
         }
     }
     return array_keys($va_item_ids);
 }
 /**
  * Returns number of elements in system
  *
  * @param $pb_root_elements_only boolean If true, then only root elements are counted; default is false
  * @param $pm_table_name_or_num mixed Optional table name or number to filter list with. If specified then only elements that have a type restriction to the table are counted. If omitted (default) then all elements, regardless of type restrictions, are returned.
  * @param $pm_type_name_or_id mixed Optional type code or type_id to restrict elements to.  If specified then only elements that have a type restriction to the specified table and type are counted. 
  * @return int The number of elements
  */
 public static function getElementCount($pb_root_elements_only = false, $pm_table_name_or_num = null, $pm_type_name_or_id = null)
 {
     $o_dm = Datamodel::load();
     $vn_table_num = $o_dm->getTableNum($pm_table_name_or_num);
     $vo_db = new Db();
     $va_wheres = array();
     if ($pb_root_elements_only) {
         $va_wheres[] = 'cme.parent_id is NULL';
     }
     if ($vn_table_num) {
         $va_wheres[] = 'cmtr.table_num = ?';
         $va_where_params[] = (int) $vn_table_num;
         if ($pm_type_name_or_id) {
             $t_list_item = new ca_list_items();
             if (!is_numeric($pm_type_name_or_id)) {
                 $t_list_item->load(array('idno' => $pm_type_name_or_id));
             } else {
                 $t_list_item->load((int) $pm_type_name_or_id);
             }
             $va_type_ids = array();
             if ($vn_type_id = $t_list_item->getPrimaryKey()) {
                 $va_type_ids[$vn_type_id] = true;
                 if ($qr_children = $t_list_item->getHierarchy($vn_type_id, array())) {
                     while ($qr_children->nextRow()) {
                         $va_type_ids[$qr_children->get('item_id')] = true;
                     }
                 }
                 $va_wheres[] = '((cmtr.type_id = ?) OR (cmtr.include_subtypes = 1 AND cmtr.type_id IN (?)))';
                 $va_where_params[] = (int) $vn_type_id;
                 $va_where_params[] = $va_type_ids;
             }
         }
         $vs_wheres = ' WHERE ' . join(' AND ', $va_wheres);
         $qr_tmp = $vo_db->query("\n\t\t\t\tSELECT count(*) c\n\t\t\t\tFROM ca_metadata_elements cme\n\t\t\t\tINNER JOIN ca_metadata_type_restrictions AS cmtr ON cme.hier_element_id = cmtr.element_id\n\t\t\t\t{$vs_wheres}\n\t\t\t", $va_where_params);
     } else {
         if (sizeof($va_wheres)) {
             $vs_wheres = ' WHERE ' . join(' AND ', $va_wheres);
         } else {
             $vs_wheres = '';
         }
         $qr_tmp = $vo_db->query("\n\t\t\t\tSELECT count(*) c\n\t\t\t\tFROM ca_metadata_elements cme\n\t\t\t\t{$vs_wheres}\n\t\t\t");
     }
     if ($qr_tmp->nextRow()) {
         return $qr_tmp->get('c');
     }
     return 0;
 }
Exemple #5
0
 /**
  * Converts the given list of list item idnos or item_ids into an expanded list of numeric item_ids. Processing
  * includes expansion of items to include sub-items and conversion of any idnos to item_ids.
  *
  * @param mixed $pm_table_name_or_num Table name or number to which types apply
  * @param array $pa_types List of item idnos and/or item_ids that are the basis of the list
  * @param array $pa_options Array of options:
  * 		dont_include_sub_items = if set, returned list is not expanded to include sub-items
  *		dontIncludeSubItems = synonym for dont_include_sub_items
  *
  * @return array List of numeric item_ids
  */
 public static function getItemIDsFromList($pm_list_name_or_id, $pa_idnos, $pa_options = null)
 {
     if (isset($pa_options['dontIncludeSubItems']) && (!isset($pa_options['dont_include_sub_items']) || !$pa_options['dont_include_sub_items'])) {
         $pa_options['dont_include_sub_items'] = $pa_options['dontIncludeSubItems'];
     }
     if (isset($pa_options['dont_include_sub_items']) && $pa_options['dont_include_sub_items']) {
         $pa_options['noChildren'] = true;
     }
     $t_list = new ca_lists();
     $t_item = new ca_list_items();
     $va_item_ids = array();
     foreach ($pa_idnos as $vs_idno) {
         $vn_item_id = null;
         if (is_numeric($vs_idno)) {
             $vn_item_id = (int) $vs_idno;
         } else {
             $vn_item_id = (int) $t_list->getItemIDFromList($pm_list_name_or_id, $vs_idno);
         }
         if ($vn_item_id && !(isset($pa_options['noChildren']) || $pa_options['noChildren'])) {
             if ($qr_children = $t_item->getHierarchy($vn_item_id, array())) {
                 while ($qr_children->nextRow()) {
                     $va_item_ids[$qr_children->get('item_id')] = true;
                 }
             }
         } else {
             if ($vn_item_id) {
                 $va_item_ids[$vn_item_id] = true;
             }
         }
     }
     return array_keys($va_item_ids);
 }
Exemple #6
0
 /**
  * Actually do the browse
  *
  * Options:
  *		checkAccess = array of access values to filter facets that have an 'access' field by
  *		no_cache = don't use cached browse results
  *		showDeleted = if set to true, related items that have been deleted are returned. Default is false.
  *		limitToModifiedOn = if set returned results will be limited to rows modified within the specified date range. The value should be a date/time expression parse-able by TimeExpressionParser
  *		user_id = If set item level access control is performed relative to specified user_id, otherwise defaults to logged in user
  */
 public function execute($pa_options = null)
 {
     global $AUTH_CURRENT_USER_ID;
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     $vn_user_id = isset($pa_options['user_id']) && (int) $pa_options['user_id'] ? (int) $pa_options['user_id'] : (int) $AUTH_CURRENT_USER_ID;
     if (!is_array($this->opa_browse_settings)) {
         return null;
     }
     $va_params = $this->opo_ca_browse_cache->getParameters();
     $vb_need_to_cache_facets = false;
     $vb_results_cached = false;
     $vb_need_to_save_in_cache = false;
     $vs_cache_key = $this->opo_ca_browse_cache->getCurrentCacheKey();
     if ($this->opo_ca_browse_cache->load($vs_cache_key)) {
         $vn_created_on = $this->opo_ca_browse_cache->getParameter('created_on');
         //$t_new_browse->get('created_on', array('GET_DIRECT_DATE' => true));
         $va_criteria = $this->getCriteria();
         if ((!isset($pa_options['no_cache']) || !$pa_options['no_cache']) && intval(time() - $vn_created_on) < $this->opo_ca_browse_config->get('cache_timeout')) {
             $vb_results_cached = true;
             //print "cache hit for [$vs_cache_key]<br>";
         } else {
             $va_criteria = $this->getCriteria();
             $this->opo_ca_browse_cache->remove();
             $this->opo_ca_browse_cache->setParameter('criteria', $va_criteria);
             //print "cache expire for [$vs_cache_key]<br>";
             $vb_need_to_save_in_cache = true;
             $vb_need_to_cache_facets = true;
         }
     } else {
         $va_criteria = $this->getCriteria();
         //print "cache miss for [$vs_cache_key]<br>";
         $vb_need_to_save_in_cache = true;
     }
     if (!$vb_results_cached) {
         $this->opo_ca_browse_cache->setParameter('sort', null);
         $this->opo_ca_browse_cache->setParameter('created_on', time());
         $this->opo_ca_browse_cache->setParameter('table_num', $this->opn_browse_table_num);
         $vb_need_to_cache_facets = true;
     }
     $this->opb_criteria_have_changed = false;
     $t_item = $this->opo_datamodel->getInstanceByTableName($this->ops_browse_table_name, true);
     $va_results = array();
     if (is_array($va_criteria) && sizeof($va_criteria) > 0) {
         if (!$vb_results_cached) {
             // generate results
             $this->_createTempTable('ca_browses_acc');
             $this->_createTempTable('ca_browses_tmp');
             $vn_i = 0;
             foreach ($va_criteria as $vs_facet_name => $va_row_ids) {
                 $vs_target_browse_table_name = $t_item->tableName();
                 $vs_target_browse_table_num = $t_item->tableNum();
                 $vs_target_browse_table_pk = $t_item->primaryKey();
                 $va_facet_info = $this->getInfoForFacet($vs_facet_name);
                 $va_row_ids = array_keys($va_row_ids);
                 $vs_relative_to_join = '';
                 switch ($va_facet_info['type']) {
                     # -----------------------------------------------------
                     case 'has':
                         $vs_rel_table_name = $va_facet_info['table'];
                         $va_joins = array();
                         if ($va_facet_info['relative_to']) {
                             if ($va_relative_execute_sql_data = $this->_getRelativeExecuteSQLData($va_facet_info['relative_to'], $pa_options)) {
                                 $va_joins = array_merge($va_joins, $va_relative_execute_sql_data['relative_joins']);
                                 $vs_target_browse_table_name = $va_relative_execute_sql_data['target_table_name'];
                                 $vs_target_browse_table_num = $va_relative_execute_sql_data['target_table_num'];
                                 $vs_target_browse_table_pk = $va_relative_execute_sql_data['target_table_pk'];
                             }
                         }
                         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'];
                             $vn_state = array_pop($va_row_ids);
                             if ($vn_state == 0) {
                                 $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 {
                                 $va_joins[] = "INNER JOIN ca_attributes AS caa ON caa.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . " AND caa.table_num = " . $t_item->tableNum();
                                 $va_wheres[] = "caa.element_id = " . $t_element->getPrimaryKey();
                             }
                         } else {
                             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_target_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);
                             $vn_state = array_pop($va_row_ids);
                             foreach ($va_path as $vs_join_table) {
                                 $va_rel_info = $this->opo_datamodel->getRelationships($vs_cur_table, $vs_join_table);
                                 $va_joins[] = ($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_wheres = array();
                             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 (!(bool) $vn_state) {
                                 // 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() . "." . $t_rel_item->primaryKey() . " IS NULL) AND (" . $t_rel_item->tableName() . ".access IS NULL)))";
                                 }
                             } 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 ($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[] = "(" . $t_item->tableName() . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
                         }
                         $vs_join_sql = join("\n", $va_joins);
                         $vs_where_sql = '';
                         if (sizeof($va_wheres) > 0) {
                             $vs_where_sql = ' WHERE ' . join(' AND ', $va_wheres);
                         }
                         if ($vn_i == 0) {
                             $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_acc\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\t\t\t";
                             //print "$vs_sql<hr>";
                             $qr_res = $this->opo_db->query($vs_sql);
                         } else {
                             $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_tmp");
                             $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_tmp\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_browses_acc ON ca_browses_acc.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}";
                             //print "$vs_sql<hr>";
                             $qr_res = $this->opo_db->query($vs_sql);
                             $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_acc");
                             $qr_res = $this->opo_db->query("INSERT IGNORE INTO ca_browses_acc SELECT row_id FROM ca_browses_tmp");
                         }
                         $vn_i++;
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'label':
                         if (!($t_label = $t_item->getLabelTableInstance())) {
                             break;
                         }
                         $vs_label_item_pk = $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();
                         if ($va_facet_info['relative_to']) {
                             if ($va_relative_execute_sql_data = $this->_getRelativeExecuteSQLData($va_facet_info['relative_to'], $pa_options)) {
                                 $vs_target_browse_table_name = $va_relative_execute_sql_data['target_table_name'];
                                 $vs_target_browse_table_num = $va_relative_execute_sql_data['target_table_num'];
                                 $vs_target_browse_table_pk = $va_relative_execute_sql_data['target_table_pk'];
                                 $t_target = $this->opo_datamodel->getInstanceByTableName($va_facet_info['relative_to'], true);
                                 $t_target_label = $t_target->getLabelTableInstance();
                                 $vs_item_pk = $t_target->primaryKey();
                                 $vs_label_table_name = $t_target_label->tableName();
                                 $vs_label_item_pk = $t_target_label->primaryKey();
                                 $va_relative_to_join = $va_relative_execute_sql_data['relative_joins'];
                                 $va_relative_to_join[] = "INNER JOIN {$vs_label_table_name} ON {$vs_label_table_name}.{$vs_label_item_pk} = {$vs_target_browse_table_name}.{$vs_target_browse_table_pk}";
                             }
                         } else {
                             $va_relative_to_join = array("INNER JOIN {$vs_label_table_name} ON {$vs_label_table_name}.{$vs_label_item_pk} = {$vs_target_browse_table_name}.{$vs_target_browse_table_pk}");
                         }
                         $vs_relative_to_join = join("\n", $va_relative_to_join);
                         foreach ($va_row_ids as $vn_row_id) {
                             if ($vn_i == 0) {
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_acc\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . "." . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t{$vs_label_table_name}.{$vs_label_item_pk} = ?";
                                 //print "$vs_sql [".intval($this->opn_browse_table_num)."]<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql, $vn_row_id);
                             } else {
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_tmp");
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_tmp\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . "." . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_browses_acc ON ca_browses_acc.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t{$vs_label_table_name}.{$vs_label_item_pk} = ?";
                                 //print "$vs_sql [".intval($this->opn_browse_table_num)."]<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql, $vn_row_id);
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_acc");
                                 $qr_res = $this->opo_db->query("INSERT IGNORE INTO ca_browses_acc SELECT row_id FROM ca_browses_tmp");
                             }
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'field':
                         $vs_field_name = $va_facet_info['field'];
                         $vs_table_name = $this->ops_browse_table_name;
                         if ($va_facet_info['relative_to']) {
                             if ($va_relative_execute_sql_data = $this->_getRelativeExecuteSQLData($va_facet_info['relative_to'], $pa_options)) {
                                 $va_relative_to_join = $va_relative_execute_sql_data['relative_joins'];
                                 $vs_relative_to_join = join("\n", $va_relative_to_join);
                                 $vs_table_name = $vs_target_browse_table_name = $va_relative_execute_sql_data['target_table_name'];
                                 $vs_target_browse_table_num = $va_relative_execute_sql_data['target_table_num'];
                                 $vs_target_browse_table_pk = $va_relative_execute_sql_data['target_table_pk'];
                             }
                         }
                         foreach ($va_row_ids as $vn_row_id) {
                             $vn_row_id = urldecode($vn_row_id);
                             if ($vn_i == 0) {
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_acc\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t({$vs_table_name}.{$vs_field_name} = ?)";
                                 //print "$vs_sql [".intval($this->opn_browse_table_num)."/".$vn_element_id."/".$vn_row_id."]<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql, (string) $vn_row_id);
                             } else {
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_tmp");
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_tmp\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_browses_acc ON ca_browses_acc.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t({$vs_table_name}.{$vs_field_name} = ?)";
                                 //print "$vs_sql [".intval($this->opn_browse_table_num)."/".$vn_element_id."/".$vn_row_id."]<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql, (string) $vn_row_id);
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_acc");
                                 $qr_res = $this->opo_db->query("INSERT IGNORE INTO ca_browses_acc SELECT row_id FROM ca_browses_tmp");
                             }
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'attribute':
                         $t_element = new ca_metadata_elements();
                         if (!$t_element->load(array('element_code' => $va_facet_info['element_code']))) {
                             return array();
                         }
                         $vn_datatype = $t_element->get('datatype');
                         if ($va_facet_info['relative_to']) {
                             if ($va_relative_execute_sql_data = $this->_getRelativeExecuteSQLData($va_facet_info['relative_to'], $pa_options)) {
                                 $va_relative_to_join = $va_relative_execute_sql_data['relative_joins'];
                                 $vs_relative_to_join = join("\n", $va_relative_to_join);
                                 $vs_target_browse_table_name = $va_relative_execute_sql_data['target_table_name'];
                                 $vs_target_browse_table_num = $va_relative_execute_sql_data['target_table_num'];
                                 $vs_target_browse_table_pk = $va_relative_execute_sql_data['target_table_pk'];
                             }
                         }
                         // TODO: check that it is a *single-value* (ie. no hierarchical ca_metadata_elements) Text or Number attribute
                         // (do we support other types as well?)
                         $vn_element_id = $t_element->getPrimaryKey();
                         $o_attr = Attribute::getValueInstance($t_element->get('datatype'));
                         foreach ($va_row_ids as $vn_row_id) {
                             $vn_row_id = urldecode($vn_row_id);
                             $vn_row_id = str_replace('&#47;', '/', $vn_row_id);
                             $va_value = $o_attr->parseValue($vn_row_id, $t_element->getFieldValuesArray());
                             $va_attr_sql = array();
                             $va_attr_values = array(intval($vs_target_browse_table_num), $vn_element_id);
                             if (is_array($va_value)) {
                                 foreach ($va_value as $vs_f => $vs_v) {
                                     if ($vn_datatype == 3) {
                                         // list
                                         $t_list_item = new ca_list_items((int) $vs_v);
                                         // Include sub-items
                                         $va_item_ids = $t_list_item->getHierarchy((int) $vs_v, array('idsOnly' => true, 'includeSelf' => true));
                                         $va_item_ids[] = (int) $vs_v;
                                         $va_attr_sql[] = "(ca_attribute_values.{$vs_f} IN (?))";
                                         $va_attr_values[] = $va_item_ids;
                                     } else {
                                         $va_attr_sql[] = "(ca_attribute_values.{$vs_f} " . (is_null($vs_v) ? " IS " : " = ") . " ?)";
                                         $va_attr_values[] = $vs_v;
                                     }
                                 }
                             }
                             if ($vs_attr_sql = join(" AND ", $va_attr_sql)) {
                                 $vs_attr_sql = " AND " . $vs_attr_sql;
                             }
                             if ($vn_i == 0) {
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_acc\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes ON ca_attributes.row_id = {$vs_target_browse_table_name}.{$vs_target_browse_table_pk} AND ca_attributes.table_num = ?\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values ON ca_attribute_values.attribute_id = ca_attributes.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.element_id = ?) {$vs_attr_sql}";
                                 //caDebug($vs_sql);
                                 //caDebug(intval($vs_target_browse_table_num)."/".$vn_element_id."/".$vn_row_id);
                                 //caDebug($va_attr_values);
                                 $qr_res = $this->opo_db->query($vs_sql, $va_attr_values);
                             } else {
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_tmp");
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_tmp\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes ON ca_attributes.row_id = {$vs_target_browse_table_name}.{$vs_target_browse_table_pk} AND ca_attributes.table_num = ?\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values ON ca_attribute_values.attribute_id = ca_attributes.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_browses_acc ON ca_browses_acc.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.element_id = ?) {$vs_attr_sql}";
                                 //print "$vs_sql [".intval($vs_target_browse_table_num)."/".$vn_element_id."/".$vn_row_id."]<hr>";print_R($va_attr_values);
                                 $qr_res = $this->opo_db->query($vs_sql, $va_attr_values);
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_acc");
                                 $qr_res = $this->opo_db->query("INSERT IGNORE INTO ca_browses_acc SELECT row_id FROM ca_browses_tmp");
                             }
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'normalizedDates':
                         $t_element = new ca_metadata_elements();
                         if (!$t_element->load(array('element_code' => $va_facet_info['element_code']))) {
                             return array();
                         }
                         // TODO: check that it is a *single-value* (ie. no hierarchical ca_metadata_elements) DateRange attribute
                         $vs_normalization = $va_facet_info['normalization'];
                         $vn_element_id = $t_element->getPrimaryKey();
                         $o_tep = new TimeExpressionParser();
                         if ($va_facet_info['relative_to']) {
                             if ($va_relative_execute_sql_data = $this->_getRelativeExecuteSQLData($va_facet_info['relative_to'], $pa_options)) {
                                 $va_relative_to_join = $va_relative_execute_sql_data['relative_joins'];
                                 $vs_relative_to_join = join("\n", $va_relative_to_join);
                                 $vs_target_browse_table_name = $va_relative_execute_sql_data['target_table_name'];
                                 $vs_target_browse_table_num = $va_relative_execute_sql_data['target_table_num'];
                                 $vs_target_browse_table_pk = $va_relative_execute_sql_data['target_table_pk'];
                             }
                         }
                         foreach ($va_row_ids as $vn_row_id) {
                             $vn_row_id = urldecode($vn_row_id);
                             if (!$o_tep->parse($vn_row_id)) {
                                 continue;
                             }
                             // invalid date?
                             $va_dates = $o_tep->getHistoricTimestamps();
                             if ($vn_i == 0) {
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_acc\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes ON ca_attributes.row_id = " . $vs_target_browse_table_name . '.' . $vs_target_browse_table_pk . " AND ca_attributes.table_num = ?\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values ON ca_attribute_values.attribute_id = ca_attributes.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.element_id = ?) AND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.value_decimal1 <= ?) AND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.value_decimal2 >= ?)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\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\t\t(ca_attribute_values.value_decimal1 BETWEEN ? AND ?)\n\t\t\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\t\t(ca_attribute_values.value_decimal2 BETWEEN ? AND ?)\n\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t";
                                 //print $vs_sql;
                                 $qr_res = $this->opo_db->query($vs_sql, intval($vs_target_browse_table_num), $vn_element_id, $va_dates['start'], $va_dates['end'], $va_dates['start'], $va_dates['end'], $va_dates['start'], $va_dates['end']);
                             } else {
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_tmp");
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_tmp\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes ON ca_attributes.row_id = " . $vs_target_browse_table_name . '.' . $vs_target_browse_table_pk . " AND ca_attributes.table_num = ?\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values ON ca_attribute_values.attribute_id = ca_attributes.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_browses_acc ON ca_browses_acc.row_id = " . $t_item->tableName() . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.element_id = ?) AND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.value_decimal1 <= ?) AND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.value_decimal2 >= ?)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\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\t\t(ca_attribute_values.value_decimal1 BETWEEN ? AND ?)\n\t\t\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\t\t(ca_attribute_values.value_decimal2 BETWEEN ? AND ?)\n\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t";
                                 //print $vs_sql;
                                 $qr_res = $this->opo_db->query($vs_sql, intval($vs_target_browse_table_num), $vn_element_id, $va_dates['start'], $va_dates['end'], $va_dates['start'], $va_dates['end'], $va_dates['start'], $va_dates['end']);
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_acc");
                                 $qr_res = $this->opo_db->query("INSERT IGNORE INTO ca_browses_acc SELECT row_id FROM ca_browses_tmp");
                             }
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'authority':
                         $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);
                         if ($va_facet_info['relative_to']) {
                             if ($va_relative_execute_sql_data = $this->_getRelativeExecuteSQLData($va_facet_info['relative_to'], $pa_options)) {
                                 $va_relative_to_join = $va_relative_execute_sql_data['relative_joins'];
                                 $vs_relative_to_join = join("\n", $va_relative_to_join);
                                 $vs_target_browse_table_name = $va_relative_execute_sql_data['target_table_name'];
                                 $vs_target_browse_table_num = $va_relative_execute_sql_data['target_table_num'];
                                 $vs_target_browse_table_pk = $va_relative_execute_sql_data['target_table_pk'];
                             }
                         }
                         foreach ($va_row_ids as $vn_row_id) {
                             switch (sizeof($va_path = array_keys($this->opo_datamodel->getPath($vs_target_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 = array();
                             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;
                             }
                             $vs_join_sql = join("\n", $va_joins);
                             $va_wheres = array();
                             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) . "))";
                             }
                             $vs_where_sql = '';
                             if (sizeof($va_wheres) > 0) {
                                 $vs_where_sql = ' AND ' . join(' AND ', $va_wheres);
                             }
                             if ((!isset($va_facet_info['dont_expand_hierarchically']) || !$va_facet_info['dont_expand_hierarchically']) && $t_rel_item->isHierarchical() && $t_rel_item->load((int) $vn_row_id)) {
                                 $vs_hier_left_fld = $t_rel_item->getProperty('HIERARCHY_LEFT_INDEX_FLD');
                                 $vs_hier_right_fld = $t_rel_item->getProperty('HIERARCHY_RIGHT_INDEX_FLD');
                                 $vs_get_item_sql = "{$vs_rel_table_name}.{$vs_hier_left_fld} >= " . $t_rel_item->get($vs_hier_left_fld) . " AND {$vs_rel_table_name}.{$vs_hier_right_fld} <= " . $t_rel_item->get($vs_hier_right_fld);
                                 if ($vn_hier_id_fld = $t_rel_item->getProperty('HIERARCHY_ID_FLD')) {
                                     $vs_get_item_sql .= " AND {$vs_rel_table_name}.{$vn_hier_id_fld} = " . (int) $t_rel_item->get($vn_hier_id_fld);
                                 }
                                 $vs_get_item_sql = "({$vs_get_item_sql})";
                             } else {
                                 $vs_get_item_sql = "({$vs_rel_table_name}.{$vs_rel_table_pk} = " . (int) $vn_row_id . ")";
                             }
                             if ($vn_i == 0) {
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_acc\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t{$vs_get_item_sql}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}";
                                 //print "$vs_sql<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql);
                             } else {
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_tmp");
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_tmp\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_browses_acc ON ca_browses_acc.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t{$vs_get_item_sql}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}";
                                 //print "$vs_sql<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql);
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_acc");
                                 $qr_res = $this->opo_db->query("INSERT IGNORE INTO ca_browses_acc SELECT row_id FROM ca_browses_tmp");
                             }
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'fieldList':
                         $vs_field_name = $va_facet_info['field'];
                         $vs_table_name = $this->ops_browse_table_name;
                         if ($va_facet_info['relative_to']) {
                             if ($va_relative_execute_sql_data = $this->_getRelativeExecuteSQLData($va_facet_info['relative_to'], $pa_options)) {
                                 $va_relative_to_join = $va_relative_execute_sql_data['relative_joins'];
                                 $vs_relative_to_join = join("\n", $va_relative_to_join);
                                 $vs_table_name = $vs_target_browse_table_name = $va_relative_execute_sql_data['target_table_name'];
                                 $vs_target_browse_table_num = $va_relative_execute_sql_data['target_table_num'];
                                 $vs_target_browse_table_pk = $va_relative_execute_sql_data['target_table_pk'];
                             }
                         }
                         foreach ($va_row_ids as $vn_row_id) {
                             $vn_row_id = urldecode($vn_row_id);
                             if ($vn_i == 0) {
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_acc\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t({$vs_table_name}.{$vs_field_name} = ?)";
                                 //print "$vs_sql [".intval($this->opn_browse_table_num)."/".$vn_row_id."]<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql, $vn_row_id);
                             } else {
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_tmp");
                                 $vs_sql = "\n\t\t\t\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO ca_browses_tmp\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_browses_acc ON ca_browses_acc.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t({$vs_table_name}.{$vs_field_name} = ?)";
                                 //print "$vs_sql [".intval($this->opn_browse_table_num)."/".$vn_row_id."]<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql, $vn_row_id);
                                 $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_acc");
                                 $qr_res = $this->opo_db->query("INSERT IGNORE INTO ca_browses_acc SELECT row_id FROM ca_browses_tmp");
                             }
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     default:
                         // handle "search" criteria - search engine queries that can be browsed
                         if ($vs_facet_name === '_search') {
                             $qr_res = $this->opo_db->query("TRUNCATE TABLE ca_browses_acc");
                             if (!($o_search = caGetSearchInstance($this->ops_browse_table_name))) {
                                 $this->postError(2900, _t("Invalid search type"), "BrowseEngine->execute()");
                                 break;
                             }
                             $vs_pk = $t_item->primaryKey();
                             if (is_array($va_type_ids = $this->getTypeRestrictionList()) && sizeof($va_type_ids)) {
                                 $o_search->setTypeRestrictions($va_type_ids);
                             }
                             $va_options = $pa_options;
                             unset($va_options['sort']);
                             // browse engine takes care of sort so there is no reason to waste time having the search engine do so
                             $va_options['filterNonPrimaryRepresentations'] = true;
                             // filter out non-primary representations in ca_objects results to save (a bit) of time
                             $qr_res = $o_search->search($va_row_ids[0], $va_options);
                             if ($qr_res->numHits() > 0) {
                                 $va_ids = array();
                                 $va_id_list = $qr_res->getPrimaryKeyValues();
                                 foreach ($va_id_list as $vn_id) {
                                     $va_ids[] = "({$vn_id})";
                                 }
                                 $this->opo_db->query("INSERT IGNORE INTO ca_browses_acc VALUES " . join(",", $va_ids));
                                 $vn_i++;
                             }
                         } else {
                             $this->postError(2900, _t("Invalid criteria type"), "BrowseEngine->execute()");
                         }
                         break;
                         # -----------------------------------------------------
                 }
             }
             $vs_filter_join_sql = $vs_filter_where_sql = '';
             $va_wheres = array();
             $va_joins = array();
             $vs_sql_distinct = '';
             if (sizeof($this->opa_result_filters)) {
                 $va_joins[$this->ops_browse_table_name] = "INNER JOIN " . $this->ops_browse_table_name . " ON " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_browses_acc.row_id';
                 $va_tmp = array();
                 foreach ($this->opa_result_filters as $va_filter) {
                     $vm_val = $this->_filterValueToQueryValue($va_filter);
                     $va_wheres[] = $this->ops_browse_table_name . '.' . $va_filter['field'] . " " . $va_filter['operator'] . " " . $vm_val;
                 }
             }
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_joins[$this->ops_browse_table_name] = "INNER JOIN " . $this->ops_browse_table_name . " ON " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_browses_acc.row_id';
                 $va_wheres[] = "(" . $this->ops_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ((!isset($pa_options['showDeleted']) || !$pa_options['showDeleted']) && $t_item->hasField('deleted')) {
                 if (!isset($va_joins[$this->ops_browse_table_name])) {
                     $va_joins[$this->ops_browse_table_name] = "INNER JOIN " . $this->ops_browse_table_name . " ON " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_browses_acc.row_id';
                 }
                 $va_wheres[] = "(" . $this->ops_browse_table_name . ".deleted = 0)";
             }
             if (isset($pa_options['limitToModifiedOn']) && $pa_options['limitToModifiedOn']) {
                 $o_tep = new TimeExpressionParser();
                 if ($o_tep->parse($pa_options['limitToModifiedOn'])) {
                     $va_range = $o_tep->getUnixTimestamps();
                     $va_joins['ca_change_log_subjects'] = "INNER JOIN ca_change_log_subjects ON ca_change_log_subjects.subject_row_id = ca_browses_acc.row_id AND ca_change_log_subjects.subject_table_num = " . $t_item->tableNum();
                     $va_joins['ca_change_log'] = "INNER JOIN ca_change_log ON ca_change_log.log_id = ca_change_log_subjects.log_id";
                     $va_wheres[] = "(((ca_change_log.log_datetime BETWEEN " . (int) $va_range['start'] . " AND " . (int) $va_range['end'] . ") AND (ca_change_log.changetype IN ('I', 'U', 'D'))))";
                     $vs_sql_distinct = 'DISTINCT';
                     // need to pull distinct rows since joining the change log can cause dupes
                 }
             }
             if (($va_browse_type_ids = $this->getTypeRestrictionList()) && sizeof($va_browse_type_ids)) {
                 $t_subject = $this->getSubjectInstance();
                 $va_joins[$this->ops_browse_table_name] = "INNER JOIN " . $this->ops_browse_table_name . " ON " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_browses_acc.row_id';
                 $va_wheres[] = '(' . $this->ops_browse_table_name . '.' . $t_subject->getTypeFieldName() . ' IN (' . join(', ', $va_browse_type_ids) . '))';
             }
             if (sizeof($va_wheres)) {
                 $vs_filter_where_sql = 'WHERE ' . join(' AND ', $va_wheres);
             }
             if (sizeof($va_joins)) {
                 $vs_filter_join_sql = join("\n", $va_joins);
             }
             $qr_res = $this->opo_db->query("\n\t\t\t\t\t\tSELECT {$vs_sql_distinct} row_id\n\t\t\t\t\t\tFROM ca_browses_acc\n\t\t\t\t\t\t{$vs_filter_join_sql}\n\t\t\t\t\t\t{$vs_filter_where_sql}\n\t\t\t\t\t");
             while ($qr_res->nextRow()) {
                 $va_results[] = $qr_res->get('row_id', array('binary' => true));
             }
             $this->_dropTempTable('ca_browses_acc');
             $this->_dropTempTable('ca_browses_tmp');
             if ((!isset($pa_options['dontFilterByACL']) || !$pa_options['dontFilterByACL']) && $this->opo_config->get('perform_item_level_access_checking') && method_exists($t_item, "supportsACL") && $t_item->supportsACL()) {
                 $va_results = array_keys($this->filterHitsByACL(array_flip($va_results), $vn_user_id, __CA_ACL_READONLY_ACCESS__));
             }
             $this->opo_ca_browse_cache->setResults($va_results);
             $vb_need_to_save_in_cache = true;
         }
     } else {
         // no criteria - don't try to find anything unless configured to do so
         $va_settings = $this->opo_ca_browse_config->getAssoc($this->ops_browse_table_name);
         if (isset($va_settings['show_all_for_no_criteria_browse']) && $va_settings['show_all_for_no_criteria_browse']) {
             $va_wheres = $va_joins = array();
             $vs_pk = $t_item->primaryKey();
             if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) {
                 $va_wheres[] = "(" . $this->ops_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))";
             }
             if ((!isset($pa_options['showDeleted']) || !$pa_options['showDeleted']) && $t_item->hasField('deleted')) {
                 $va_wheres[] = "(" . $this->ops_browse_table_name . ".deleted = 0)";
             }
             if (isset($pa_options['limitToModifiedOn']) && $pa_options['limitToModifiedOn']) {
                 $o_tep = new TimeExpressionParser();
                 if ($o_tep->parse($pa_options['limitToModifiedOn'])) {
                     $va_range = $o_tep->getUnixTimestamps();
                     $va_joins['ca_change_log_subjects'] = "INNER JOIN ca_change_log_subjects ON ca_change_log_subjects.subject_row_id = " . $this->ops_browse_table_name . ".{$vs_pk} AND ca_change_log_subjects.subject_table_num = " . $t_item->tableNum();
                     $va_joins['ca_change_log'] = "INNER JOIN ca_change_log ON ca_change_log.log_id = ca_change_log_subjects.log_id";
                     $va_wheres[] = "(((ca_change_log.log_datetime BETWEEN " . (int) $va_range['start'] . " AND " . (int) $va_range['end'] . ") AND (ca_change_log.changetype IN ('I', 'U', 'D'))))";
                     $vs_sql_distinct = 'DISTINCT';
                     // need to pull distinct rows since joining the change log can cause dupes
                 }
             }
             if (($va_browse_type_ids = $this->getTypeRestrictionList()) && sizeof($va_browse_type_ids)) {
                 $t_subject = $this->getSubjectInstance();
                 $va_wheres[] = '(' . $this->ops_browse_table_name . '.' . $t_subject->getTypeFieldName() . ' IN (' . join(', ', $va_browse_type_ids) . '))';
             }
             if (sizeof($va_wheres)) {
                 $vs_filter_where_sql = 'WHERE ' . join(' AND ', $va_wheres);
             }
             if (sizeof($va_joins)) {
                 $vs_filter_join_sql = join("\n", $va_joins);
             }
             $qr_res = $this->opo_db->query("\n\t\t\t\t\t\tSELECT {$vs_pk}\n\t\t\t\t\t\tFROM " . $t_item->tableName() . "\n\t\t\t\t\t\t{$vs_filter_join_sql}\n\t\t\t\t\t\t{$vs_filter_where_sql}\n\t\t\t\t\t");
             $va_results = $qr_res->getAllFieldValues($vs_pk);
             if ((!isset($pa_options['dontFilterByACL']) || !$pa_options['dontFilterByACL']) && $this->opo_config->get('perform_item_level_access_checking') && method_exists($t_item, "supportsACL") && $t_item->supportsACL()) {
                 $va_results = array_keys($this->filterHitsByACL(array_flip($va_results), $vn_user_id, __CA_ACL_READONLY_ACCESS__));
             }
             $this->opo_ca_browse_cache->setResults($va_results);
         } else {
             $this->opo_ca_browse_cache->setResults(array());
         }
         $vb_need_to_save_in_cache = true;
     }
     if ($vb_need_to_cache_facets) {
         if (!$pa_options['dontCheckFacetAvailability']) {
             $this->loadFacetContent($pa_options);
         }
     }
     if ($vb_need_to_save_in_cache) {
         $this->opo_ca_browse_cache->save();
     }
     return true;
 }