/** * Returns array of name for bundles in the specified form. The array is keyed on bundle name (in <table>.<name> format) with values set to arrays of bundle-specific form options (no such options are currently supported however) * * @param string $ps_code The code for the form * @param string $ps_target The type of search the form targets. This should be a table name (ca_objects, ca_entities, etc.). If omitted defaults to ca_objects. * @return array An array of bundle names with associated bundle-level form option arrays */ function caGetAdvancedSearchFormElementNames($ps_code, $ps_target = 'ca_objects', $pa_options = null) { $o_config = Configuration::load(Configuration::load()->get('advanced_search_config')); $va_forms = $o_config->getAssoc($ps_target); $va_form_elements = array(); if (isset($va_forms[$ps_code]) && is_array($va_forms[$ps_code])) { $t_element = new ca_metadata_elements(); foreach ($va_forms[$ps_code]['bundles'] as $vs_bundle => $va_info) { $va_tmp = explode('.', $vs_bundle); if ($t_element->load(array('element_code' => $va_tmp[1]))) { if ($t_element->get('datatype') > 0) { $va_form_elements[$vs_bundle] = $va_info; continue; } if (isset($pa_options['includeSubElements']) && $pa_options['includeSubElements']) { if (sizeof($va_sub_elements = $t_element->getElementsInSet()) > 1) { foreach ($va_sub_elements as $vn_element_id => $va_element_info) { if ($va_tmp[1] == $va_element_info['element_code']) { continue; } if ($va_element_info['datatype'] == 0) { continue; } $va_form_elements[$va_tmp[0] . '.' . $va_element_info['element_code']] = array(); } } } } $va_form_elements[$vs_bundle] = $va_info; } return $va_form_elements; } return null; }
public static function updateSolrConfiguration($pb_invoked_from_command_line = false) { /* get search and search indexing configuration */ $po_app_config = Configuration::load(); $po_search_config = Configuration::load($po_app_config->get("search_config")); $po_search_indexing_config = Configuration::load($po_search_config->get("search_indexing_config")); $ps_solr_home_dir = $po_search_config->get('search_solr_home_dir'); $po_datamodel = Datamodel::load(); $po_search_base = new SearchBase(); global $o_db; if (!is_object($o_db)) { /* catch command line usage */ $o_db = new Db(); } $t_element = new ca_metadata_elements(); /* parse search indexing configuration to see which tables are indexed */ $va_tables = $po_search_indexing_config->getAssocKeys(); /* create solr.xml first to support multicore */ $vs_solr_xml = ""; $vs_solr_xml .= '<?xml version="1.0" encoding="UTF-8" ?>' . SolrConfiguration::nl(); $vs_solr_xml .= '<solr persistent="true">' . SolrConfiguration::nl(); $vs_solr_xml .= SolrConfiguration::tabs(1) . '<cores adminPath="/admin/cores">' . SolrConfiguration::nl(); foreach ($va_tables as $vs_table) { /* I don't like tablenums, so we use the table name to name the cores */ $vs_solr_xml .= SolrConfiguration::tabs(2) . '<core name="' . $vs_table . '" instanceDir="' . $vs_table . '" />' . SolrConfiguration::nl(); } $vs_solr_xml .= SolrConfiguration::tabs(1) . '</cores>' . SolrConfiguration::nl(); $vs_solr_xml .= '</solr>' . SolrConfiguration::nl(); /* try to write configuration file */ $vr_solr_xml_file = fopen($ps_solr_home_dir . "/solr.xml", 'w+'); // overwrite old one if (!is_resource($vr_solr_xml_file)) { die("Couldn't write to solr.xml file in Solr home directory. Please check the permissions.\n"); } fprintf($vr_solr_xml_file, "%s", $vs_solr_xml); fclose($vr_solr_xml_file); /* configure the cores */ foreach ($va_tables as $vs_table) { $t_instance = $po_datamodel->getTableInstance($vs_table); /* create core directory */ if (!file_exists($ps_solr_home_dir . "/" . $vs_table)) { if (!mkdir($ps_solr_home_dir . "/" . $vs_table, 0777)) { /* TODO: think about permissions */ die("Couldn't create directory in Solr home. Please check the permissions.\n"); } } /* create conf directory */ if (!file_exists($ps_solr_home_dir . "/" . $vs_table . "/conf")) { if (!mkdir($ps_solr_home_dir . "/" . $vs_table . "/conf", 0777)) { die("Couldn't create directory in core directory. Please check the permissions.\n"); } } /* create solrconfig.xml for this core */ $vr_solrconfig_xml_file = fopen($ps_solr_home_dir . "/" . $vs_table . "/conf/solrconfig.xml", 'w+'); if (!is_resource($vr_solrconfig_xml_file)) { die("Couldn't write to solrconfig.xml file for core {$vs_table}. Please check the permissions.\n"); } /* read template and copy it */ $va_solrconfig_xml_template = file(__CA_LIB_DIR__ . "/core/Search/Solr/solrplugin_templates/solrconfig.xml"); if (!is_array($va_solrconfig_xml_template)) { die("Couldn't read solrconfig.xml template."); } foreach ($va_solrconfig_xml_template as $vs_line) { fprintf($vr_solrconfig_xml_file, "%s", $vs_line); } fclose($vr_solrconfig_xml_file); /* create schema.xml for this core */ $vr_schema_xml_file = fopen($ps_solr_home_dir . "/" . $vs_table . "/conf/schema.xml", 'w+'); if (!is_resource($vr_schema_xml_file)) { die("Couldn't write to schema.xml file for core {$vs_table}. Please check the permissions.\n"); } /* read template, modify it, add table-specific fields and write to schema.xml configuration for this core */ $va_schema_xml_template = file(__CA_LIB_DIR__ . "/core/Search/Solr/solrplugin_templates/schema.xml"); if (!is_array($va_schema_xml_template)) { die("Couldn't read solrconfig.xml template."); } foreach ($va_schema_xml_template as $vs_line) { /* 1st replacement: core name */ if (strpos($vs_line, "CORE_NAME") !== false) { fprintf($vr_schema_xml_file, "%s", str_replace("CORE_NAME", $vs_table, $vs_line)); continue; } /* 2nd replacement: fields - the big part */ if (strpos($vs_line, "<!--FIELDS-->") !== false) { $vs_field_schema = ""; $vs_subject_table_copyfields = ""; /* the schema is very very hardcoded, so we have to create a design that still fits * when new metadata elements are created or sth like that. for now, we're just considering * the "straightforward" fields */ $va_schema_fields = array(); /* list of all fields created - is used for copyField directives after field block */ /* subject table */ /* we add the PK - this is used for incremental indexing */ $vs_field_schema .= SolrConfiguration::tabs(2) . '<field name="' . $vs_table . '.' . $t_instance->primaryKey() . '" type="int" indexed="true" stored="true" />' . SolrConfiguration::nl(); $vs_field_schema .= SolrConfiguration::tabs(2) . '<field name="' . $t_instance->primaryKey() . '" type="int" indexed="true" stored="true" />' . SolrConfiguration::nl(); $vs_subject_table_copyfields .= SolrConfiguration::tabs(1) . '<copyField source="' . $vs_table . '.' . $t_instance->primaryKey() . '" dest="' . $t_instance->primaryKey() . '" />' . SolrConfiguration::nl(); /* get fields-to-index from search indexing configuration */ if (!is_array($va_table_fields = $po_search_base->getFieldsToIndex($vs_table))) { $va_table_fields = array(); } $vn_table_num = $po_datamodel->getTableNum($vs_table); $va_attributes = null; if (is_array($va_table_fields)) { foreach ($va_table_fields as $vs_field_name => $va_field_options) { if (preg_match('!^_ca_attribute_(\\d+)$!', $vs_field_name, $va_matches)) { $t_element->load($va_matches[1]); $va_attributes[$t_element->getPrimaryKey()] = array('element_id' => $t_element->get('element_id'), 'element_code' => $t_element->get('element_code'), 'datatype' => $t_element->get('datatype')); } } } if (is_array($va_attributes)) { $va_metadata_fields = array(); foreach ($va_attributes as $vn_element_id => $va_element_info) { $va_metadata_fields += SolrConfiguration::getElementType($va_element_info); } /*set datatype for metadata elements in $va_table_fields array*/ foreach ($va_metadata_fields as $key => $value) { if (array_key_exists($key, $va_table_fields)) { unset($va_table_fields[$key]); } $va_table_fields[$key] = $value; } } /* we now have the current configuration */ /* since Solr supports live updates only if changes are 'backwards-compatible' * (i.e. no fields are deleted), we have to merge the current configuration with the * cached one, create the new configuration based upon that and cache it. * * Invocation of the command-line script support/utils/createSolrConfiguration.php, * however, creates a completely fresh configuration and caches it. */ $va_frontend_options = array('lifetime' => null, 'logging' => false, 'write_control' => true, 'automatic_cleaning_factor' => 0, 'automatic_serialization' => true); $vs_cache_dir = __CA_APP_DIR__ . '/tmp'; $va_backend_options = array('cache_dir' => $vs_cache_dir, 'file_locking' => true, 'read_control' => false, 'file_name_prefix' => 'ca_cache', 'cache_file_perm' => 0777); $vo_cache = Zend_Cache::factory('Core', 'File', $va_frontend_options, $va_backend_options); if (!($va_cache_data = $vo_cache->load('ca_search_indexing_info_' . $vs_table))) { $va_cache_data = array(); } if (!$pb_invoked_from_command_line) { $va_table_fields = array_merge($va_cache_data, $va_table_fields); } $vo_cache->save($va_table_fields, 'ca_search_indexing_info_' . $vs_table); if (is_array($va_table_fields)) { foreach ($va_table_fields as $vs_field_name => $va_field_options) { if (in_array("STORE", $va_field_options)) { $vb_field_is_stored = true; } else { $vb_field_is_stored = false; } if (in_array("DONT_TOKENIZE", $va_field_options)) { $vb_field_is_tokenized = false; } else { $vb_field_is_tokenized = true; } $va_schema_fields[] = $vs_table . '.' . SolrConfiguration::adjustFieldsToIndex($vs_field_name); if (in_array($va_field_options['type'], array('text', 'string'))) { $vs_type = $vb_field_is_tokenized ? 'text' : 'string'; } else { if (!isset($va_field_options['type']) && $t_instance->hasField($vs_field_name)) { // if the primary key is configured to be indexed in search_indexing.conf, ignore it here // (we add it anyway and solr doesn't like duplicate fields!) if ($t_instance->primaryKey() == $vs_field_name) { continue; } switch ($t_instance->getFieldInfo($vs_field_name, "FIELD_TYPE")) { case FT_TEXT: case FT_MEDIA: case FT_FILE: case FT_PASSWORD: case FT_VARS: $va_field_options['type'] = 'text'; break; case FT_NUMBER: case FT_TIME: case FT_TIMERANGE: case FT_TIMECODE: $va_field_options['type'] = 'float'; break; case FT_TIMESTAMP: case FT_DATETIME: case FT_HISTORIC_DATETIME: case FT_DATE: case FT_HISTORIC_DATE: case FT_DATERANGE: case FT_HISTORIC_DATERANGE: $va_field_options['type'] = 'daterange'; break; case FT_BIT: $va_field_options['type'] = 'bool'; break; default: $va_field_options['type'] = null; break; } } $vs_type = isset($va_field_options['type']) && $va_field_options['type'] ? $va_field_options['type'] : 'text'; } $vs_field_schema .= SolrConfiguration::tabs(2) . '<field name="' . $vs_table . '.' . SolrConfiguration::adjustFieldsToIndex($vs_field_name) . '" type="' . $vs_type; $vs_field_schema .= '" indexed="true" '; $vb_field_is_stored ? $vs_field_schema .= 'stored="true" ' : ($vs_field_schema .= 'stored="false" '); $vs_field_schema .= '/>' . SolrConfiguration::nl(); } } /* related tables */ $va_related_tables = $po_search_base->getRelatedIndexingTables($vs_table); foreach ($va_related_tables as $vs_related_table) { $va_related_table_fields = $po_search_base->getFieldsToIndex($vs_table, $vs_related_table); foreach ($va_related_table_fields as $vs_related_table_field => $va_related_table_field_options) { if (in_array("STORE", $va_related_table_field_options)) { $vb_field_is_stored = true; } else { $vb_field_is_stored = false; } if (in_array("DONT_TOKENIZE", $va_related_table_field_options)) { $vb_field_is_tokenized = false; } else { $vb_field_is_tokenized = true; } $va_schema_fields[] = $vs_related_table . '.' . $vs_related_table_field; $vs_field_schema .= SolrConfiguration::tabs(2) . '<field name="' . $vs_related_table . '.' . $vs_related_table_field . '" type="'; $vb_field_is_tokenized ? $vs_field_schema .= 'text' : ($vs_field_schema .= 'string'); $vs_field_schema .= '" indexed="true" '; $vb_field_is_stored ? $vs_field_schema .= 'stored="true" ' : ($vs_field_schema .= 'stored="false" '); $vs_field_schema .= '/>' . SolrConfiguration::nl(); } } /* copyfield directives * we use a single field in each index (called "text") where * all other fields are copied. the text field is the default * search field. it is used if a field name specification is * omitted in a search query. */ $vs_copyfields = ""; foreach ($va_schema_fields as $vs_schema_field) { $vs_copyfields .= SolrConfiguration::tabs(1) . '<copyField source="' . $vs_schema_field . '" dest="text" />' . SolrConfiguration::nl(); } // // Get access points // if (!is_array($va_access_points = $po_search_base->getAccessPoints($vs_table))) { $va_access_points = array(); } foreach ($va_access_points as $vs_access_point => $va_access_point_info) { foreach ($va_access_point_info['fields'] as $vn_i => $vs_schema_field) { $vs_copyfields .= SolrConfiguration::tabs(1) . '<copyField source="' . $vs_schema_field . '" dest="' . $vs_access_point . '" />' . SolrConfiguration::nl(); } $vs_field_schema .= SolrConfiguration::tabs(2) . '<field name="' . $vs_access_point . '" type="text" indexed="true" stored="true" multiValued="true"/>' . SolrConfiguration::nl(); } /* write field indexing config into file */ fprintf($vr_schema_xml_file, "%s", $vs_field_schema); continue; } /* 3rd replacement: uniquekey */ if (strpos($vs_line, "<!--KEY-->") !== false) { $vs_pk = $t_instance->primaryKey(); fprintf($vr_schema_xml_file, "%s", str_replace("<!--KEY-->", $vs_table . "." . $vs_pk, $vs_line)); continue; } /* 4th replacement: copyFields */ if (strpos($vs_line, "<!--COPYFIELDS-->") !== false) { /* $vs_copyfields *should* be set, otherwise the template has been messed up */ fprintf($vr_schema_xml_file, "%s", $vs_copyfields); // add copyField for the subject table fields so that the pk can be adressed in 2 ways: // "objects.object_id" or "object.id" fprintf($vr_schema_xml_file, "%s", $vs_subject_table_copyfields); continue; } /* "normal" line */ fprintf($vr_schema_xml_file, "%s", $vs_line); } fclose($vr_schema_xml_file); } }
private function _getMetadataElement($ps_element_code) { if (isset(WLPlugSearchEngineSolr::$s_element_code_cache[$ps_element_code])) { return WLPlugSearchEngineSolr::$s_element_code_cache[$ps_element_code]; } $t_element = new ca_metadata_elements($ps_element_code); if (!($vn_element_id = $t_element->getPrimaryKey())) { return WLPlugSearchEngineSolr::$s_element_code_cache[$ps_element_code] = null; } return WLPlugSearchEngineSolr::$s_element_code_cache[$ps_element_code] = array('element_id' => $vn_element_id, 'element_code' => $t_element->get('element_code'), 'datatype' => $t_element->get('datatype')); }
/** * @param $pa_hits Array of row_ids to sort. *MUST HAVE row_ids AS KEYS, NOT VALUES* */ public function sortHits($pa_hits, $ps_field, $ps_direction = 'asc', $pa_options = null) { if (!in_array(strtolower($ps_direction), array('asc', 'desc'))) { $ps_direction = 'asc'; } if (!is_array($pa_hits) || !sizeof($pa_hits)) { return $pa_hits; } $vs_search_tmp_table = $this->loadListIntoTemporaryResultTable($pa_hits, $pa_options['search']); $t_table = $this->opo_datamodel->getInstanceByTableNum($this->opn_tablenum, true); $vs_table_pk = $t_table->primaryKey(); $vs_table_name = $this->ops_tablename; $va_fields = explode(';', $ps_field); $va_sorted_hits = array(); $vn_num_locales = ca_locales::numberOfCataloguingLocales(); foreach ($va_fields as $vs_field) { $va_joins = $va_orderbys = array(); $vs_locale_where = $vs_is_preferred_sql = ''; $va_tmp = explode('.', $vs_field); // Rewrite for <table>.preferred_labels.* syntax if ($va_tmp[1] == 'preferred_labels') { if ($t_labeled_item_table = $this->opo_datamodel->getInstanceByTableName($va_tmp[0], true)) { if ($t_label_table = $t_labeled_item_table->getLabelTableInstance()) { $va_tmp2 = array($t_label_table->tableName()); if (isset($va_tmp[2]) && $t_label_table->hasField($va_tmp[2])) { $va_tmp2[] = $va_tmp[2]; } else { $va_tmp2[] = $t_labeled_item_table->getLabelDisplayField(); } $va_tmp = $va_tmp2; $vs_field = join(".", $va_tmp); } } } if ($va_tmp[0] == $vs_table_name) { // // sort field is in search table // if (!$t_table->hasField($va_tmp[1])) { // // is it an attribute? // $t_element = new ca_metadata_elements(); $vs_sort_element_code = array_pop($va_tmp); if ($t_element->load(array('element_code' => $vs_sort_element_code))) { $vn_element_id = $t_element->getPrimaryKey(); if (!($vs_sortable_value_fld = Attribute::getSortFieldForDatatype($t_element->get('datatype')))) { return $pa_hits; } if ((int) $t_element->get('datatype') == 3) { $vs_sortable_value_fld = 'lil.name_plural'; $vs_sort_field = array_pop(explode('.', $vs_sortable_value_fld)); $vs_locale_where = $vn_num_locales > 1 ? ', lil.locale_id' : ''; $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT attr.row_id, lil.locale_id, lower({$vs_sortable_value_fld}) {$vs_sort_field}\n\t\t\t\t\t\t\t\tFROM ca_attributes attr\n\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values AS attr_vals ON attr_vals.attribute_id = attr.attribute_id\n\t\t\t\t\t\t\t\tINNER JOIN ca_list_item_labels AS lil ON lil.item_id = attr_vals.item_id\n\t\t\t\t\t\t\t\tINNER JOIN {$vs_browse_tmp_table} ON {$vs_browse_tmp_table}.row_id = attr.row_id\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t(attr_vals.element_id = ?) AND (attr.table_num = ?) AND (lil.{$vs_sort_field} IS NOT NULL)\n\t\t\t\t\t\t\t\tORDER BY lil.{$vs_sort_field}\n\t\t\t\t\t\t\t"; } else { $vs_sortable_value_fld = 'attr_vals.' . $vs_sortable_value_fld; $vs_sort_field = array_pop(explode('.', $vs_sortable_value_fld)); $vs_locale_where = $vn_num_locales > 1 ? 'attr.locale_id' : ''; $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT attr.row_id, attr.locale_id, lower({$vs_sortable_value_fld}) {$vs_sort_field}\n\t\t\t\t\t\t\t\tFROM ca_attributes attr\n\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values AS attr_vals ON attr_vals.attribute_id = attr.attribute_id\n\t\t\t\t\t\t\t\tINNER JOIN {$vs_search_tmp_table} ON {$vs_search_tmp_table}.row_id = attr.row_id\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t(attr_vals.element_id = ?) AND (attr.table_num = ?) AND (attr_vals.{$vs_sort_field} IS NOT NULL)\n\t\t\t\t\t\t\t\tORDER BY attr_vals.{$vs_sort_field}\n\t\t\t\t\t\t\t"; //print $vs_sql." ; $vn_element_id/; ".$this->opn_tablenum."<br>"; } $qr_sort = $this->opo_db->query($vs_sql, (int) $vn_element_id, (int) $this->opn_tablenum); while ($qr_sort->nextRow()) { $va_row = $qr_sort->getRow(); if (!$va_row['row_id']) { continue; } if ($vn_num_locales > 1) { $va_sorted_hits[$va_row['row_id']][$va_row['locale_id']] .= trim(str_replace(array("'", '"'), array('', ''), $va_row[$vs_sort_field])); } else { $va_sorted_hits[$va_row['row_id']] .= trim(str_replace(array("'", '"'), array('', ''), $va_row[$vs_sort_field])); } unset($pa_hits[$va_row['row_id']]); } // Add on hits that aren't sorted because they don't have an attribute associated foreach ($pa_hits as $vn_id => $va_row) { if (!is_array($va_row)) { $va_row = array(); } if ($vn_num_locales > 1) { $va_sorted_hits[$vn_id][1] = $va_row; } else { $va_sorted_hits[$vn_id] = $va_row; } } } continue; } else { $va_field_info = $t_table->getFieldInfo($va_tmp[1]); if ($va_field_info['START'] && $va_field_info['END']) { $va_orderbys[] = $va_field_info['START'] . ' ' . $ps_direction; $va_orderbys[] = $va_field_info['END'] . ' ' . $ps_direction; } else { $va_orderbys[] = $vs_field . ' ' . $ps_direction; } if ($t_table->hasField('locale_id')) { $vs_locale_where = ", " . $vs_table_name . ".locale_id"; } $vs_sortable_value_fld = $vs_field; } } else { // sort field is in related table $va_path = $this->opo_datamodel->getPath($vs_table_name, $va_tmp[0]); if (sizeof($va_path) > 2) { // many-many $vs_last_table = null; // generate related joins foreach ($va_path as $vs_table => $va_info) { $t_table = $this->opo_datamodel->getInstanceByTableName($vs_table, true); if (!$vs_last_table) { //$va_joins[$vs_table] = "INNER JOIN ".$vs_table." ON ".$vs_table.".".$t_table->primaryKey()." = ca_sql_search_search_final.row_id"; } else { $va_rels = $this->opo_datamodel->getOneToManyRelations($vs_last_table, $vs_table); if (!sizeof($va_rels)) { $va_rels = $this->opo_datamodel->getOneToManyRelations($vs_table, $vs_last_table); } if ($vs_table == $va_rels['one_table']) { $va_joins[$vs_table] = "INNER JOIN " . $va_rels['one_table'] . " ON " . $va_rels['one_table'] . "." . $va_rels['one_table_field'] . " = " . $va_rels['many_table'] . "." . $va_rels['many_table_field']; } else { $va_joins[$vs_table] = "INNER JOIN " . $va_rels['many_table'] . " ON " . $va_rels['many_table'] . "." . $va_rels['many_table_field'] . " = " . $va_rels['one_table'] . "." . $va_rels['one_table_field']; } } $t_last_table = $t_table; $vs_last_table = $vs_table; } $va_orderbys[] = $vs_field . ' ' . $ps_direction; $vs_sortable_value_fld = $vs_field; } else { $va_rels = $this->opo_datamodel->getRelationships($vs_table_name, $va_tmp[0]); if (!$va_rels) { return $pa_hits; } // return hits unsorted if field is not valid $t_rel = $this->opo_datamodel->getInstanceByTableName($va_tmp[0], true); if (!$t_rel->hasField($va_tmp[1])) { return $pa_hits; } $va_joins[$va_tmp[0]] = 'LEFT JOIN ' . $va_tmp[0] . ' ON ' . $vs_table_name . '.' . $va_rels[$vs_table_name][$va_tmp[0]][0][0] . ' = ' . $va_tmp[0] . '.' . $va_rels[$vs_table_name][$va_tmp[0]][0][1] . "\n"; $va_orderbys[] = $vs_field . ' ' . $ps_direction; // if the related supports preferred values (eg. *_labels tables) then only consider those in the sort if ($t_rel->hasField('is_preferred')) { $vs_is_preferred_sql = " " . $va_tmp[0] . ".is_preferred = 1"; } if ($t_rel->hasField('locale_id')) { $vs_locale_where = ", " . $va_tmp[0] . ".locale_id"; } $vs_sortable_value_fld = $vs_field; } } // // Grab values and index for sorting later // $va_tmp = explode('.', $vs_sortable_value_fld); $vs_sort_field = array_pop($va_tmp); $vs_join_sql = join("\n", $va_joins); $vs_sql = "\n\t\t\t\tSELECT {$vs_table_name}.{$vs_table_pk}{$vs_locale_where}, lower({$vs_sortable_value_fld}) {$vs_sort_field}\n\t\t\t\tFROM {$vs_table_name}\n\t\t\t\t{$vs_join_sql}\n\t\t\t\tINNER JOIN {$vs_search_tmp_table} ON {$vs_search_tmp_table}.row_id = {$vs_table_name}.{$vs_table_pk}\n\t\t\t\t" . ($vs_is_preferred_sql ? 'WHERE' : '') . "\n\t\t\t\t\t{$vs_is_preferred_sql}\n\t\t\t"; //print $vs_sql; $qr_sort = $this->opo_db->query($vs_sql); while ($qr_sort->nextRow()) { $va_row = $qr_sort->getRow(); if (!($vs_sortable_value = str_replace(array("'", '"'), array('', ''), $va_row[$vs_sort_field]))) { $vs_sortable_value = ''; } if ($vn_num_locales > 1 && $vs_locale_where) { $va_sorted_hits[$va_row[$vs_table_pk]][$va_row['locale_id']] .= $vs_sortable_value; } else { $va_sorted_hits[$va_row[$vs_table_pk]] .= $vs_sortable_value; } } } // // Actually sort the hits here... // if ($vn_num_locales > 1 && $vs_locale_where) { $va_sorted_hits = caExtractValuesByUserLocale($va_sorted_hits); } asort($va_sorted_hits, SORT_STRING); if ($ps_direction == 'desc') { $va_sorted_hits = array_reverse($va_sorted_hits, true); } $this->cleanupTemporaryResultTable(); return $va_sorted_hits; }
/** * Processes single exporter item for a given record * * @param int $pn_item_id Primary of exporter item * @param int $pn_table_num Table num of item to export * @param int $pn_record_id Primary key value of item to export * @param array $pa_options * ignoreContext = don't switch context even though context may be set for current item * relationship_type_id, relationship_type_code, relationship_typename = * if this export is a sub-export (context-switch), we have no way of knowing the relationship * to the 'parent' element in the export, so there has to be a means to pass it down to make it accessible * attribute_id = signals that this is an export relative to a specific attribute instance * this triggers special behavior that allows getting container values in a kind of sub-export * it's really only useful for Containers but in theory can be any attribute * logger = KLogger instance to use for logging. This option is mandatory! * @return array Item info */ public function processExporterItem($pn_item_id, $pn_table_num, $pn_record_id, $pa_options = array()) { $o_log = caGetOption('logger', $pa_options); // always set by exportRecord() $vb_ignore_context = caGetOption('ignoreContext', $pa_options); $vn_attribute_id = caGetOption('attribute_id', $pa_options); $o_log->logInfo(_t("Export mapping processor called with parameters [exporter_item_id:%1 table_num:%2 record_id:%3]", $pn_item_id, $pn_table_num, $pn_record_id)); $t_exporter_item = ca_data_exporters::loadExporterItemByID($pn_item_id); $t_instance = ca_data_exporters::loadInstanceByID($pn_record_id, $pn_table_num); // switch context to a different set of records if necessary and repeat current exporter item for all those selected records // (e.g. hierarchy children or related items in another table, restricted by types or relationship types) if (!$vb_ignore_context && ($vs_context = $t_exporter_item->getSetting('context'))) { $va_restrict_to_types = $t_exporter_item->getSetting('restrictToTypes'); $va_restrict_to_rel_types = $t_exporter_item->getSetting('restrictToRelationshipTypes'); $va_restrict_to_bundle_vals = $t_exporter_item->getSetting('restrictToBundleValues'); $va_check_access = $t_exporter_item->getSetting('checkAccess'); $va_sort = $t_exporter_item->getSetting('sort'); $vn_new_table_num = $this->getAppDatamodel()->getTableNum($vs_context); $vb_context_is_related_table = false; $va_related = null; if ($vn_new_table_num) { // switch to new table $vs_key = $this->getAppDatamodel()->getTablePrimaryKeyName($vs_context); } else { // this table, i.e. hierarchy context switch $vs_key = $t_instance->primaryKey(); } $o_log->logInfo(_t("Initiating context switch to '%1' for mapping ID %2 and record ID %3. The processor now tries to find matching records for the switch and calls itself for each of those items.", $vs_context, $pn_item_id, $pn_record_id)); switch ($vs_context) { case 'children': $va_related = $t_instance->getHierarchyChildren(); break; case 'parent': $va_related = array(); if ($vs_parent_id_fld = $t_instance->getProperty("HIERARCHY_PARENT_ID_FLD")) { $va_related[] = array($vs_key => $t_instance->get($vs_parent_id_fld)); } break; case 'ancestors': $va_parents = $t_instance->getHierarchyAncestors(null, array('idsOnly' => true)); $va_related = array(); foreach (array_unique($va_parents) as $vn_pk) { $va_related[] = array($vs_key => intval($vn_pk)); } break; case 'ca_sets': $t_set = new ca_sets(); $va_set_options = array(); if (isset($va_restrict_to_types[0])) { // the utility used below doesn't support passing multiple types so we just pass the first. // this should be enough for 99.99% of the actual use cases anyway $va_set_options['setType'] = $va_restrict_to_types[0]; } $va_set_options['checkAccess'] = $va_check_access; $va_set_options['setIDsOnly'] = true; $va_set_ids = $t_set->getSetsForItem($pn_table_num, $t_instance->getPrimaryKey(), $va_set_options); $va_related = array(); foreach (array_unique($va_set_ids) as $vn_pk) { $va_related[] = array($vs_key => intval($vn_pk)); } break; case 'ca_list_items.firstLevel': if ($t_instance->tableName() == 'ca_lists') { $o_dm = Datamodel::load(); $va_related = array(); $va_items_legacy_format = $t_instance->getListItemsAsHierarchy(null, array('maxLevels' => 1, 'dontIncludeRoot' => true)); $vn_new_table_num = $o_dm->getTableNum('ca_list_items'); $vs_key = 'item_id'; foreach ($va_items_legacy_format as $va_item_legacy_format) { $va_related[$va_item_legacy_format['NODE']['item_id']] = $va_item_legacy_format['NODE']; } break; } else { return array(); } break; default: if ($vn_new_table_num) { $va_options = array('restrictToTypes' => $va_restrict_to_types, 'restrictToRelationshipTypes' => $va_restrict_to_rel_types, 'restrictToBundleValues' => $va_restrict_to_bundle_vals, 'checkAccess' => $va_check_access, 'sort' => $va_sort); $o_log->logDebug(_t("Calling getRelatedItems with options: %1.", print_r($va_options, true))); $va_related = $t_instance->getRelatedItems($vs_context, $va_options); $vb_context_is_related_table = true; } else { // container or invalid context $va_context_tmp = explode('.', $vs_context); if (sizeof($va_context_tmp) != 2) { $o_log->logError(_t("Invalid context %1. Ignoring this mapping.", $vs_context)); return array(); } $va_attrs = $t_instance->getAttributesByElement($va_context_tmp[1]); $va_info = array(); if (is_array($va_attrs) && sizeof($va_attrs) > 0) { $o_log->logInfo(_t("Switching context for element code: %1.", $va_context_tmp[1])); $o_log->logDebug(_t("Raw attribute value array is as follows. The mapping will now be repeated for each (outer) attribute. %1", print_r($va_attrs, true))); foreach ($va_attrs as $vo_attr) { $va_attribute_export = $this->processExporterItem($pn_item_id, $pn_table_num, $pn_record_id, array_merge(array('ignoreContext' => true, 'attribute_id' => $vo_attr->getAttributeID()), $pa_options)); $va_info = array_merge($va_info, $va_attribute_export); } } else { $o_log->logInfo(_t("Switching context for element code %1 failed. Either there is no attribute with that code attached to the current row or the code is invalid. Mapping is ignored for current row.", $va_context_tmp[1])); } return $va_info; } break; } $va_info = array(); if (is_array($va_related)) { $o_log->logDebug(_t("The current mapping will now be repreated for these items: %1", print_r($va_related, true))); if (!$vn_new_table_num) { $vn_new_table_num = $pn_table_num; } foreach ($va_related as $va_rel) { // if we're dealing with a related table, pass on some info the relationship type to the context-switched invocation of processExporterItem(), // because we can't access that information from the related item simply because we don't exactly know where the call originated if ($vb_context_is_related_table) { $pa_options['relationship_typename'] = $va_rel['relationship_typename']; $pa_options['relationship_type_code'] = $va_rel['relationship_type_code']; $pa_options['relationship_type_id'] = $va_rel['relationship_type_id']; } $va_rel_export = $this->processExporterItem($pn_item_id, $vn_new_table_num, $va_rel[$vs_key], array_merge(array('ignoreContext' => true), $pa_options)); $va_info = array_merge($va_info, $va_rel_export); } } else { $o_log->logDebug(_t("No matching related items found for last context switch")); } return $va_info; } // end switch context // Don't prevent context switches for children of context-switched exporter items. This way you can // build cascades for jobs like exporting objects related to the creator of the record in question. unset($pa_options['ignoreContext']); $va_item_info = array(); $vs_source = $t_exporter_item->get('source'); $vs_element = $t_exporter_item->get('element'); $vb_repeat = $t_exporter_item->getSetting('repeat_element_for_multiple_values'); // if omitIfEmpty is set and get() returns nothing, we ignore this exporter item and all children if ($vs_omit_if_empty = $t_exporter_item->getSetting('omitIfEmpty')) { if (!(strlen($t_instance->get($vs_omit_if_empty)) > 0)) { return array(); } } // if omitIfNotEmpty is set and get() returns a value, we ignore this exporter item and all children if ($vs_omit_if_not_empty = $t_exporter_item->getSetting('omitIfNotEmpty')) { if (strlen($t_instance->get($vs_omit_if_not_empty)) > 0) { return array(); } } // always return URL for export, not an HTML tag $va_get_options = array('returnURL' => true); if ($vs_delimiter = $t_exporter_item->getSetting("delimiter")) { $va_get_options['delimiter'] = $vs_delimiter; } if ($vs_template = $t_exporter_item->getSetting('template')) { $va_get_options['template'] = $vs_template; } if ($vs_locale = $t_exporter_item->getSetting('locale')) { // the global UI locale for some reason has a higher priority // than the locale setting in BaseModelWithAttributes::get // which is why we unset it here and restore it later global $g_ui_locale; $vs_old_ui_locale = $g_ui_locale; $g_ui_locale = null; $va_get_options['locale'] = $vs_locale; } // AttributeValue settings that are simply passed through by the exporter if ($t_exporter_item->getSetting('convertCodesToDisplayText')) { $va_get_options['convertCodesToDisplayText'] = true; // try to return text suitable for display for system lists stored in intrinsics (ex. ca_objects.access, ca_objects.status, ca_objects.source_id) // this does not affect list attributes } else { $va_get_options['convertCodesToIdno'] = true; // if display text is not requested try to return list item idno's... since underlying integer ca_list_items.item_id values are unlikely to be useful in an export context } if ($t_exporter_item->getSetting('returnIdno')) { $va_get_options['returnIdno'] = true; } if ($t_exporter_item->getSetting('start_as_iso8601')) { $va_get_options['start_as_iso8601'] = true; } if ($t_exporter_item->getSetting('end_as_iso8601')) { $va_get_options['end_as_iso8601'] = true; } if ($t_exporter_item->getSetting('dontReturnValueIfOnSameDayAsStart')) { $va_get_options['dontReturnValueIfOnSameDayAsStart'] = true; } if ($vs_date_format = $t_exporter_item->getSetting('dateFormat')) { $va_get_options['dateFormat'] = $vs_date_format; } // context was switched to attribute if ($vn_attribute_id) { $o_log->logInfo(_t("Processing mapping in attribute mode for attribute_id = %1.", $vn_attribute_id)); if ($vs_source) { // trying to find the source only makes sense if the source is set $t_attr = new ca_attributes($vn_attribute_id); $va_values = $t_attr->getAttributeValues(); $va_src_tmp = explode('.', $vs_source); if (sizeof($va_src_tmp) == 2) { $o_dm = Datamodel::load(); if ($t_attr->get('table_num') == $o_dm->getTableNum($va_src_tmp[0])) { $vs_source = $va_src_tmp[1]; } } $o_log->logDebug(_t("Trying to find code %1 in value array for the current attribute.", $vs_source)); $o_log->logDebug(_t("Value array is %1.", print_r($va_values, true))); foreach ($va_values as $vo_val) { $va_display_val_options = array(); if ($vo_val instanceof ListAttributeValue) { // figure out list_id -- without it we can't pull display values $t_element = new ca_metadata_elements($vo_val->getElementID()); $va_display_val_options = array('list_id' => $t_element->get('list_id')); if ($t_exporter_item->getSetting('returnIdno') || $t_exporter_item->getSetting('convertCodesToIdno')) { $va_display_val_options['output'] = 'idno'; } elseif ($t_exporter_item->getSetting('convertCodesToDisplayText')) { $va_display_val_options['output'] = 'text'; } } $o_log->logDebug(_t("Trying to match code from array %1 and the code we're looking for %2.", $vo_val->getElementCode(), $vs_source)); if ($vo_val->getElementCode() == $vs_source) { $vs_display_value = $vo_val->getDisplayValue($va_display_val_options); $o_log->logDebug(_t("Found value %1.", $vs_display_value)); $va_item_info[] = array('text' => $vs_display_value, 'element' => $vs_element); } } } else { // no source in attribute context probably means this is some form of wrapper, e.g. a MARC field $va_item_info[] = array('element' => $vs_element); } } else { if ($vs_source) { $o_log->logDebug(_t("Source for current mapping is %1", $vs_source)); $va_matches = array(); // CONSTANT value if (preg_match("/^_CONSTANT_:(.*)\$/", $vs_source, $va_matches)) { $o_log->logDebug(_t("This is a constant. Value for this mapping is '%1'", trim($va_matches[1]))); $va_item_info[] = array('text' => trim($va_matches[1]), 'element' => $vs_element); } else { if (in_array($vs_source, array("relationship_type_id", "relationship_type_code", "relationship_typename"))) { if (isset($pa_options[$vs_source]) && strlen($pa_options[$vs_source]) > 0) { $o_log->logDebug(_t("Source refers to releationship type information. Value for this mapping is '%1'", $pa_options[$vs_source])); $va_item_info[] = array('text' => $pa_options[$vs_source], 'element' => $vs_element); } } else { if (!$vb_repeat) { $vs_get = $t_instance->get($vs_source, $va_get_options); $o_log->logDebug(_t("Source is a simple get() for some bundle. Value for this mapping is '%1'", $vs_get)); $o_log->logDebug(_t("get() options are: %1", print_r($va_get_options, true))); $va_item_info[] = array('text' => $vs_get, 'element' => $vs_element); } else { // user wants current element repeated in case of multiple returned values $va_get_options['delimiter'] = ';#;'; $vs_values = $t_instance->get($vs_source, $va_get_options); $o_log->logDebug(_t("Source is a get() that should be repeated for multiple values. Value for this mapping is '%1'. It includes the custom delimiter ';#;' that is later used to split the value into multiple values.", $vs_values)); $o_log->logDebug(_t("get() options are: %1", print_r($va_get_options, true))); $va_tmp = explode(";#;", $vs_values); foreach ($va_tmp as $vs_text) { $va_item_info[] = array('element' => $vs_element, 'text' => $vs_text); } } } } } else { if ($vs_template) { // templates without source are probably just static text, but you never know // -> run them through processor anyways $vs_proc_template = caProcessTemplateForIDs($vs_template, $pn_table_num, array($pn_record_id), array()); $o_log->logDebug(_t("Current mapping has no source but a template '%1'. Value from extracted via template processor is '%2'", $vs_template, $vs_proc_template)); $va_item_info[] = array('element' => $vs_element, 'text' => $vs_proc_template); } else { // no source, no template -> probably wrapper $o_log->logDebug(_t("Current mapping has no source and no template and is probably an XML/MARC wrapper element")); $va_item_info[] = array('element' => $vs_element); } } } // reset UI locale if we unset it if ($vs_locale) { $g_ui_locale = $vs_old_ui_locale; } $o_log->logDebug(_t("We're now processing other settings like default, prefix, suffix, skipIfExpression, filterByRegExp, maxLength, plugins and replacements for this mapping")); $o_log->logDebug(_t("Local data before processing is: %1", print_r($va_item_info, true))); // handle other settings and plugin hooks $vs_default = $t_exporter_item->getSetting('default'); $vs_prefix = $t_exporter_item->getSetting('prefix'); $vs_suffix = $t_exporter_item->getSetting('suffix'); //$vs_regexp = $t_exporter_item->getSetting('filterByRegExp'); // Deprecated -- remove? $vn_max_length = $t_exporter_item->getSetting('maxLength'); $vs_skip_if_expr = $t_exporter_item->getSetting('skipIfExpression'); $vs_original_values = $t_exporter_item->getSetting('original_values'); $vs_replacement_values = $t_exporter_item->getSetting('replacement_values'); $va_replacements = ca_data_exporter_items::getReplacementArray($vs_original_values, $vs_replacement_values); foreach ($va_item_info as $vn_key => &$va_item) { $this->opo_app_plugin_manager->hookExportItemBeforeSettings(array('instance' => $t_instance, 'exporter_item_instance' => $t_exporter_item, 'export_item' => &$va_item)); // handle dontReturnValueIfOnSameDayAsStart if (caGetOption('dontReturnValueIfOnSameDayAsStart', $va_get_options, false)) { if (strlen($va_item['text']) < 1) { unset($va_item_info[$vn_key]); } } // handle skipIfExpression setting if ($vs_skip_if_expr) { // Add current value as variable "value", accessible in expressions as ^value $va_vars = array_merge(array('value' => $va_item['text']), ca_data_exporters::$s_variables); if (ExpressionParser::evaluate($vs_skip_if_expr, $va_vars)) { unset($va_item_info[$vn_key]); continue; } } // filter by regex (deprecated since you can do the same thing and more with skipIfExpression) -- remove? //if((strlen($va_item['text'])>0) && $vs_regexp) { // if(!preg_match("!".$vs_regexp."!i", $va_item['text'])) { // unset($va_item_info[$vn_key]); // continue; // } //} // do replacements $va_item['text'] = ca_data_exporter_items::replaceText($va_item['text'], $va_replacements); // if text is empty, fill in default // if text isn't empty, respect prefix and suffix if (strlen($va_item['text']) == 0) { if ($vs_default) { $va_item['text'] = $vs_default; } } else { if (strlen($vs_prefix) > 0 || strlen($vs_suffix) > 0) { $va_item['text'] = $vs_prefix . $va_item['text'] . $vs_suffix; } } if ($vn_max_length && strlen($va_item['text']) > $vn_max_length) { $va_item['text'] = substr($va_item['text'], 0, $vn_max_length) . " ..."; } // if this is a variable, set the value and delete it from the export tree $va_matches = array(); if (preg_match("/^_VARIABLE_:(.*)\$/", $va_item['element'], $va_matches)) { ca_data_exporters::$s_variables[$va_matches[1]] = $va_item['text']; unset($va_item_info[$vn_key]); continue; } // if returned value is null then we skip the item $this->opo_app_plugin_manager->hookExportItem(array('instance' => $t_instance, 'exporter_item_instance' => $t_exporter_item, 'export_item' => &$va_item)); } $o_log->logInfo(_t("Extracted data for this mapping is as follows:")); foreach ($va_item_info as $va_tmp) { $o_log->logInfo(sprintf(" element:%-20s value: %-10s", $va_tmp['element'], $va_tmp['text'])); } $va_children = $t_exporter_item->getHierarchyChildren(); if (is_array($va_children) && sizeof($va_children) > 0) { $o_log->logInfo(_t("Now proceeding to process %1 direct children in the mapping hierarchy", sizeof($va_children))); foreach ($va_children as $va_child) { foreach ($va_item_info as &$va_info) { $va_child_export = $this->processExporterItem($va_child['item_id'], $pn_table_num, $pn_record_id, $pa_options); $va_info['children'] = array_merge((array) $va_info['children'], $va_child_export); } } } return $va_item_info; }
/** * @param string $ps_table * @param string $ps_content_fieldname * @return \ElasticSearch\FieldTypes\FieldType */ public static function getInstance($ps_table, $ps_content_fieldname) { if ($ps_table == 'created' || $ps_table == 'modified') { return new Timestamp($ps_table); } // if this is an indexing field name, rewrite it if (preg_match("/^(I|A)[0-9]+\$/", $ps_content_fieldname)) { if ($ps_content_fieldname[0] === 'A') { // Metadata attribute $vn_field_num_proc = (int) substr($ps_content_fieldname, 1); $t_element = new \ca_metadata_elements($vn_field_num_proc); if (!$t_element->getPrimaryKey()) { return null; } $ps_content_fieldname = $t_element->get('element_code'); } else { // Plain intrinsic $vn_field_num_proc = (int) substr($ps_content_fieldname, 1); $ps_content_fieldname = \Datamodel::load()->getFieldName($ps_table, $vn_field_num_proc); } } if ($vn_datatype = \ca_metadata_elements::getDataTypeForElementCode($ps_content_fieldname)) { switch ($vn_datatype) { case 2: return new DateRange($ps_table, $ps_content_fieldname); case 4: return new Geocode($ps_table, $ps_content_fieldname); case 6: return new Currency($ps_table, $ps_content_fieldname); case 8: return new Length($ps_table, $ps_content_fieldname); case 9: return new Weight($ps_table, $ps_content_fieldname); case 10: return new Timecode($ps_table, $ps_content_fieldname); case 11: return new Integer($ps_table, $ps_content_fieldname); case 12: return new Float($ps_table, $ps_content_fieldname); default: return new GenericElement($ps_table, $ps_content_fieldname); } } else { return new Intrinsic($ps_table, $ps_content_fieldname); } }
/** * Given a item_id (request parameter 'id') returns a list of direct children for use in the hierarchy browser * Returned data is JSON format */ public function getFacetHierarchyLevel() { $va_access_values = caGetUserAccessValues($this->request); $ps_facet_name = $this->request->getParameter('facet', pString); $this->opo_browse->setTypeRestrictions(array($this->opn_type_restriction_id)); if (!is_array($va_facet_info = $this->opo_browse->getInfoForFacet($ps_facet_name))) { return null; } $va_facet = $this->opo_browse->getFacet($ps_facet_name, array('sort' => 'name', 'checkAccess' => $va_access_values)); $pa_ids = explode(";", $ps_ids = $this->request->getParameter('id', pString)); if (!sizeof($pa_ids)) { $pa_ids = array(null); } $va_level_data = array(); if (($vn_max_items_per_page = $this->request->getParameter('max', pInteger)) < 1 || $vn_max_items_per_page > 1000) { $vn_max_items_per_page = null; } $t_model = $this->opo_datamodel->getInstanceByTableName($this->ops_tablename, true); $o_config = Configuration::load(); if (!is_array($va_sorts = $o_config->getList($this->ops_tablename . '_hierarchy_browser_sort_values')) || !sizeof($va_sorts)) { $va_sorts = array(); } foreach ($va_sorts as $vn_i => $vs_sort_fld) { $va_tmp = explode(".", $vs_sort_fld); if ($va_tmp[1] == 'preferred_labels') { $va_tmp[0] = $vs_label_table_name; if (!($va_tmp[1] = $va_tmp[2])) { $va_tmp[1] = $vs_label_display_field_name; } unset($va_tmp[2]); $va_sorts[$vn_i] = join(".", $va_tmp); } } if (!in_array($vs_sort_dir = strtolower($o_config->get($this->ops_tablename . '_hierarchy_browser_sort_direction')), array('asc', 'desc'))) { $vs_sort_dir = 'asc'; } $va_expanded_facet = array(); $t_item = new ca_list_items(); foreach ($va_facet as $vn_id => $va_facet_item) { $va_expanded_facet[$vn_id] = true; $va_ancestors = $t_item->getHierarchyAncestors($vn_id, array('idsOnly' => true)); if (is_array($va_ancestors)) { foreach ($va_ancestors as $vn_ancestor_id) { $va_expanded_facet[$vn_ancestor_id] = true; } } } foreach ($pa_ids as $pn_id) { $va_json_data = array('_primaryKey' => 'item_id'); $va_tmp = explode(":", $pn_id); $vn_id = $va_tmp[0]; $vn_start = (int) $va_tmp[1]; if ($vn_start < 0) { $vn_start = 0; } switch ($va_facet_info['type']) { case 'attribute': // is it a list attribute? $t_element = new ca_metadata_elements(); if ($t_element->load(array('element_code' => $va_facet_info['element_code']))) { if ($t_element->get('datatype') == 3) { // 3=list $t_list = new ca_lists(); if (!$vn_id) { $vn_id = $t_list->getRootListItemID($t_element->get('list_id')); } $t_item = new ca_list_items($vn_id); $va_children = $t_item->getHierarchyChildren(null, array('idsOnly' => true)); $va_child_counts = $t_item->getHierarchyChildCountsForIDs($va_children); $qr_res = caMakeSearchResult('ca_list_items', $va_children); $vs_pk = $t_model->primaryKey(); if ($qr_res) { while ($qr_res->nextHit()) { $vn_parent_id = $qr_res->get('ca_list_items.parent_id'); $vn_item_id = $qr_res->get('ca_list_items.item_id'); if (!isset($va_expanded_facet[$vn_item_id])) { continue; } $va_item = array(); $va_item['item_id'] = $vn_item_id; $va_item['name'] = $qr_res->get('ca_list_items.preferred_labels'); $va_item['children'] = isset($va_child_counts[$vn_item_id]) && $va_child_counts[$vn_item_id] ? $va_child_counts[$vn_item_id] : 0; $va_json_data[$vn_item_id] = $va_item; } } } } break; case 'label': // label facet $va_facet_info['table'] = $this->ops_tablename; // fall through to default case // fall through to default case default: if (!$vn_id) { $va_hier_ids = $this->opo_browse->getHierarchyIDsForFacet($ps_facet_name, array('checkAccess' => $va_access_values)); $t_item = $this->opo_datamodel->getInstanceByTableName($va_facet_info['table']); $t_item->load($vn_id); $vn_id = $vn_root = $t_item->getHierarchyRootID(); $va_hierarchy_list = $t_item->getHierarchyList(true); $vn_last_id = null; $vn_c = 0; foreach ($va_hierarchy_list as $vn_i => $va_item) { if (!in_array($vn_i, $va_hier_ids)) { continue; } // only show hierarchies that have items in browse result if ($vn_start <= $vn_c) { $va_item['item_id'] = $va_item[$t_item->primaryKey()]; if (!isset($va_facet[$va_item['item_id']]) && $vn_root == $va_item['item_id']) { continue; } unset($va_item['parent_id']); unset($va_item['label']); $va_json_data[$va_item['item_id']] = $va_item; $vn_last_id = $va_item['item_id']; } $vn_c++; if (!is_null($vn_max_items_per_page) && $vn_c >= $vn_max_items_per_page + $vn_start) { break; } } if (sizeof($va_json_data) == 2) { // if only one hierarchy root (root + _primaryKey in array) then don't bother showing it $vn_id = $vn_last_id; unset($va_json_data[$vn_last_id]); } } if ($vn_id) { $vn_c = 0; foreach ($va_facet as $vn_i => $va_item) { if ($va_item['parent_id'] == $vn_id) { if ($vn_start <= $vn_c) { $va_item['item_id'] = $va_item['id']; $va_item['name'] = $va_item['label']; $va_item['children'] = $va_item['child_count']; unset($va_item['label']); unset($va_item['child_count']); unset($va_item['id']); $va_json_data[$va_item['item_id']] = $va_item; } $vn_c++; if (!is_null($vn_max_items_per_page) && $vn_c >= $vn_max_items_per_page + $vn_start) { break; } } } } break; } $vs_rank_fld = $t_item->getProperty('RANK'); $va_sorted_items = array(); foreach ($va_json_data as $vn_id => $va_node) { if (!is_array($va_node)) { continue; } $vs_key = preg_replace('![^A-Za-z0-9]!', '_', $va_node['name']); if (isset($va_node['sort']) && $va_node['sort']) { $va_sorted_items[$va_node['sort']][$vs_key] = $va_node; } else { if ($vs_rank_fld && ($vs_rank = (int) sprintf("%08d", $va_node[$vs_rank_fld]))) { $va_sorted_items[$vs_rank][$vs_key] = $va_node; } else { $va_sorted_items[$vs_key][$vs_key] = $va_node; } } } ksort($va_sorted_items); if ($vs_sort_dir == 'desc') { $va_sorted_items = array_reverse($va_sorted_items); } $va_json_data = array(); $va_sorted_items = array_slice($va_sorted_items, $vn_start, $vn_max_items_per_page); foreach ($va_sorted_items as $vs_k => $va_v) { ksort($va_v); if ($vs_sort_dir == 'desc') { $va_v = array_reverse($va_v); } $va_json_data = array_merge($va_json_data, $va_v); } $va_json_data['_itemCount'] = sizeof($va_json_data); $va_json_data['_sortOrder'] = array_keys($va_json_data); $va_json_data['_primaryKey'] = $t_model->primaryKey(); // pass the name of the primary key so the hierbrowser knows where to look for item_id's $va_level_data[$pn_id] = $va_json_data; } if (!trim($this->request->getParameter('init', pString))) { $this->opo_result_context->setParameter($ps_facet_name . '_browse_last_id', $pn_id); $this->opo_result_context->saveContext(); } $this->view->setVar('facet_list', $va_level_data); return $this->render('Browse/facet_hierarchy_level_json.php'); }
private function _doQueriesForSqlSearch($po_rewritten_query, $pn_subject_tablenum, $ps_dest_table, $pn_level = 0) { // query is always of type Zend_Search_Lucene_Search_Query_Boolean $vn_i = 0; $va_old_signs = $po_rewritten_query->getSigns(); foreach ($po_rewritten_query->getSubqueries() as $o_lucene_query_element) { $vb_is_blank_search = false; if (is_null($va_old_signs)) { // if array is null then according to Zend Lucene all subqueries should be "are required"... so we AND them $vs_op = "AND"; } else { if (is_null($va_old_signs[$vn_i])) { // is the sign for a particular query is null then OR is (it is "neither required nor prohibited") $vs_op = 'OR'; } else { $vs_op = $va_old_signs[$vn_i] === false ? 'NOT' : 'AND'; // true sign indicated "required" (AND) operation, false indicated "prohibited" (NOT) operation } } if ($vn_i == 0) { $vs_op = 'OR'; } $va_direct_query_temp_tables = array(); // List of temporary tables created by direct search queries; tables listed here are dropped at the end of processing for the query element switch (get_class($o_lucene_query_element)) { case 'Zend_Search_Lucene_Search_Query_Boolean': $this->_createTempTable('ca_sql_search_temp_' . $pn_level); $this->_doQueriesForSqlSearch($o_lucene_query_element, $pn_subject_tablenum, 'ca_sql_search_temp_' . $pn_level, $pn_level + 1); // merge with current destination switch ($vs_op) { case 'AND': // and $this->_createTempTable($ps_dest_table . '_acc'); if ($vn_i == 0) { $vs_sql = "\n\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}\n\t\t\t\t\t\t\t\t\tSELECT DISTINCT row_id, boost\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_temp_{$pn_level}\n\t\t\t\t\t\t\t\t"; //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql); } else { $vs_sql = "\n\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}_acc\n\t\t\t\t\t\t\t\t\tSELECT mfs.row_id, SUM(mfs.boost)\n\t\t\t\t\t\t\t\t\tFROM {$ps_dest_table} mfs\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_temp_{$pn_level} AS ftmp1 ON ftmp1.row_id = mfs.row_id\n\t\t\t\t\t\t\t\t\tGROUP BY mfs.row_id\n\t\t\t\t\t\t\t\t"; //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql); $qr_res = $this->opo_db->query("TRUNCATE TABLE {$ps_dest_table}"); $qr_res = $this->opo_db->query("INSERT INTO {$ps_dest_table} SELECT row_id, boost FROM {$ps_dest_table}_acc"); } $this->_dropTempTable($ps_dest_table . '_acc'); break; case 'NOT': $vs_sql = "\n\t\t\t\t\t\t\t\tDELETE FROM {$ps_dest_table} WHERE row_id IN\n\t\t\t\t\t\t\t\t(SELECT row_id FROM ca_sql_search_temp_{$pn_level})\n\t\t\t\t\t\t\t"; //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql); break; default: case 'OR': // or $vs_sql = "\n\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}\n\t\t\t\t\t\t\t\tSELECT row_id, SUM(boost)\n\t\t\t\t\t\t\t\tFROM ca_sql_search_temp_{$pn_level}\n\t\t\t\t\t\t\t\tGROUP BY row_id\n\t\t\t\t\t\t\t"; //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql); break; } $this->_dropTempTable('ca_sql_search_temp_' . $pn_level); break; case 'Zend_Search_Lucene_Search_Query_Term': case 'Zend_Search_Lucene_Search_Query_MultiTerm': case 'Zend_Search_Lucene_Search_Query_Phrase': case 'Zend_Search_Lucene_Search_Query_Range': $va_ft_terms = array(); $va_ft_like_terms = array(); $va_ft_stem_terms = array(); $vs_direct_sql_query = null; $pa_direct_sql_query_params = null; // set to array with values to use with direct SQL query placeholders or null to pass single standard table_num value as param (most queries just need this single value) $va_tmp = array(); $vs_access_point = ''; $va_raw_terms = array(); switch (get_class($o_lucene_query_element)) { case 'Zend_Search_Lucene_Search_Query_Range': $va_lower_term = $o_lucene_query_element->getLowerTerm(); $va_upper_term = $o_lucene_query_element->getUpperTerm(); $va_element = $this->_getElementIDForAccessPoint($va_lower_term->field); switch ($va_element['datatype']) { case 4: // geocode $t_geocode = new GeocodeAttributeValue(); $va_parsed_value = $t_geocode->parseValue($va_lower_term->text, $va_element['element_info']); $vs_lower_lat = $va_parsed_value['value_decimal1']; $vs_lower_long = $va_parsed_value['value_decimal2']; $va_parsed_value = $t_geocode->parseValue($va_upper_term->text, $va_element['element_info']); $vs_upper_lat = $va_parsed_value['value_decimal1']; $vs_upper_long = $va_parsed_value['value_decimal2']; $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t(cav.element_id = " . intval($va_element['element_id']) . ") AND (ca.table_num = ?)\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($vs_lower_lat) . " AND " . floatval($vs_upper_lat) . ")\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal2 BETWEEN " . floatval($vs_lower_long) . " AND " . floatval($vs_upper_long) . ")\t\n\t\t\t\t\t\t\t\t\t"; break; case 6: // currency $t_cur = new CurrencyAttributeValue(); $va_parsed_value = $t_cur->parseValue($va_lower_term->text, $va_element['element_info']); $vs_currency = preg_replace('![^A-Z0-9]+!', '', $va_parsed_value['value_longtext1']); $vn_lower_val = $va_parsed_value['value_decimal1']; $va_parsed_value = $t_cur->parseValue($va_upper_term->text, $va_element['element_info']); $vn_upper_val = $va_parsed_value['value_decimal1']; $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t(cav.element_id = " . intval($va_element['element_id']) . ") AND (ca.table_num = ?)\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($vn_lower_val) . " AND " . floatval($vn_upper_val) . ")\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_longtext1 = '" . $this->opo_db->escape($vs_currency) . "')\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t"; break; case 10: // timecode $t_timecode = new TimecodeAttributeValue(); $va_parsed_value = $t_timecode->parseValue($va_lower_term->text, $va_element['element_info']); $vn_lower_val = $va_parsed_value['value_decimal1']; $va_parsed_value = $t_timecode->parseValue($va_upper_term->text, $va_element['element_info']); $vn_upper_val = $va_parsed_value['value_decimal1']; break; case 8: // length $t_len = new LengthAttributeValue(); $va_parsed_value = $t_len->parseValue($va_lower_term->text, $va_element['element_info']); $vn_lower_val = $va_parsed_value['value_decimal1']; $va_parsed_value = $t_len->parseValue($va_upper_term->text, $va_element['element_info']); $vn_upper_val = $va_parsed_value['value_decimal1']; break; case 9: // weight $t_weight = new WeightAttributeValue(); $va_parsed_value = $t_weight->parseValue($va_lower_term->text, $va_element['element_info']); $vn_lower_val = $va_parsed_value['value_decimal1']; $va_parsed_value = $t_weight->parseValue($va_upper_term->text, $va_element['element_info']); $vn_upper_val = $va_parsed_value['value_decimal1']; break; case 11: // integer $vn_lower_val = intval($va_lower_term->text); $vn_upper_val = intval($va_upper_term->text); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t(cav.element_id = " . intval($va_element['element_id']) . ") AND (ca.table_num = ?)\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_integer1 BETWEEN " . floatval($vn_lower_val) . " AND " . floatval($vn_upper_val) . ")\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t"; break; case 12: // decimal $vn_lower_val = floatval($va_lower_term->text); $vn_upper_val = floatval($va_upper_term->text); break; } if (!$vs_direct_sql_query) { $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t(cav.element_id = " . intval($va_element['element_id']) . ") AND (ca.table_num = ?)\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($vn_lower_val) . " AND " . floatval($vn_upper_val) . ")\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t"; } break; case 'Zend_Search_Lucene_Search_Query_Phrase': $va_words = array(); foreach ($o_lucene_query_element->getQueryTerms() as $o_term) { if (!$vs_access_point && ($vs_field = $o_term->field)) { $vs_access_point = $vs_field; } $va_raw_terms[] = $vs_text = (string) $o_term->text; if (strlen($vs_escaped_text = $this->opo_db->escape($vs_text))) { $va_words[] = $vs_escaped_text; } } if (!sizeof($va_words)) { continue 3; } $va_ap_tmp = explode(".", $vs_access_point); $vn_fld_table = $vn_fld_num = null; if (sizeof($va_ap_tmp) == 2) { $va_element = $this->_getElementIDForAccessPoint($vs_access_point); if ($va_element) { $vs_fld_num = $va_element['field_num']; $vs_fld_table_num = $va_element['table_num']; $vs_fld_limit_sql = " AND (swi.field_table_num = {$vs_fld_table_num} AND swi.field_num = '{$vs_fld_num}')"; } } $va_temp_tables = array(); $vn_w = 0; foreach ($va_words as $vs_word) { $vn_w++; $vs_temp_table = 'ca_sql_search_phrase_' . md5($pn_subject_tablenum . "/" . $vs_word . "/" . $vn_w); $this->_createTempTable($vs_temp_table); $vs_sql = "\n\t\t\t\t\t\t\t\t\tINSERT INTO {$vs_temp_table}\n\t\t\t\t\t\t\t\t\tSELECT swi.index_id + 1, 1\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_words sw \n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_word_index AS swi ON sw.word_id = swi.word_id \n\t\t\t\t\t\t\t\t\t" . (sizeof($va_temp_tables) ? " INNER JOIN " . $va_temp_tables[sizeof($va_temp_tables) - 1] . " AS tt ON swi.index_id = tt.row_id" : "") . "\n\t\t\t\t\t\t\t\t\tWHERE \n\t\t\t\t\t\t\t\t\t\tsw.word = ? AND swi.table_num = ? {$vs_fld_limit_sql}\n \t\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : '') . "\n\t\t\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql, $vs_word, (int) $pn_subject_tablenum); $qr_count = $this->opo_db->query("SELECT count(*) c FROM {$vs_temp_table}"); if (!$qr_count->nextRow() || !(int) $qr_count->get('c')) { foreach ($va_temp_tables as $vs_temp_table) { $this->_dropTempTable($vs_temp_table); } break 2; } $va_temp_tables[] = $vs_temp_table; } $vs_results_temp_table = array_pop($va_temp_tables); $this->opo_db->query("UPDATE {$vs_results_temp_table} SET row_id = row_id - 1"); $va_direct_query_temp_tables[$vs_results_temp_table] = true; $vs_direct_sql_query = "SELECT swi.row_id, ca.boost \n\t\t\t\t\t\t\t\t\t\t\t\t\tFROM {$vs_results_temp_table} ca\n\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_word_index AS swi ON swi.index_id = ca.row_id \n\t\t\t\t\t\t\t"; $pa_direct_sql_query_params = array(); // don't pass any params foreach ($va_temp_tables as $vs_temp_table) { $this->_dropTempTable($vs_temp_table); } break; case 'Zend_Search_Lucene_Search_Query_MultiTerm': $va_ft_like_term_list = array(); foreach ($o_lucene_query_element->getTerms() as $o_term) { $va_raw_terms[] = $vs_term = (string) (method_exists($o_term, "getTerm") ? $o_term->getTerm()->text : $o_term->text); if (!$vs_access_point && ($vs_field = method_exists($o_term, "getTerm") ? $o_term->getTerm()->field : $o_term->field)) { $vs_access_point = $vs_field; } $vs_stripped_term = preg_replace('!\\*+$!u', '', $vs_term); $va_ft_like_terms[] = $vs_stripped_term . ($vb_had_wildcard ? '%' : ''); } break; default: $vs_access_point = $o_lucene_query_element->getTerm()->field; $vs_term = $o_lucene_query_element->getTerm()->text; if ($vs_access_point && mb_strtoupper($vs_term) == _t('[BLANK]')) { $vb_is_blank_search = true; break; } $va_terms = $this->_tokenize($vs_term, true, $vn_i); $vb_output_term = false; foreach ($va_terms as $vs_term) { if (in_array(trim(mb_strtolower($vs_term, 'UTF-8')), WLPlugSearchEngineSqlSearch::$s_stop_words)) { continue; } if (get_class($o_lucene_query_element) != 'Zend_Search_Lucene_Search_Query_MultiTerm') { $vs_stripped_term = preg_replace('!\\*+$!u', '', $vs_term); // do stemming if ($this->opb_do_stemming) { $vs_to_stem = preg_replace('!\\*$!u', '', $vs_term); if (!preg_match('!y$!u', $vs_to_stem) && !preg_match('![0-9]+!', $vs_to_stem)) { // don't stem things ending in 'y' as that can cause problems (eg "Bowery" becomes "Boweri") if (!($vs_stem = trim($this->opo_stemmer->stem($vs_to_stem)))) { $vs_stem = (string) $vs_term; } $va_ft_stem_terms[] = "'" . $this->opo_db->escape($vs_stem) . "'"; } else { $va_ft_terms[] = '"' . $this->opo_db->escape($vs_term) . '"'; } } else { $va_ft_terms[] = '"' . $this->opo_db->escape($vs_term) . '"'; } $vb_output_term = true; } } if ($vb_output_term) { $va_raw_terms[] = $vs_term; } else { $vn_i--; } break; } $vs_fld_num = $vs_table_num = $t_table = null; $vb_ft_bit_optimization = false; if ($vs_access_point) { list($vs_table, $vs_field, $vs_sub_field) = explode('.', $vs_access_point); if (in_array($vs_table, array('created', 'modified'))) { $o_tep = new TimeExpressionParser(); $vs_date = join(' ', $va_raw_terms); if (!$o_tep->parse($vs_date)) { break; } $va_range = $o_tep->getUnixTimestamps(); $vn_user_id = null; if ($vs_field = trim($vs_field)) { if (!is_int($vs_field)) { $t_user = new ca_users(); if ($t_user->load(array("user_name" => $vs_field))) { $vn_user_id = (int) $t_user->getPrimaryKey(); } } else { $vn_user_id = (int) $vs_field; } } $vs_user_sql = $vn_user_id ? " AND (ccl.user_id = " . (int) $vn_user_id . ")" : ""; switch ($vs_table) { case 'created': $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\tSELECT ccl.logged_row_id, 1\n\t\t\t\t\t\t\t\t\t\t\tFROM ca_change_log ccl\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(ccl.log_datetime BETWEEN " . (int) $va_range['start'] . " AND " . (int) $va_range['end'] . ")\n\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(ccl.logged_table_num = ?)\n\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(ccl.changetype = 'I')\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_user_sql}\n\t\t\t\t\t\t\t\t\t\t"; break; case 'modified': $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\tSELECT ccl.logged_row_id, 1\n\t\t\t\t\t\t\t\t\t\t\tFROM ca_change_log ccl\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(ccl.log_datetime BETWEEN " . (int) $va_range['start'] . " AND " . (int) $va_range['end'] . ")\n\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(ccl.logged_table_num = ?)\n\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(ccl.changetype = 'U')\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_user_sql}\n\t\t\t\t\t\t\t\t\t\tUNION\n\t\t\t\t\t\t\t\t\t\t\tSELECT ccls.subject_row_id, 1\n\t\t\t\t\t\t\t\t\t\t\tFROM ca_change_log ccl\n\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_change_log_subjects AS ccls ON ccls.log_id = ccl.log_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(ccl.log_datetime BETWEEN " . (int) $va_range['start'] . " AND " . (int) $va_range['end'] . ")\n\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(ccls.subject_table_num = {$pn_subject_tablenum})\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_user_sql}\n\t\t\t\t\t\t\t\t\t\t"; break; } } else { if ($vs_table && $vs_field) { $t_table = $this->opo_datamodel->getInstanceByTableName($vs_table, true); if ($t_table) { $vs_table_num = $t_table->tableNum(); if (is_numeric($vs_field)) { $vs_fld_num = 'I' . $vs_field; $vn_fld_num = (int) $vs_field; } else { $vn_fld_num = $this->getFieldNum($vs_table, $vs_field); $vs_fld_num = 'I' . $vn_fld_num; if (!strlen($vn_fld_num)) { $t_element = new ca_metadata_elements(); if ($t_element->load(array('element_code' => $vs_sub_field ? $vs_sub_field : $vs_field))) { $vn_fld_num = $t_element->getPrimaryKey(); $vs_fld_num = 'A' . $vn_fld_num; if (!$vb_is_blank_search) { // // For certain types of attributes we can directly query the // attributes in the database rather than using the full text index // This allows us to do "intelligent" querying... for example on date ranges // parsed from natural language input and for length dimensions using unit conversion // switch ($t_element->get('datatype')) { case 2: // dates $vb_all_numbers = true; foreach ($va_raw_terms as $vs_term) { if (!is_numeric($vs_term)) { $vb_all_numbers = false; break; } } $vs_raw_term = join(' ', $va_raw_terms); $vb_exact = $vs_raw_term[0] == "#" ? true : false; // dates prepended by "#" are considered "exact" or "contained - the matched dates must be wholly contained by the search term if ($vb_exact) { $vs_raw_term = substr($vs_raw_term, 1); if ($this->opo_tep->parse($vs_raw_term)) { $va_dates = $this->opo_tep->getHistoricTimestamps(); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\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\t\t\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\t\t\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\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\n\t\t\t\t\t\t\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\t\t\t\t\t\t(cav.value_decimal2 BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\n\t\t\t\t\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\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; } } else { if ($this->opo_tep->parse($vs_raw_term)) { $va_dates = $this->opo_tep->getHistoricTimestamps(); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\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\t\t\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\t\t\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\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\n\t\t\t\t\t\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\t\t\t\t\t(cav.value_decimal2 BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\n\t\t\t\t\t\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\t\t\t\t\t(cav.value_decimal1 <= " . floatval($va_dates['start']) . " AND cav.value_decimal2 >= " . floatval($va_dates['end']) . ")\t\n\t\t\t\t\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\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; } } break; case 4: // geocode $t_geocode = new GeocodeAttributeValue(); // If it looks like a lat/long pair that has been tokenized by Lucene // into oblivion rehydrate it here. if ($va_coords = caParseGISSearch(join(' ', $va_raw_terms))) { $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\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\t\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\t\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\t\t\t\t(cav.value_decimal1 BETWEEN {$va_coords['min_latitude']} AND {$va_coords['max_latitude']})\n\t\t\t\t\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\t\t\t\t(cav.value_decimal2 BETWEEN {$va_coords['min_longitude']} AND {$va_coords['max_longitude']})\n\t\t\t\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"; } break; case 6: // currency $t_cur = new CurrencyAttributeValue(); $va_parsed_value = $t_cur->parseValue(join(' ', $va_raw_terms), $t_element->getFieldValuesArray()); $vn_amount = $va_parsed_value['value_decimal1']; $vs_currency = preg_replace('![^A-Z0-9]+!', '', $va_parsed_value['value_longtext1']); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\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\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\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\t\t\t(cav.value_decimal1 = " . floatval($vn_amount) . ")\n\t\t\t\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\t\t\t(cav.value_longtext1 = '" . $this->opo_db->escape($vs_currency) . "')\n\t\t\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"; break; case 8: // length $t_len = new LengthAttributeValue(); $va_parsed_value = $t_len->parseValue(array_shift($va_raw_terms), $t_element->getFieldValuesArray()); $vn_len = $va_parsed_value['value_decimal1']; // this is always in meters so we can compare this value to the one in the database $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\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\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\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\t\t\t(cav.value_decimal1 = " . floatval($vn_len) . ")\n\t\t\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"; break; case 9: // weight $t_weight = new WeightAttributeValue(); $va_parsed_value = $t_weight->parseValue(array_shift($va_raw_terms), $t_element->getFieldValuesArray()); $vn_weight = $va_parsed_value['value_decimal1']; // this is always in kilograms so we can compare this value to the one in the database $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\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\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\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\t\t\t(cav.value_decimal1 = " . floatval($vn_weight) . ")\n\t\t\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"; break; case 10: // timecode $t_timecode = new TimecodeAttributeValue(); $va_parsed_value = $t_timecode->parseValue(join(' ', $va_raw_terms), $t_element->getFieldValuesArray()); $vn_timecode = $va_parsed_value['value_decimal1']; $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\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\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\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\t\t\t(cav.value_decimal1 = " . floatval($vn_timecode) . ")\n\t\t\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"; break; case 11: // integer $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\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\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\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\t\t\t(cav.value_integer1 = " . intval(array_shift($va_raw_terms)) . ")\n\t\t\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"; break; case 12: // decimal $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\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\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\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\t\t\t(cav.value_decimal1 = " . floatval(array_shift($va_raw_terms)) . ")\n\t\t\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"; break; } } } else { // neither table fields nor elements, i.e. 'virtual' fields like _count should $vn_fld_num = false; $vs_fld_num = $vs_field; } } } if ($t_table->getFieldInfo($t_table->fieldName($vn_fld_num), 'FIELD_TYPE') == FT_BIT) { $vb_ft_bit_optimization = true; } } } } } // // If we're querying on the fulltext index then we need to construct // the query here... if we already have a direct SQL query to run then we can skip this // if ($vb_is_blank_search) { $va_sql_where[] = "((swi.field_table_num = " . intval($vs_table_num) . ") AND (swi.field_num = '{$vs_fld_num}') AND (swi.word_id = 0))"; if (!sizeof($va_sql_where)) { continue; } $vs_sql_where = join(' OR ', $va_sql_where); } elseif (!$vs_direct_sql_query) { $va_sql_where = array(); if (sizeof($va_ft_terms)) { if ($t_table && strlen($vs_fld_num) > 1) { $va_sql_where[] = "((swi.field_table_num = " . intval($vs_table_num) . ") AND (swi.field_num = '{$vs_fld_num}') AND (sw.word IN (" . join(',', $va_ft_terms) . ")))"; } else { if (sizeof($va_ft_terms) == 1) { $va_sql_where[] = "(sw.word = " . $va_ft_terms[0] . ")"; } else { $va_sql_where[] = "(sw.word IN (" . join(',', $va_ft_terms) . "))"; } } } if (sizeof($va_ft_like_terms)) { $va_tmp = array(); foreach ($va_ft_like_terms as $vs_term) { if ($vb_ft_bit_optimization) { $va_tmp[] = '(sw.word = \' ' . $this->opo_db->escape(trim($vs_term)) . ' \')'; } else { $va_tmp[] = '(sw.word LIKE \'' . $this->opo_db->escape(trim($vs_term)) . '%\')'; } } if ($t_table && strlen($vs_fld_num) > 1) { $va_sql_where[] = "((swi.field_table_num = " . intval($vs_table_num) . ") AND (swi.field_num = '{$vs_fld_num}') AND (" . join(' AND ', $va_tmp) . "))"; } else { $va_sql_where[] = "(" . join(' AND ', $va_tmp) . ")"; } } if (sizeof($va_ft_stem_terms)) { if ($t_table && strlen($vs_fld_num) > 1) { $va_sql_where[] = "((swi.field_table_num = " . intval($vs_table_num) . ") AND (swi.field_num = '{$vs_fld_num}') AND (sw.stem IN (" . join(',', $va_ft_stem_terms) . ")))"; } else { $va_sql_where[] = "(sw.stem IN (" . join(',', $va_ft_stem_terms) . "))"; } } if (!sizeof($va_sql_where)) { continue; } $vs_sql_where = join(' OR ', $va_sql_where); } else { $va_ft_terms = $va_ft_like_terms = $va_ft_like_terms = array(); } //print "OP=$vs_op<br>"; if ($vn_i == 0) { if ($vs_direct_sql_query) { $vs_direct_sql_query = str_replace('^JOIN', "", $vs_direct_sql_query); } $vs_sql = $vs_direct_sql_query ? "INSERT IGNORE INTO {$ps_dest_table} {$vs_direct_sql_query}" : "\n\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}\n\t\t\t\t\t\t\tSELECT swi.row_id, SUM(swi.boost)\n\t\t\t\t\t\t\tFROM ca_sql_search_word_index swi\n\t\t\t\t\t\t\t" . (!$vb_is_blank_search ? "INNER JOIN ca_sql_search_words AS sw ON sw.word_id = swi.word_id" : '') . "\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\tswi.table_num = ?\n\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : '') . "\n\t\t\t\t\t\t\tGROUP BY swi.row_id \n\t\t\t\t\t\t"; if (($vn_num_terms = sizeof($va_ft_terms) + sizeof($va_ft_like_terms) + sizeof($va_ft_stem_terms)) > 1 && !$vs_direct_sql_query) { $vs_sql .= " HAVING count(distinct sw.word_id) = {$vn_num_terms}"; } if ($this->debug) { print 'FIRST: ' . $vs_sql . " [{$pn_subject_tablenum}]<hr>\n"; } //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql, is_array($pa_direct_sql_query_params) ? $pa_direct_sql_query_params : array((int) $pn_subject_tablenum)); } else { switch ($vs_op) { case 'AND': if ($vs_direct_sql_query) { $vs_direct_sql_query = str_replace('^JOIN', "INNER JOIN {$ps_dest_table} AS ftmp1 ON ftmp1.row_id = ca.row_id", $vs_direct_sql_query); } $this->_createTempTable($ps_dest_table . '_acc'); $vs_sql = $vs_direct_sql_query ? "INSERT IGNORE INTO {$ps_dest_table}_acc {$vs_direct_sql_query}" : "\n\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}_acc\n\t\t\t\t\t\t\t\t\tSELECT swi.row_id, SUM(swi.boost)\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_word_index swi\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_words AS sw ON sw.word_id = swi.word_id\n\t\t\t\t\t\t\t\t\tINNER JOIN {$ps_dest_table} AS ftmp1 ON ftmp1.row_id = swi.row_id\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\tswi.table_num = ?\n\t\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : '') . "\n\t\t\t\t\t\t\t\t\tGROUP BY\n\t\t\t\t\t\t\t\t\t\tswi.row_id\n\t\t\t\t\t\t\t\t"; if (($vn_num_terms = sizeof($va_ft_terms) + sizeof($va_ft_like_terms) + sizeof($va_ft_stem_terms)) > 1) { $vs_sql .= " HAVING count(distinct sw.word_id) = {$vn_num_terms}"; } if ($this->debug) { print 'AND:' . $vs_sql . "<hr>\n"; } $qr_res = $this->opo_db->query($vs_sql, is_array($pa_direct_sql_query_params) ? $pa_direct_sql_query_params : array((int) $pn_subject_tablenum)); $qr_res = $this->opo_db->query("TRUNCATE TABLE {$ps_dest_table}"); $qr_res = $this->opo_db->query("INSERT INTO {$ps_dest_table} SELECT row_id, boost FROM {$ps_dest_table}_acc"); //$qr_res = $this->opo_db->query("TRUNCATE TABLE ca_sql_search_temp_2"); $this->_dropTempTable($ps_dest_table . '_acc'); break; case 'NOT': if ($vs_direct_sql_query) { $vs_direct_sql_query = str_replace('^JOIN', "", $vs_direct_sql_query); } $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT row_id\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_words sw\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_word_index AS swi ON sw.word_id = swi.word_id\n\t\t\t\t\t\t\t\t\tWHERE \n\t\t\t\t\t\t\t\t\t\t" . ($vs_sql_where ? "{$vs_sql_where} AND " : "") . " swi.table_num = ? \n\t\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : ''); //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql, is_array($pa_direct_sql_query_params) ? $pa_direct_sql_query_params : array((int) $pn_subject_tablenum)); $va_ids = $qr_res->getAllFieldValues("row_id"); $vs_sql = "\n\t\t\t\t\t\t\t\t\tDELETE FROM {$ps_dest_table} \n\t\t\t\t\t\t\t\t\tWHERE \n\t\t\t\t\t\t\t\t\t\trow_id IN (?)\n\t\t\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql, array($va_ids)); //print "$vs_sql<hr>"; break; default: case 'OR': if ($vs_direct_sql_query) { $vs_direct_sql_query = str_replace('^JOIN', "", $vs_direct_sql_query); } $vs_sql = $vs_direct_sql_query ? "INSERT IGNORE INTO {$ps_dest_table} {$vs_direct_sql_query}" : "\n\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}\n\t\t\t\t\t\t\t\t\tSELECT swi.row_id, SUM(swi.boost)\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_word_index swi\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_words AS sw ON sw.word_id = swi.word_id\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\tswi.table_num = ?\n\t\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : '') . "\n\t\t\t\t\t\t\t\t\tGROUP BY\n\t\t\t\t\t\t\t\t\t\tswi.row_id\n\t\t\t\t\t\t\t\t"; if ($this->debug) { print 'OR' . $vs_sql . "<hr>\n"; } $qr_res = $this->opo_db->query($vs_sql, is_array($pa_direct_sql_query_params) ? $pa_direct_sql_query_params : array((int) $pn_subject_tablenum)); break; } } // Drop any temporary tables created by direct search queries foreach (array_keys($va_direct_query_temp_tables) as $vs_temp_table_to_drop) { $this->_dropTempTable($vs_temp_table_to_drop); } break; default: //print get_class($o_lucene_query_element); break; } $vn_i++; } }
/** * Given a item_id (request parameter 'id') returns a list of ancestors for use in the hierarchy browser * Returned data is JSON format */ public function getFacetHierarchyAncestorList() { $pn_id = $this->request->getParameter('id', pInteger); $va_access_values = caGetUserAccessValues($this->request); $ps_facet_name = $this->request->getParameter('facet', pString); $this->view->setVar("facet_name", $ps_facet_name); $this->view->setVar("key", $this->request->getParameter('key', pString)); $ps_browse_type = $this->request->getParameter('browseType', pString); if (!($va_browse_info = caGetInfoForBrowseType($ps_browse_type))) { // invalid browse type – throw error die("Invalid browse type"); } $this->view->setVar("browse_type", $ps_browse_type); $vs_class = $va_browse_info['table']; $o_browse = caGetBrowseInstance($vs_class); if (!is_array($va_facet_info = $o_browse->getInfoForFacet($ps_facet_name))) { return null; } if ($ps_cache_key = $this->request->getParameter('key', pString)) { $o_browse->reload($ps_cache_key); } $va_ancestors = array(); switch ($va_facet_info['type']) { case 'attribute': // is it a list attribute? $t_element = new ca_metadata_elements(); if ($t_element->load(array('element_code' => $va_facet_info['element_code']))) { if ($t_element->get('datatype') == 3) { // 3=list if (!$pn_id) { $t_list = new ca_lists(); $pn_id = $t_list->getRootListItemID($t_element->get('list_id')); } $t_item = new ca_list_items($pn_id); if ($t_item->getPrimaryKey()) { $vs_primary_key = $t_item->primaryKey(); $this->view->setVar("primary_key", $vs_primary_key); $vs_display_fld = $t_item->getLabelDisplayField(); $this->view->setVar("display_field", $vs_display_fld); $vs_label_table_name = $t_item->getLabelTableName(); $va_ancestors = array_reverse($t_item->getHierarchyAncestors(null, array('includeSelf' => true, 'additionalTableToJoin' => $vs_label_table_name, 'additionalTableJoinType' => 'LEFT', 'additionalTableSelectFields' => array($vs_display_fld, 'locale_id'), 'additionalTableWheres' => array('(' . $vs_label_table_name . '.is_preferred = 1 OR ' . $vs_label_table_name . '.is_preferred IS NULL)')))); array_shift($va_ancestors); } } } break; case 'label': // label facet $va_facet_info['table'] = $this->ops_tablename; // fall through to default case // fall through to default case default: $t_item = $this->request->datamodel->getInstanceByTableName($va_facet_info['table']); $t_item->load($pn_id); if (method_exists($t_item, "getHierarchyList")) { $va_access_values = caGetUserAccessValues($this->request); $va_facet = $o_browse->getFacet($ps_facet_name, array('sort' => 'name', 'checkAccess' => $va_access_values)); $va_hierarchy_list = $t_item->getHierarchyList(true); $vn_hierarchies_in_use = 0; foreach ($va_hierarchy_list as $vn_i => $va_item) { if (isset($va_facet[$va_item[$t_item->primaryKey()]])) { $vn_hierarchies_in_use++; if ($vn_hierarchies_in_use > 1) { break; } } } } if ($t_item->getPrimaryKey()) { $vs_primary_key = $t_item->primaryKey(); $this->view->setVar("primary_key", $vs_primary_key); $vs_display_fld = $t_item->getLabelDisplayField(); $this->view->setVar("display_field", $vs_display_fld); $vs_label_table_name = $t_item->getLabelTableName(); $va_ancestors = array_reverse($t_item->getHierarchyAncestors(null, array('includeSelf' => true, 'additionalTableToJoin' => $vs_label_table_name, 'additionalTableJoinType' => 'LEFT', 'additionalTableSelectFields' => array($vs_display_fld, 'locale_id'), 'additionalTableWheres' => array('(' . $vs_label_table_name . '.is_preferred = 1 OR ' . $vs_label_table_name . '.is_preferred IS NULL)')))); } if ($vn_hierarchies_in_use <= 1) { array_shift($va_ancestors); } break; } $this->view->setVar('ancestors', $va_ancestors); switch ($this->request->getParameter('returnAs', pString)) { case "json": return $this->render('Browse/facet_hierarchy_ancestors_json.php'); break; # ------------------------------------------------ # ------------------------------------------------ case "html": default: return $this->render('Browse/facet_hierarchy_ancestors_html.php'); break; # ------------------------------------------------ } }
/** * */ public function sortHits(&$pa_hits, $ps_table, $ps_field, $ps_key, $ps_direction = 'asc', $pa_options = null) { //$t= new Timer(); $vs_browse_tmp_table = $this->loadListIntoTemporaryResultTable($pa_hits, $ps_key); if (!in_array(strtolower($ps_direction), array('asc', 'desc'))) { $ps_direction = 'asc'; } if (!is_array($pa_hits) || !sizeof($pa_hits)) { return $pa_hits; } $t_table = $this->opo_datamodel->getInstanceByTableName($ps_table, true); $vs_table_pk = $t_table->primaryKey(); $vn_table_num = $t_table->tableNum(); $va_sort_tmp = explode('/', $ps_field); $ps_field = $va_sort_tmp[0]; $vs_rel_type = sizeof($va_sort_tmp) > 1 ? $va_sort_tmp[1] : null; $va_fields = explode(';', $ps_field); $va_sorted_hits = array(); $va_joins = array(); $vs_locale_where = $vs_is_preferred_sql = ''; $vs_primary_sort_field = array_shift($va_fields); $va_primary_sort_field = explode('.', $vs_primary_sort_field); $va_additional_sort_fields = array(); foreach ($va_fields as $vs_additional_sort_field) { $va_tmp = explode('.', $vs_additional_sort_field); if ($va_tmp[0] == $va_primary_sort_field[0]) { $va_additional_sort_fields[] = $va_tmp; } } if ($va_primary_sort_field[0] == $ps_table) { // // sort field is in search table // if (!$t_table->hasField($va_primary_sort_field[1])) { // // is it an attribute? // $t_element = new ca_metadata_elements(); $vs_sort_element_code = array_pop($va_primary_sort_field); if ($t_element->load(array('element_code' => $vs_sort_element_code))) { $vn_element_id = $t_element->getPrimaryKey(); if (!($vs_sortable_value_fld = Attribute::getSortFieldForDatatype($t_element->get('datatype')))) { return $pa_hits; } if ((int) $t_element->get('datatype') == __CA_ATTRIBUTE_VALUE_LIST__) { $vs_sortable_value_fld = 'lil.name_plural'; $vs_sort_field = array_pop(explode('.', $vs_sortable_value_fld)); $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT attr.row_id, lil.locale_id, lower({$vs_sortable_value_fld}) {$vs_sort_field}\n\t\t\t\t\t\t\t\tFROM ca_attributes attr\n\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values AS attr_vals ON attr_vals.attribute_id = attr.attribute_id\n\t\t\t\t\t\t\t\tINNER JOIN ca_list_item_labels AS lil ON lil.item_id = attr_vals.item_id\n\t\t\t\t\t\t\t\tINNER JOIN {$vs_browse_tmp_table} ON {$vs_browse_tmp_table}.row_id = attr.row_id\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t(attr_vals.element_id = ?) AND (attr.table_num = ?) AND (lil.{$vs_sort_field} IS NOT NULL)\n\t\t\t\t\t\t\t\tORDER BY lil.{$vs_sort_field} {$ps_direction}\n\t\t\t\t\t\t\t"; } elseif ((int) $t_element->get('datatype') == __CA_ATTRIBUTE_VALUE_DATERANGE__) { $vs_sortable_value_fld = 'attr_vals.' . $vs_sortable_value_fld; $vs_sort_field = array_pop(explode('.', $vs_sortable_value_fld)); $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT attr.row_id, attr.locale_id, {$vs_sortable_value_fld}\n\t\t\t\t\t\t\t\tFROM ca_attributes attr\n\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values AS attr_vals ON attr_vals.attribute_id = attr.attribute_id\n\t\t\t\t\t\t\t\tINNER JOIN {$vs_browse_tmp_table} ON {$vs_browse_tmp_table}.row_id = attr.row_id\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t(attr_vals.element_id = ?) AND (attr.table_num = ?) AND (attr_vals.{$vs_sort_field} IS NOT NULL)\n\t\t\t\t\t\t\t\tORDER BY attr_vals.{$vs_sort_field} {$ps_direction}, attr.row_id\n\t\t\t\t\t\t\t"; } else { $vs_sortable_value_fld = 'attr_vals.' . $vs_sortable_value_fld; $vs_sort_field = array_pop(explode('.', $vs_sortable_value_fld)); $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT attr.row_id, attr.locale_id, lower({$vs_sortable_value_fld}) {$vs_sort_field}\n\t\t\t\t\t\t\t\tFROM ca_attributes attr\n\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values AS attr_vals ON attr_vals.attribute_id = attr.attribute_id\n\t\t\t\t\t\t\t\tINNER JOIN {$vs_browse_tmp_table} ON {$vs_browse_tmp_table}.row_id = attr.row_id\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t(attr_vals.element_id = ?) AND (attr.table_num = ?) AND (attr_vals.{$vs_sort_field} IS NOT NULL)\n\t\t\t\t\t\t\t\tORDER BY attr_vals.{$vs_sort_field} {$ps_direction}, attr.row_id\n\t\t\t\t\t\t\t"; } $qr_sort = $this->opo_db->query($vs_sql, (int) $vn_element_id, (int) $vn_table_num); $va_sorted_hits = $qr_sort->getAllFieldValues('row_id'); // Add on hits that aren't sorted because they don't have an attribute associated $va_missing_items = array_diff($pa_hits, $va_sorted_hits); $va_sorted_hits = array_merge($va_sorted_hits, $va_missing_items); } return $va_sorted_hits; } else { $va_field_info = $t_table->getFieldInfo($va_primary_sort_field[1]); if ($va_field_info['START'] && $va_field_info['END']) { $vs_sortable_value_fld = $vs_primary_sort_field; $va_additional_sort_fields[] = $va_field_info['END']; } else { $vs_sortable_value_fld = $vs_primary_sort_field; } } } else { // sort field is in related table $va_path = $this->opo_datamodel->getPath($ps_table, $va_primary_sort_field[0]); if (sizeof($va_path) > 2) { // many-many $vs_last_table = null; // generate related joins foreach ($va_path as $vs_table => $va_info) { $t_table = $this->opo_datamodel->getInstanceByTableName($vs_table, true); $vs_rel_type_sql = null; if ($t_table->isRelationship() && $vs_rel_type) { if (is_array($va_rel_types = caMakeRelationshipTypeIDList($vs_table, array($vs_rel_type))) && sizeof($va_rel_types)) { $vs_rel_type_sql = " AND {$vs_table}.type_id IN (" . join(",", $va_rel_types) . ")"; } } if ($vs_last_table) { $va_rels = $this->opo_datamodel->getOneToManyRelations($vs_last_table, $vs_table); if (!sizeof($va_rels)) { $va_rels = $this->opo_datamodel->getOneToManyRelations($vs_table, $vs_last_table); } if ($vs_table == $va_rels['one_table']) { $va_joins[$vs_table] = "INNER JOIN " . $va_rels['one_table'] . " ON " . $va_rels['one_table'] . "." . $va_rels['one_table_field'] . " = " . $va_rels['many_table'] . "." . $va_rels['many_table_field'] . $vs_rel_type_sql; } else { $va_joins[$vs_table] = "INNER JOIN " . $va_rels['many_table'] . " ON " . $va_rels['many_table'] . "." . $va_rels['many_table_field'] . " = " . $va_rels['one_table'] . "." . $va_rels['one_table_field'] . $vs_rel_type_sql; } } $t_last_table = $t_table; $vs_last_table = $vs_table; } $vs_sortable_value_fld = $vs_primary_sort_field; } else { $va_rels = $this->opo_datamodel->getRelationships($ps_table, $va_primary_sort_field[0]); if (!$va_rels) { return $pa_hits; } // return hits unsorted if field is not valid $t_rel = $this->opo_datamodel->getInstanceByTableName($va_primary_sort_field[0], true); if (!$t_rel->hasField($va_primary_sort_field[1])) { return $pa_hits; } $va_joins[$va_primary_sort_field[0]] = 'LEFT JOIN ' . $va_primary_sort_field[0] . ' ON ' . $ps_table . '.' . $va_rels[$ps_table][$va_primary_sort_field[0]][0][0] . ' = ' . $va_primary_sort_field[0] . '.' . $va_rels[$ps_table][$va_primary_sort_field[0]][0][1] . "\n"; // if the related supports preferred values (eg. *_labels tables) then only consider those in the sort if ($t_rel->hasField('is_preferred')) { $vs_is_preferred_sql = " " . $va_primary_sort_field[0] . ".is_preferred = 1"; } $vs_sortable_value_fld = $vs_primary_sort_field; } } // // Grab values and index for sorting later // //Debug::msg("sort pre query ".$t->getTime(4)); $va_primary_sort_field = explode('.', $vs_sortable_value_fld); $vs_join_sql = join("\n", $va_joins); $va_sort_fields = array("{$vs_sortable_value_fld} {$ps_direction}"); foreach ($va_additional_sort_fields as $va_additional_sort_field) { $va_sort_fields[] = "{$va_additional_sort_field[0]}.{$va_additional_sort_field[1]} {$ps_direction}"; } $vs_sql = "\n\t\t\t\tSELECT {$ps_table}.{$vs_table_pk}\n\t\t\t\tFROM {$ps_table}\n\t\t\t\t{$vs_join_sql}\n\t\t\t\tINNER JOIN {$vs_browse_tmp_table} ON {$vs_browse_tmp_table}.row_id = {$ps_table}.{$vs_table_pk}\n\t\t\t\t" . ($vs_is_preferred_sql ? 'WHERE' : '') . "\n\t\t\t\t\t{$vs_is_preferred_sql}\n\t\t\t\tORDER BY " . join(',', $va_sort_fields) . ", {$ps_table}.{$vs_table_pk}\n\t\t\t"; $qr_sort = $this->opo_db->query($vs_sql); $va_sorted_hits = $qr_sort->getAllFieldValues($vs_table_pk); return $va_sorted_hits; }
/** * Fetch details on an item from a remote data source and output results of the 'display' key in the response. * */ public function GetDetail() { $pn_element_id = $this->request->getParameter('element_id', pInteger); $t_element = new ca_metadata_elements($pn_element_id); $va_data = array(); if (!$t_element->getPrimaryKey()) { // error $va_items['error'] = array('label' => _t('ERROR: Invalid element_id'), 'idno' => ''); } else { $vs_service = $t_element->getSetting('service'); $va_settings = $t_element->getSettings(); $pn_attribute_id = $this->request->getParameter('id', pInteger); $t_attr_val = new ca_attribute_values(); if ($t_attr_val->load(array('attribute_id' => $pn_attribute_id, 'element_id' => $pn_element_id))) { $t_attr = new ca_attributes(); if ($t_attr->load($pn_attribute_id)) { if (!caCanRead($this->request->getUserID(), $t_attr->get('table_num'), $t_attr->get('row_id'), $t_element->get('element_code'))) { $va_items['error'] = array('label' => _t('ERROR: You do not have access to this item'), 'idno' => ''); } else { $vs_url = $t_attr_val->get('value_longtext2'); if (!($o_plugin = InformationServiceManager::getInformationServiceInstance($vs_service))) { $va_items['error'] = array('label' => _t('ERROR: Invalid service'), 'idno' => ''); } else { $vs_cache_key = md5(print_r($va_settings, true) . $vs_url); if (CompositeCache::contains($vs_cache_key, 'InformationServiceExtendedInfo')) { $va_data = CompositeCache::fetch($vs_cache_key, 'InformationServiceExtendedInfo'); } else { $va_data = $o_plugin->getExtendedInformation($va_settings, $vs_url); CompositeCache::save($vs_cache_key, $va_data, 'InformationServiceExtendedInfo'); } } } } } } $this->view->setVar('detail', $va_data); return $this->render('ajax_information_service_detail_html.php'); }
/** * Initiates user download of media stored in a media attribute, returning file in response to request. * Adds download output to response directly. No view is used. * * @param array $pa_options Array of options passed through to _initView */ public function DownloadAttributeMedia($pa_options = null) { if (!($pn_value_id = $this->request->getParameter('value_id', pInteger))) { return; } $t_attr_val = new ca_attribute_values($pn_value_id); if (!$t_attr_val->getPrimaryKey()) { return; } $t_attr = new ca_attributes($t_attr_val->get('attribute_id')); $vn_table_num = $this->opo_datamodel->getTableNum($this->ops_table_name); if ($t_attr->get('table_num') != $vn_table_num) { $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2580?r=' . urlencode($this->request->getFullUrlPath())); return; } $t_element = new ca_metadata_elements($t_attr->get('element_id')); $this->request->setParameter($this->opo_datamodel->getTablePrimaryKeyName($vn_table_num), $t_attr->get('row_id')); list($vn_subject_id, $t_subject) = $this->_initView($pa_options); $ps_version = $this->request->getParameter('version', pString); if (!$this->_checkAccess($t_subject)) { return false; } // // Does user have access to bundle? // if ($this->request->user->getBundleAccessLevel($this->ops_table_name, $t_element->get('element_code')) < __CA_BUNDLE_ACCESS_READONLY__) { $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2580?r=' . urlencode($this->request->getFullUrlPath())); return; } $t_attr_val->useBlobAsMediaField(true); if (!in_array($ps_version, $t_attr_val->getMediaVersions('value_blob'))) { $ps_version = 'original'; } $o_view = new View($this->request, $this->request->getViewsDirectoryPath() . '/bundles/'); // get value $t_element = new ca_metadata_elements($t_attr_val->get('element_id')); // check that value is a media attribute if ($t_element->get('datatype') != 16) { // 16=media return; } $vs_path = $t_attr_val->getMediaPath('value_blob', $ps_version); $vs_path_ext = pathinfo($vs_path, PATHINFO_EXTENSION); if ($vs_name = trim($t_attr_val->get('value_longtext2'))) { $vs_file_name = pathinfo($vs_name, PATHINFO_FILENAME); $vs_name = "{$vs_file_name}.{$vs_path_ext}"; } else { $vs_name = _t("downloaded_file.%1", $vs_path_ext); } $o_view->setVar('file_path', $vs_path); $o_view->setVar('file_name', $vs_name); // send download $this->response->addContent($o_view->render('ca_attributes_download_media.php')); }
/** * */ public static function getInstance($pm_element_code_or_id) { if (isset(ca_metadata_elements::$s_element_instance_cache[$pm_element_code_or_id])) { return ca_metadata_elements::$s_element_instance_cache[$pm_element_code_or_id]; } $t_element = new ca_metadata_elements(is_numeric($pm_element_code_or_id) ? $pm_element_code_or_id : null); if (!($vn_element_id = $t_element->getPrimaryKey())) { if ($t_element->load(array('element_code' => $pm_element_code_or_id))) { return ca_metadata_elements::$s_element_instance_cache[$t_element->getPrimaryKey()] = ca_metadata_elements::$s_element_instance_cache[$t_element->get('element_code')] = $t_element; } } else { return ca_metadata_elements::$s_element_instance_cache[$vn_element_id] = ca_metadata_elements::$s_element_instance_cache[$t_element->get('element_code')] = $t_element; } return null; }
/** * Returns array of with information about usage of metadata element(s) in user interfaces * * @param $pm_element_code_or_id mixed Optional element_id or code. If set then counts are only returned for the specified element. If omitted then counts are returned for all elements. * @return array Array of counts. Keys are element_codes, values are arrays keyed on table DISPLAY name (eg. "set items", not "ca_set_items"). Values are the number of times the element is references in a user interface for the table. */ public static function getUIUsageCounts($pm_element_code_or_id = null) { // Get UI usage counts $vo_db = new Db(); $vn_element_id = null; if ($pm_element_code_or_id) { $t_element = new ca_metadata_elements($pm_element_code_or_id); if (!($vn_element_id = $t_element->getPrimaryKey())) { if ($t_element->load(array('element_code' => $pm_element_code_or_id))) { $vn_element_id = $t_element->getPrimaryKey(); } } } $vs_sql_where = ''; if ($vn_element_id) { $vs_sql_where = " WHERE p.bundle_name = 'ca_attribute_" . $t_element->get('element_code') . "'"; } $qr_use_counts = $vo_db->query("\n\t\t\tSELECT count(*) c, p.bundle_name, u.editor_type \n\t\t\tFROM ca_editor_ui_bundle_placements p \n\t\t\tINNER JOIN ca_editor_ui_screens AS s ON s.screen_id = p.screen_id \n\t\t\tINNER JOIN ca_editor_uis AS u ON u.ui_id = s.ui_id \n\t\t\t{$vs_sql_where}\n\t\t\tGROUP BY \n\t\t\t\tp.bundle_name, u.editor_type\n\t\t"); $va_counts_by_attribute = array(); $o_dm = Datamodel::load(); while ($qr_use_counts->nextRow()) { if (preg_match('!^ca_attribute_([A-Za-z0-9_\\-]+)$!', $qr_use_counts->get('bundle_name'), $va_matches)) { if (!($t_table = $o_dm->getInstanceByTableNum($qr_use_counts->get('editor_type'), true))) { continue; } $va_counts_by_attribute[$va_matches[1]][$t_table->getProperty('NAME_PLURAL')] = $qr_use_counts->get('c'); } } return $va_counts_by_attribute; }
/** * Given a item_id (request parameter 'id') returns a list of ancestors for use in the hierarchy browser * Returned data is JSON format */ public function getFacetHierarchyAncestorList() { $pn_id = $this->request->getParameter('id', pInteger); $ps_facet_name = $this->request->getParameter('facet', pString); if (!is_array($va_facet_info = $this->opo_browse->getInfoForFacet($ps_facet_name))) { return null; } $va_ancestors = array(); switch ($va_facet_info['type']) { case 'attribute': // is it a list attribute? $t_element = new ca_metadata_elements(); if ($t_element->load(array('element_code' => $va_facet_info['element_code']))) { if ($t_element->get('datatype') == 3) { // 3=list if (!$pn_id) { $t_list = new ca_lists(); $pn_id = $t_list->getRootListItemID($t_element->get('list_id')); } $t_item = new ca_list_items($pn_id); if ($t_item->getPrimaryKey()) { $va_ancestors = array_reverse($t_item->getHierarchyAncestors(null, array('includeSelf' => true, 'idsOnly' => true))); array_shift($va_ancestors); } } } break; case 'label': // label facet $va_facet_info['table'] = $this->ops_tablename; // fall through to default case // fall through to default case default: $t_item = $this->opo_datamodel->getInstanceByTableName($va_facet_info['table']); $t_item->load($pn_id); if (method_exists($t_item, "getHierarchyList")) { $va_access_values = caGetUserAccessValues($this->request); $va_facet = $this->opo_browse->getFacet($ps_facet_name, array('sort' => 'name', 'checkAccess' => $va_access_values)); $va_hierarchy_list = $t_item->getHierarchyList(true); $vn_hierarchies_in_use = 0; foreach ($va_hierarchy_list as $vn_i => $va_item) { if (isset($va_facet[$va_item[$t_item->primaryKey()]])) { $vn_hierarchies_in_use++; if ($vn_hierarchies_in_use > 1) { break; } } } } if ($t_item->getPrimaryKey()) { $va_ancestors = array_reverse($t_item->getHierarchyAncestors(null, array('includeSelf' => true, 'idsOnly' => true))); if (!is_array($va_ancestors)) { $va_ancestors = array(); } } if ($vn_hierarchies_in_use <= 1) { array_shift($va_ancestors); } break; } $this->view->setVar('ancestors', $va_ancestors); return $this->render('Browse/facet_hierarchy_ancestors_json.php'); }
/** * Return list of items from the specified table that are related to the current browse set. This is the method that actually * pulls the facet content, regardless of whether the facet is cached yet or not. If you want to use the facet cache, call * BrowseEngine::getFacet() * * @see BrowseEngine::getFacet() * Options: * checkAccess = array of access values to filter facets that have an 'access' field by * checkAvailabilityOnly = if true then content is not actually fetch - only the availablility of content is verified * user_id = If set item level access control is performed relative to specified user_id, otherwise defaults to logged in user */ public function getFacetContent($ps_facet_name, $pa_options = null) { global $AUTH_CURRENT_USER_ID; $vs_browse_table_name = $this->ops_browse_table_name; $vs_browse_table_num = $this->opn_browse_table_num; $vn_user_id = isset($pa_options['user_id']) && (int) $pa_options['user_id'] ? (int) $pa_options['user_id'] : (int) $AUTH_CURRENT_USER_ID; $vb_show_if_no_acl = (bool) ($this->opo_config->get('default_item_access_level') > __CA_ACL_NO_ACCESS__); $t_user = new ca_users($vn_user_id); if (is_array($va_groups = $t_user->getUserGroups()) && sizeof($va_groups)) { $va_group_ids = array_keys($va_groups); } else { $va_group_ids = array(); } if (!is_array($this->opa_browse_settings)) { return null; } if (!isset($this->opa_browse_settings['facets'][$ps_facet_name])) { return null; } if (!is_array($pa_options)) { $pa_options = array(); } $vb_check_availability_only = isset($pa_options['checkAvailabilityOnly']) ? (bool) $pa_options['checkAvailabilityOnly'] : false; $va_all_criteria = $this->getCriteria(); $va_criteria = $this->getCriteria($ps_facet_name); $va_facet_info = $this->opa_browse_settings['facets'][$ps_facet_name]; $t_subject = $this->getSubjectInstance(); if ($va_facet_info['relative_to']) { $vs_browse_table_name = $va_facet_info['relative_to']; $vs_browse_table_num = $this->opo_datamodel->getTableNum($vs_browse_table_name); } $vs_browse_type_limit_sql = ''; if (($va_browse_type_ids = $this->getTypeRestrictionList()) && sizeof($va_browse_type_ids)) { // type restrictions $vs_browse_type_limit_sql = '(' . $t_subject->tableName() . '.' . $t_subject->getTypeFieldName() . ' IN (' . join(', ', $va_browse_type_ids) . ')' . ($t_subject->getFieldInfo('type_id', 'IS_NULL') ? " OR (" . $this->ops_browse_table_name . '.' . $t_subject->getTypeFieldName() . " IS NULL)" : '') . ')'; if (is_array($va_facet_info['type_restrictions'])) { // facet type restrictions bind a facet to specific types; we check them here $va_restrict_to_types = $this->_convertTypeCodesToIDs($va_facet_info['type_restrictions']); $vb_is_ok_to_browse = false; foreach ($va_browse_type_ids as $vn_type_id) { if (in_array($vn_type_id, $va_restrict_to_types)) { $vb_is_ok_to_browse = true; break; } } if (!$vb_is_ok_to_browse) { return array(); } } } // Values to exclude from list attributes and authorities; can be idnos or ids $va_exclude_values = caGetOption('exclude_values', $va_facet_info, array(), array('castTo' => 'array')); $va_results = $this->opo_ca_browse_cache->getResults(); $vb_single_value_is_present = false; $vs_single_value = isset($va_facet_info['single_value']) ? $va_facet_info['single_value'] : null; $va_wheres = array(); switch ($va_facet_info['type']) { # ----------------------------------------------------- case 'has': $vn_state = null; if (isset($va_all_criteria[$ps_facet_name])) { break; } // only one instance of this facet allowed per browse if (!($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true))) { break; } $vs_yes_text = isset($va_facet_info['label_yes']) && $va_facet_info['label_yes'] ? $va_facet_info['label_yes'] : _t('Yes'); $vs_no_text = isset($va_facet_info['label_no']) && $va_facet_info['label_no'] ? $va_facet_info['label_no'] : _t('No'); $va_facet_values = array('yes' => array('id' => 1, 'label' => $vs_yes_text), 'no' => array('id' => 0, 'label' => $vs_no_text)); // Actually check that both yes and no values will result in something if ($va_facet_info['element_code']) { $t_element = new ca_metadata_elements(); if (!$t_element->load(array('element_code' => $va_facet_info['element_code']))) { break; } $vs_element_code = $va_facet_info['element_code']; $va_facet = array(); $va_counts = array(); foreach ($va_facet_values as $vs_state_name => $va_state_info) { $va_wheres = array(); $va_joins = array(); if (!(bool) $va_state_info['id']) { // no option $va_wheres[] = $this->ops_browse_table_name . '.' . $t_item->primaryKey() . " NOT IN (select row_id from ca_attributes where table_num = " . $t_item->tableNum() . " AND element_id = " . $t_element->getPrimaryKey() . ")"; } else { // yes option $va_joins[] = "LEFT JOIN ca_attributes AS caa ON " . $this->ops_browse_table_name . '.' . $t_item->primaryKey() . " = caa.row_id AND " . $t_item->tableNum() . " = caa.table_num"; $va_wheres[] = "caa.element_id = " . $t_element->getPrimaryKey(); } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $t_item->tableName() . ".deleted = 0)"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if (sizeof($va_results)) { $va_wheres[] = $vs_browse_table_name . "." . $t_item->primaryKey() . " IN (" . join(",", $va_results) . ")"; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); $vs_where_sql = ''; if (sizeof($va_wheres) > 0) { $vs_where_sql = ' WHERE ' . join(' AND ', $va_wheres); } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 2\n\t\t\t\t\t\t\t\t"; //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql); if ($qr_res->nextRow()) { $va_counts[$vs_state_name] = (int) $qr_res->numRows(); } } else { $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT " . $vs_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t"; //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql); if ($qr_res->numRows() > 0) { $va_facet[$vs_state_name] = $va_state_info; } else { return array(); // if either option in a "has" facet fails then don't show the facet } } } } else { $vs_rel_table_name = $va_facet_info['table']; if (!is_array($va_restrict_to_relationship_types = $va_facet_info['restrict_to_relationship_types'])) { $va_restrict_to_relationship_types = array(); } $va_restrict_to_relationship_types = $this->_getRelationshipTypeIDs($va_restrict_to_relationship_types, $va_facet_info['relationship_table']); if (!is_array($va_exclude_relationship_types = $va_facet_info['exclude_relationship_types'])) { $va_exclude_relationship_types = array(); } $va_exclude_relationship_types = $this->_getRelationshipTypeIDs($va_exclude_relationship_types, $va_facet_info['relationship_table']); $vn_table_num = $this->opo_datamodel->getTableNum($vs_rel_table_name); $vs_rel_table_pk = $this->opo_datamodel->getTablePrimaryKeyName($vn_table_num); switch (sizeof($va_path = array_keys($this->opo_datamodel->getPath($vs_browse_table_name, $vs_rel_table_name)))) { case 3: $t_item_rel = $this->opo_datamodel->getInstanceByTableName($va_path[1], true); $t_rel_item = $this->opo_datamodel->getInstanceByTableName($va_path[2], true); $vs_key = 'relation_id'; break; case 2: $t_item_rel = null; $t_rel_item = $this->opo_datamodel->getInstanceByTableName($va_path[1], true); $vs_key = $t_rel_item->primaryKey(); break; default: // bad related table return null; break; } $vs_cur_table = array_shift($va_path); $va_joins_init = array(); foreach ($va_path as $vs_join_table) { $va_rel_info = $this->opo_datamodel->getRelationships($vs_cur_table, $vs_join_table); $va_joins_init[] = ($vn_state ? 'INNER' : 'LEFT') . ' JOIN ' . $vs_join_table . ' ON ' . $vs_cur_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][0] . ' = ' . $vs_join_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][1] . "\n"; $vs_cur_table = $vs_join_table; } $va_facet = array(); $va_counts = array(); foreach ($va_facet_values as $vs_state_name => $va_state_info) { $va_wheres = array(); $va_joins = $va_joins_init; if (!(bool) $va_state_info['id']) { // no option $va_wheres[] = "(" . $t_rel_item->tableName() . "." . $t_rel_item->primaryKey() . " IS NULL)"; if ($t_rel_item->hasField('deleted')) { $va_wheres[] = "((" . $t_rel_item->tableName() . ".deleted = 0) OR (" . $t_rel_item->tableName() . ".deleted IS NULL))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access')) { $va_wheres[] = "((" . $t_rel_item->tableName() . ".access NOT IN (" . join(',', $pa_options['checkAccess']) . ")) OR (" . $t_rel_item->tableName() . ".access IS NULL))"; } if (sizeof($va_restrict_to_relationship_types) > 0 && is_object($t_item_rel)) { $va_wheres[] = "((" . $t_item_rel->tableName() . ".type_id NOT IN (" . join(',', $va_restrict_to_relationship_types) . ")) OR (" . $t_item_rel->tableName() . ".type_id IS NULL))"; } if (sizeof($va_exclude_relationship_types) > 0 && is_object($t_item_rel)) { $va_wheres[] = "(" . $t_item_rel->tableName() . ".type_id IN (" . join(',', $va_exclude_relationship_types) . "))"; } } else { // yes option $va_wheres[] = "(" . $t_rel_item->tableName() . "." . $t_rel_item->primaryKey() . " IS NOT NULL)"; if ($t_rel_item->hasField('deleted')) { $va_wheres[] = "(" . $t_rel_item->tableName() . ".deleted = 0)"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access')) { $va_wheres[] = "(" . $t_rel_item->tableName() . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if (sizeof($va_restrict_to_relationship_types) > 0 && is_object($t_item_rel)) { $va_wheres[] = "(" . $t_item_rel->tableName() . ".type_id IN (" . join(',', $va_restrict_to_relationship_types) . "))"; } if (sizeof($va_exclude_relationship_types) > 0 && is_object($t_item_rel)) { $va_wheres[] = "(" . $t_item_rel->tableName() . ".type_id NOT IN (" . join(',', $va_exclude_relationship_types) . "))"; } } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $t_item->tableName() . ".deleted = 0)"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if (sizeof($va_results)) { $va_wheres[] = $vs_browse_table_name . "." . $t_item->primaryKey() . " IN (" . join(",", $va_results) . ")"; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); $vs_where_sql = ''; if (sizeof($va_wheres) > 0) { $vs_where_sql = ' WHERE ' . join(' AND ', $va_wheres); } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 2\n\t\t\t\t\t\t\t\t"; //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql); if ($qr_res->nextRow()) { $va_counts[$vs_state_name] = (int) $qr_res->numRows(); } } else { $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT " . $vs_browse_table_name . '.' . $t_item->primaryKey() . "\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t"; //print "$vs_sql<hr>"; $qr_res = $this->opo_db->query($vs_sql); if ($qr_res->numRows() > 0) { $va_facet[$vs_state_name] = $va_state_info; } else { return array(); // if either option in a "has" facet fails then don't show the facet } } } } if ($vb_check_availability_only) { return sizeof($va_counts) > 1 ? true : false; } return $va_facet; break; # ----------------------------------------------------- # ----------------------------------------------------- case 'label': if (!($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true))) { break; } if (!($t_label = $t_item->getLabelTableInstance())) { break; } if (!is_array($va_restrict_to_types = $va_facet_info['restrict_to_types'])) { $va_restrict_to_types = array(); } $vs_item_pk = $t_item->primaryKey(); $vs_label_table_name = $t_label->tableName(); $vs_label_pk = $t_label->primaryKey(); $vs_label_display_field = $t_item->getLabelDisplayField(); $vs_label_sort_field = $t_item->getLabelSortField(); $vs_where_sql = $vs_join_sql = ''; $vb_needs_join = false; $va_where_sql = array(); $va_joins = array(); if ($vs_browse_type_limit_sql) { $va_where_sql[] = $vs_browse_type_limit_sql; } if (isset($va_facet_info['preferred_labels_only']) && $va_facet_info['preferred_labels_only'] && $t_label->hasField('is_preferred')) { $va_where_sql[] = "l.is_preferred = 1"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_where_sql[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($t_item->hasField('deleted')) { $va_where_sql[] = "(" . $vs_browse_table_name . ".deleted = 0)"; $vb_needs_join = true; } if (sizeof($va_restrict_to_types)) { $va_restrict_to_type_ids = caMakeTypeIDList($vs_browse_table_name, $va_restrict_to_types, array('dont_include_subtypes_in_type_restriction' => true)); if (sizeof($va_restrict_to_type_ids)) { $va_where_sql[] = "(" . $vs_browse_table_name . "." . $t_item->getTypeFieldName() . " IN (" . join(", ", $va_restrict_to_type_ids) . ")" . ($t_item->getFieldInfo('type_id', 'IS_NULL') ? " OR (" . $vs_browse_table_name . '.' . $t_item->getTypeFieldName() . " IS NULL)" : '') . ")"; $vb_needs_join = true; } } if (sizeof($va_exclude_types)) { $va_exclude_type_ids = caMakeTypeIDList($vs_browse_table_name, $va_exclude_types, array('dont_include_subtypes_in_type_restriction' => true)); if (sizeof($va_exclude_type_ids)) { $va_where_sql[] = "(" . $vs_browse_table_name . "." . $t_item->getTypeFieldName() . " NOT IN (" . join(", ", $va_exclude_type_ids) . ")" . ($t_item->getFieldInfo('type_id', 'IS_NULL') ? " OR (" . $vs_browse_table_name . '.' . $t_item->getTypeFieldName() . " IS NULL)" : '') . ")"; $vb_needs_join = true; } } if ($vb_needs_join) { $va_joins[] = "INNER JOIN " . $vs_browse_table_name . " ON " . $vs_browse_table_name . "." . $t_item->primaryKey() . " = l." . $t_item->primaryKey(); } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_where_sql[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_where_sql = array_merge($va_where_sql, $va_relative_sql_data['wheres']); } } if (sizeof($va_results)) { if ($va_facet_info['relative_to']) { $va_where_sql[] = $this->ops_browse_table_name . "." . $t_subject->primaryKey() . " IN (" . join(",", $va_results) . ")"; } else { $va_where_sql[] = "l.{$vs_item_pk} IN (" . join(",", $va_results) . ")"; } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_where_sql[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if (sizeof($va_where_sql)) { $vs_where_sql = "WHERE " . join(" AND ", $va_where_sql); } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM {$vs_label_table_name} l\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql); return (int) $qr_res->numRows() > 0 ? true : false; } else { $vs_parent_fld = $t_item->getProperty('HIERARCHY_PARENT_ID_FLD'); $vs_sql = "\n\t\t\t\t\t\t\tSELECT l.* " . ($vs_parent_fld ? ", " . $vs_browse_table_name . "." . $vs_parent_fld : '') . " \n\t\t\t\t\t\t\tFROM {$vs_label_table_name} l\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql); $va_values = array(); $va_child_counts = array(); $vn_parent_id = null; while ($qr_res->nextRow()) { $vn_id = $qr_res->get($t_item->primaryKey()); if ($vs_parent_fld) { $vn_parent_id = $qr_res->get($vs_parent_fld); if ($vn_parent_id) { $va_child_counts[$vn_parent_id]++; } } $va_values[$vn_id][$qr_res->get('locale_id')] = array_merge($qr_res->getRow(), array('id' => $vn_id, 'parent_id' => $vn_parent_id, 'label' => $qr_res->get($vs_label_display_field))); if (!is_null($vs_single_value) && $vn_id == $vs_single_value) { $vb_single_value_is_present = true; } } if ($vs_parent_fld) { foreach ($va_values as $vn_id => $va_values_by_locale) { foreach ($va_values_by_locale as $vn_locale_id => $va_value) { $va_values[$vn_id][$vn_locale_id]['child_count'] = (int) $va_child_counts[$vn_id]; } } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } $va_values = caExtractValuesByUserLocale($va_values); return $va_values; } break; # ----------------------------------------------------- # ----------------------------------------------------- case 'attribute': $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true); $t_element = new ca_metadata_elements(); if (!$t_element->load(array('element_code' => $va_facet_info['element_code']))) { return array(); } $vn_element_type = $t_element->get('datatype'); $vn_element_id = $t_element->getPrimaryKey(); $va_joins = array('INNER JOIN ca_attribute_values ON ca_attributes.attribute_id = ca_attribute_values.attribute_id', 'INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_attributes.row_id AND ca_attributes.table_num = ' . intval($vs_browse_table_num)); $va_wheres = array(); if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)"; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = ' AND (' . $vs_where_sql . ')'; } if ($vb_check_availability_only) { // exclude criteria values $vs_criteria_exclude_sql = ''; if (is_array($va_criteria) && sizeof($va_criteria)) { $vs_criteria_exclude_sql = ' AND (ca_attribute_values.value_longtext1 NOT IN (' . join(", ", caQuoteList(array_keys($va_criteria))) . ')) '; } $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t(ca_attribute_values.element_id = ?) {$vs_criteria_exclude_sql} {$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 2"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql, $vn_element_id); return (int) $qr_res->numRows() > 1 ? true : false; } else { $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT value_longtext1, value_decimal1, value_longtext2, value_integer1\n\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\tca_attribute_values.element_id = ? {$vs_where_sql}"; $qr_res = $this->opo_db->query($vs_sql, $vn_element_id); $va_values = array(); $va_list_items = null; $va_suppress_values = null; if ($va_facet_info['suppress'] && !is_array($va_facet_info['suppress'])) { $va_facet_info['suppress'] = array($va_facet_info['suppress']); } if (!is_array($va_suppress_values = caGetOption('suppress', $va_facet_info, null))) { $va_suppress_values = caGetOption('exclude_values', $va_facet_info, null); } switch ($vn_element_type) { case __CA_ATTRIBUTE_VALUE_LIST__: $va_values = $qr_res->getAllFieldValues('value_longtext1'); $qr_res->seek(0); $t_list_item = new ca_list_items(); $va_list_item_cache = $t_list_item->getFieldValuesForIDs($va_values, array('idno', 'item_value', 'parent_id', 'access')); $va_list_child_count_cache = array(); if (is_array($va_list_item_cache)) { foreach ($va_list_item_cache as $vn_id => $va_item) { if (!($vn_parent_id = $va_item['parent_id'])) { continue; } if (is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && !in_array($va_item['access'], $pa_options['checkAccess'])) { continue; } $va_list_child_count_cache[$vn_parent_id]++; } } $va_list_label_cache = $t_list_item->getPreferredDisplayLabelsForIDs($va_values); // Translate value idnos to ids if (is_array($va_suppress_values)) { $va_suppress_values = ca_lists::getItemIDsFromList($t_element->get('list_id'), $va_suppress_values); } $va_facet_list = array(); foreach ($va_values as $vn_val) { if (!$vn_val) { continue; } if (is_array($va_suppress_values) && in_array($vn_val, $va_suppress_values)) { continue; } if (is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && !in_array($va_item['access'], $pa_options['checkAccess'])) { continue; } if ($va_criteria[$vn_val]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on $vn_child_count = isset($va_list_child_count_cache[$vn_val]) ? $va_list_child_count_cache[$vn_val] : 0; $va_facet_list[$vn_val] = array('id' => $vn_val, 'label' => html_entity_decode($va_list_label_cache[$vn_val]), 'parent_id' => isset($va_list_item_cache[$vn_val]['parent_id']) ? $va_list_item_cache[$vn_val]['parent_id'] : null, 'child_count' => $vn_child_count); } // preserve order of list $va_values_sorted_by_list_order = array(); if (is_array($va_list_item_cache)) { foreach ($va_list_item_cache as $vn_item_id => $va_item) { if (isset($va_facet_list[$vn_item_id])) { $va_values_sorted_by_list_order[$vn_item_id] = $va_facet_list[$vn_item_id]; } } } return caSortArrayByKeyInValue($va_values_sorted_by_list_order, array('label')); break; case __CA_ATTRIBUTE_VALUE_OBJECTS__: case __CA_ATTRIBUTE_VALUE_ENTITIES__: case __CA_ATTRIBUTE_VALUE_PLACES__: case __CA_ATTRIBUTE_VALUE_OCCURRENCES__: case __CA_ATTRIBUTE_VALUE_COLLECTIONS__: case __CA_ATTRIBUTE_VALUE_LOANS__: case __CA_ATTRIBUTE_VALUE_MOVEMENTS__: case __CA_ATTRIBUTE_VALUE_STORAGELOCATIONS__: case __CA_ATTRIBUTE_VALUE_OBJECTLOTS__: if ($t_rel_item = AuthorityAttributeValue::elementTypeToInstance($vn_element_type)) { $va_ids = $qr_res->getAllFieldValues('value_integer1'); $va_auth_items = $t_rel_item->getPreferredDisplayLabelsForIDs($va_ids); $qr_res->seek(0); } break; default: if (isset($va_facet_info['suppress']) && is_array($va_facet_info['suppress'])) { $va_suppress_values = $va_facet_info['suppress']; } break; } while ($qr_res->nextRow()) { $o_attr = Attribute::getValueInstance($vn_element_type, $qr_res->getRow(), true); if (!($vs_val = trim($o_attr->getDisplayValue()))) { continue; } if (is_array($va_suppress_values) && in_array($vs_val, $va_suppress_values)) { continue; } if ($va_criteria[$vs_val]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on switch ($vn_element_type) { case __CA_ATTRIBUTE_VALUE_LIST__: $vn_child_count = 0; if ($va_list_parent_ids[$vs_val]) { $vn_child_count++; } $va_values[$vs_val] = array('id' => str_replace('/', '/', $vs_val), 'label' => html_entity_decode($va_list_items[$vs_val]['name_plural'] ? $va_list_items[$vs_val]['name_plural'] : $va_list_items[$vs_val]['item_value']), 'parent_id' => $va_list_items[$vs_val]['parent_id'], 'child_count' => $vn_child_count); break; case __CA_ATTRIBUTE_VALUE_OBJECTS__: case __CA_ATTRIBUTE_VALUE_ENTITIES__: case __CA_ATTRIBUTE_VALUE_PLACES__: case __CA_ATTRIBUTE_VALUE_OCCURRENCES__: case __CA_ATTRIBUTE_VALUE_COLLECTIONS__: case __CA_ATTRIBUTE_VALUE_LOANS__: case __CA_ATTRIBUTE_VALUE_MOVEMENTS__: case __CA_ATTRIBUTE_VALUE_STORAGELOCATIONS__: case __CA_ATTRIBUTE_VALUE_OBJECTLOTS__: $va_values[$vs_val] = array('id' => $vn_id, 'label' => html_entity_decode($va_auth_items[$vn_id] ? $va_auth_items[$vn_id] : $vs_val)); break; case __CA_ATTRIBUTE_VALUE_CURRENCY__: $va_values[sprintf("%014.2f", preg_replace("![\\D]+!", "", $vs_val))] = array('id' => str_replace('/', '/', $vs_val), 'label' => $vs_val); break; default: $va_values[$vs_val] = array('id' => str_replace('/', '/', $vs_val), 'label' => $vs_val); break; } if (!is_null($vs_single_value) && $vs_val == $vs_single_value) { $vb_single_value_is_present = true; } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } ksort($va_values); return $va_values; } break; # ----------------------------------------------------- # ----------------------------------------------------- case 'location': $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true); $vs_sort_field = null; if ($t_item->getProperty('ID_NUMBERING_ID_FIELD') == $vs_field_name) { $vs_sort_field = $t_item->getProperty('ID_NUMBERING_SORT_FIELD'); } $va_joins = array(); $va_wheres = array(); $vs_where_sql = ''; $va_wheres[] = "({$vs_browse_table_name}.current_loc_class IS NOT NULL)"; if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)"; } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = '(' . $vs_where_sql . ')'; } if ($vb_check_availability_only) { if (sizeof($va_criteria) > 0) { return false; } // only one current location criteria allowed $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 2"; $qr_res = $this->opo_db->query($vs_sql); if ($qr_res->nextRow()) { return (int) $qr_res->numRows() > 0 ? true : false; } return false; } else { if (sizeof($va_criteria) > 0) { return array(); } // only one current location criteria allowed $vs_pk = $t_item->primaryKey(); $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT {$vs_browse_table_name}.current_loc_class, {$vs_browse_table_name}.current_loc_subclass, {$vs_browse_table_name}.current_loc_id\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}"; if ($vs_sort_field) { $vs_sql .= " ORDER BY {$vs_sort_field}"; } $qr_res = $this->opo_db->query($vs_sql); $va_collapse_map = $this->getCollapseMapForLocationFacet($va_facet_info); $va_values = $va_values_by_table = array(); while ($qr_res->nextRow()) { if (!($vs_loc_class = trim($qr_res->get('current_loc_class')))) { continue; } if (!($vs_loc_subclass = trim($qr_res->get('current_loc_subclass')))) { continue; } if (!($vs_loc_id = trim($qr_res->get('current_loc_id')))) { continue; } $vs_val = "{$vs_loc_class}:{$vs_loc_subclass}:{$vs_loc_id}"; if ($va_criteria[$vs_val]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on $va_values_by_table[$vs_loc_class][$vs_loc_subclass][$vs_loc_id] = true; } foreach ($va_values_by_table as $vs_loc_class => $va_loc_id_by_subclass) { foreach ($va_loc_id_by_subclass as $vs_loc_subclass => $va_loc_ids) { if (sizeof($va_tmp = array_keys($va_loc_ids))) { $vs_loc_table_name = $this->opo_datamodel->getTableName($vs_loc_class); if (($vs_table_name = $vs_loc_table_name) == 'ca_objects_x_storage_locations') { $vs_table_name = 'ca_storage_locations'; } $qr_res = caMakeSearchResult($vs_table_name, $va_tmp); if (isset($va_collapse_map[$vs_table_name]) && isset($va_collapse_map[$vs_table_name]['*']) && $va_collapse_map[$vs_table_name]['*']) { $va_values[$vs_id = "{$vs_loc_class}"] = array('id' => $vs_id, 'label' => $va_collapse_map[$vs_table_name]['*']); continue; } while ($qr_res->nextHit()) { $vn_id = $qr_res->getPrimaryKey(); $va_config = ca_objects::getConfigurationForCurrentLocationType($vs_table_name, $vs_loc_subclass, array('facet' => isset($va_facet_info['display']) ? $va_facet_info['display'] : null)); $vs_template = isset($va_config['template']) ? $va_config['template'] : "^{$vs_table_name}.preferred_labels"; if (isset($va_collapse_map[$vs_table_name]) && isset($va_collapse_map[$vs_table_name][$vs_loc_subclass]) && $va_collapse_map[$vs_table_name][$vs_loc_subclass]) { $va_values[$vs_id = "{$vs_loc_class}:{$vs_loc_subclass}"] = array('id' => $vs_id, 'label' => $va_collapse_map[$vs_table_name][$vs_loc_subclass]); continue; } $va_values[$vs_id = "{$vs_loc_class}:{$vs_loc_subclass}:{$vn_id}"] = array('id' => $vs_id, 'label' => $qr_res->getWithTemplate($vs_template)); } } } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } return caSortArrayByKeyInValue($va_values, array('label')); } return array(); break; # ----------------------------------------------------- # ----------------------------------------------------- case 'fieldList': $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true); $vs_field_name = $va_facet_info['field']; $va_field_info = $t_item->getFieldInfo($vs_field_name); $t_list = new ca_lists(); $t_list_item = new ca_list_items(); $va_joins = array(); $va_wheres = array(); $vs_where_sql = ''; if (isset($va_field_info['LIST_CODE']) && ($vs_list_name = $va_field_info['LIST_CODE'])) { // Handle fields containing ca_list_item.item_id's $va_joins = array('INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $vs_field_name . ' = li.item_id', 'INNER JOIN ca_lists ON ca_lists.list_id = li.list_id'); if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; $va_wheres[] = "(li.access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_facet_info['relative_to']) { if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if (is_array($va_criteria) && sizeof($va_criteria)) { $va_wheres[] = "(li.item_id NOT IN (" . join(",", array_keys($va_criteria)) . "))"; } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = ' AND (' . $vs_where_sql . ')'; } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\tFROM ca_list_items li\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\tca_lists.list_code = ? {$vs_where_sql}\n\t\t\t\t\t\t\t\tLIMIT 2"; $qr_res = $this->opo_db->query($vs_sql, $vs_list_name); return (int) $qr_res->numRows() > 1 ? true : false; } else { // Get label ordering fields $va_ordering_fields_to_fetch = isset($va_facet_info['order_by_label_fields']) && is_array($va_facet_info['order_by_label_fields']) ? $va_facet_info['order_by_label_fields'] : array(); $va_orderbys = array(); $t_rel_item_label = new ca_list_item_labels(); foreach ($va_ordering_fields_to_fetch as $vs_sort_by_field) { if (!$t_rel_item_label->hasField($vs_sort_by_field)) { continue; } $va_orderbys[] = $va_label_selects[] = 'lil.' . $vs_sort_by_field; } $vs_order_by = sizeof($va_orderbys) ? "ORDER BY " . join(', ', $va_orderbys) : ''; $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT DISTINCT lil.item_id, lil.name_singular, lil.name_plural, lil.locale_id\n\t\t\t\t\t\t\t\tFROM ca_list_items li\n\t\t\t\t\t\t\t\tINNER JOIN ca_list_item_labels AS lil ON lil.item_id = li.item_id\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\tca_lists.list_code = ? AND lil.is_preferred = 1 {$vs_where_sql} {$vs_order_by}"; //print $vs_sql." [$vs_list_name]"; $qr_res = $this->opo_db->query($vs_sql, $vs_list_name); $va_values = array(); while ($qr_res->nextRow()) { $vn_id = $qr_res->get('item_id'); if ($va_criteria[$vn_id]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on $va_values[$vn_id][$qr_res->get('locale_id')] = array('id' => $vn_id, 'label' => $qr_res->get('name_plural')); if (!is_null($vs_single_value) && $vn_id == $vs_single_value) { $vb_single_value_is_present = true; } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } return caExtractValuesByUserLocale($va_values); } } else { if ($vs_list_name = $va_field_info['LIST']) { $va_list_items_by_value = array(); // fields with values set according to ca_list_items (not a foreign key ref) if ($va_list_items = caExtractValuesByUserLocale($t_list->getItemsForList($vs_list_name))) { foreach ($va_list_items as $vn_id => $va_list_item) { $va_list_items_by_value[$va_list_item['item_value']] = $va_list_item['name_plural']; } } else { foreach ($va_field_info['BOUNDS_CHOICE_LIST'] as $vs_val => $vn_id) { $va_list_items_by_value[$vn_id] = $vs_val; } } if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_facet_info['relative_to']) { if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t\t)"; } } if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = '(' . $vs_where_sql . ')'; } $vs_join_sql = join("\n", $va_joins); if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t" . ($vs_where_sql ? 'WHERE' : '') . "\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 2"; $qr_res = $this->opo_db->query($vs_sql); return (int) $qr_res->numRows() > 1 ? true : false; } else { $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT DISTINCT " . $vs_browse_table_name . '.' . $vs_field_name . "\n\t\t\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t" . ($vs_where_sql ? 'WHERE' : '') . "\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}"; //print $vs_sql." [$vs_list_name]"; $qr_res = $this->opo_db->query($vs_sql); $va_values = array(); while ($qr_res->nextRow()) { $vn_id = $qr_res->get($vs_field_name); if ($va_criteria[$vn_id]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on if (isset($va_list_items_by_value[$vn_id])) { $va_values[$vn_id] = array('id' => $vn_id, 'label' => $va_list_items_by_value[$vn_id]); if (!is_null($vs_single_value) && $vn_id == $vs_single_value) { $vb_single_value_is_present = true; } } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } return $va_values; } } else { if ($t_browse_table = $this->opo_datamodel->getInstanceByTableName($vs_facet_table = $va_facet_info['table'], true)) { // Handle fields containing ca_list_item.item_id's $va_joins = array('INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $vs_field_name . ' = ' . $vs_facet_table . '.' . $t_browse_table->primaryKey()); $vs_display_field_name = null; if (method_exists($t_browse_table, 'getLabelTableInstance')) { $t_label_instance = $t_browse_table->getLabelTableInstance(); $vs_display_field_name = isset($va_facet_info['display']) && $va_facet_info['display'] ? $va_facet_info['display'] : $t_label_instance->getDisplayField(); $va_joins[] = 'INNER JOIN ' . $t_label_instance->tableName() . " AS lab ON lab." . $t_browse_table->primaryKey() . ' = ' . $t_browse_table->tableName() . '.' . $t_browse_table->primaryKey(); } if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = 'WHERE (' . $vs_where_sql . ')'; } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\t\tFROM {$vs_facet_table}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\t\tLIMIT 1"; $qr_res = $this->opo_db->query($vs_sql); return (int) $qr_res->numRows() > 0 ? true : false; } else { $vs_sql = "\n\t\t\t\t\t\t\t\t\t\tSELECT DISTINCT *\n\t\t\t\t\t\t\t\t\t\tFROM {$vs_facet_table}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql); $va_values = array(); $vs_pk = $t_browse_table->primaryKey(); while ($qr_res->nextRow()) { $vn_id = $qr_res->get($vs_pk); if ($va_criteria[$vn_id]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on $va_values[$vn_id][$qr_res->get('locale_id')] = array('id' => $vn_id, 'label' => $qr_res->get($vs_display_field_name)); if (!is_null($vs_single_value) && $vn_id == $vs_single_value) { $vb_single_value_is_present = true; } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } return caExtractValuesByUserLocale($va_values); } } } } return array(); break; # ----------------------------------------------------- # ----------------------------------------------------- case 'field': $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true); if (!is_array($va_restrict_to_types = $va_facet_info['restrict_to_types'])) { $va_restrict_to_types = array(); } if (!is_array($va_restrict_to_types = $this->_convertTypeCodesToIDs($va_restrict_to_types, array('instance' => $t_item, 'dontExpandHierarchically' => true)))) { $va_restrict_to_types = array(); } $va_restrict_to_types_expanded = $this->_convertTypeCodesToIDs($va_restrict_to_types, array('instance' => $t_item)); $vs_field_name = $va_facet_info['field']; $va_field_info = $t_item->getFieldInfo($vs_field_name); $vs_sort_field = null; if ($t_item->getProperty('ID_NUMBERING_ID_FIELD') == $vs_field_name) { $vs_sort_field = $vs_browse_table_name . '.' . $t_item->getProperty('ID_NUMBERING_SORT_FIELD'); } $t_list = new ca_lists(); $t_list_item = new ca_list_items(); $va_joins = array(); $va_wheres = array(); $vs_where_sql = ''; $va_facet_values = null; if ($vb_is_bit = $va_field_info['FIELD_TYPE'] == FT_BIT) { $vs_yes_text = caGetOption('label_yes', $va_facet_info, _t('Yes')); $vs_no_text = caGetOption('label_no', $va_facet_info, _t('No')); $va_facet_values = array(1 => array('id' => 1, 'label' => $vs_yes_text), 0 => array('id' => 0, 'label' => $vs_no_text)); } if (is_array($va_restrict_to_types) && sizeof($va_restrict_to_types) > 0 && method_exists($t_rel_item, "getTypeList")) { $va_wheres[] = "{$va_restrict_to_types_expanded}.type_id IN (" . join(',', caGetOption('dont_include_subtypes', $va_facet_info, false) ? $va_restrict_to_types : $va_restrict_to_types_expanded) . ")"; $va_selects[] = "{$va_restrict_to_types_expanded}.type_id"; } if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)"; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = '(' . $vs_where_sql . ')'; } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT {$vs_browse_table_name}.{$vs_field_name}\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 2"; $qr_res = $this->opo_db->query($vs_sql); if ($qr_res->numRows() > 1) { return true; } return false; } else { $vs_pk = $t_item->primaryKey(); $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT {$vs_browse_table_name}.{$vs_field_name}\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}"; if ($vs_sort_field) { $vs_sql .= " ORDER BY {$vs_sort_field}"; } $qr_res = $this->opo_db->query($vs_sql); $va_values = array(); while ($qr_res->nextRow()) { if (!($vs_val = trim($qr_res->get($vs_field_name))) && !$vb_is_bit) { continue; } if ($va_criteria[$vs_val]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on if ($vb_is_bit && isset($va_facet_values[$vs_val])) { $va_values[$vs_val] = $va_facet_values[$vs_val]; } else { $va_values[$vs_val] = array('id' => str_replace('/', '/', $vs_val), 'label' => $vs_val); } if (!is_null($vs_single_value) && $vs_val == $vs_single_value) { $vb_single_value_is_present = true; } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } return $va_values; } return array(); break; # ----------------------------------------------------- # ----------------------------------------------------- case 'violations': $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true); $vs_field_name = $va_facet_info['field']; $va_field_info = $t_item->getFieldInfo($vs_field_name); $va_joins = array(); $va_wheres = array(); $vs_where_sql = ''; $va_facet_values = null; if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)"; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = '(' . $vs_where_sql . ')'; } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\tINNER JOIN ca_metadata_dictionary_rule_violations ON ca_metadata_dictionary_rule_violations.row_id = {$vs_browse_table_name}." . $t_item->primaryKey() . " AND ca_metadata_dictionary_rule_violations.table_num = {$vs_browse_table_num}\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\tLIMIT 2"; $qr_res = $this->opo_db->query($vs_sql); if ($qr_res->nextRow()) { return (int) $qr_res->numRows() > 0 ? true : false; } return false; } else { $vs_pk = $t_item->primaryKey(); $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT ca_metadata_dictionary_rules.rule_id\n\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\tINNER JOIN ca_metadata_dictionary_rule_violations ON ca_metadata_dictionary_rule_violations.row_id = {$vs_browse_table_name}." . $t_item->primaryKey() . " AND ca_metadata_dictionary_rule_violations.table_num = {$vs_browse_table_num}\n\t\t\t\t\t\t\tINNER JOIN ca_metadata_dictionary_rules ON ca_metadata_dictionary_rules.rule_id = ca_metadata_dictionary_rule_violations.rule_id\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t{$vs_where_sql}"; $qr_res = $this->opo_db->query($vs_sql); $va_values = array(); $t_rule = new ca_metadata_dictionary_rules(); while ($qr_res->nextRow()) { if ($t_rule->load($qr_res->get('rule_id'))) { if (!($vs_val = trim($t_rule->getSetting('label')))) { continue; } $vs_code = $t_rule->get('rule_code'); if ($va_criteria[$vs_val]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on if (isset($va_facet_values[$vs_code])) { $va_values[$vs_code] = $va_facet_values[$vs_code]; } else { $va_values[$vs_code] = array('id' => $vs_code, 'label' => $vs_val); } if (!is_null($vs_single_value) && $vs_code == $vs_single_value) { $vb_single_value_is_present = true; } } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } return $va_values; } return array(); break; # ----------------------------------------------------- # ----------------------------------------------------- case 'checkouts': if ($vs_browse_table_name != 'ca_objects') { return array(); } $t_item = new ca_objects(); $va_joins = array(); $va_wheres = array(); $vs_where_sql = ''; $va_facet_values = null; if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)"; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } $vs_checkout_join_sql = "INNER JOIN ca_object_checkouts ON ca_object_checkouts.object_id = ca_objects.object_id"; $vn_current_time = time(); switch ($va_facet_info['status']) { case 'overdue': $va_wheres[] = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL) AND (ca_object_checkouts.due_date <= {$vn_current_time}))"; break; case 'reserved': $va_wheres[] = "((ca_object_checkouts.checkout_date IS NULL) AND (ca_object_checkouts.return_date IS NULL))"; break; case 'available': $vs_checkout_join_sql = ''; $va_wheres[] = "(ca_objects.object_id NOT IN (SELECT object_id FROM ca_object_checkouts WHERE (ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL)))"; break; default: case 'out': $va_wheres[] = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL))"; break; } if ($vs_checkout_join_sql) { $va_joins[] = $vs_checkout_join_sql; $va_joins[] = "INNER JOIN ca_users ON ca_object_checkouts.user_id = ca_users.user_id"; } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = '(' . $vs_where_sql . ')'; } if ($vb_check_availability_only) { switch ($va_facet_info['mode']) { case 'user': $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM ca_objects\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql} AND ca_objects.deleted = 0\n\t\t\t\t\t\t\t\t\tLIMIT 2"; break; default: case 'all': $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\t\tFROM ca_objects\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\tca_objects.deleted = 0 " . (sizeof($va_results) ? "AND (" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tLIMIT 2"; break; } $qr_res = $this->opo_db->query($vs_sql); if ($qr_res->nextRow()) { return (int) $qr_res->numRows() > 0 ? true : false; } return false; } else { $va_values = array(); $vs_pk = $t_item->primaryKey(); switch ($va_facet_info['mode']) { case 'user': $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT DISTINCT ca_object_checkouts.user_id, ca_users.fname, ca_users.lname, ca_users.email\n\t\t\t\t\t\t\t\t\tFROM ca_objects\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql} " . (sizeof($va_results) ? " AND (" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))" : ""); $qr_res = $this->opo_db->query($vs_sql); while ($qr_res->nextRow()) { $vn_user_id = $qr_res->get('user_id'); $vs_val = $qr_res->get('fname') . ' ' . $qr_res->get('lname') . (($vs_email = $qr_res->get('email')) ? "({$vs_email})" : ''); if ($va_criteria[$vs_val]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on if (isset($va_facet_values[$vn_user_id])) { $va_values[$vn_user_id] = $va_facet_values[$vn_user_id]; } else { $va_values[$vn_user_id] = array('id' => $vn_user_id, 'label' => $vs_val); } if (!is_null($vs_single_value) && $vn_user_id == $vs_single_value) { $vb_single_value_is_present = true; } } break; case 'all': default: foreach (array(_t('Available') => 'available', _t('Out') => 'out', _t('Reserved') => 'reserved', _t('Overdue') => 'overdue') as $vs_status_text => $vs_status) { $vs_join_sql = "INNER JOIN ca_object_checkouts ON ca_object_checkouts.object_id = ca_objects.object_id"; switch ($vs_status) { case 'overdue': $vs_where = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL) AND (ca_object_checkouts.due_date <= {$vn_current_time}))"; break; case 'reserved': $vs_where = "((ca_object_checkouts.checkout_date IS NULL) AND (ca_object_checkouts.return_date IS NULL))"; break; case 'available': $vs_join_sql = ''; $vs_where = "(ca_objects.object_id NOT IN (SELECT object_id FROM ca_object_checkouts WHERE (ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL)))"; break; default: case 'out': $vs_where = "((ca_object_checkouts.checkout_date <= {$vn_current_time}) AND (ca_object_checkouts.return_date IS NULL))"; break; } if (sizeof($va_results) && $this->numCriteria() > 0) { $vs_where .= " AND (" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } $vs_sql = "\n\t\t\t\t\t\t\t\t\t\tSELECT count(*) c\n\t\t\t\t\t\t\t\t\t\tFROM ca_objects\n\t\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t{$vs_where}\n\t\t\t\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql); $qr_res->nextRow(); if (!$qr_res->get('c')) { continue; } $va_values[$vs_status] = array('id' => $vs_status, 'label' => $vs_status_text); if (!is_null($vs_single_value) && $vs_status == $vs_single_value) { $vb_single_value_is_present = true; } } break; } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } return $va_values; } return array(); break; # ----------------------------------------------------- # ----------------------------------------------------- case 'normalizedDates': $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true); $t_element = new ca_metadata_elements(); $vb_is_element = $vb_is_field = false; if (!($vb_is_element = $t_element->load(array('element_code' => $va_facet_info['element_code']))) && !($vb_is_field = $t_item->hasField($va_facet_info['element_code']) && $t_item->getFieldInfo($va_facet_info['element_code'], 'FIELD_TYPE') === FT_HISTORIC_DATERANGE)) { return array(); } if ($vb_is_element) { $va_joins = array('INNER JOIN ca_attribute_values ON ca_attributes.attribute_id = ca_attribute_values.attribute_id', 'INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_attributes.row_id AND ca_attributes.table_num = ' . intval($vs_browse_table_num)); } else { $va_joins = array(); } $va_wheres = array(); $vs_normalization = $va_facet_info['normalization']; // how do we construct the date ranges presented to uses. In other words - how do we want to allow users to browse dates? By year, decade, century? if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)"; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_where_sql = ''; if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = ' AND (' . $vs_where_sql . ')'; } $vs_join_sql = join("\n", $va_joins); if ($vb_is_element) { $vn_element_id = $t_element->getPrimaryKey(); $vs_dir = strtoupper($va_facet_info['sort']) === 'DESC' ? "DESC" : "ASC"; $o_tep = new TimeExpressionParser(); $vn_min_date = $vn_max_date = null; $vs_min_sql = $vs_max_sql = ''; if (isset($va_facet_info['minimum_date'])) { if ($o_tep->parse($va_facet_info['minimum_date'])) { $va_tmp = $o_tep->getHistoricTimestamps(); $vn_min_date = (double) $va_tmp['start']; $vs_min_sql = " AND (ca_attribute_values.value_decimal1 >= {$vn_min_date})"; } } if (isset($va_facet_info['maximum_date'])) { if ($o_tep->parse($va_facet_info['maximum_date'])) { $va_tmp = $o_tep->getHistoricTimestamps(); $vn_max_date = (double) $va_tmp['end']; $vs_max_sql = " AND (ca_attribute_values.value_decimal2 <= {$vn_max_date})"; } } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\tca_attribute_values.element_id = ? \n\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 1"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql, $vn_element_id); return (int) $qr_res->numRows() > 0 ? true : false; } else { $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT DISTINCT ca_attribute_values.value_decimal1, ca_attribute_values.value_decimal2\n\t\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\tca_attribute_values.element_id = ? \n\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql, $vn_element_id); $vn_current_year = (int) date("Y"); $va_values = array(); $vb_include_unknown = (bool) caGetOption('include_unknown', $va_facet_info, false); $vb_unknown_is_set = false; while ($qr_res->nextRow()) { $vn_start = $qr_res->get('value_decimal1'); $vn_end = $qr_res->get('value_decimal2'); if (!($vn_start && $vn_end)) { if ($vb_include_unknown) { $vb_unknown_is_set = true; } continue; } if ($vn_end > $vn_current_year + 50) { continue; } // bad years can make for large facets that cause timeouts so cut it off 50 years into the future $va_normalized_values = $o_tep->normalizeDateRange($vn_start, $vn_end, $vs_normalization); foreach ($va_normalized_values as $vn_sort_value => $vs_normalized_value) { if ($va_criteria[$vs_normalized_value]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on if (is_numeric($vs_normalized_value) && (int) $vs_normalized_value === 0) { continue; } // don't include year=0 $va_values[$vn_sort_value][$vs_normalized_value] = array('id' => $vs_normalized_value, 'label' => $vs_normalized_value); if (!is_null($vs_single_value) && $vs_normalized_value == $vs_single_value) { $vb_single_value_is_present = true; } } } if ($vb_include_unknown && !$vb_unknown_is_set) { // Check for rows where no data is set at all as opposed to null dates $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT DISTINCT ca_attributes.row_id\n\t\t\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\tca_attribute_values.element_id = ? \n\t\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql, $vn_element_id); if ($qr_res->numRows() < sizeof($va_results)) { $vb_unknown_is_set = true; } } if ($vb_unknown_is_set && sizeof($va_values) > 0) { $va_values['999999999'][_t('Date unknown')] = array('id' => 'null', 'label' => _t('Date unknown')); } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } ksort($va_values); if ($vs_dir == 'DESC') { $va_values = array_reverse($va_values); } $va_sorted_values = array(); foreach ($va_values as $vn_sort_value => $va_values_for_sort_value) { $va_sorted_values = array_merge($va_sorted_values, $va_values_for_sort_value); } return $va_sorted_values; } } else { // is intrinsic $vs_dir = strtoupper($va_facet_info['sort']) === 'DESC' ? "DESC" : "ASC"; $vs_browse_start_fld = $t_item->getFieldInfo($va_facet_info['element_code'], 'START'); $vs_browse_end_fld = $t_item->getFieldInfo($va_facet_info['element_code'], 'END'); $o_tep = new TimeExpressionParser(); $vn_min_date = $vn_max_date = null; $vs_min_sql = $vs_max_sql = ''; if (isset($va_facet_info['minimum_date'])) { if ($o_tep->parse($va_facet_info['minimum_date'])) { $va_tmp = $o_tep->getHistoricTimestamps(); $vn_min_date = (double) $va_tmp['start']; $vs_min_sql = " AND ({$vs_browse_table_name}.{$vs_browse_start_fld} >= {$vn_min_date})"; } } if (isset($va_facet_info['maximum_date'])) { if ($o_tep->parse($va_facet_info['maximum_date'])) { $va_tmp = $o_tep->getHistoricTimestamps(); $vn_max_date = (double) $va_tmp['end']; $vs_max_sql = " AND ({$vs_browse_table_name}.{$vs_browse_end_fld} <= {$vn_max_date})"; } } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t1 = 1\n\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\t\tLIMIT 1"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql); return (int) $qr_res->numRows() > 0 ? true : false; } else { $vs_sql = "\n\t\t\t\t\t\t\t\tSELECT DISTINCT {$vs_browse_table_name}.{$vs_browse_start_fld}, {$vs_browse_table_name}.{$vs_browse_end_fld}\n\t\t\t\t\t\t\t\tFROM {$vs_browse_table_name}\n\t\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t1 = 1\n\t\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql); $va_values = array(); while ($qr_res->nextRow()) { $vn_start = $qr_res->get($vs_browse_start_fld); $vn_end = $qr_res->get($vs_browse_end_fld); if (!($vn_start && $vn_end)) { continue; } $va_normalized_values = $o_tep->normalizeDateRange($vn_start, $vn_end, $vs_normalization); foreach ($va_normalized_values as $vn_sort_value => $vs_normalized_value) { if ($va_criteria[$vs_normalized_value]) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on if (is_numeric($vs_normalized_value) && (int) $vs_normalized_value === 0) { continue; } // don't include year=0 $va_values[$vn_sort_value][$vs_normalized_value] = array('id' => $vs_normalized_value, 'label' => $vs_normalized_value); if (!is_null($vs_single_value) && $vs_normalized_value == $vs_single_value) { $vb_single_value_is_present = true; } } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } ksort($va_values); if ($vs_dir == 'DESC') { $va_values = array_reverse($va_values); } $va_sorted_values = array(); foreach ($va_values as $vn_sort_value => $va_values_for_sort_value) { $va_sorted_values = array_merge($va_sorted_values, $va_values_for_sort_value); } return $va_sorted_values; } } break; # ----------------------------------------------------- # ----------------------------------------------------- case 'normalizedLength': $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true); $t_element = new ca_metadata_elements(); $vb_is_element = $vb_is_field = false; if (!($vb_is_element = $t_element->load(array('element_code' => $va_facet_info['element_code']))) && !($vb_is_field = $t_item->hasField($va_facet_info['element_code']) && $t_item->getFieldInfo($va_facet_info['element_code'], 'FIELD_TYPE') === FT_HISTORIC_DATERANGE)) { return array(); } if ($vb_is_element) { $va_joins = array('INNER JOIN ca_attribute_values ON ca_attributes.attribute_id = ca_attribute_values.attribute_id', 'INNER JOIN ' . $vs_browse_table_name . ' ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_attributes.row_id AND ca_attributes.table_num = ' . intval($vs_browse_table_num)); } else { $va_joins = array(); } $va_wheres = array(); $vs_normalization = $va_facet_info['normalization']; // how do we construct the dimensions ranges presented to users. In other words - what increments do we can to use to browse measurments? if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_item->hasField('access')) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($t_item->hasField('deleted')) { $va_wheres[] = "(" . $vs_browse_table_name . ".deleted = 0)"; } if ($va_facet_info['relative_to']) { if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_where_sql = ''; if (is_array($va_wheres) && sizeof($va_wheres) && ($vs_where_sql = join(' AND ', $va_wheres))) { $vs_where_sql = ' AND (' . $vs_where_sql . ')'; } $vs_join_sql = join("\n", $va_joins); $vn_element_id = $t_element->getPrimaryKey(); $vs_dir = strtoupper($va_facet_info['sort']) === 'DESC' ? "DESC" : "ASC"; $vs_min_sql = $vs_max_sql = ''; $vo_minimum_dimension = caParseLengthDimension(caGetOption('minimum_dimension', $va_facet_info, "0 in")); $vo_maximum_dimension = caParseLengthDimension(caGetOption('maximum_dimension', $va_facet_info, "0 in")); if ($vo_minimum_dimension) { $vn_tmp = (double) $vo_minimum_dimension->convertTo('METER', 6, 'en_US'); $vs_min_sql = " AND (ca_attribute_values.value_decimal1 >= {$vn_tmp})"; } if (caGetOption('maximum_dimension', $va_facet_info, null) && $vo_maximum_dimension) { $vn_tmp = (double) $vo_maximum_dimension->convertTo('METER', 6, 'en_US'); $vs_max_sql = " AND (ca_attribute_values.value_decimal1 <= {$vn_tmp})"; } if ($vb_check_availability_only) { $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\tca_attribute_values.element_id = ? \n\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t\t\tLIMIT 1"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql, $vn_element_id); return (int) $qr_res->numRows() > 0 ? true : false; } else { $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT ca_attribute_values.value_decimal1, ca_attribute_values.value_decimal2, ca_attribute_values.value_longtext1, ca_attribute_values.value_longtext2\n\t\t\t\t\t\t\tFROM ca_attributes\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\tca_attribute_values.element_id = ? \n\t\t\t\t\t\t\t\t{$vs_min_sql}\n\t\t\t\t\t\t\t\t{$vs_max_sql}\n\t\t\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t\t\t"; //print $vs_sql; $qr_res = $this->opo_db->query($vs_sql, $vn_element_id); $va_values = array(); if (!($vs_output_units = caGetLengthUnitType($vs_units = caGetOption('units', $va_facet_info, 'm')))) { $vs_output_units = Zend_Measure_Length::METER; } $vs_increment = caGetOption('increment', $va_facet_info, '1 m'); $vo_increment = caParseLengthDimension($vs_increment); $vn_increment_in_current_units = (double) $vo_increment->convertTo($vs_output_units, 6, 'en_US'); while ($qr_res->nextRow()) { $vn_meters = $qr_res->get('value_decimal1'); // measurement in meters // convert to target dimensions // normalize $vo_dim = new Zend_Measure_Length($vn_meters, Zend_Measure_Length::METER, 'en_US'); $vs_dim = $vo_dim->convertTo($vs_output_units, 6, 'en_US'); $vn_dim = (double) $vs_dim; $vn_normalized = floor($vn_dim / $vn_increment_in_current_units) * $vn_increment_in_current_units; if (isset($va_criteria[$vn_normalized])) { continue; } $vs_normalized_range_with_units = "{$vn_normalized} {$vs_units} - " . ($vn_normalized + $vn_increment_in_current_units) . " {$vs_units}"; $va_values[$vn_normalized][$vn_normalized] = array('id' => $vn_normalized, 'label' => $vs_normalized_range_with_units); if (!is_null($vs_single_value) && $vn_normalized == $vs_single_value) { $vb_single_value_is_present = true; } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } ksort($va_values); if ($vs_dir == 'DESC') { $va_values = array_reverse($va_values); } $va_sorted_values = array(); foreach ($va_values as $vn_sort_value => $va_values_for_sort_value) { $va_sorted_values = array_merge($va_sorted_values, $va_values_for_sort_value); } return $va_sorted_values; } break; # ----------------------------------------------------- # ----------------------------------------------------- case 'authority': $vs_rel_table_name = $va_facet_info['table']; $va_params = $this->opo_ca_browse_cache->getParameters(); // Make sure we honor type restrictions for the related authority $va_user_type_restrictions = caGetTypeRestrictionsForUser($vs_rel_table_name); $va_restrict_to_types = $va_facet_info['restrict_to_types']; if (is_array($va_user_type_restrictions)) { if (!is_array($va_restrict_to_types)) { $va_restrict_to_types = $va_user_type_restrictions; } else { $va_restrict_to_types = array_intersect($va_restrict_to_types, $va_user_type_restrictions); } } if (!is_array($va_exclude_types = $va_facet_info['exclude_types'])) { $va_exclude_types = array(); } if (!is_array($va_restrict_to_relationship_types = $va_facet_info['restrict_to_relationship_types'])) { $va_restrict_to_relationship_types = array(); } if (!is_array($va_exclude_relationship_types = $va_facet_info['exclude_relationship_types'])) { $va_exclude_relationship_types = array(); } $t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true); if ($vs_browse_table_name == $vs_rel_table_name) { // browsing on self-relations not supported break; } else { switch (sizeof($va_path = array_keys($this->opo_datamodel->getPath($vs_browse_table_name, $vs_rel_table_name)))) { case __CA_ATTRIBUTE_VALUE_LIST__: $t_item_rel = $this->opo_datamodel->getInstanceByTableName($va_path[1], true); $t_rel_item = $this->opo_datamodel->getInstanceByTableName($va_path[2], true); $vs_key = 'relation_id'; break; case __CA_ATTRIBUTE_VALUE_DATERANGE__: $t_item_rel = null; $t_rel_item = $this->opo_datamodel->getInstanceByTableName($va_path[1], true); $vs_key = $t_rel_item->primaryKey(); break; default: // bad related table return null; break; } } $vb_rel_is_hierarchical = (bool) $t_rel_item->isHierarchical(); // // Convert related item type_code specs in restrict_to_types and exclude_types lists to numeric type_ids we need for the query // if (!is_array($va_restrict_to_types = $this->_convertTypeCodesToIDs($va_restrict_to_types, array('instance' => $t_rel_item, 'dontExpandHierarchically' => true)))) { $va_restrict_to_types = array(); } if (!is_array($va_exclude_types = $this->_convertTypeCodesToIDs($va_exclude_types, array('instance' => $t_rel_item, 'dontExpandHierarchically' => true)))) { $va_exclude_types = array(); } $va_restrict_to_types_expanded = $this->_convertTypeCodesToIDs($va_restrict_to_types, array('instance' => $t_rel_item)); $va_exclude_types_expanded = $this->_convertTypeCodesToIDs($va_exclude_types, array('instance' => $t_rel_item)); // look up relationship type restrictions $va_restrict_to_relationship_types = $this->_getRelationshipTypeIDs($va_restrict_to_relationship_types, $va_facet_info['relationship_table']); $va_exclude_relationship_types = $this->_getRelationshipTypeIDs($va_exclude_relationship_types, $va_facet_info['relationship_table']); $va_joins = array(); $va_selects = array(); $va_wheres = array(); $va_orderbys = array(); if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) { $vs_cur_table = array_shift($va_path); foreach ($va_path as $vs_join_table) { $va_rel_info = $this->opo_datamodel->getRelationships($vs_cur_table, $vs_join_table); $va_joins[] = 'INNER JOIN ' . $vs_join_table . ' ON ' . $vs_cur_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][0] . ' = ' . $vs_join_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][1] . "\n"; $vs_cur_table = $vs_join_table; } } else { if ($va_facet_info['show_all_when_first_facet']) { $va_path = array_reverse($va_path); // in "show_all" mode we turn the browse on it's head and grab records by the "subject" table, rather than the browse table $vs_cur_table = array_shift($va_path); $vs_join_table = $va_path[0]; $va_rel_info = $this->opo_datamodel->getRelationships($vs_cur_table, $vs_join_table); $va_joins[] = 'LEFT JOIN ' . $vs_join_table . ' ON ' . $vs_cur_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][0] . ' = ' . $vs_join_table . '.' . $va_rel_info[$vs_cur_table][$vs_join_table][0][1] . "\n"; } } if (sizeof($va_results) && $this->numCriteria() > 0) { $va_wheres[] = "(" . $t_subject->tableName() . '.' . $t_subject->primaryKey() . " IN (" . join(',', $va_results) . "))"; } if (!is_array($va_restrict_to_lists = $va_facet_info['restrict_to_lists'])) { $va_restrict_to_lists = array(); } if (is_array($va_restrict_to_lists) && sizeof($va_restrict_to_lists) > 0 && $t_rel_item->tableName() == 'ca_list_items') { $va_list_ids = array(); foreach ($va_restrict_to_lists as $vm_list) { if (is_numeric($vm_list)) { $vn_list_id = (int) $vm_list; } else { $vn_list_id = (int) ca_lists::getListID($vm_list); } if ($vn_list_id) { $va_list_ids[] = $vn_list_id; } } if (sizeof($va_list_ids) > 0) { $va_wheres[] = "{$vs_rel_table_name}.list_id IN (" . join(',', $va_list_ids) . ")"; } } if (is_array($va_restrict_to_types) && sizeof($va_restrict_to_types) > 0 && method_exists($t_rel_item, "getTypeList")) { $va_wheres[] = "{$vs_rel_table_name}.type_id IN (" . join(',', caGetOption('dont_include_subtypes', $va_facet_info, false) ? $va_restrict_to_types : $va_restrict_to_types_expanded) . ")" . ($t_rel_item->getFieldInfo('type_id', 'IS_NULL') ? " OR ({$vs_rel_table_name}.type_id IS NULL)" : ''); $va_selects[] = "{$vs_rel_table_name}.type_id"; } if (is_array($va_exclude_types) && sizeof($va_exclude_types) > 0 && method_exists($t_rel_item, "getTypeList")) { $va_wheres[] = "{$vs_rel_table_name}.type_id NOT IN (" . join(',', caGetOption('dont_include_subtypes', $va_facet_info, false) ? $va_exclude_types : $va_exclude_types_expanded) . ")"; } if (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access')) { $va_wheres[] = "(" . $t_rel_item->tableName() . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; // exclude non-accessible authority items if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) { $va_wheres[] = "(" . $vs_browse_table_name . ".access IN (" . join(',', $pa_options['checkAccess']) . "))"; // exclude non-accessible browse items } } if ($t_item->hasField('deleted') && !$va_facet_info['show_all_when_first_facet']) { $va_wheres[] = "(" . $t_item->tableName() . ".deleted = 0)"; } if ($t_rel_item->hasField('deleted')) { $va_wheres[] = "(" . $t_rel_item->tableName() . ".deleted = 0)"; } $vs_rel_pk = $t_rel_item->primaryKey(); $va_rel_attr_elements = $t_rel_item->getApplicableElementCodes(null, true, false); $va_attrs_to_fetch = array(); if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) { //$va_selects[] = $t_item->tableName().'.'.$t_item->primaryKey(); // get primary key of subject } $va_selects[] = $t_rel_item->tableName() . '.' . $vs_rel_pk; // get primary key of related $vs_hier_parent_id_fld = $vs_hier_id_fld = null; if ($vb_rel_is_hierarchical) { $vs_hier_parent_id_fld = $t_rel_item->getProperty('HIERARCHY_PARENT_ID_FLD'); $va_selects[] = $t_rel_item->tableName() . '.' . $vs_hier_parent_id_fld; if ($vs_hier_id_fld = $t_rel_item->getProperty('HIERARCHY_ID_FLD')) { $va_selects[] = $t_rel_item->tableName() . '.' . $vs_hier_id_fld; } } // analyze group_fields (if defined) and add them to the query $va_groupings_to_fetch = array(); if (isset($va_facet_info['groupings']) && is_array($va_facet_info['groupings']) && sizeof($va_facet_info['groupings'])) { foreach ($va_facet_info['groupings'] as $vs_grouping => $vs_grouping_name) { // is grouping type_id? if ($vs_grouping === 'type' && $t_rel_item->hasField('type_id')) { $va_selects[] = $t_rel_item->tableName() . '.type_id'; $va_groupings_to_fetch[] = 'type_id'; } // is group field a relationship type? if ($vs_grouping === 'relationship_types') { $va_selects[] = $va_facet_info['relationship_table'] . '.type_id rel_type_id'; $va_groupings_to_fetch[] = 'rel_type_id'; } // is group field an attribute? if (preg_match('!^ca_attribute_([^:]*)!', $vs_grouping, $va_matches)) { if ($vn_element_id = array_search($va_matches[1], $va_rel_attr_elements)) { $va_attrs_to_fetch[] = $vn_element_id; } } } } if ($va_facet_info['relative_to']) { // TODO: do this everywhere $va_restrict_to_relationship_types = array(); $vs_browse_type_limit_sql = ''; if ($t_subject->hasField('deleted')) { $va_wheres[] = "(" . $t_subject->tableName() . ".deleted = 0)"; } if ($va_relative_sql_data = $this->_getRelativeFacetSQLData($va_facet_info['relative_to'], $pa_options)) { $va_joins = array_merge($va_joins, $va_relative_sql_data['joins']); $va_wheres = array_merge($va_wheres, $va_relative_sql_data['wheres']); } } if (sizeof($va_restrict_to_relationship_types) > 0 && is_object($t_item_rel)) { $va_wheres[] = $t_item_rel->tableName() . ".type_id IN (" . join(',', $va_restrict_to_relationship_types) . ")"; } if (sizeof($va_exclude_relationship_types) > 0 && is_object($t_item_rel)) { $va_wheres[] = $t_item_rel->tableName() . ".type_id NOT IN (" . join(',', $va_exclude_relationship_types) . ")"; } if ($vs_browse_type_limit_sql) { $va_wheres[] = $vs_browse_type_limit_sql; } if ($this->opo_config->get('perform_item_level_access_checking')) { if ($t_item = $this->opo_datamodel->getInstanceByTableName($vs_browse_table_name, true)) { // Join to limit what browse table items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl ON ' . $vs_browse_table_name . '.' . $t_item->primaryKey() . ' = ca_acl.row_id AND ca_acl.table_num = ' . $t_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(ca_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(ca_acl.user_id IS NULL and ca_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND ca_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR ca_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; // Join to limit what related items are used to generate facet $va_joins[] = 'LEFT JOIN ca_acl AS rel_acl ON ' . $t_rel_item->tableName() . '.' . $t_rel_item->primaryKey() . ' = rel_acl.row_id AND rel_acl.table_num = ' . $t_rel_item->tableNum() . "\n"; $va_wheres[] = "(\n\t\t\t\t\t\t\t\t((\n\t\t\t\t\t\t\t\t\t(rel_acl.user_id = " . (int) $vn_user_id . ")\n\t\t\t\t\t\t\t\t\t" . (sizeof($va_group_ids) > 0 ? "OR\n\t\t\t\t\t\t\t\t\t(rel_acl.group_id IN (" . join(",", $va_group_ids) . "))" : "") . "\n\t\t\t\t\t\t\t\t\tOR\n\t\t\t\t\t\t\t\t\t(rel_acl.user_id IS NULL and rel_acl.group_id IS NULL)\n\t\t\t\t\t\t\t\t) AND rel_acl.access >= " . __CA_ACL_READONLY_ACCESS__ . ")\n\t\t\t\t\t\t\t\t" . ($vb_show_if_no_acl ? "OR rel_acl.acl_id IS NULL" : "") . "\n\t\t\t\t\t\t\t)"; } } $vs_join_sql = join("\n", $va_joins); if ($vb_check_availability_only) { if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) { $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t" . (sizeof($va_wheres) ? ' WHERE ' : '') . join(" AND ", $va_wheres) . " LIMIT 1"; } else { $vs_sql = "\n\t\t\t\t\t\t\tSELECT 1\n\t\t\t\t\t\t\tFROM " . $t_rel_item->tableName() . "\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t" . (sizeof($va_wheres) ? ' WHERE ' : '') . join(" AND ", $va_wheres) . " LIMIT 1"; } $qr_res = $this->opo_db->query($vs_sql); //print "<hr>$vs_sql<hr>\n"; return (int) $qr_res->numRows() > 0 ? true : false; } else { if (!$va_facet_info['show_all_when_first_facet'] || $this->numCriteria() > 0) { $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT " . join(', ', $va_selects) . "\n\t\t\t\t\t\t\tFROM " . $vs_browse_table_name . "\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t" . (sizeof($va_wheres) ? ' WHERE ' : '') . join(" AND ", $va_wheres) . "\n\t\t\t\t\t\t\t\t" . (sizeof($va_orderbys) ? "ORDER BY " . join(', ', $va_orderbys) : ''); } else { $vs_sql = "\n\t\t\t\t\t\t\tSELECT DISTINCT " . join(', ', $va_selects) . "\n\t\t\t\t\t\t\tFROM " . $t_rel_item->tableName() . "\n\t\t\t\t\t\t\t{$vs_join_sql}\n\t\t\t\t\t\t\t\t" . (sizeof($va_wheres) ? ' WHERE ' : '') . join(" AND ", $va_wheres) . "\n\t\t\t\t\t\t\t\t" . (sizeof($va_orderbys) ? "ORDER BY " . join(', ', $va_orderbys) : ''); } //print "<hr>$vs_sql<hr>\n"; $qr_res = $this->opo_db->query($vs_sql); $va_facet = $va_facet_items = array(); $vs_rel_pk = $t_rel_item->primaryKey(); // First get related ids with type and relationship type values // (You could get all of the data we need for the facet in a single query but it turns out to be faster for very large facets to // do it in separate queries, one for the primary ids and another for the labels; a third is done if attributes need to be fetched. // There appears to be a significant [~10%] performance for smaller facets and a larger one [~20-25%] for very large facets) $vn_max_level = caGetOption('maximum_levels', $va_facet_info, null); while ($qr_res->nextRow()) { $va_fetched_row = $qr_res->getRow(); $vn_id = $va_fetched_row[$vs_rel_pk]; //if (isset($va_facet_items[$vn_id])) { continue; } --- we can't do this as then we don't detect items that have multiple rel_type_ids... argh. if (isset($va_criteria[$vn_id])) { continue; } // skip items that are used as browse critera - don't want to browse on something you're already browsing on if (!$va_facet_items[$va_fetched_row[$vs_rel_pk]]) { // if(!is_null($vn_max_level)) { // if (sizeof($va_ancestors) + 1 > $vn_max_level) { // if ($va_tmp = $va_ancestors[sizeof($va_ancestors) - $vn_max_level]) { // $va_ancestors = array(); // $va_fetched_row = $va_tmp['NODE']; // } // } // } if (is_array($va_restrict_to_types) && sizeof($va_restrict_to_types) && $va_fetched_row['type_id'] && !in_array($va_fetched_row['type_id'], $va_restrict_to_types)) { continue; } $va_facet_items[$va_fetched_row[$vs_rel_pk]] = array('id' => $va_fetched_row[$vs_rel_pk], 'type_id' => array(), 'parent_id' => $vb_rel_is_hierarchical ? $va_fetched_row[$vs_hier_parent_id_fld] : null, 'hierarchy_id' => $vb_rel_is_hierarchical ? $va_fetched_row[$vs_hier_id_fld] : null, 'rel_type_id' => array(), 'child_count' => 0); if (!is_null($vs_single_value) && $va_fetched_row[$vs_rel_pk] == $vs_single_value) { $vb_single_value_is_present = true; } } if ($va_fetched_row['type_id']) { $va_facet_items[$va_fetched_row[$vs_rel_pk]]['type_id'][] = $va_fetched_row['type_id']; } if ($va_fetched_row['rel_type_id']) { $va_facet_items[$va_fetched_row[$vs_rel_pk]]['rel_type_id'][] = $va_fetched_row['rel_type_id']; } } if (!isset($va_facet_info['dont_expand_hierarchically']) || !$va_facet_info['dont_expand_hierarchically']) { $qr_res->seek(0); $va_ids = $qr_res->getAllFieldValues($vs_rel_pk); $qr_ancestors = call_user_func($t_rel_item->tableName() . '::getHierarchyAncestorsForIDs', $va_ids, array('returnAs' => 'SearchResult')); $vs_rel_table = $t_rel_item->tableName(); $vs_rel_pk = $t_rel_item->primaryKey(); $vb_check_ancestor_access = (bool) (isset($pa_options['checkAccess']) && is_array($pa_options['checkAccess']) && sizeof($pa_options['checkAccess']) && $t_rel_item->hasField('access')); if ($qr_ancestors) { while ($qr_ancestors->nextHit()) { $vn_parent_type_id = $qr_ancestors->get('type_id'); if (sizeof($va_exclude_types) > 0 && in_array($vn_parent_type_id, $va_exclude_types)) { continue; } if (sizeof($va_restrict_to_types) > 0 && !in_array($vn_parent_type_id, $va_restrict_to_types)) { continue; } if ($vb_check_ancestor_access && !in_array($qr_ancestors->get('access'), $pa_options['checkAccess'])) { continue; } $va_facet_items[$vn_ancestor_id = (int) $qr_ancestors->get("{$vs_rel_pk}")] = array('id' => $vn_ancestor_id, 'type_id' => array(), 'parent_id' => $vb_rel_is_hierarchical ? $qr_ancestors->get("{$vs_hier_parent_id_fld}") : null, 'hierarchy_id' => $vb_rel_is_hierarchical && $vs_hier_id_fld ? $qr_ancestors->get($vs_hier_id_fld) : null, 'rel_type_id' => array(), 'child_count' => 0); } } } // Set child counts foreach ($va_facet_items as $vn_i => $va_item) { if ($va_item['parent_id'] && isset($va_facet_items[$va_item['parent_id']])) { $va_facet_items[$va_item['parent_id']]['child_count']++; } } // Get labels for facet items if (sizeof($va_row_ids = array_keys($va_facet_items))) { if ($vs_label_table_name = $t_rel_item->getLabelTableName()) { $t_rel_item_label = $this->opo_datamodel->getInstanceByTableName($vs_label_table_name, true); $vs_label_display_field = $t_rel_item_label->getDisplayField(); $vs_rel_pk = $t_rel_item->primaryKey(); $va_label_wheres = array(); if ($t_rel_item_label->hasField('is_preferred')) { $va_label_wheres[] = "({$vs_label_table_name}.is_preferred = 1)"; } $va_label_wheres[] = "({$vs_label_table_name}.{$vs_rel_pk} IN (" . join(",", $va_row_ids) . "))"; $va_label_selects[] = "{$vs_label_table_name}.{$vs_rel_pk}"; $va_label_selects[] = "{$vs_label_table_name}.locale_id"; $va_label_fields = $t_rel_item->getLabelUIFields(); foreach ($va_label_fields as $vs_label_field) { $va_label_selects[] = "{$vs_label_table_name}.{$vs_label_field}"; } // Get label ordering fields $va_ordering_fields_to_fetch = isset($va_facet_info['order_by_label_fields']) && is_array($va_facet_info['order_by_label_fields']) ? $va_facet_info['order_by_label_fields'] : array(); $va_orderbys = array(); foreach ($va_ordering_fields_to_fetch as $vs_sort_by_field) { if (!$t_rel_item_label->hasField($vs_sort_by_field)) { continue; } $va_orderbys[] = $va_label_selects[] = $vs_label_table_name . '.' . $vs_sort_by_field; } // get labels $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT " . join(', ', $va_label_selects) . "\n\t\t\t\t\t\t\t\t\tFROM " . $vs_label_table_name . "\n\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_label_wheres) ? ' WHERE ' : '') . join(" AND ", $va_label_wheres) . "\n\t\t\t\t\t\t\t\t\t\t" . (sizeof($va_orderbys) ? "ORDER BY " . join(', ', $va_orderbys) : '') . ""; //print $vs_sql; $qr_labels = $this->opo_db->query($vs_sql); while ($qr_labels->nextRow()) { $va_fetched_row = $qr_labels->getRow(); $va_facet_item = array_merge($va_facet_items[$va_fetched_row[$vs_rel_pk]], array('label' => $va_fetched_row[$vs_label_display_field])); foreach ($va_ordering_fields_to_fetch as $vs_to_fetch) { $va_facet_item[$vs_to_fetch] = $va_fetched_row[$vs_to_fetch]; } $va_facet[$va_fetched_row[$vs_rel_pk]][$va_fetched_row['locale_id']] = $va_facet_item; } } // get attributes for facet items if (sizeof($va_attrs_to_fetch)) { $qr_attrs = $this->opo_db->query("\n\t\t\t\t\t\t\t\t\tSELECT c_av.*, c_a.locale_id, c_a.row_id\n\t\t\t\t\t\t\t\t\tFROM ca_attributes c_a\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_attribute_values c_av ON c_a.attribute_id = c_av.attribute_id\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\tc_av.element_id IN (" . join(',', $va_attrs_to_fetch) . ")\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\tc_a.table_num = ? \n\t\t\t\t\t\t\t\t\t\tAND \n\t\t\t\t\t\t\t\t\t\tc_a.row_id IN (" . join(',', $va_row_ids) . ")\n\t\t\t\t\t\t\t\t", $t_rel_item->tableNum()); while ($qr_attrs->nextRow()) { $va_fetched_row = $qr_attrs->getRow(); $vn_id = $va_fetched_row['row_id']; // if no locale is set for the attribute default it to whatever the locale for the item is if (!($vn_locale_id = $va_fetched_row['locale_id'])) { $va_tmp = array_keys($va_facet[$vn_id]); $vn_locale_id = $va_tmp[0]; } $va_facet[$vn_id][$vn_locale_id]['ca_attribute_' . $va_fetched_row['element_id']][] = $va_fetched_row; } } } if (!is_null($vs_single_value) && !$vb_single_value_is_present) { return array(); } return caExtractValuesByUserLocale($va_facet); } break; # ----------------------------------------------------- # ----------------------------------------------------- default: return null; break; # ----------------------------------------------------- } }
/** * */ public function getElementsForForm($pa_options = null) { $va_placements = $this->getPlacements(); $t_element = new ca_metadata_elements(); $va_elements = array(); foreach ($va_placements as $vn_i => $va_placement) { $va_tmp = explode('.', $va_placement['bundle_name']); if ($t_element->load(array('element_code' => $va_tmp[1]))) { if ($t_element->get('datatype') > 0) { $va_elements[] = $va_placement['bundle_name']; } if (sizeof($va_sub_elements = $t_element->getElementsInSet()) > 1) { foreach ($va_sub_elements as $vn_element_id => $va_element_info) { if ($va_tmp[1] == $va_element_info['element_code']) { continue; } $va_elements[] = $va_tmp[0] . '.' . $va_element_info['element_code']; } } } else { $va_elements[] = $va_placement['bundle_name']; } } return $va_elements; }
$va_types = $this->getVar('type_list'); $va_relationship_types = $this->getVar('relationship_type_list'); if (!is_array($va_other_params = $this->getVar('other_parameters'))) { $va_other_params = array(); } $vs_grouping_field = $this->getVar('grouping'); if ((!isset($va_facet_info['groupings'][$vs_grouping_field]) || !$va_facet_info['groupings'][$vs_grouping_field]) && is_array($va_facet_info['groupings'])) { $va_tmp = array_keys($va_facet_info['groupings']); $vs_grouping_field = $va_tmp[0]; } $vn_element_datatype = null; if ($vs_grouping_attribute_element_code = preg_match('!^ca_attribute_([\\w]+)!', $vs_grouping_field, $va_matches) ? $va_matches[1] : null) { $t_element = new ca_metadata_elements(); $t_element->load(array('element_code' => $vs_grouping_attribute_element_code)); $vn_grouping_attribute_id = $t_element->getPrimaryKey(); $vn_element_datatype = $t_element->get('datatype'); } $vs_group_mode = $this->getVar('group_mode'); if (!$va_facet || !$vs_facet_name) { print 'No facet defined'; return; } if (!($vm_modify_id = $this->getVar('modify'))) { $vm_modify_id = '0'; } ?> <div id="facetList"> <div id="facetTitle"> <?php print caNavLink($this->request, _t('start over') . " ›", '', '', 'Browse', 'clearCriteria', array()); ?>
private function _doQueriesForSqlSearch($po_rewritten_query, $pn_subject_tablenum, $ps_dest_table, $pn_level = 0, $pa_options = null) { // query is always of type Zend_Search_Lucene_Search_Query_Boolean $vn_i = 0; switch (get_class($po_rewritten_query)) { case 'Zend_Search_Lucene_Search_Query_MultiTerm': $va_elements = $po_rewritten_query->getTerms(); break; default: $va_elements = $po_rewritten_query->getSubqueries(); break; } $o_base = new SearchBase(); $va_old_signs = $po_rewritten_query->getSigns(); foreach ($va_elements as $o_lucene_query_element) { $vb_is_blank_search = false; if (is_null($va_old_signs)) { // if array is null then according to Zend Lucene all subqueries should be "are required"... so we AND them $vs_op = "AND"; } else { if (is_null($va_old_signs[$vn_i])) { // is the sign for a particular query is null then OR is (it is "neither required nor prohibited") $vs_op = 'OR'; } else { $vs_op = $va_old_signs[$vn_i] === false ? 'NOT' : 'AND'; // true sign indicated "required" (AND) operation, false indicated "prohibited" (NOT) operation } } if ($vn_i == 0) { $vs_op = 'OR'; } $va_direct_query_temp_tables = array(); // List of temporary tables created by direct search queries; tables listed here are dropped at the end of processing for the query element $pa_direct_sql_query_params = null; // set to array with values to use with direct SQL query placeholders or null to pass single standard table_num value as param (most queries just need this single value) $vs_direct_sql_query = null; $vn_direct_sql_target_table_num = $pn_subject_tablenum; switch ($vs_class = get_class($o_lucene_query_element)) { case 'Zend_Search_Lucene_Search_Query_Boolean': case 'Zend_Search_Lucene_Search_Query_MultiTerm': $this->_createTempTable('ca_sql_search_temp_' . $pn_level); if ($vs_op == 'AND' && $vn_i == 0) { $this->_doQueriesForSqlSearch($o_lucene_query_element, $pn_subject_tablenum, $ps_dest_table, $pn_level + 1); } else { $this->_doQueriesForSqlSearch($o_lucene_query_element, $pn_subject_tablenum, 'ca_sql_search_temp_' . $pn_level, $pn_level + 1); } // merge with current destination switch ($vs_op) { case 'AND': if ($vn_i > 0) { $this->_createTempTable("{$ps_dest_table}_acc"); $vs_sql = "\n\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}_acc\n\t\t\t\t\t\t\t\t\tSELECT mfs.row_id, SUM(mfs.boost)\n\t\t\t\t\t\t\t\t\tFROM {$ps_dest_table} mfs\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_temp_{$pn_level} AS ftmp1 ON ftmp1.row_id = mfs.row_id\n\t\t\t\t\t\t\t\t\tGROUP BY mfs.row_id\n\t\t\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql); $qr_res = $this->opo_db->query("TRUNCATE TABLE {$ps_dest_table}"); $qr_res = $this->opo_db->query("INSERT INTO {$ps_dest_table} SELECT row_id, boost FROM {$ps_dest_table}_acc"); $this->_dropTempTable("{$ps_dest_table}_acc"); } break; case 'NOT': $qr_res = $this->opo_db->query("SELECT row_id FROM ca_sql_search_temp_{$pn_level}"); if (is_array($va_ids = $qr_res->getAllFieldValues()) && sizeof($va_ids)) { $vs_sql = "\n\t\t\t\t\t\t\t\t\tDELETE FROM {$ps_dest_table} WHERE row_id IN (?)\n\t\t\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql, array($va_ids)); } break; default: case 'OR': $vs_sql = "\n\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}\n\t\t\t\t\t\t\t\tSELECT row_id, SUM(boost)\n\t\t\t\t\t\t\t\tFROM ca_sql_search_temp_{$pn_level}\n\t\t\t\t\t\t\t\tGROUP BY row_id\n\t\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql); break; } $vn_i++; $this->_dropTempTable('ca_sql_search_temp_' . $pn_level); break; case 'Zend_Search_Lucene_Search_Query_Term': case 'Zend_Search_Lucene_Index_Term': case 'Zend_Search_Lucene_Search_Query_Phrase': case 'Zend_Search_Lucene_Search_Query_Range': $va_ft_terms = array(); $va_ft_like_terms = array(); $va_ft_stem_terms = array(); $vs_access_point = ''; $va_raw_terms = array(); switch (get_class($o_lucene_query_element)) { case 'Zend_Search_Lucene_Search_Query_Range': $va_lower_term = $o_lucene_query_element->getLowerTerm(); $va_upper_term = $o_lucene_query_element->getUpperTerm(); $va_element = $this->_getElementIDForAccessPoint($pn_subject_tablenum, $va_lower_term->field); $vn_direct_sql_target_table_num = $va_element['table_num']; $va_indexed_fields = $o_base->getFieldsToIndex($pn_subject_tablenum, $vn_direct_sql_target_table_num); $vn_root_element_id = $va_element['element_info']['hier_element_id']; if (!isset($va_indexed_fields['_ca_attribute_' . $va_element['element_id']]) && (!$vn_root_element_id || $vn_root_element_id && !isset($va_indexed_fields['_ca_attribute_' . $vn_root_element_id]))) { break 2; } // skip if not indexed switch ($va_element['datatype']) { case __CA_ATTRIBUTE_VALUE_GEOCODE__: $t_geocode = new GeocodeAttributeValue(); $va_parsed_value = $t_geocode->parseValue('[' . $va_lower_term->text . ']', $va_element['element_info']); $vs_lower_lat = $va_parsed_value['value_decimal1']; $vs_lower_long = $va_parsed_value['value_decimal2']; $va_parsed_value = $t_geocode->parseValue('[' . $va_upper_term->text . ']', $va_element['element_info']); $vs_upper_lat = $va_parsed_value['value_decimal1']; $vs_upper_long = $va_parsed_value['value_decimal2']; // mysql BETWEEN always wants the lower value first ... BETWEEN 5 AND 3 wouldn't match 4 ... So we swap the values if necessary if ($vs_upper_lat < $vs_lower_lat) { $tmp = $vs_upper_lat; $vs_upper_lat = $vs_lower_lat; $vs_lower_lat = $tmp; } if ($vs_upper_long < $vs_lower_long) { $tmp = $vs_upper_long; $vs_upper_long = $vs_lower_long; $vs_lower_long = $tmp; } $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t(cav.element_id = " . intval($va_element['element_id']) . ") AND (ca.table_num = ?)\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($vs_lower_lat) . " AND " . floatval($vs_upper_lat) . ")\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal2 BETWEEN " . floatval($vs_lower_long) . " AND " . floatval($vs_upper_long) . ")\t\n\t\t\t\t\t\t\t\t\t"; break; case __CA_ATTRIBUTE_VALUE_CURRENCY__: $t_cur = new CurrencyAttributeValue(); $va_parsed_value = $t_cur->parseValue($va_lower_term->text, $va_element['element_info']); $vs_currency = preg_replace('![^A-Z0-9]+!', '', $va_parsed_value['value_longtext1']); $vn_lower_val = $va_parsed_value['value_decimal1']; $va_parsed_value = $t_cur->parseValue($va_upper_term->text, $va_element['element_info']); $vn_upper_val = $va_parsed_value['value_decimal1']; $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t(cav.element_id = " . intval($va_element['element_id']) . ") AND (ca.table_num = ?)\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($vn_lower_val) . " AND " . floatval($vn_upper_val) . ")\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_longtext1 = '" . $this->opo_db->escape($vs_currency) . "')\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t"; break; case __CA_ATTRIBUTE_VALUE_TIMECODE__: $t_timecode = new TimecodeAttributeValue(); $va_parsed_value = $t_timecode->parseValue($va_lower_term->text, $va_element['element_info']); $vn_lower_val = $va_parsed_value['value_decimal1']; $va_parsed_value = $t_timecode->parseValue($va_upper_term->text, $va_element['element_info']); $vn_upper_val = $va_parsed_value['value_decimal1']; break; case __CA_ATTRIBUTE_VALUE_LENGTH__: $t_len = new LengthAttributeValue(); $va_parsed_value = $t_len->parseValue($va_lower_term->text, $va_element['element_info']); $vn_lower_val = $va_parsed_value['value_decimal1']; $va_parsed_value = $t_len->parseValue($va_upper_term->text, $va_element['element_info']); $vn_upper_val = $va_parsed_value['value_decimal1']; break; case __CA_ATTRIBUTE_VALUE_WEIGHT__: $t_weight = new WeightAttributeValue(); $va_parsed_value = $t_weight->parseValue($va_lower_term->text, $va_element['element_info']); $vn_lower_val = $va_parsed_value['value_decimal1']; $va_parsed_value = $t_weight->parseValue($va_upper_term->text, $va_element['element_info']); $vn_upper_val = $va_parsed_value['value_decimal1']; break; case __CA_ATTRIBUTE_VALUE_INTEGER__: $vn_lower_val = intval($va_lower_term->text); $vn_upper_val = intval($va_upper_term->text); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t\t(cav.element_id = " . intval($va_element['element_id']) . ") AND (ca.table_num = ?)\n\t\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t\t(cav.value_integer1 BETWEEN " . floatval($vn_lower_val) . " AND " . floatval($vn_upper_val) . ")\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t"; break; case __CA_ATTRIBUTE_VALUE_NUMERIC__: $vn_lower_val = floatval($va_lower_term->text); $vn_upper_val = floatval($va_upper_term->text); break; } if (!$vs_direct_sql_query) { $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t(cav.element_id = " . intval($va_element['element_id']) . ") AND (ca.table_num = ?)\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($vn_lower_val) . " AND " . floatval($vn_upper_val) . ")\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t"; } break; case 'Zend_Search_Lucene_Search_Query_Phrase': if ($this->getOption('strictPhraseSearching')) { $vs_search_tokenizer_regex = $this->opo_search_config->get('search_tokenizer_regex'); $va_words = array(); foreach ($o_lucene_query_element->getQueryTerms() as $o_term) { if (!$vs_access_point && ($vs_field = $o_term->field)) { $vs_access_point = $vs_field; } $va_terms = preg_split("![{$vs_search_tokenizer_regex}]+!u", (string) $o_term->text); $va_raw_terms[] = (string) $o_term->text; foreach ($va_terms as $vs_term) { if (strlen($vs_escaped_text = $this->opo_db->escape($vs_term))) { $va_words[] = $vs_escaped_text; } } } if (!sizeof($va_words)) { continue 3; } $va_ap_tmp = explode(".", $vs_access_point); $vn_fld_table = $vn_fld_num = null; if (sizeof($va_ap_tmp) >= 2) { $va_element = $this->_getElementIDForAccessPoint($pn_subject_tablenum, $vs_access_point); if ($va_element) { $vs_fld_num = $va_element['field_num']; $vs_fld_table_num = $va_element['table_num']; $vs_fld_limit_sql = " AND (swi.field_table_num = {$vs_fld_table_num} AND swi.field_num = '{$vs_fld_num}')"; if (is_array($va_element['relationship_type_ids']) && sizeof($va_element['relationship_type_ids'])) { $vs_fld_limit_sql .= " AND (swi.rel_type_id IN (" . join(",", $va_element['relationship_type_ids']) . "))"; } } } $va_temp_tables = array(); $vn_w = 0; foreach ($va_words as $vs_word) { $vn_w++; $vs_temp_table = 'ca_sql_search_phrase_' . md5($pn_subject_tablenum . "/" . $vs_word . "/" . $vn_w); $this->_createTempTable($vs_temp_table); $vs_sql = "\n\t\t\t\t\t\t\t\t\tINSERT INTO {$vs_temp_table}\n\t\t\t\t\t\t\t\t\tSELECT swi.index_id + 1, 1\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_words sw \n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_word_index AS swi ON sw.word_id = swi.word_id \n\t\t\t\t\t\t\t\t\t" . (sizeof($va_temp_tables) ? " INNER JOIN " . $va_temp_tables[sizeof($va_temp_tables) - 1] . " AS tt ON swi.index_id = tt.row_id" : "") . "\n\t\t\t\t\t\t\t\t\tWHERE \n\t\t\t\t\t\t\t\t\t\tsw.word = ? AND swi.table_num = ? {$vs_fld_limit_sql}\n \t\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : '') . "\n\t\t\t\t\t\t\t\t"; $qr_res = $this->opo_db->query($vs_sql, $vs_word, (int) $pn_subject_tablenum); $qr_count = $this->opo_db->query("SELECT count(*) c FROM {$vs_temp_table}"); if (!$qr_count->nextRow() || !(int) $qr_count->get('c')) { foreach ($va_temp_tables as $vs_temp_table) { $this->_dropTempTable($vs_temp_table); } break 2; } $va_temp_tables[] = $vs_temp_table; } $vs_results_temp_table = array_pop($va_temp_tables); $this->opo_db->query("UPDATE {$vs_results_temp_table} SET row_id = row_id - 1"); $va_direct_query_temp_tables[$vs_results_temp_table] = true; $vs_direct_sql_query = "SELECT swi.row_id, ca.boost \n\t\t\t\t\t\t\t\t\t\t\t\t\tFROM {$vs_results_temp_table} ca\n\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_word_index AS swi ON swi.index_id = ca.row_id \n\t\t\t\t\t\t\t"; $pa_direct_sql_query_params = array(); // don't pass any params foreach ($va_temp_tables as $vs_temp_table) { $this->_dropTempTable($vs_temp_table); } break; } default: switch ($vs_class) { case 'Zend_Search_Lucene_Search_Query_Phrase': $va_term_objs = $o_lucene_query_element->getQueryTerms(); break; case 'Zend_Search_Lucene_Index_Term': $va_term_objs = array($o_lucene_query_element); break; default: $va_term_objs = array($o_lucene_query_element->getTerm()); break; } foreach ($va_term_objs as $o_term) { $va_access_point_info = $this->_getElementIDForAccessPoint($pn_subject_tablenum, $o_term->field); $vs_access_point = $va_access_point_info['access_point']; $vs_term = $o_term->text; if ($vs_access_point && mb_strtoupper($vs_term) == _t('[BLANK]')) { $t_ap = $this->opo_datamodel->getInstanceByTableNum($va_access_point_info['table_num'], true); if (is_a($t_ap, 'BaseLabel')) { // labels have the literal text "[Blank]" indexed to "blank" to indicate blank-ness $vb_is_blank_search = false; $vs_term = _t('blank'); } else { $vb_is_blank_search = true; break; } } $va_terms = array($vs_term); //$this->_tokenize($vs_term, true, $vn_i); $vb_has_wildcard = (bool) preg_match('!\\*$!', $vs_term); $vb_output_term = false; foreach ($va_terms as $vs_term) { if ($vb_has_wildcard) { $vs_term .= '*'; } if (in_array(trim(mb_strtolower($vs_term, 'UTF-8')), WLPlugSearchEngineSqlSearch::$s_stop_words)) { continue; } $vs_stripped_term = preg_replace('!\\*+$!u', '', $vs_term); if ($vb_has_wildcard) { $va_ft_like_terms[] = $vs_stripped_term; } else { // do stemming $vb_do_stemming = $this->opb_do_stemming; if (mb_substr($vs_term, -1) == '|') { $vs_term = mb_substr($vs_term, 0, mb_strlen($vs_term) - 1); $vb_do_stemming = false; } if ($vb_do_stemming) { $vs_to_stem = preg_replace('!\\*$!u', '', $vs_term); if (!preg_match('!y$!u', $vs_to_stem) && !preg_match('![0-9]+!', $vs_to_stem)) { // don't stem things ending in 'y' as that can cause problems (eg "Bowery" becomes "Boweri") if (!($vs_stem = trim($this->opo_stemmer->stem($vs_to_stem)))) { $vs_stem = (string) $vs_term; } $va_ft_stem_terms[] = "'" . $this->opo_db->escape($vs_stem) . "'"; } else { $va_ft_terms[] = '"' . $this->opo_db->escape($vs_term) . '"'; } } else { $va_ft_terms[] = '"' . $this->opo_db->escape($vs_term) . '"'; } } $vb_output_term = true; } if ($vb_output_term) { $va_raw_terms[] = $vs_term; } } break; } $vs_fld_num = $vs_table_num = $t_table = null; $vb_ft_bit_optimization = false; if ($vs_access_point) { list($vs_table, $vs_field, $vs_sub_field) = explode('.', $vs_access_point); if (in_array($vs_table, array('created', 'modified'))) { $o_tep = new TimeExpressionParser(); $vs_date = join(' ', $va_raw_terms); if (!$o_tep->parse($vs_date)) { break; } $va_range = $o_tep->getUnixTimestamps(); $vn_user_id = null; if ($vs_field = trim($vs_field)) { if (!is_int($vs_field)) { $t_user = new ca_users(); if ($t_user->load(array("user_name" => $vs_field))) { $vn_user_id = (int) $t_user->getPrimaryKey(); } } else { $vn_user_id = (int) $vs_field; } } $vs_user_sql = $vn_user_id ? " AND (ccl.user_id = " . (int) $vn_user_id . ")" : ""; switch ($vs_table) { case 'created': $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\tSELECT ccl.logged_row_id row_id, 1\n\t\t\t\t\t\t\t\t\t\t\tFROM ca_change_log ccl\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(ccl.log_datetime BETWEEN " . (int) $va_range['start'] . " AND " . (int) $va_range['end'] . ")\n\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(ccl.logged_table_num = ?)\n\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(ccl.changetype = 'I')\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_user_sql}\n\t\t\t\t\t\t\t\t\t\t"; break; case 'modified': $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\tSELECT ccl.logged_row_id row_id, 1\n\t\t\t\t\t\t\t\t\t\t\tFROM ca_change_log ccl\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(ccl.log_datetime BETWEEN " . (int) $va_range['start'] . " AND " . (int) $va_range['end'] . ")\n\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(ccl.logged_table_num = ?)\n\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(ccl.changetype = 'U')\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_user_sql}\n\t\t\t\t\t\t\t\t\t\tUNION\n\t\t\t\t\t\t\t\t\t\t\tSELECT ccls.subject_row_id row_id, 1\n\t\t\t\t\t\t\t\t\t\t\tFROM ca_change_log ccl\n\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_change_log_subjects AS ccls ON ccls.log_id = ccl.log_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(ccl.log_datetime BETWEEN " . (int) $va_range['start'] . " AND " . (int) $va_range['end'] . ")\n\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(ccls.subject_table_num = {$pn_subject_tablenum})\n\t\t\t\t\t\t\t\t\t\t\t\t{$vs_user_sql}\n\t\t\t\t\t\t\t\t\t\t"; break; } } else { if ($vs_table && $vs_field && ($t_table = $this->opo_datamodel->getInstanceByTableName($vs_table, true))) { $vs_table_num = $t_table->tableNum(); if (is_numeric($vs_field)) { $vs_fld_num = 'I' . $vs_field; $vn_fld_num = (int) $vs_field; } else { $vn_fld_num = $this->getFieldNum($vs_table, $vs_field); $vs_fld_num = 'I' . $vn_fld_num; $vn_direct_sql_target_table_num = $vs_table_num; if (!strlen($vn_fld_num)) { $t_element = new ca_metadata_elements(); if ($t_element->load(array('element_code' => $vs_sub_field ? $vs_sub_field : $vs_field))) { $va_indexed_fields = $o_base->getFieldsToIndex($pn_subject_tablenum, $vn_direct_sql_target_table_num); $vn_fld_num = $t_element->getPrimaryKey(); $vn_root_element_id = $t_element->get('hier_element_id'); if (!isset($va_indexed_fields['_ca_attribute_' . $vn_fld_num]) && (!$vn_root_element_id || $vn_root_element_id && !isset($va_indexed_fields['_ca_attribute_' . $vn_root_element_id]))) { break 2; } // skip if not indexed $vs_fld_num = 'A' . $vn_fld_num; if (!$vb_is_blank_search) { // // For certain types of attributes we can directly query the // attributes in the database rather than using the full text index // This allows us to do "intelligent" querying... for example on date ranges // parsed from natural language input and for length dimensions using unit conversion // switch ($t_element->get('datatype')) { case __CA_ATTRIBUTE_VALUE_DATERANGE__: $vb_all_numbers = true; foreach ($va_raw_terms as $vs_term) { if (!is_numeric($vs_term)) { $vb_all_numbers = false; break; } } $vs_raw_term = join(' ', $va_raw_terms); $vb_exact = $vs_raw_term[0] == "#" ? true : false; // dates prepended by "#" are considered "exact" or "contained - the matched dates must be wholly contained by the search term if ($vb_exact) { $vs_raw_term = substr($vs_raw_term, 1); if ($this->opo_tep->parse($vs_raw_term)) { $va_dates = $this->opo_tep->getHistoricTimestamps(); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\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\t\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\t\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\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\n\t\t\t\t\t\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\t\t\t\t\t(cav.value_decimal2 BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\n\t\t\t\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\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; } } else { if ($this->opo_tep->parse($vs_raw_term)) { $va_dates = $this->opo_tep->getHistoricTimestamps(); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\t\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\t\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\t\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\t\t\t\t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(cav.value_decimal1 BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\n\t\t\t\t\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\t\t\t\t(cav.value_decimal2 BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\n\t\t\t\t\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\t\t\t\t(cav.value_decimal1 <= " . floatval($va_dates['start']) . " AND cav.value_decimal2 >= " . floatval($va_dates['end']) . ")\t\n\t\t\t\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\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; } } break; case __CA_ATTRIBUTE_VALUE_GEOCODE__: // At this point $va_raw_terms has been tokenized by Lucene into oblivion // and is also dependent on the search_tokenizer_regex so we can't really do anything with it. // We now build our own un-tokenized term array instead. caParseGISSearch() can handle it. $va_gis_terms = array(); foreach ($o_lucene_query_element->getQueryTerms() as $o_term) { $va_gis_terms[] = trim((string) $o_term->text); } if ($va_coords = caParseGISSearch(join(' ', $va_gis_terms))) { $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\t\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\t\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\t\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\t\t\t(cav.value_decimal1 BETWEEN {$va_coords['min_latitude']} AND {$va_coords['max_latitude']})\n\t\t\t\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\t\t\t(cav.value_decimal2 BETWEEN {$va_coords['min_longitude']} AND {$va_coords['max_longitude']})\n\t\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"; } break; case __CA_ATTRIBUTE_VALUE_CURRENCY__: $t_cur = new CurrencyAttributeValue(); $va_parsed_value = $t_cur->parseValue(join(' ', $va_raw_terms), $t_element->getFieldValuesArray()); $vn_amount = $va_parsed_value['value_decimal1']; $vs_currency = preg_replace('![^A-Z0-9]+!', '', $va_parsed_value['value_longtext1']); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\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\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\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\t\t(cav.value_decimal1 = " . floatval($vn_amount) . ")\n\t\t\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\t\t(cav.value_longtext1 = '" . $this->opo_db->escape($vs_currency) . "')\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"; break; case __CA_ATTRIBUTE_VALUE_LENGTH__: // If it looks like a dimension that has been tokenized by Lucene // into oblivion rehydrate it here. try { switch (sizeof($va_raw_terms)) { case 2: $vs_dimension = $va_raw_terms[0] . caGetDecimalSeparator() . $va_raw_terms[1]; break; case 3: $vs_dimension = $va_raw_terms[0] . caGetDecimalSeparator() . $va_raw_terms[1] . " " . $va_raw_terms[2]; break; default: $vs_dimension = join(' ', $va_raw_terms); } $vo_parsed_measurement = caParseLengthDimension($vs_dimension); $vn_len = $vo_parsed_measurement->convertTo('METER', 6, 'en_US'); } catch (Exception $e) { $vs_direct_sql_query = null; break; } $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\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\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\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\t\t(cav.value_decimal1 = " . floatval($vn_len) . ")\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"; break; case __CA_ATTRIBUTE_VALUE_WEIGHT__: // If it looks like a weight that has been tokenized by Lucene // into oblivion rehydrate it here. try { switch (sizeof($va_raw_terms)) { case 2: $vs_dimension = $va_raw_terms[0] . caGetDecimalSeparator() . $va_raw_terms[1]; break; case 3: $vs_dimension = $va_raw_terms[0] . caGetDecimalSeparator() . $va_raw_terms[1] . " " . $va_raw_terms[2]; break; default: $vs_dimension = join(' ', $va_raw_terms); } $vo_parsed_measurement = caParseWeightDimension($vs_dimension); $vn_weight = $vo_parsed_measurement->convertTo('KILOGRAM', 6, 'en_US'); } catch (Exception $e) { $vs_direct_sql_query = null; break; } $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\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\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\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\t\t(cav.value_decimal1 = " . floatval($vn_weight) . ")\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"; break; case __CA_ATTRIBUTE_VALUE_TIMECODE__: $t_timecode = new TimecodeAttributeValue(); $va_parsed_value = $t_timecode->parseValue(join(' ', $va_raw_terms), $t_element->getFieldValuesArray()); $vn_timecode = $va_parsed_value['value_decimal1']; $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\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\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\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\t\t(cav.value_decimal1 = " . floatval($vn_timecode) . ")\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"; break; case __CA_ATTRIBUTE_VALUE_INTEGER__: $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\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\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\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\t\t(cav.value_integer1 = " . intval(array_shift($va_raw_terms)) . ")\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"; break; case __CA_ATTRIBUTE_VALUE_NUMERIC__: $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT ca.row_id, 1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM ca_attribute_values cav\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tINNER JOIN ca_attributes AS ca ON ca.attribute_id = cav.attribute_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t^JOIN\n\t\t\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\t\t(cav.element_id = {$vn_fld_num}) AND (ca.table_num = ?)\n\t\t\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\t\t(cav.value_decimal1 = " . floatval(array_shift($va_raw_terms)) . ")\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"; break; } } } else { // neither table fields nor elements, i.e. 'virtual' fields like _count should $vn_fld_num = false; $vs_fld_num = $vs_field; } } } if (($vs_intrinsic_field_name = $t_table->fieldName($vn_fld_num)) && ($vn_intrinsic_type = $t_table->getFieldInfo($vs_intrinsic_field_name, 'FIELD_TYPE')) == FT_BIT) { $vb_ft_bit_optimization = true; } elseif ($vn_intrinsic_type == FT_HISTORIC_DATERANGE) { $vb_all_numbers = true; foreach ($va_raw_terms as $vs_term) { if (!is_numeric($vs_term)) { $vb_all_numbers = false; break; } } $vs_date_start_fld = $t_table->getFieldInfo($vs_intrinsic_field_name, 'START'); $vs_date_end_fld = $t_table->getFieldInfo($vs_intrinsic_field_name, 'END'); $vs_raw_term = join(' ', $va_raw_terms); $vb_exact = $vs_raw_term[0] == "#" ? true : false; // dates prepended by "#" are considered "exact" or "contained - the matched dates must be wholly contained by the search term if ($vb_exact) { $vs_raw_term = substr($vs_raw_term, 1); if ($this->opo_tep->parse($vs_raw_term)) { $va_dates = $this->opo_tep->getHistoricTimestamps(); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $t_table->primaryKey() . ", 1\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $t_table->tableName() . "\n\t\t\t\t\t\t\t\t\t\t\t\t^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(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t({$vs_date_start_fld} BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\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({$vs_date_end_fld} BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\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\n\t\t\t\t\t\t\t\t\t\t\t"; } } else { if ($this->opo_tep->parse($vs_raw_term)) { $va_dates = $this->opo_tep->getHistoricTimestamps(); $vs_direct_sql_query = "\n\t\t\t\t\t\t\t\t\t\t\t\tSELECT " . $t_table->primaryKey() . ", 1\n\t\t\t\t\t\t\t\t\t\t\t\tFROM " . $t_table->tableName() . "\n\t\t\t\t\t\t\t\t\t\t\t\t^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(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t({$vs_date_start_fld} BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\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({$vs_date_end_fld} BETWEEN " . floatval($va_dates['start']) . " AND " . floatval($va_dates['end']) . ")\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({$vs_date_start_fld} <= " . floatval($va_dates['start']) . " AND {$vs_date_end_fld} >= " . floatval($va_dates['end']) . ")\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\n\t\t\t\t\t\t\t\t\t\t\t"; } } $pa_direct_sql_query_params = array(); } } } } // // If we're querying on the fulltext index then we need to construct // the query here... if we already have a direct SQL query to run then we can skip this // if ($vb_is_blank_search) { $va_sql_where[] = "((swi.field_table_num = " . intval($vs_table_num) . ") AND (swi.field_num = '{$vs_fld_num}') AND (swi.word_id = 0))"; if (!sizeof($va_sql_where)) { continue; } $vs_sql_where = join(' OR ', $va_sql_where); } elseif (!$vs_direct_sql_query) { $va_sql_where = array(); if (sizeof($va_ft_terms)) { if ($t_table && strlen($vs_fld_num) > 1) { $va_sql_where[] = "((swi.field_table_num = " . intval($vs_table_num) . ") AND (swi.field_num = '{$vs_fld_num}') AND (sw.word IN (" . join(',', $va_ft_terms) . ")))"; } else { if (sizeof($va_ft_terms) == 1) { $va_sql_where[] = "(sw.word = " . $va_ft_terms[0] . ")"; } else { $va_sql_where[] = "(sw.word IN (" . join(',', $va_ft_terms) . "))"; } } } if (sizeof($va_ft_like_terms)) { $va_tmp = array(); foreach ($va_ft_like_terms as $vs_term) { if ($vb_ft_bit_optimization) { $va_tmp[] = '(sw.word = \' ' . $this->opo_db->escape(trim($vs_term)) . ' \')'; } else { $va_tmp[] = '(sw.word LIKE \'' . $this->opo_db->escape(trim($vs_term)) . '%\')'; } } if ($t_table && strlen($vs_fld_num) > 1) { $va_sql_where[] = "((swi.field_table_num = " . intval($vs_table_num) . ") AND (swi.field_num = '{$vs_fld_num}') AND (" . join(' AND ', $va_tmp) . "))"; } else { $va_sql_where[] = "(" . join(' AND ', $va_tmp) . ")"; } } if (sizeof($va_ft_stem_terms)) { if ($t_table && strlen($vs_fld_num) > 1) { $va_sql_where[] = "((swi.field_table_num = " . intval($vs_table_num) . ") AND (swi.field_num = '{$vs_fld_num}') AND (sw.stem IN (" . join(',', $va_ft_stem_terms) . ")))"; } else { $va_sql_where[] = "(sw.stem IN (" . join(',', $va_ft_stem_terms) . "))"; } } if (!sizeof($va_sql_where)) { continue; } $vs_sql_where = join(' OR ', $va_sql_where); } else { $va_ft_terms = $va_ft_like_terms = $va_ft_like_terms = array(); } $vs_rel_type_id_sql = null; if (is_array($va_access_point_info['relationship_type_ids']) && sizeof($va_access_point_info['relationship_type_ids'])) { $vs_rel_type_id_sql = " AND (swi.rel_type_id IN (" . join(",", $va_access_point_info['relationship_type_ids']) . "))"; } if (!$vs_fld_num && is_array($va_restrict_to_fields = caGetOption('restrictSearchToFields', $pa_options, null)) && sizeof($va_restrict_to_fields)) { $va_field_restrict_sql = array(); foreach ($va_restrict_to_fields as $va_restrict) { $va_field_restrict_sql[] = "((swi.field_table_num = " . intval($va_restrict['table_num']) . ") AND (swi.field_num = '" . $va_restrict['field_num'] . "'))"; } $vs_sql_where .= " AND (" . join(" OR ", $va_field_restrict_sql) . ")"; } $va_join = array(); if ($vn_direct_sql_target_table_num != $pn_subject_tablenum) { // We're doing direct queries on metadata in a related table, fun! // Now let's rewrite the direct query to work... if ($t_target = $this->opo_datamodel->getInstanceByTableNum($vn_direct_sql_target_table_num, true)) { // First we create the join from the related table to our subject $vs_target_table_name = $t_target->tableName(); $va_path = array_keys($this->opo_datamodel->getPath($vn_direct_sql_target_table_num, $pn_subject_tablenum)); $vs_left_table = array_shift($va_path); $vn_cj = 0; foreach ($va_path as $vs_right_table) { if (sizeof($va_rels = $this->opo_datamodel->getRelationships($vs_left_table, $vs_right_table)) > 0) { $va_join[] = "INNER JOIN {$vs_right_table} ON {$vs_right_table}." . $va_rels[$vs_left_table][$vs_right_table][0][1] . " = " . ($vn_cj == 0 ? 'ca.row_id' : "{$vs_left_table}." . $va_rels[$vs_left_table][$vs_right_table][0][0]); } $vs_left_table = $vs_right_table; $vn_cj++; } // Next we rewrite the key we're pulling to be from our subject $vs_direct_sql_query = str_replace("SELECT ca.row_id", "SELECT " . $this->opo_datamodel->primaryKey($pn_subject_tablenum, true), $vs_direct_sql_query); // Finally we pray } } if ($vn_i == 0) { if ($vs_direct_sql_query) { $vs_direct_sql_query = str_replace('^JOIN', join("\n", $va_join), $vs_direct_sql_query); $vs_sql = "INSERT IGNORE INTO {$ps_dest_table} {$vs_direct_sql_query}"; if (strpos($vs_sql, '?') !== false && (!is_array($pa_direct_sql_query_params) || sizeof($pa_direct_sql_query_params) == 0)) { $pa_direct_sql_query_params = array($vn_direct_sql_target_table_num != $pn_subject_tablenum ? $vn_direct_sql_target_table_num : (int) $pn_subject_tablenum); } } else { $vs_sql = "\n\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}\n\t\t\t\t\t\t\t\tSELECT swi.row_id, SUM(swi.boost)\n\t\t\t\t\t\t\t\tFROM ca_sql_search_word_index swi\n\t\t\t\t\t\t\t\t" . (!$vb_is_blank_search ? "INNER JOIN ca_sql_search_words AS sw ON sw.word_id = swi.word_id" : '') . "\n\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\tswi.table_num = ?\n\t\t\t\t\t\t\t\t\t{$vs_rel_type_id_sql}\n\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : '') . "\n\t\t\t\t\t\t\t\tGROUP BY swi.row_id\n\t\t\t\t\t\t\t"; $pa_direct_sql_query_params = array((int) $pn_subject_tablenum); } if (($vn_num_terms = sizeof($va_ft_terms) + sizeof($va_ft_like_terms) + sizeof($va_ft_stem_terms)) > 1 && !$vs_direct_sql_query) { $vs_sql .= " HAVING count(distinct sw.word_id) = {$vn_num_terms}"; } $t = new Timer(); $pa_direct_sql_query_params = is_array($pa_direct_sql_query_params) ? $pa_direct_sql_query_params : array(); if (strpos($vs_sql, '?') === false) { $pa_direct_sql_query_params = array(); } $this->opo_db->query($vs_sql, $pa_direct_sql_query_params); $vn_i++; if ($this->debug) { Debug::msg('FIRST: ' . $vs_sql . " [{$pn_subject_tablenum}] " . $t->GetTime(4)); } } else { switch ($vs_op) { case 'AND': if ($vs_direct_sql_query) { if ($vn_direct_sql_target_table_num != $pn_subject_tablenum) { array_push($va_join, "INNER JOIN {$ps_dest_table} AS ftmp1 ON ftmp1.row_id = " . $this->opo_datamodel->primaryKey($pn_subject_tablenum, true)); } else { array_unshift($va_join, "INNER JOIN {$ps_dest_table} AS ftmp1 ON ftmp1.row_id = ca.row_id"); } $vs_direct_sql_query = str_replace('^JOIN', join("\n", $va_join), $vs_direct_sql_query); $pa_direct_sql_query_params = array($vn_direct_sql_target_table_num != $pn_subject_tablenum ? $vn_direct_sql_target_table_num : (int) $pn_subject_tablenum); } $vs_sql = $vs_direct_sql_query ? "{$vs_direct_sql_query}" : "\n\t\t\t\t\t\t\t\t\tSELECT swi.row_id\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_word_index swi\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_words AS sw ON sw.word_id = swi.word_id\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\tswi.table_num = ?\n\t\t\t\t\t\t\t\t\t\t{$vs_rel_type_id_sql}\n\t\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : '') . "\n\t\t\t\t\t\t\t\t\tGROUP BY swi.row_id\n\t\t\t\t\t\t\t\t"; if (($vn_num_terms = sizeof($va_ft_terms) + sizeof($va_ft_like_terms) + sizeof($va_ft_stem_terms)) > 1) { $vs_sql .= " HAVING count(distinct sw.word_id) = {$vn_num_terms}"; } $t = new Timer(); $pa_direct_sql_query_params = is_array($pa_direct_sql_query_params) ? $pa_direct_sql_query_params : array((int) $pn_subject_tablenum); if (strpos($vs_sql, '?') === false) { $pa_direct_sql_query_params = array(); } $qr_res = $this->opo_db->query($vs_sql, $pa_direct_sql_query_params); if ($this->debug) { Debug::msg('AND: ' . $vs_sql . ' ' . $t->GetTime(4) . ' ' . $qr_res->numRows()); } if (is_array($va_ids = $qr_res->getAllFieldValues($vs_direct_sql_query && $vn_direct_sql_target_table_num != $pn_subject_tablenum ? $this->opo_datamodel->primaryKey($pn_subject_tablenum) : 'row_id')) && sizeof($va_ids)) { $vs_sql = "DELETE FROM {$ps_dest_table} WHERE row_id NOT IN (?)"; $qr_res = $this->opo_db->query($vs_sql, array($va_ids)); if ($this->debug) { Debug::msg('AND DELETE: ' . $vs_sql . ' ' . $t->GetTime(4)); } } else { // we don't have any results left, ie. our AND query should yield an empty result $this->opo_db->query("DELETE FROM {$ps_dest_table}"); } $vn_i++; break; case 'NOT': if ($vs_direct_sql_query) { $vs_direct_sql_query = str_replace('^JOIN', join("\n", $va_join), $vs_direct_sql_query); $pa_direct_sql_query_params = array($vn_direct_sql_target_table_num != $pn_subject_tablenum ? $vn_direct_sql_target_table_num : (int) $pn_subject_tablenum); } $vs_sql = "\n\t\t\t\t\t\t\t\t\tSELECT row_id\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_words sw\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_word_index AS swi ON sw.word_id = swi.word_id\n\t\t\t\t\t\t\t\t\tWHERE \n\t\t\t\t\t\t\t\t\t\t" . ($vs_sql_where ? "{$vs_sql_where} AND " : "") . " swi.table_num = ? \n\t\t\t\t\t\t\t\t\t\t{$vs_rel_type_id_sql}\n\t\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : ''); $pa_direct_sql_query_params = is_array($pa_direct_sql_query_params) ? $pa_direct_sql_query_params : array((int) $pn_subject_tablenum); if (strpos($vs_sql, '?') === false) { $pa_direct_sql_query_params = array(); } $qr_res = $this->opo_db->query($vs_sql, $pa_direct_sql_query_params); $va_ids = $qr_res->getAllFieldValues($vs_direct_sql_query && $vn_direct_sql_target_table_num != $pn_subject_tablenum ? $this->opo_datamodel->primaryKey($pn_subject_tablenum) : 'row_id'); if (sizeof($va_ids) > 0) { $vs_sql = "\n\t\t\t\t\t\t\t\t\t\tDELETE FROM {$ps_dest_table} \n\t\t\t\t\t\t\t\t\t\tWHERE \n\t\t\t\t\t\t\t\t\t\t\trow_id IN (?)\n\t\t\t\t\t\t\t\t\t"; if ($this->debug) { Debug::msg('NOT ' . $vs_sql); } $qr_res = $this->opo_db->query($vs_sql, array($va_ids)); } $vn_i++; break; default: case 'OR': if ($vs_direct_sql_query) { $vs_direct_sql_query = str_replace('^JOIN', join("\n", $va_join), $vs_direct_sql_query); $pa_direct_sql_query_params = array($vn_direct_sql_target_table_num != $pn_subject_tablenum ? $vn_direct_sql_target_table_num : (int) $pn_subject_tablenum); } $vs_sql = $vs_direct_sql_query ? "INSERT IGNORE INTO {$ps_dest_table} {$vs_direct_sql_query}" : "\n\t\t\t\t\t\t\t\t\tINSERT IGNORE INTO {$ps_dest_table}\n\t\t\t\t\t\t\t\t\tSELECT swi.row_id, SUM(swi.boost)\n\t\t\t\t\t\t\t\t\tFROM ca_sql_search_word_index swi\n\t\t\t\t\t\t\t\t\tINNER JOIN ca_sql_search_words AS sw ON sw.word_id = swi.word_id\n\t\t\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\t\t\t\t\t\tAND\n\t\t\t\t\t\t\t\t\t\tswi.table_num = ?\n\t\t\t\t\t\t\t\t\t\t{$vs_rel_type_id_sql}\n\t\t\t\t\t\t\t\t\t\t" . ($this->getOption('omitPrivateIndexing') ? " AND swi.access = 0" : '') . "\n\t\t\t\t\t\t\t\t\tGROUP BY\n\t\t\t\t\t\t\t\t\t\tswi.row_id\n\t\t\t\t\t\t\t\t"; if ($this->debug) { Debug::msg('OR ' . $vs_sql); } $vn_i++; $pa_direct_sql_query_params = is_array($pa_direct_sql_query_params) ? $pa_direct_sql_query_params : array((int) $pn_subject_tablenum); if (strpos($vs_sql, '?') === false) { $pa_direct_sql_query_params = array(); } $qr_res = $this->opo_db->query($vs_sql, $pa_direct_sql_query_params); break; } } // Drop any temporary tables created by direct search queries foreach (array_keys($va_direct_query_temp_tables) as $vs_temp_table_to_drop) { $this->_dropTempTable($vs_temp_table_to_drop); } break; default: //print get_class($o_lucene_query_element); break; } } }
/** * * @param string $type can be one of: ["ca_objects", "ca_entities", "ca_places", "ca_occurrences", "ca_collections", "ca_list_items", "ca_object_representations", "ca_storage_locations", "ca_movements", "ca_loans", "ca_tours", "ca_tour_stops"] * @param int $item_id primary key * @param string $attribute_code_or_id * @return array * @throws SoapFault */ public function getAttributesByElement($type, $item_id, $attribute_code_or_id) { if (!($t_subject_instance = $this->getTableInstance($type, $item_id, true))) { throw new SoapFault("Server", "Invalid type or item_id"); } $t_locale = new ca_locales(); $t_element = new ca_metadata_elements(); $va_attrs = $t_subject_instance->getAttributesByElement($attribute_code_or_id); $va_return = array(); $va_element_type_cfg = ca_metadata_elements::getAttributeTypes(); foreach ($va_attrs as $vo_attr) { $va_attr = array(); foreach ($vo_attr->getValues() as $vo_value) { $t_element->load($vo_value->getElementID()); $va_attr[] = array("value_id" => $vo_value->getValueID(), "display_value" => $vo_value->getDisplayValue(), "element_code" => $vo_value->getElementCode(), "element_id" => $vo_value->getElementID(), "attribute_info" => $t_subject_instance->getAttributeLabelAndDescription($vo_value->getElementCode()), "datatype" => $va_element_type_cfg[$t_element->get("datatype")], "locale" => $t_locale->localeIDToCode($vo_attr->getLocaleID())); } $va_return[$vo_attr->getAttributeID()] = $va_attr; } return $va_return; }
private function stabilizeElementRanks($pn_parent_id, $pa_ranks) { $vo_db = new Db(); $t_element = new ca_metadata_elements(); do { $va_ranks = array_keys($pa_ranks); $vn_rank = $va_ranks[0]; $qr_res = $vo_db->query("\n\t\t\t\tSELECT * FROM\n\t\t\t\t\tca_metadata_elements\n\t\t\t\t\tWHERE\n\t\t\t\t\t\t(parent_id=?)\n\t\t\t\t\t\tAND\n\t\t\t\t\t\t(rank>?)\n\t\t\t\t\tORDER BY\n\t\t\t\t\t\trank\n\t\t\t", $pn_parent_id, $vn_rank); while ($qr_res->nextRow()) { $t_element->load($qr_res->get('element_id')); $t_element->set('rank', intval($t_element->get('rank')) + $pa_ranks[0]); $t_element->setMode(ACCESS_WRITE); $t_element->update(); } $qr_res = $vo_db->query("\n\t\t\t\tSELECT * FROM\n\t\t\t\t\tca_metadata_elements\n\t\t\t\t\tWHERE\n\t\t\t\t\t\t(parent_id=?)\n\t\t\t\t\t\tAND\n\t\t\t\t\t\t(rank=?)\n\t\t\t\t\tORDER BY\n\t\t\t\t\t\trank\n\t\t\t", $pn_parent_id, $vn_rank); $i = 0; while ($qr_res->nextRow()) { $i++; $t_element->load($qr_res->get('element_id')); $t_element->set('rank', intval($t_element->get('rank')) + $i); $t_element->setMode(ACCESS_WRITE); $t_element->update(); } $pa_ranks = $this->elementRankStabilizationNeeded($pn_parent_id); } while (is_array($pa_ranks)); }