diff --git a/module/VuFind/src/VuFind/Search/Base/Params.php b/module/VuFind/src/VuFind/Search/Base/Params.php index fa5defef2d76ef6217cca6514ae4350bd5b686af..7f59bd02d5abf5ab53b19c19ed3f4ca356b132aa 100644 --- a/module/VuFind/src/VuFind/Search/Base/Params.php +++ b/module/VuFind/src/VuFind/Search/Base/Params.php @@ -955,6 +955,9 @@ class Params implements ServiceLocatorAwareInterface if ($firstChar == '-') { $operator = 'NOT'; $field = substr($field, 1); + } else if ($firstChar == '~') { + $operator = 'OR'; + $field = substr($field, 1); } else { $operator = 'AND'; } diff --git a/module/VuFind/src/VuFind/Search/Solr/Params.php b/module/VuFind/src/VuFind/Search/Solr/Params.php index 0e36fcbd414f925adf739986358df58c6b0b2511..b3df70047c6141c95460e783dd6278f90c0756f1 100644 --- a/module/VuFind/src/VuFind/Search/Solr/Params.php +++ b/module/VuFind/src/VuFind/Search/Solr/Params.php @@ -95,18 +95,32 @@ class Params extends \VuFind\Search\Base\Params { // Define Filter Query $filterQuery = $this->getOptions()->getHiddenFilters(); + $orFilters = array(); foreach ($this->filterList as $field => $filter) { + if ($orFacet = (substr($field, 0, 1) == '~')) { + $field = substr($field, 1); + } foreach ($filter as $value) { // Special case -- allow trailing wildcards and ranges: if (substr($value, -1) == '*' || preg_match('/\[[^\]]+\s+TO\s+[^\]]+\]/', $value) ) { - $filterQuery[] = $field.':'.$value; + $q = $field.':'.$value; + } else { + $q = $field.':"'.addcslashes($value, '"\\').'"'; + } + if ($orFacet) { + $orFilters[$field] = isset($orFilters[$field]) + ? $orFilters[$field] : array(); + $orFilters[$field][] = $q; } else { - $filterQuery[] = $field.':"'.addcslashes($value, '"\\').'"'; + $filterQuery[] = $q; } } } + foreach ($orFilters as $field => $parts) { + $filterQuery[] = $field . ':(' . implode(' OR ', $parts) . ')'; + } return $filterQuery; } diff --git a/module/VuFind/src/VuFind/Search/Summon/Params.php b/module/VuFind/src/VuFind/Search/Summon/Params.php index ef348c0aec93327ad9442924c9f08cf06625c680..4cd61a468091153cdf3dcb418f5d4ace1686ee2a 100644 --- a/module/VuFind/src/VuFind/Search/Summon/Params.php +++ b/module/VuFind/src/VuFind/Search/Summon/Params.php @@ -211,6 +211,8 @@ class Params extends \VuFind\Search\Base\Params // Which filters should be applied to our query? $filterList = $this->getFilterList(); if (!empty($filterList)) { + $orFacets = array(); + // Loop through all filters and add appropriate values to request: foreach ($filterList as $filterArray) { foreach ($filterArray as $filt) { @@ -232,6 +234,11 @@ class Params extends \VuFind\Search\Base\Params $to = SummonQuery::escapeParam($range['to']); $params ->add('rangeFilters', "{$filt['field']},{$from}:{$to}"); + } else if ($filt['operator'] == 'OR') { + // Special case -- OR facets: + $orFacets[$filt['field']] = isset($orFacets[$filt['field']]) + ? $orFacets[$filt['field']] : array(); + $orFacets[$filt['field']][] = $safeValue; } else { // Standard case: $fq = "{$filt['field']},{$safeValue}"; @@ -241,6 +248,13 @@ class Params extends \VuFind\Search\Base\Params $params->add('filters', $fq); } } + + // Deal with OR facets: + foreach ($orFacets as $field => $values) { + $params->add( + 'groupFilters', $field . ',or,' . implode(',', $values) + ); + } } } } diff --git a/module/VuFind/src/VuFind/Search/UrlQueryHelper.php b/module/VuFind/src/VuFind/Search/UrlQueryHelper.php index 8df3e3e2d57fc8415b046f68c32667bd0cef8cf0..275bdb97cc5f0ee81c98888629faa59dde520a2b 100644 --- a/module/VuFind/src/VuFind/Search/UrlQueryHelper.php +++ b/module/VuFind/src/VuFind/Search/UrlQueryHelper.php @@ -297,6 +297,8 @@ class UrlQueryHelper // Account for operators: if ($operator == 'NOT') { $field = '-' . $field; + } else if ($operator == 'OR') { + $field = '~' . $field; } // Remove the filter: diff --git a/module/VuFindSearch/src/VuFindSearch/Backend/Summon/Backend.php b/module/VuFindSearch/src/VuFindSearch/Backend/Summon/Backend.php index ab506b4eece19ae6a98c9603237648f0ecc52f0e..d1ef8fd603603ed91032053bb008ea618a3edd9d 100644 --- a/module/VuFindSearch/src/VuFindSearch/Backend/Summon/Backend.php +++ b/module/VuFindSearch/src/VuFindSearch/Backend/Summon/Backend.php @@ -328,14 +328,11 @@ class Backend implements BackendInterface // Convert the options: $options = array(); + // Most parameters need to be flattened from array format, but a few + // should remain as arrays: + $arraySettings = array('facets', 'filters', 'groupFilters', 'rangeFilters'); foreach ($params as $key => $param) { - // Most parameters need to be flattened from array format, but a few - // should remain as arrays: - if (in_array($key, array('facets', 'filters', 'rangeFilters'))) { - $options[$key] = $param; - } else { - $options[$key] = $param[0]; - } + $options[$key] = in_array($key, $arraySettings) ? $param : $param[0]; } return new SummonQuery($query, $options); diff --git a/themes/blueprint/templates/Recommend/SideFacets.phtml b/themes/blueprint/templates/Recommend/SideFacets.phtml index 55bed4b78e3b4f9a06acb6ec1f6ea58c419196e5..5eeb7962fd1fd0e7f1c327135e84659a6b189b7e 100644 --- a/themes/blueprint/templates/Recommend/SideFacets.phtml +++ b/themes/blueprint/templates/Recommend/SideFacets.phtml @@ -16,7 +16,7 @@ <strong><?=$this->transEsc('Remove Filters')?></strong> <ul class="filters"> <? foreach ($filterList as $field => $filters): ?> - <? foreach ($filters as $filter): ?> + <? foreach ($filters as $i => $filter): ?> <? if (isset($filter['specialType']) && $filter['specialType'] == 'keyword') { $removeLink = $this->currentPath().$results->getUrlQuery()->replaceTerm($filter['value'], ''); @@ -27,7 +27,7 @@ ?> <li> <a href="<?=$removeLink?>"><img src="<?=$this->imageLink('silk/delete.png')?>" alt="Delete"/></a> - <a href="<?=$removeLink?>"><? if ($filter['operator'] == 'NOT') echo $this->transEsc('NOT') . ' '; ?><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a> + <a href="<?=$removeLink?>"><? if ($filter['operator'] == 'NOT') echo $this->transEsc('NOT') . ' '; if ($filter['operator'] == 'OR' && $i > 0) echo $this->transEsc('OR') . ' '; ?><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a> </li> <? endforeach; ?> <? endforeach; ?> diff --git a/themes/jquerymobile/templates/Recommend/SideFacets.phtml b/themes/jquerymobile/templates/Recommend/SideFacets.phtml index 91ed4b99df31524c605bed2cff747f2d7dc6cdaa..bb69c5fefddcf713148cda17727420f8d5784bed 100644 --- a/themes/jquerymobile/templates/Recommend/SideFacets.phtml +++ b/themes/jquerymobile/templates/Recommend/SideFacets.phtml @@ -3,13 +3,13 @@ <ul class="filters" data-role="listview" data-inset="true" data-dividertheme="e"> <li data-role="list-divider"><?=$this->transEsc('adv_search_filters')?></li> <? $i = 0; foreach ($filterList as $field => $filters): ?> - <? foreach ($filters as $filter): ?> + <? foreach ($filters as $j => $filter): ?> <? $removeLink = $this->currentPath().$results->getUrlQuery()->removeFacet($filter['field'], $filter['value'], true, $filter['operator']); if ($filter['displayText'] == '[* TO *]') $filter['displayText'] = $this->translate('filter_wildcard'); ?> <li data-icon="minus"> - <a data-icon="minus" rel="external" href="<?=$removeLink?>"><?=$i++ > 0 ? $this->transEsc("AND") . ' ' : ''?><? if ($filter['operator'] == 'NOT') echo $this->transEsc('NOT') . ' '; ?><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a> + <a data-icon="minus" rel="external" href="<?=$removeLink?>"><?=($i++ > 0 && ($j == 0 || $filter['operator'] != 'OR')) ? $this->transEsc("AND") . ' ' : ''?><? if ($filter['operator'] == 'NOT') echo $this->transEsc('NOT') . ' '; if ($filter['operator'] == 'OR' && $j > 0) echo $this->transEsc('OR') . ' '; ?><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a> </li> <? endforeach; ?> <? endforeach; ?>