Esempio n. 1
0
 /**
  * Test capitalizeBooleans functionality.
  *
  * @return void
  * @access public
  */
 public function testCapitalizeBooleans()
 {
     // Set up an array of expected inputs and outputs:
     // @codingStandardsIgnoreStart
     $tests = array(array('this not that', 'this NOT that'), array('this and that', 'this AND that'), array('this or that', 'this OR that'), array('apples and oranges (not that)', 'apples AND oranges (NOT that)'), array('"this not that"', '"this not that"'), array('"this and that"', '"this and that"'), array('"this or that"', '"this or that"'), array('"apples and oranges (not that)"', '"apples and oranges (not that)"'), array('this AND that', 'this AND that'), array('and and and', 'and AND and'), array('andornot noted andy oranges', 'andornot noted andy oranges'), array('(this or that) and (apples not oranges)', '(this OR that) AND (apples NOT oranges)'), array('this aNd that', 'this AND that'), array('this nOt that', 'this NOT that'));
     // @codingStandardsIgnoreEnd
     // Test all the operations:
     foreach ($tests as $current) {
         $this->assertEquals(VuFindSolrUtils::capitalizeBooleans($current[0]), $current[1]);
     }
 }
Esempio n. 2
0
 /**
  * Build Query string from search parameters
  *
  * @param array $search An array of search parameters
  *
  * @return string       The query
  * @access protected
  */
 protected function buildQuery($search)
 {
     $groups = array();
     $excludes = array();
     if (is_array($search)) {
         $query = '';
         foreach ($search as $params) {
             // Advanced Search
             if (isset($params['group'])) {
                 $thisGroup = array();
                 // Process each search group
                 foreach ($params['group'] as $group) {
                     // Build this group individually as a basic search
                     $thisGroup[] = $this->buildQuery(array($group));
                 }
                 // Is this an exclusion (NOT) group or a normal group?
                 if ($params['group'][0]['bool'] == 'NOT') {
                     $excludes[] = join(" OR ", $thisGroup);
                 } else {
                     $groups[] = join(" " . $params['group'][0]['bool'] . " ", $thisGroup);
                 }
             }
             // Basic Search
             if (isset($params['lookfor']) && $params['lookfor'] != '') {
                 // Clean and validate input -- note that index may be in a
                 // different field depending on whether this is a basic or
                 // advanced search.
                 $lookfor = $params['lookfor'];
                 if (isset($params['field'])) {
                     $index = $params['field'];
                 } else {
                     if (isset($params['index'])) {
                         $index = $params['index'];
                     } else {
                         $index = 'AllFields';
                     }
                 }
                 // Force boolean operators to uppercase if we are in a
                 // case-insensitive mode:
                 if (!$this->caseSensitiveBooleans) {
                     $lookfor = VuFindSolrUtils::capitalizeBooleans($lookfor);
                 }
                 // Prepend the index name, unless it's the special "AllFields"
                 // index:
                 if ($index != 'AllFields') {
                     $query .= "{$index}=({$lookfor})";
                 } else {
                     $query .= "WRD=({$lookfor})";
                 }
             }
         }
     }
     // Put our advanced search together
     if (count($groups) > 0) {
         $query = "(" . join(") " . $search[0]['join'] . " (", $groups) . ")";
     }
     // and concatenate exclusion after that
     if (count($excludes) > 0) {
         $query .= " NOT ((" . join(") OR (", $excludes) . "))";
     }
     // Ensure we have a valid query to this point
     return isset($query) ? $query : '';
 }
Esempio n. 3
0
 /**
  * Execute a search.
  *
  * @param string $query           The search query
  * @param string $handler         The Query Handler to use (null for default)
  * @param array  $filter          The fields and values to filter results on
  * @param string $start           The record to start with
  * @param string $limit           The amount of records to return
  * @param array  $facet           An array of faceting options
  * @param string $spell           Phrase to spell check
  * @param string $dictionary      Spell check dictionary to use
  * @param string $sort            Field name to use for sorting
  * @param string $fields          A list of fields to be returned
  * @param string $method          Method to use for sending request (GET/POST)
  * @param bool   $returnSolrError Fail outright on syntax error (false) or
  * treat it as an empty result set with an error key set (true)?
  *
  * @throws object                 PEAR Error
  * @return array                  An array of query results
  * @access public
  */
 public function search($query, $handler = null, $filter = null, $start = 0, $limit = 20, $facet = null, $spell = '', $dictionary = null, $sort = null, $fields = null, $method = HTTP_REQUEST_METHOD_POST, $returnSolrError = false)
 {
     // Query String Parameters
     $options = array('q' => $query, 'rows' => $limit, 'start' => $start, 'indent' => 'yes');
     // Force sort by title_sort for empty search sorted by score
     if ($limit > 0 && $query == '*:*' && (empty($sort) || $sort == 'score desc')) {
         $sort = 'title asc';
     }
     // Add Sorting
     if ($sort && !empty($sort)) {
         // There may be multiple sort options (ranked, with tie-breakers);
         // process each individually, then assemble them back together again:
         $sortParts = explode(',', $sort);
         for ($x = 0; $x < count($sortParts); $x++) {
             $sortParts[$x] = $this->_normalizeSort($sortParts[$x]);
         }
         $options['sort'] = implode(',', $sortParts);
     }
     // Determine which handler to use
     if (!$this->isAdvanced($query)) {
         $ss = is_null($handler) ? null : $this->_getSearchSpecs($handler, $query);
         // Is this a Dismax search?
         if (isset($ss['DismaxFields'])) {
             // Specify the fields to do a Dismax search on:
             $options['qf'] = implode(' ', $ss['DismaxFields']);
             // Specify the default dismax search handler so we can use any
             // global settings defined by the user:
             $options['qt'] = 'dismax';
             // Load any custom Dismax parameters from the YAML search spec file:
             if (isset($ss['DismaxParams']) && is_array($ss['DismaxParams'])) {
                 foreach ($ss['DismaxParams'] as $current) {
                     // The way we process the current parameter depends on
                     // whether or not we have previously encountered it.  If
                     // we have multiple values for the same parameter, we need
                     // to turn its entry in the $options array into a subarray;
                     // otherwise, one-off parameters can be safely represented
                     // as single values.
                     if (isset($options[$current[0]])) {
                         if (!is_array($options[$current[0]])) {
                             $options[$current[0]] = array($options[$current[0]]);
                         }
                         $options[$current[0]][] = $current[1];
                     } else {
                         $options[$current[0]] = $current[1];
                     }
                 }
             }
             // Apply search-specific filters if necessary:
             if (isset($ss['FilterQuery'])) {
                 if (is_array($filter)) {
                     $filter[] = $ss['FilterQuery'];
                 } else {
                     $filter = array($ss['FilterQuery']);
                 }
             }
         } else {
             // Not DisMax... but if we have a handler set, we may still need
             // to build a query using a setting in the YAML search specs or a
             // simple field name:
             if (!empty($handler)) {
                 $options['q'] = $this->_buildQueryComponent($handler, $query);
             }
         }
     } else {
         // Force boolean operators to uppercase if we are in a case-insensitive
         // mode:
         if (!$this->_caseSensitiveBooleans) {
             $query = VuFindSolrUtils::capitalizeBooleans($query);
         }
         // Adjust range operators if we are in a case-insensitive mode:
         if (!$this->_caseSensitiveRanges) {
             $query = VuFindSolrUtils::capitalizeRanges($query);
         }
         // Process advanced search -- if a handler was specified, let's see
         // if we can adapt the search to work with the appropriate fields.
         if (!empty($handler)) {
             $options['q'] = $this->_buildAdvancedQuery($handler, $query);
             // If highlighting is enabled, we only want to use the inner query
             // for highlighting; anything added outside of this is a boost and
             // should be ignored for highlighting purposes!
             if ($this->_highlight) {
                 $options['hl.q'] = $this->_buildAdvancedInnerQuery($handler, $query);
             }
         }
     }
     // Limit Fields
     if ($fields) {
         $options['fl'] = $fields;
     } else {
         // This should be an explicit list
         $options['fl'] = '*,score';
     }
     // Build Facet Options
     if ($facet && !empty($facet['field'])) {
         $options['facet'] = 'true';
         $options['facet.mincount'] = 1;
         $options['facet.limit'] = isset($facet['limit']) ? $facet['limit'] : null;
         unset($facet['limit']);
         $options['facet.field'] = isset($facet['field']) ? $facet['field'] : null;
         unset($facet['field']);
         if (isset($facet['prefix'])) {
             if (is_array($facet['prefix'])) {
                 foreach ($facet['prefix'] as $name => $prefix) {
                     $options["f.{$name}.facet.prefix"] = $prefix;
                     // TODO: This is a kludge, maybe something better is
                     // needed to indicate when we want more than the default
                     // limit for hierarchical facets.
                     $options["f.{$name}.facet.limit"] = 1000;
                 }
             } else {
                 $options['facet.prefix'] = $facet['prefix'];
             }
         }
         unset($facet['prefix']);
         $options['facet.sort'] = isset($facet['sort']) ? $facet['sort'] : 'count';
         unset($facet['sort']);
         if (isset($facet['offset'])) {
             $options['facet.offset'] = $facet['offset'];
             unset($facet['offset']);
         }
         if (isset($facet['query'])) {
             $options['facet.query'] = $facet['query'];
             unset($facet['query']);
         }
         foreach ($facet as $param => $value) {
             $options[$param] = $value;
         }
     }
     // Don't use the filters for an id query
     if ($handler != 'ids') {
         if ($this->_mergedRecords) {
             // Filter out merged children by default
             if (!isset($filter)) {
                 $filter = array();
             }
             $filter[] = '-merged_child_boolean:TRUE';
         } elseif ($this->_mergedRecords !== null) {
             // Filter out merged records by default
             if (!isset($filter)) {
                 $filter = array();
             }
             $filter[] = '-merged_boolean:TRUE';
         }
         if ($this->_hideComponentParts) {
             // Filter out component parts by default
             if (!isset($filter)) {
                 $filter = array();
             }
             $filter[] = '-hidden_component_boolean:TRUE';
         }
     }
     // Build Filter Query
     $this->_mergeBuildingPriority = array();
     if (is_array($filter) && count($filter)) {
         // Change 'online_boolean' filter to 'online_str_mv'
         // if sources contain merged records (i.e. if deduplication is enabled).
         if (($pos = array_search('online_boolean:"1"', $filter)) !== false) {
             $searchSettings = getExtraConfigArray('searches');
             if (isset($searchSettings['Records']['merged_records']) && $searchSettings['Records']['merged_records']) {
                 if (isset($searchSettings['Records']['sources']) && ($sources = $searchSettings['Records']['sources']) !== '') {
                     $tmp = array();
                     foreach (explode(',', $sources) as $source) {
                         $tmp[] = "\"{$source}\"";
                     }
                     $filter[$pos] = 'online_str_mv:(' . implode(' OR ', $tmp) . ')';
                 } else {
                     $filter[$pos] = 'online_str_mv:*';
                 }
             }
         }
         $options['fq'] = $filter;
         foreach ($filter as $f) {
             if (strncmp($f, 'building:', 9) == 0) {
                 // Assume we have a facet hierarchy...
                 $fullHierarchy = substr($f, 12, -1);
                 foreach (explode('/', $fullHierarchy) as $part) {
                     $this->_mergeBuildingPriority[] = $part;
                 }
             }
         }
     }
     // Enable Spell Checking
     if ($spell != '') {
         $options['spellcheck'] = 'true';
         $options['spellcheck.q'] = $spell;
         if ($dictionary != null) {
             $options['spellcheck.dictionary'] = $dictionary;
         }
     }
     // Enable highlighting
     if ($this->_highlight) {
         $options['hl'] = 'true';
         $options['hl.fl'] = '*';
         $options['hl.simple.pre'] = '{{{{START_HILITE}}}}';
         $options['hl.simple.post'] = '{{{{END_HILITE}}}}';
     }
     // Hack to make it possible to see the search debug information
     if (isset($_REQUEST['debugSolrQuery'])) {
         $options['debugQuery'] = 'true';
     }
     if ($this->debug) {
         echo '<pre>Search options: ' . print_r($options, true) . "\n";
         if ($filter) {
             echo "\nFilterQuery: ";
             foreach ($filter as $filterItem) {
                 echo " {$filterItem}";
             }
         }
         if ($sort) {
             echo "\nSort: " . $options['sort'];
         }
         echo "</pre>\n";
     }
     $result = $this->_select($method, $options, $returnSolrError);
     if (PEAR::isError($result)) {
         PEAR::raiseError($result);
     }
     return $result;
 }