/**
  * Run all the search queries set by the implementation and check if the number of hits fits!
  */
 public function testSearchQueries()
 {
     if (!is_array($this->opa_search_queries)) {
         $this->assertTrue(false, 'no queries set up!');
     }
     $o_search = caGetSearchInstance($this->ops_primary_table);
     foreach ($this->opa_search_queries as $vs_query => $vn_expected_num_results) {
         $o_result = $o_search->search($vs_query);
         $this->assertEquals($vn_expected_num_results, $o_result->numHits(), 'Must match the expected number of search results. Query was: ' . $vs_query);
     }
 }
 public function testDelete()
 {
     $va_objects = array();
     $this->assertGreaterThan(0, $va_objects[] = $this->addTestRecord('ca_objects', array('intrinsic_fields' => array('type_id' => 'dataset'), 'preferred_labels' => array(array("locale" => "en_US", "name" => "My test dataset")))));
     $this->assertGreaterThan(0, $va_objects[] = $this->addTestRecord('ca_objects', array('intrinsic_fields' => array('type_id' => 'physical_object'), 'preferred_labels' => array(array("locale" => "en_US", "name" => "Test physical object")))));
     foreach ($va_objects as $vn_object_id) {
         $t_object = new ca_objects($vn_object_id);
         $t_object->setMode(ACCESS_WRITE);
         $t_object->delete(true, array('hard' => true));
     }
     $o_search = caGetSearchInstance('ca_objects');
     $o_result = $o_search->search('dataset');
     $this->assertEquals(0, $o_result->numHits(), 'dataset should not be indexed anymore');
     $o_result = $o_search->search('physical');
     $this->assertEquals(0, $o_result->numHits(), 'physical object should not be indexed anymore');
 }
 public function testGets()
 {
     $o_search = caGetSearchInstance('ca_objects');
     $this->assertInstanceOf('SearchEngine', $o_search);
     $o_res = $o_search->search('*');
     /** @var SearchResult $o_res */
     $this->assertInstanceOf('SearchResult', $o_res);
     $this->assertEquals(10, $o_res->numHits());
     //$o_res->disableGetWithTemplatePrefetch();
     $i = 0;
     while ($o_res->nextHit()) {
         $vs_label = $o_res->getWithTemplate('^ca_objects.preferred_labels');
         $this->assertGreaterThan(0, strlen($vs_label));
         $this->assertRegExp("/{$i}\$/", $vs_label);
         $i++;
     }
 }
 /**
  *
  */
 protected function search($pa_bundles = null)
 {
     if (!($vo_search = caGetSearchInstance($this->getTableName()))) {
         $this->addError(_t("Invalid table"));
         return false;
     }
     $t_instance = $this->_getTableInstance($vs_table_name = $this->getTableName());
     $va_return = array();
     $vo_result = $vo_search->search($this->ops_query, array('deletedOnly' => $this->opb_deleted_only, 'sort' => $this->opo_request->getParameter('sort', pString)));
     $vs_template = $this->opo_request->getParameter('template', pString);
     // allow user-defined template to be passed; allows flexible formatting of returned label
     while ($vo_result->nextHit()) {
         $va_item = array();
         $va_item[$t_instance->primaryKey()] = $vn_id = $vo_result->get($t_instance->primaryKey());
         $va_item['id'] = $vn_id;
         if ($vs_idno = $vo_result->get("idno")) {
             $va_item["idno"] = $vs_idno;
         }
         if ($vs_template) {
             $va_item["display_label"] = caProcessTemplateForIDs($vs_template, $vs_table_name, array($vn_id), array('convertCodesToDisplayText' => true));
         } else {
             if (is_array($va_display_labels = $vo_result->getDisplayLabels())) {
                 $va_item["display_label"] = array_pop($va_display_labels);
             }
         }
         if (is_array($pa_bundles)) {
             foreach ($pa_bundles as $vs_bundle => $va_options) {
                 if (!is_array($va_options)) {
                     $va_options = array();
                 }
                 if ($this->_isBadBundle($vs_bundle)) {
                     continue;
                 }
                 $vm_return = $vo_result->get($vs_bundle, $va_options);
                 // render 'empty' arrays as JSON objects, not as lists (which is the default behavior of json_encode)
                 if (is_array($vm_return) && sizeof($vm_return) == 0) {
                     $va_item[$vs_bundle] = new stdClass();
                 } else {
                     $va_item[$vs_bundle] = $vm_return;
                 }
             }
         }
         $va_return["results"][] = $va_item;
     }
     return $va_return;
 }
 public function testGets()
 {
     $o_search = caGetSearchInstance('ca_objects');
     $this->assertInstanceOf('SearchEngine', $o_search);
     $o_res = $o_search->search('*', array('sort' => 'ca_object_labels.name'));
     /** @var SearchResult $o_res */
     $this->assertInstanceOf('SearchResult', $o_res);
     $this->assertEquals(10, $o_res->numHits());
     SearchResult::clearGetWithTemplatePrefetch();
     // old values may be cached from previous tests
     $i = 0;
     while ($o_res->nextHit()) {
         $vs_label = $o_res->getWithTemplate('^ca_objects.preferred_labels');
         $this->assertGreaterThan(0, strlen($vs_label));
         $this->assertRegExp("/{$i}\$/", $vs_label);
         $i++;
     }
 }
Exemple #6
0
 /**
  * Perform the browse using currently applied criteria, calculating the result set and browse facets 
  * required for subsequent browse refinement. You need to call execute() after setting up your browse
  * criteria and options to:
  *		• Get the result set reflecting the current browse state
  *		• Fetch browse facets that reflect the current browse state
  *
  * @param array $pa_options Options include:
  *		checkAccess = array of access values to filter facets that have an 'access' field by
  *		noCache = 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
  *
  * @return bool True on success, null if the browse could not be executed (Eg. no settings), false no error
  */
 public function execute($pa_options = null)
 {
     global $AUTH_CURRENT_USER_ID;
     if (!is_array($this->opa_browse_settings)) {
         return null;
     }
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     $vn_user_id = caGetOption('user_id', $pa_options, $AUTH_CURRENT_USER_ID, array('castTo' => 'int'));
     $vb_no_cache = caGetOption('noCache', $pa_options, caGetOption('no_cache', $pa_options, false, array('castTo' => 'bool')), array('castTo' => 'bool'));
     $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('getDirectDate' => true));
         $va_criteria = $this->getCriteria();
         if (!$vb_no_cache && intval(time() - $vn_created_on) < $this->opo_ca_browse_config->get('cache_timeout')) {
             $vb_results_cached = true;
             $this->opo_ca_browse_cache->setParameter('created_on', time() + $this->opo_ca_browse_config->get('cache_timeout'));
             $vb_need_to_save_in_cache = true;
             Debug::msg("Cache hit for {$vs_cache_key}");
         } else {
             $va_criteria = $this->getCriteria();
             //$this->opo_ca_browse_cache->remove();
             //$this->opo_ca_browse_cache->setParameter('criteria', $va_criteria);
             $vb_need_to_save_in_cache = true;
             $vb_need_to_cache_facets = true;
             Debug::msg("Cache expire for {$vs_cache_key}");
         }
     } else {
         $va_criteria = $this->getCriteria();
         $vb_need_to_save_in_cache = true;
         Debug::msg("Cache miss for {$vs_cache_key}");
     }
     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) {
             $va_acc = array();
             $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) && (bool) $vn_state) {
                                 $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) && (bool) $vn_state) {
                                 $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\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";
                             $qr_res = $this->opo_db->query($vs_sql);
                         } else {
                             $vs_sql = "\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}";
                             $qr_res = $this->opo_db->query($vs_sql);
                         }
                         $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                         $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);
                         $va_labels = $t_item->getPreferredDisplayLabelsForIDs($va_row_ids);
                         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\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_display_field} = ?";
                                 //print "$vs_sql [".intval($this->opn_browse_table_num)."]<hr>";
                                 $qr_res = $this->opo_db->query($vs_sql, $va_labels[$vn_row_id]);
                             } else {
                                 $vs_sql = "\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_display_field} = ?";
                                 $qr_res = $this->opo_db->query($vs_sql, $va_labels[$vn_row_id]);
                             }
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $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(str_replace('&#47;', '/', $vn_row_id));
                             if ($vn_i == 0) {
                                 $vs_sql = "\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} = ?)";
                                 $qr_res = $this->opo_db->query($vs_sql, (string) $vn_row_id);
                             } else {
                                 $vs_sql = "\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} = ?)";
                                 $qr_res = $this->opo_db->query($vs_sql, (string) $vn_row_id);
                             }
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $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($vn_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 == __CA_ATTRIBUTE_VALUE_LIST__) {
                                         if ($vs_f != 'item_id') {
                                             continue;
                                         }
                                         // Include sub-items
                                         $t_list_item = new ca_list_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\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}";
                                 $qr_res = $this->opo_db->query($vs_sql, $va_attr_values);
                             } else {
                                 $vs_sql = "\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}";
                                 $qr_res = $this->opo_db->query($vs_sql, $va_attr_values);
                             }
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'normalizedDates':
                         $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();
                         }
                         // TODO: check that it is a *single-value* (ie. no hierarchical ca_metadata_elements) DateRange attribute
                         $vs_normalization = $va_facet_info['normalization'];
                         $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'];
                             }
                         }
                         $vn_element_id = $vb_is_element ? $t_element->getPrimaryKey() : null;
                         $vs_browse_start_fld = $vs_browse_start_fld = null;
                         if ($vb_is_field) {
                             $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');
                         }
                         foreach ($va_row_ids as $vn_row_id) {
                             $vn_row_id = urldecode($vn_row_id);
                             $va_dates = null;
                             if ($vn_row_id !== 'null') {
                                 if (!$o_tep->parse($vn_row_id)) {
                                     continue;
                                 }
                                 // invalid date?
                                 $va_dates = $o_tep->getHistoricTimestamps();
                             }
                             if ($vb_is_element) {
                                 if (is_null($va_dates)) {
                                     $vs_sql = "\n\t\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\t\tFROM " . $this->ops_browse_table_name . "\n\t\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\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\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\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.element_id = ?) \n\t\t\t\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.value_decimal1 IS NULL)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tAND \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(ca_attribute_values.value_decimal2 IS NULL)\n\t\t\t\t\t\t\t\t\t\t\t\t";
                                     $qr_res = $this->opo_db->query($vs_sql, intval($vs_target_browse_table_num), $vn_element_id);
                                 } else {
                                     $vs_sql = "\n\t\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\t\tFROM " . $this->ops_browse_table_name . "\n\t\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\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\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\t\tWHERE\n\t\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\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(\n\t\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\t(ca_attribute_values.value_decimal2 >= ?)\n\t\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\tOR\n\t\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\t\tOR \n\t\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\t)\n\t\t\t\t\t\t\t\t\t\t\t\t";
                                     $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 {
                                 // is intrinsic
                                 if (is_null($va_dates)) {
                                     $vs_sql = "\n\t\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\t\tFROM " . $this->ops_browse_table_name . "\n\t\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\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t({$this->ops_browse_table_name}.{$vs_browse_start_fld} IS NULL)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tAND \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t({$this->ops_browse_table_name}.{$vs_browse_end_fld} IS NULL)\n\t\t\t\t\t\t\t\t\t\t\t\t";
                                     $qr_res = $this->opo_db->query($vs_sql);
                                 } else {
                                     $vs_sql = "\n\t\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\t\tFROM " . $this->ops_browse_table_name . "\n\t\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\tWHERE\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(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t({$this->ops_browse_table_name}.{$vs_browse_start_fld} <= ?) AND\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t({$this->ops_browse_table_name}.{$vs_browse_end_fld} >= ?)\n\t\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\tOR\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t({$this->ops_browse_table_name}.{$vs_browse_start_fld} BETWEEN ? AND ?)\n\t\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\t({$this->ops_browse_table_name}.{$vs_browse_end_fld} BETWEEN ? AND ?)\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";
                                     $qr_res = $this->opo_db->query($vs_sql, $va_dates['start'], $va_dates['end'], $va_dates['start'], $va_dates['end'], $va_dates['start'], $va_dates['end']);
                                 }
                             }
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'normalizedLength':
                         $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();
                         }
                         // TODO: check that it is a *single-value* (ie. no hierarchical ca_metadata_elements) DateRange attribute
                         $vs_normalization = $va_facet_info['normalization'];
                         $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'];
                             }
                         }
                         $vn_element_id = $vb_is_element ? $t_element->getPrimaryKey() : null;
                         $vs_browse_start_fld = $vs_browse_start_fld = null;
                         if ($vb_is_field) {
                             $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');
                         }
                         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');
                         foreach ($va_row_ids as $vn_row_id) {
                             $vn_start = urldecode($vn_row_id);
                             // is start dimension
                             // calculate end dimension
                             $vn_end = $vn_start + $vn_increment_in_current_units;
                             // convert to meters
                             $vo_start = new Zend_Measure_Length($vn_start, $vs_output_units, 'en_US');
                             $vo_end = new Zend_Measure_Length($vn_end, $vs_output_units, 'en_US');
                             $vn_start_in_meters = (double) $vo_start->convertTo(Zend_Measure_Length::METER, 6, 'en_US');
                             $vn_end_in_meters = (double) $vo_end->convertTo(Zend_Measure_Length::METER, 6, 'en_US');
                             $vs_sql = "\n\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\tFROM " . $this->ops_browse_table_name . "\n\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\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\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\tWHERE\n\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(ca_attribute_values.value_decimal1 BETWEEN ? AND ?)\n\t\t\t\t\t\t\t\t\t\t";
                             $qr_res = $this->opo_db->query($vs_sql, intval($vs_target_browse_table_num), $vn_element_id, $vn_start_in_meters, $vn_end_in_meters);
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $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\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}";
                                 $qr_res = $this->opo_db->query($vs_sql);
                             } else {
                                 $vs_sql = "\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}";
                                 $qr_res = $this->opo_db->query($vs_sql);
                             }
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'location':
                         foreach ($va_row_ids as $vn_row_id) {
                             $vn_row_id = urldecode($vn_row_id);
                             $va_row_tmp = explode(":", $vn_row_id);
                             if ($vn_i == 0) {
                                 $vs_sql = "\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\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t({$this->ops_browse_table_name}.current_loc_class = ?)" . (sizeof($va_row_tmp) > 1 ? " AND ({$this->ops_browse_table_name}.current_loc_subclass = ?)" : "") . (sizeof($va_row_tmp) > 2 ? " AND ({$this->ops_browse_table_name}.current_loc_id = ?)" : "");
                                 $qr_res = $this->opo_db->query($vs_sql, $va_row_tmp);
                             } else {
                                 $vs_sql = "\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\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t\t({$this->ops_browse_table_name}.current_loc_class = ?)" . (sizeof($va_row_tmp) > 1 ? " AND ({$this->ops_browse_table_name}.current_loc_subclass = ?)" : "") . (sizeof($va_row_tmp) > 2 ? " AND ({$this->ops_browse_table_name}.current_loc_id = ?)" : "");
                                 $qr_res = $this->opo_db->query($vs_sql, $va_row_tmp);
                             }
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $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\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} = ?)";
                                 $qr_res = $this->opo_db->query($vs_sql, $vn_row_id);
                             } else {
                                 $vs_sql = "\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} = ?)";
                                 $qr_res = $this->opo_db->query($vs_sql, $vn_row_id);
                             }
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'violations':
                         $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\tSELECT " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . "\n\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\tINNER JOIN ca_metadata_dictionary_rule_violations ON ca_metadata_dictionary_rule_violations.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . " AND ca_metadata_dictionary_rule_violations.table_num = " . $t_item->tableNum() . "\n\t\t\t\t\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\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t(ca_metadata_dictionary_rules.rule_code = ?)";
                                 $qr_res = $this->opo_db->query($vs_sql, $vn_row_id);
                             } else {
                                 $vs_sql = "\n\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\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_metadata_dictionary_rule_violations ON ca_metadata_dictionary_rule_violations.row_id = " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . " AND ca_metadata_dictionary_rule_violations.table_num = " . $t_item->tableNum() . "\n\t\t\t\t\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\t\t\t\t{$vs_relative_to_join}\n\t\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t\t(ca_metadata_dictionary_rules.rule_code = ?)";
                                 $qr_res = $this->opo_db->query($vs_sql, $vn_row_id);
                             }
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues($this->ops_browse_table_name . '.' . $t_item->primaryKey());
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     case 'checkouts':
                         $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'];
                             }
                         }
                         $vs_where = null;
                         $vn_current_time = time();
                         foreach ($va_row_ids as $vn_row_id) {
                             $vs_checkout_join_sql = "INNER JOIN ca_object_checkouts ON ca_object_checkouts.object_id = ca_objects.object_id";
                             $vs_status_code = isset($va_facet_info['status']) && $va_facet_info['status'] ? $va_facet_info['status'] : $vn_row_id;
                             switch ($vs_status_code) {
                                 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_checkout_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;
                                 case 'all':
                                     $vs_where = "(ca_object_checkouts.checkout_date <= {$vn_current_time})";
                                     break;
                                 default:
                                 case 'out':
                                     $vs_where = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL))";
                                     break;
                             }
                             $vs_sql = "\n\t\t\t\t\t\t\t\t\t\tSELECT ca_objects.object_id\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_checkout_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";
                             $vs_user_sql = null;
                             $va_params = array();
                             switch ($va_facet_info['mode']) {
                                 case 'user':
                                     foreach ($va_row_ids as $vn_index => $vn_row_id) {
                                         $va_row_ids[$vn_index] = (int) $vn_row_id;
                                     }
                                     $va_params[] = $va_row_ids;
                                     $vs_user_sql .= " AND (ca_object_checkouts.user_id IN (?))";
                                     break;
                                 case 'all':
                                 default:
                                     // noop
                                     break;
                             }
                             $qr_res = $this->opo_db->query($vs_sql . $vs_user_sql, $va_params);
                             $va_acc[$vn_i] = $qr_res->getAllFieldValues('ca_objects.object_id');
                             $vn_i++;
                         }
                         break;
                         # -----------------------------------------------------
                     # -----------------------------------------------------
                     default:
                         // handle "search" criteria - search engine queries that can be browsed
                         if ($vs_facet_name === '_search') {
                             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);
                             }
                             if (is_array($va_source_ids = $this->getSourceRestrictionList()) && sizeof($va_source_ids)) {
                                 $o_search->setSourceRestrictions($va_source_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
                             $o_search->setOption('strictPhraseSearching', caGetOption('strictPhraseSearching', $va_options, true));
                             $qr_res = $o_search->search($va_row_ids[0], $va_options);
                             if ($qr_res->numHits() > 0) {
                                 $va_acc[$vn_i] = $qr_res->getPrimaryKeyValues();
                             }
                             $vn_i++;
                         } else {
                             $this->postError(2900, _t("Invalid criteria type"), "BrowseEngine->execute()");
                         }
                         break;
                         # -----------------------------------------------------
                 }
             }
             foreach ($va_acc as $vn_i => $va_hits) {
                 $va_acc[$vn_i] = array_flip($va_hits);
             }
             $vn_smallest_list_index = null;
             foreach ($va_acc as $vn_i => $va_hits) {
                 if (is_null($vn_smallest_list_index)) {
                     $vn_smallest_list_index = $vn_i;
                     continue;
                 }
                 if (sizeof($va_hits) < sizeof($va_acc[$vn_smallest_list_index])) {
                     $vn_smallest_list_index = $vn_i;
                 }
             }
             $va_res = array();
             $va_acc_indices = array_keys($va_acc);
             if (is_array($va_acc[$vn_smallest_list_index])) {
                 foreach ($va_acc[$vn_smallest_list_index] as $vn_row_id => $vb_dummy) {
                     foreach ($va_acc_indices as $vn_i) {
                         if ($vn_i == $vn_smallest_list_index) {
                             continue;
                         }
                         if (!isset($va_acc[$vn_i][$vn_row_id])) {
                             continue 2;
                         }
                     }
                     $va_res[$vn_row_id] = true;
                 }
             }
             if (sizeof($va_res)) {
                 $vs_filter_join_sql = $vs_filter_where_sql = '';
                 $va_wheres = array();
                 $va_joins = array();
                 $vs_sql_distinct = '';
                 if (sizeof($this->opa_result_filters)) {
                     $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_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 . "." . $t_item->primaryKey() . " 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) . ')' . ($t_subject->getFieldInfo('type_id', 'IS_NULL') ? " OR (" . $this->ops_browse_table_name . '.' . $t_subject->getTypeFieldName() . " IS NULL)" : '') . ')';
                 }
                 if (is_array($va_browse_source_ids) && sizeof($va_browse_source_ids)) {
                     $va_wheres[] = '(' . $this->ops_browse_table_name . '.' . $t_subject->getSourceFieldName() . ' IN (' . join(', ', $va_browse_source_ids) . ') OR (' . $this->ops_browse_table_name . '.' . $t_subject->getSourceFieldName() . ' IS NULL))';
                 }
                 $vs_filter_where_sql = "WHERE (" . $this->ops_browse_table_name . "." . $t_item->primaryKey() . " IN (?)) ";
                 if (sizeof($va_wheres)) {
                     $vs_filter_where_sql .= ' AND (' . 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\t\tSELECT {$vs_sql_distinct} " . $this->ops_browse_table_name . "." . $t_item->primaryKey() . "\n\t\t\t\t\t\t\tFROM " . $this->ops_browse_table_name . "\n\t\t\t\t\t\t\t{$vs_filter_join_sql}\n\t\t\t\t\t\t\t{$vs_filter_where_sql}\n\t\t\t\t\t\t", array(array_keys($va_res)));
                 $va_results = $qr_res->getAllFieldValues($t_item->primaryKey());
                 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 = $this->filterHitsByACL($va_results, $this->opn_browse_table_num, $vn_user_id, __CA_ACL_READONLY_ACCESS__);
                 }
                 $this->opo_ca_browse_cache->setResults($va_results);
                 $vb_need_to_save_in_cache = true;
             } else {
                 // No results for some reason - we're here because we don't want to throw a SQL error
                 $this->opo_ca_browse_cache->setResults($va_results = array());
                 $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'] || isset($pa_options['showAllForNoCriteriaBrowse']) && $pa_options['showAllForNoCriteriaBrowse']) {
             $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
                 }
             }
             $va_browse_type_ids = $this->getTypeRestrictionList();
             $va_browse_source_ids = $this->getSourceRestrictionList();
             if (is_array($va_browse_type_ids) && sizeof($va_browse_type_ids) || is_array($va_browse_source_ids) && sizeof($va_browse_source_ids)) {
                 $t_subject = $this->getSubjectInstance();
                 if (is_array($va_browse_type_ids) && sizeof($va_browse_type_ids)) {
                     $va_wheres[] = '(' . $this->ops_browse_table_name . '.' . $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_browse_source_ids) && sizeof($va_browse_source_ids)) {
                     $va_wheres[] = '(' . $this->ops_browse_table_name . '.' . $t_subject->getSourceFieldName() . ' IN (' . join(', ', $va_browse_source_ids) . ') OR (' . $this->ops_browse_table_name . '.' . $t_subject->getSourceFieldName() . ' IS NULL))';
                 }
             }
             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\tORDER BY\n\t\t\t\t\t\t\t{$vs_pk}\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($va_results, $this->opn_browse_table_num, $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 && !$pa_options['dontCheckFacetAvailability']) {
         $this->loadFacetContent($pa_options);
     }
     if ($vb_need_to_save_in_cache) {
         $this->opo_ca_browse_cache->save();
     }
     return true;
 }
 /**
  * Perform search
  * @param array|null $pa_bundles list of bundles to return for search result
  * @return array|bool
  */
 protected function search($pa_bundles = null)
 {
     if (!($vo_search = caGetSearchInstance($this->getTableName()))) {
         $this->addError(_t("Invalid table"));
         return false;
     }
     $t_instance = $this->_getTableInstance($vs_table_name = $this->getTableName());
     $va_return = array();
     $vo_result = $vo_search->search($this->ops_query, array('deletedOnly' => $this->opb_deleted_only, 'sort' => $this->opo_request->getParameter('sort', pString), 'sortDirection' => $this->opo_request->getParameter('sortDirection', pString), 'start' => $this->opo_request->getParameter('start', pInteger), 'limit' => $this->opo_request->getParameter('limit', pInteger)));
     $vs_template = $this->opo_request->getParameter('template', pString);
     // allow user-defined template to be passed; allows flexible formatting of returned label
     while ($vo_result->nextHit()) {
         $va_item = array();
         $va_item[$t_instance->primaryKey()] = $vn_id = $vo_result->get($t_instance->primaryKey());
         $va_item['id'] = $vn_id;
         if ($vs_idno = $vo_result->get("idno")) {
             $va_item["idno"] = $vs_idno;
         }
         if ($vs_template) {
             $va_item["display_label"] = caProcessTemplateForIDs($vs_template, $vs_table_name, array($vn_id), array('convertCodesToDisplayText' => true));
         } else {
             $va_item["display_label"] = $vo_result->get($vs_table_name . '.preferred_labels');
         }
         if (is_array($pa_bundles)) {
             foreach ($pa_bundles as $vs_bundle => $va_options) {
                 if (!is_array($va_options)) {
                     $va_options = array();
                 }
                 if ($this->_isBadBundle($vs_bundle)) {
                     continue;
                 }
                 // special treatment for ca_object_representations.media bundle
                 // it should provide a means to get the media info array
                 if (trim($vs_bundle) == 'ca_object_representations.media') {
                     if ($t_instance instanceof RepresentableBaseModel) {
                         $va_reps = $vo_result->getMediaInfo($vs_bundle);
                         if (is_array($va_reps) && sizeof($va_reps) > 0) {
                             $va_item[$vs_bundle] = $va_reps;
                             continue;
                         }
                     }
                 }
                 $vm_return = $vo_result->get($vs_bundle, $va_options);
                 // render 'empty' arrays as JSON objects, not as lists (which is the default behavior of json_encode)
                 if (is_array($vm_return) && sizeof($vm_return) == 0) {
                     $va_item[$vs_bundle] = new stdClass();
                 } else {
                     $va_item[$vs_bundle] = $vm_return;
                 }
             }
         }
         $va_return["results"][] = $va_item;
     }
     return $va_return;
 }
 /**
  * @param array $pa_config
  * @param RequestHTTP $po_request
  * @return array
  * @throws Exception
  */
 private static function runSearchEndpoint($pa_config, $po_request)
 {
     $o_dm = Datamodel::load();
     // load blank instance
     $t_instance = $o_dm->getInstance($pa_config['table']);
     if (!$t_instance instanceof BundlableLabelableBaseModelWithAttributes) {
         throw new Exception('invalid table');
     }
     if (!($ps_q = $po_request->getParameter('q', pString))) {
         throw new Exception('No query specified');
     }
     $o_search = caGetSearchInstance($pa_config['table']);
     // restrictToTypes
     if ($pa_config['restrictToTypes'] && is_array($pa_config['restrictToTypes']) && sizeof($pa_config['restrictToTypes']) > 0) {
         $va_type_filter = array();
         foreach ($pa_config['restrictToTypes'] as $vs_type_code) {
             $va_type_filter[] = caGetListItemID($t_instance->getTypeListCode(), $vs_type_code);
         }
         $o_search->addResultFilter($t_instance->tableName() . '.type_id', 'IN', join(",", $va_type_filter));
     }
     $o_res = $o_search->search($ps_q, array('sort' => $po_request->getParameter('sort', pString), 'sortDirection' => $po_request->getParameter('sortDirection', pString), 'start' => $po_request->getParameter('start', pInteger), 'limit' => $po_request->getParameter('limit', pInteger), 'checkAccess' => $pa_config['checkAccess']));
     $va_return = array();
     while ($o_res->nextHit()) {
         $va_hit = array();
         foreach ($pa_config['content'] as $vs_key => $vs_template) {
             $va_hit[self::sanitizeKey($vs_key)] = $o_res->getWithTemplate($vs_template);
         }
         $va_return[$o_res->get($t_instance->primaryKey(true))] = $va_hit;
     }
     return $va_return;
 }
 * the terms of the provided license as published by Whirl-i-Gig
 *
 * CollectiveAccess is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTIES whatsoever, including any implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 *
 * This source code is free and modifiable under the terms of 
 * GNU General Public License. (http://www.gnu.org/copyleft/gpl.html). See
 * the "license.txt" file for details, or visit the CollectiveAccess web site at
 * http://www.CollectiveAccess.org
 *
 * ----------------------------------------------------------------------
 */
$t_subject = $this->getVar('t_subject');
$vs_search = $this->getVar('search');
?>
	
<div id="resultBox">
	<div class="subTitle"><?php 
print $this->getVar('search') ? _t("Your search found no %1", $this->getVar('mode_type_plural')) : _t("Please enter a search");
$o_search = caGetSearchInstance($t_subject->tableNum());
if (sizeof($va_suggestions = $o_search->suggest($vs_search, array('returnAsLink' => true, 'request' => $this->request)))) {
    if (sizeof($va_suggestions) > 1) {
        print "<div class='searchSuggestion'>" . _t("Did you mean one of these: %1 ?", join(', ', $va_suggestions)) . "</div>";
    } else {
        print "<div class='searchSuggestion'>" . _t("Did you mean %1 ?", join(', ', $va_suggestions)) . "</div>";
    }
}
?>
	</div>
</div><!-- end resultbox -->
 /**
  * Export a record set as defined by the given search expression and the table_num for this exporter.
  * This function wraps the record-level exports using the settings 'wrap_before' and 'wrap_after' if they are set.
  * @param string $ps_exporter_code defines the exporter to use
  * @param string $ps_expression A valid search expression
  * @param string $ps_filename Destination filename (we can't keep everything in memory here)
  * @param array $pa_options
  *		showCLIProgressBar = Show command-line progress bar. Default is false.
  *		logDirectory = path to directory where logs should be written
  *		logLevel = KLogger constant for minimum log level to record. Default is KLogger::INFO. Constants are, in descending order of shrillness:
  *			KLogger::EMERG = Emergency messages (system is unusable)
  *			KLogger::ALERT = Alert messages (action must be taken immediately)
  *			KLogger::CRIT = Critical conditions
  *			KLogger::ERR = Error conditions
  *			KLogger::WARN = Warnings
  *			KLogger::NOTICE = Notices (normal but significant conditions)
  *			KLogger::INFO = Informational messages
  *			KLogger::DEBUG = Debugging messages
  * @return boolean success state
  */
 public static function exportRecordsFromSearchExpression($ps_exporter_code, $ps_expression, $ps_filename, $pa_options = array())
 {
     ca_data_exporters::$s_exporter_cache = array();
     ca_data_exporters::$s_exporter_item_cache = array();
     if (!($t_mapping = ca_data_exporters::loadExporterByCode($ps_exporter_code))) {
         return false;
     }
     $o_search = caGetSearchInstance($t_mapping->get('table_num'));
     $o_result = $o_search->search($ps_expression);
     return self::exportRecordsFromSearchResult($ps_exporter_code, $o_result, $ps_filename, $pa_options);
 }
 /**
  * Responds to the two main List verbs, includes resumption and limiting.
  *
  * @param string $verb OAI-PMH verb for the request
  * @param string $metadataPrefix Metadata prefix
  * @param int $cursor Offset in response to begin output at
  * @param mixed $set Optional set argument
  * @param string $from Optional from date argument
  * @param string $until Optional until date argument
  * @uses createResumptionToken()
  */
 private function listResponse($oaiData, $verb, $metadataPrefix, $cursor, $set, $from, $until)
 {
     $listLimit = $this->_listLimit;
     $o_dm = Datamodel::load();
     // by this point, the mapping code was checked to be valid
     $t_instance = $o_dm->getInstanceByTableName($this->table, true);
     $vs_pk = $t_instance->primaryKey();
     $va_access_values = caGetUserAccessValues($this->opo_request, $this->opa_provider_info);
     $vb_show_deleted = (bool) $this->opa_provider_info['show_deleted'];
     $vb_dont_enforce_access_settings = (bool) $this->opa_provider_info['dont_enforce_access_settings'];
     $vb_dont_cache = (bool) $this->opa_provider_info['dont_cache'];
     $vs_table = $t_instance->tableName();
     if (!($o_search = caGetSearchInstance($vs_table))) {
         $this->throwError(self::OAI_ERR_BAD_ARGUMENT);
         return;
     }
     // Construct date range for from/until if defined
     $o_tep = new TimeExpressionParser();
     $o_lang_settings = $o_tep->getLanguageSettings();
     $vs_conj = array_shift($o_lang_settings->getList("rangeConjunctions"));
     $vs_range = $from && $until ? "{$from} {$vs_conj} {$until}" : '';
     if ($set && $this->opa_provider_info['setFacet']) {
         $o_browse = caGetBrowseInstance($this->table);
         if (($vs_query = $this->opa_provider_info['query']) && $vs_query != "*") {
             $o_browse->addCriteria("_search", $vs_query);
         }
         $o_browse->addCriteria($this->opa_provider_info['setFacet'], $set);
         $o_browse->execute(array('showDeleted' => $vb_show_deleted, 'no_cache' => $vb_dont_cache, 'limitToModifiedOn' => $vs_range, 'checkAccess' => $vb_dont_enforce_access_settings ? null : $va_access_values));
         $qr_res = $o_browse->getResults();
     } else {
         $qr_res = $o_search->search(strlen($this->opa_provider_info['query']) ? $this->opa_provider_info['query'] : "*", array('no_cache' => $vb_dont_cache, 'limitToModifiedOn' => $vs_range, 'showDeleted' => $vb_show_deleted, 'checkAccess' => $vb_dont_enforce_access_settings ? null : $va_access_values));
     }
     if (!$qr_res) {
         $this->throwError(self::OAI_ERR_NO_RECORDS_MATCH, _t('Query failed'));
         return;
     }
     $rows = $qr_res->numHits();
     if (count($qr_res->numHits()) == 0) {
         $this->throwError(self::OAI_ERR_NO_RECORDS_MATCH, _t('No records match the given criteria'));
     } else {
         $verbElement = $oaiData->createElement($verb);
         $oaiData->documentElement->appendChild($verbElement);
         $t_change_log = new ApplicationChangeLog();
         if ($vb_show_deleted) {
             // get list of deleted records
             $va_deleted_items = array();
             $qr_res->seek($cursor);
             $vn_c = 0;
             $va_get_deleted_timestamps_for = array();
             while ($qr_res->nextHit()) {
                 if ((bool) $qr_res->get("{$vs_table}.deleted")) {
                     $va_deleted_items[$vs_pk_val = (int) $qr_res->get("{$vs_table}.{$vs_pk}")] = true;
                     $va_get_deleted_timestamps_for[$vs_pk_val] = true;
                 } else {
                     $vn_access = (int) $qr_res->get("{$vs_table}.access");
                     if (!in_array($vn_access, $va_access_values)) {
                         $va_deleted_items[(int) $qr_res->get("{$vs_table}.{$vs_pk}")] = true;
                     }
                 }
                 $vn_c++;
                 if ($vn_c >= $listLimit) {
                     break;
                 }
             }
             $qr_res->seek(0);
             $va_deleted_timestamps = $t_change_log->getDeleteOnTimestampsForIDs($vs_table, array_keys($va_get_deleted_timestamps_for));
         }
         // Export data using metadata mapping
         $va_items = ca_data_exporters::exportRecordsFromSearchResultToArray($this->getMappingCode(), $qr_res, array('start' => $cursor, 'limit' => $listLimit));
         if (is_array($va_items) && sizeof($va_items)) {
             $va_timestamps = $t_change_log->getLastChangeTimestampsForIDs($vs_table, array_keys($va_items));
             foreach ($va_items as $vn_id => $vs_item_xml) {
                 if ($vb_show_deleted && $va_deleted_items[$vn_id]) {
                     $headerData = array('identifier' => OaiIdentifier::itemToOaiId($vn_id), 'datestamp' => self::unixToUtc($va_deleted_timestamps[$vn_id]['timestamp'] ? $va_deleted_timestamps[$vn_id]['timestamp'] : $va_timestamps[$vn_id]['timestamp']));
                     if ($verb == 'ListIdentifiers') {
                         $header = $this->createElementWithChildren($oaiData, $verbElement, 'header', $headerData);
                         $header->setAttribute("status", "deleted");
                     } else {
                         $recordElement = $verbElement->appendChild($oaiData->createElement('record'));
                         $header = $this->createElementWithChildren($oaiData, $recordElement, 'header', $headerData);
                         $header->setAttribute("status", "deleted");
                     }
                 } else {
                     $headerData = array('identifier' => OaiIdentifier::itemToOaiId($vn_id), 'datestamp' => self::unixToUtc($va_timestamps[$vn_id]['timestamp']));
                     if ($verb == 'ListIdentifiers') {
                         $this->createElementWithChildren($oaiData, $verbElement, 'header', $headerData);
                     } else {
                         $recordElement = $verbElement->appendChild($oaiData->createElement('record'));
                         $this->createElementWithChildren($oaiData, $recordElement, 'header', $headerData);
                         $metadataElement = $oaiData->createElement('metadata');
                         $o_doc_src = DomDocument::loadXML($vs_item_xml);
                         if ($o_doc_src) {
                             // just in case the xml fails to load through DomDocument for some reason (e.g. a bad mapping or very weird characters)
                             $metadataElement->appendChild($oaiData->importNode($o_doc_src->documentElement, true));
                         }
                         $recordElement->appendChild($metadataElement);
                     }
                 }
             }
         }
         if ($rows > $cursor + $listLimit) {
             $token = $this->createResumptionToken($verb, $metadataPrefix, $cursor + $listLimit, $set, $from, $until);
             $tokenElement = $oaiData->createElement('resumptionToken', $token['key']);
             $tokenElement->setAttribute('expirationDate', self::unixToUtc($token['expiration']));
             $tokenElement->setAttribute('completeListSize', $rows);
             $tokenElement->setAttribute('cursor', $cursor);
             $verbElement->appendChild($tokenElement);
         } else {
             if ($cursor != 0) {
                 $tokenElement = $this->oaiData->createElement('resumptionToken');
                 $verbElement->appendChild($tokenElement);
             }
         }
     }
 }
Exemple #12
0
<?php

MetaTagManager::setWindowTitle($this->request->config->get("app_display_name") . ": Body of Knowledge");
# --- do a occurrece search to get all the competences
$o_search = caGetSearchInstance("ca_occurrences");
$t_lists = new ca_lists();
$vn_category_type_id = $t_lists->getItemIDFromList("occurrence_types", "category");
$qr_res = $o_search->search('type_id:' . $vn_category_type_id, $va_options['sort'] = "ca_occurrences.preferred_labels.name");
$va_all_competences = array();
$va_competences_by_area = array();
if ($qr_res->numHits()) {
    while ($qr_res->nextHit()) {
        $va_all_competences[$qr_res->get("ca_occurrences.occurrence_id")] = array("idno" => $qr_res->get("ca_occurrences.idno"), "label" => strtolower($qr_res->get("ca_occurrences.preferred_labels.name")));
        $va_competences_by_area[str_replace(" Pa ", " PA ", ucwords(strtolower($qr_res->get("ca_occurrences.area", array("convertCodesToDisplayText" => true)))))][$qr_res->get("ca_occurrences.occurrence_id")] = array("idno" => $qr_res->get("ca_occurrences.idno"), "label" => strtolower($qr_res->get("ca_occurrences.preferred_labels.name")));
    }
}
if (sizeof($va_competences_by_area)) {
    ?>
	<div class="container containerTextPadding" id="comp_nav">
		<div class="row">
			<div class="col-sm-12">
				<H2>Choose a competence category to explore:</H2>
<?php 
    if ($this->request->config->get("onlyLinkTrpCategory")) {
        ?>
				<H5 class="indent red"><i>* Content currently under development.  Please use the competence category TRP (Tourism, Recreation, and Public Use) to explore how the Body of Knowledge works.</i></H5>
<?php 
    }
    ?>
			
			</div>
Exemple #13
0
/**
 * Performs search using expression for each provided search "block." A block defines a
 * search on a specific item (Eg. ca_objects, ca_entities), with or without type restriction, with
 * results rendered using a provided view. The results for all blocks are returned in an array.
 * 
 * Used by MultiSearch to generate results. Blame Sophie for the function name.
 *
 * @param RequestHTTP $po_request
 * @param string $ps_search_expression
 * @param array $pa_blocks
 * @param array $pa_options
 *			itemsPerPage =
 *			itemsPerColumn =
 *			contexts =
 *			... any other options passed through as-is to SearchEngine::search()
 *
 * @return array 
 */
function caPuppySearch($po_request, $ps_search_expression, $pa_blocks, $pa_options = null)
{
    if (!is_array($pa_options)) {
        $pa_options = array();
    }
    $va_access_values = caGetUserAccessValues($po_request);
    if (is_array($va_access_values) && sizeof($va_access_values)) {
        $pa_options["checkAccess"] = $va_access_values;
    }
    $vn_items_per_page_default = caGetOption('itemsPerPage', $pa_options, 10);
    $vn_items_per_column_default = caGetOption('itemsPerColumn', $pa_options, 1);
    $vb_match_on_stem = caGetOption('matchOnStem', $pa_options, false);
    $va_contexts = caGetOption('contexts', $pa_options, array(), array('castTo' => 'array'));
    unset($pa_options['contexts']);
    //
    // Block are lazy-loaded using Ajax requests with additional items as they are scrolled.
    // "Ajax mode" is used by caPuppySearch to render a single block when it is scrolled
    // The block to be rendered is specified in the "block" request parameter. The offset
    // from the beginning of the result to start rendering from is specified in the "s" request parameter.
    //
    $vb_ajax_mode = false;
    if ($po_request->isAjax() && ($ps_block = $po_request->getParameter('block', pString)) && isset($pa_blocks[$ps_block])) {
        $pa_blocks = array($ps_block => $pa_blocks[$ps_block]);
        $vb_ajax_mode = true;
    }
    $va_ret = array();
    $vn_i = 0;
    $vn_total_cnt = 0;
    $va_table_counts = array();
    foreach ($pa_blocks as $vs_block => $va_block_info) {
        if (!($o_search = caGetSearchInstance($va_block_info['table']))) {
            continue;
        }
        if (!is_array($va_block_info['options'])) {
            $va_block_info['options'] = array();
        }
        $va_options = array_merge($pa_options, $va_block_info['options']);
        $va_sorts = caGetOption('sortBy', $va_block_info, null);
        $ps_sort = null;
        $vb_sort_changed = false;
        if (!($ps_sort = $po_request->getParameter("{$vs_block}Sort", pString))) {
            if (isset($va_contexts[$vs_block])) {
                if (!($ps_sort = $va_contexts[$vs_block]->getCurrentSort()) && $va_sorts && sizeof($va_sorts)) {
                    $ps_sort = array_shift(array_keys($va_sorts));
                    $va_contexts[$vs_block]->setCurrentSort($ps_sort);
                    $vb_sort_changed = true;
                    //} else {
                    //	if (isset($va_sorts[$ps_sort])) {
                    //		$ps_sort = $va_sorts[$ps_sort];
                    //	}
                }
            }
        } else {
            $vb_sort_changed = true;
        }
        if ($vb_sort_changed && $va_sorts && sizeof($va_sorts)) {
            # --- set the default sortDirection if available
            $va_sort_directions = caGetOption('sortDirection', $va_block_info, null);
            //$ps_sort_key = array_search($ps_sort, $va_sorts);
            if (is_array($va_sort_directions) && ($ps_sort_direction = $va_sort_directions[$ps_sort])) {
                $va_contexts[$vs_block]->setCurrentSortDirection($ps_sort_direction);
            }
        }
        if (!($ps_sort_direction = $po_request->getParameter("{$vs_block}SortDirection", pString))) {
            if (!($ps_sort_direction = $va_contexts[$vs_block]->getCurrentSortDirection())) {
                $ps_sort_direction = 'asc';
            }
        }
        $va_contexts[$vs_block]->setCurrentSortDirection($ps_sort_direction);
        $va_options['sort'] = $ps_sort;
        $va_options['sort_direction'] = $ps_sort_direction;
        $va_types = caGetOption('restrictToTypes', $va_block_info, array(), array('castTo' => 'array'));
        if (is_array($va_types) && sizeof($va_types)) {
            $o_search->setTypeRestrictions($va_types);
        }
        $va_options['restrictSearchToFields'] = caGetOption('restrictSearchToFields', $va_block_info, null);
        if (caGetOption('dontShowChildren', $va_block_info, false)) {
            $o_search->addResultFilter('ca_objects.parent_id', 'is', 'null');
        }
        $qr_res = $o_search->search($ps_search_expression . ($vb_match_on_stem && !preg_match('!\\*$!', $ps_search_expression) ? '*' : ''), $va_options);
        $va_contexts[$vs_block]->setSearchExpression($ps_search_expression);
        $va_contexts[$vs_block]->setResultList($qr_res->getPrimaryKeyValues());
        // In Ajax mode we scroll to an offset
        $vn_start = 0;
        if ($vb_ajax_mode) {
            if (($vn_start = $po_request->getParameter('s', pInteger)) < $qr_res->numHits()) {
                $qr_res->seek($vn_start);
                if (isset($va_contexts[$vs_block])) {
                    $va_contexts[$vs_block]->setParameter('start', $vn_start);
                }
            } else {
                // If the offset is past the end of the result return an empty string to halt the continuous scrolling
                return '';
            }
        } else {
            //
            // Reset start if it's a new search
            //
            if ($va_contexts[$vs_block]->getSearchExpression(true) != $ps_search_expression) {
                $va_contexts[$vs_block]->setParameter('start', 0);
            }
        }
        $va_contexts[$vs_block]->saveContext();
        $vn_items_per_page = caGetOption('itemsPerPage', $va_block_info, $vn_items_per_page_default);
        $vn_items_per_column = caGetOption('itemsPerColumn', $va_block_info, $vn_items_per_column_default);
        $vn_count = $qr_res->numHits();
        $va_sort_by = caGetOption('sortBy', $va_block_info, null);
        $vs_sort_list = '';
        if (is_array($va_sort_by)) {
            $va_sort_list = array();
            foreach ($va_sort_by as $vs_sort_label => $vs_sort) {
                $va_sort_list[] = "<li" . ($vs_sort_label == $ps_sort ? " class='selectedSort'" : '') . "><a href='#' rel='{$vs_sort_label}'>{$vs_sort_label}</a></li>";
            }
            $vs_sort_list = "<ul id='{$vs_block}_sort'>" . join("\n", $va_sort_list) . "</ul>";
        }
        $o_view = new View($po_request, $po_request->getViewsDirectoryPath());
        $o_view->setVar('result', $qr_res);
        $o_view->setVar('count', $vn_count);
        $o_view->setVar('block', $vs_block);
        $o_view->setVar('blockInfo', $va_block_info);
        $o_view->setVar('blockIndex', $vn_i);
        $o_view->setVar('start', $vn_start);
        $o_view->setVar('itemsPerPage', $vn_items_per_page);
        $o_view->setVar('itemsPerColumn', $vn_items_per_column);
        $o_view->setVar('hasMore', (bool) ($vn_count > $vn_start + $vn_items_per_page));
        $o_view->setVar('sortBy', is_array($va_sort_by) ? $va_sort_by : null);
        $o_view->setVar('sortBySelect', $vs_sort_by_select = is_array($va_sort_by) ? caHTMLSelect("{$vs_block}_sort", $va_sort_by, array('id' => "{$vs_block}_sort", "class" => "form-control input-sm"), array("value" => $ps_sort)) : '');
        $o_view->setVar('sortByControl', $va_block_info["sortControlType"] && $va_block_info["sortControlType"] == "list" ? $vs_sort_list : $vs_sort_by_select);
        // synonym for sortBySelect
        $o_view->setVar('sortByList', $vs_sort_list);
        $o_view->setVar('sort', $ps_sort);
        $o_view->setVar('sortDirectionControl', '<a href="#" id="' . $vs_block . '_sort_direction"><span class="glyphicon glyphicon-sort-by-alphabet' . ($ps_sort_direction == 'desc' ? '-alt' : '') . '"></span></a>');
        $o_view->setVar('sortDirection', $ps_sort_direction);
        $o_view->setVar('search', $ps_search_expression);
        $o_view->setVar('cacheKey', md5($ps_search_expression));
        if (!$vb_ajax_mode) {
            if (isset($va_contexts[$vs_block])) {
                $o_view->setVar('initializeWithStart', (int) $va_contexts[$vs_block]->getParameter('start'));
            } else {
                $o_view->setVar('initializeWithStart', 0);
            }
        }
        $vs_html = $o_view->render($va_block_info['view']);
        $va_ret[$vs_block] = array('count' => $vn_count, 'html' => $vs_html, 'displayName' => $va_block_info['displayName'], 'ids' => $qr_res->getPrimaryKeyValues(), 'sort' => $ps_sort, 'sortDirection' => $ps_sort_direction);
        $va_table_counts[$va_block_info['table']] += $vn_count;
        $vn_total_cnt += $vn_count;
        $vn_i++;
        if ($vb_ajax_mode) {
            // In Ajax mode return rendered HTML for the single block
            return $va_ret;
        }
    }
    $va_ret['_info_'] = array('totalCount' => $vn_total_cnt);
    // Set generic contexts for each table in multisearch (no specific block);
    // used to house search history and overall counts when there is more than one block for a given table
    foreach ($va_table_counts as $vs_table => $vn_count) {
        $va_contexts["_multisearch_{$vs_table}"]->setSearchExpression($ps_search_expression);
        $va_contexts["_multisearch_{$vs_table}"]->setSearchHistory($vn_count);
        $va_contexts["_multisearch_{$vs_table}"]->saveContext();
    }
    return $va_ret;
}
Exemple #14
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;
 }
 /**
  * Export a record set as defined by the given search expression and the table_num for this exporter.
  * This function wraps the record-level exports using the settings 'wrap_before' and 'wrap_after' if they are set.
  * @param string $ps_exporter_code defines the exporter to use
  * @param string $ps_expression A valid search expression
  * @param string $ps_filename Destination filename (we can't keep everything in memory here)
  * @param array $pa_options
  *		showCLIProgressBar = Show command-line progress bar. Default is false.
  * @return boolean success state
  */
 public static function exportRecordsFromSearchExpression($ps_exporter_code, $ps_expression, $ps_filename, $pa_options = array())
 {
     ca_data_exporters::$s_exporter_cache = array();
     ca_data_exporters::$s_exporter_item_cache = array();
     $vb_show_cli_progress_bar = isset($pa_options['showCLIProgressBar']) && $pa_options['showCLIProgressBar'];
     $po_request = isset($pa_options['request']) ? $pa_options['request'] : null;
     if (!($t_mapping = ca_data_exporters::loadExporterByCode($ps_exporter_code))) {
         return false;
     }
     $va_errors = ca_data_exporters::checkMapping($ps_exporter_code);
     if (sizeof($va_errors) > 0) {
         if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) {
             $ps_callback($po_request, 0, -1, _t('Export failed: %1', join("; ", $va_errors)), 0, memory_get_usage(true), 0);
         }
         return false;
     }
     $vn_start_time = time();
     $vs_wrap_before = $t_mapping->getSetting('wrap_before');
     $vs_wrap_after = $t_mapping->getSetting('wrap_after');
     $t_instance = $t_mapping->getAppDatamodel()->getInstanceByTableNum($t_mapping->get('table_num'));
     $o_search = caGetSearchInstance($t_mapping->get('table_num'));
     $o_result = $o_search->search($ps_expression);
     $vn_num_items = $o_result->numHits();
     if ($vs_wrap_before) {
         file_put_contents($ps_filename, $vs_wrap_before . "\n", FILE_APPEND);
     }
     if ($vb_show_cli_progress_bar) {
         print CLIProgressBar::start($vn_num_items, _t('Processing search result'));
     }
     if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) {
         if ($vn_num_items > 0) {
             $ps_callback($po_request, 0, $vn_num_items, _t("Exporting result for search expression '%1'", $ps_expression), time() - $vn_start_time, memory_get_usage(true), 0);
         } else {
             $ps_callback($po_request, 0, -1, _t('Found no records to export'), time() - $vn_start_time, memory_get_usage(true), 0);
         }
     }
     $vn_num_processed = 0;
     while ($o_result->nextHit()) {
         $vs_item_export = ca_data_exporters::exportRecord($ps_exporter_code, $o_result->get($t_instance->primaryKey()));
         file_put_contents($ps_filename, $vs_item_export . "\n", FILE_APPEND);
         if ($vb_show_cli_progress_bar) {
             print CLIProgressBar::next(1, _t("Exporting records ..."));
         }
         $vn_num_processed++;
         if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) {
             $ps_callback($po_request, $vn_num_processed, $vn_num_items, _t("Exporting ... [%1/%2]", $vn_num_processed, $vn_num_items), time() - $vn_start_time, memory_get_usage(true), $vn_num_processed);
         }
     }
     if ($vs_wrap_after) {
         file_put_contents($ps_filename, $vs_wrap_after . "\n", FILE_APPEND);
     }
     if ($vb_show_cli_progress_bar) {
         print CLIProgressBar::finish();
     }
     if ($po_request && isset($pa_options['progressCallback']) && ($ps_callback = $pa_options['progressCallback'])) {
         $ps_callback($po_request, $vn_num_items, $vn_num_items, _t('Export completed'), time() - $vn_start_time, memory_get_usage(true), $vn_num_processed);
     }
     return true;
 }