updated and repatched search_api module
please check this thread : Decide on strategy for language aware search https://www.drupal.org/node/1393058
This commit is contained in:
@@ -57,14 +57,94 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue
|
||||
if ($active = $this->adapter->getActiveItems($this->facet)) {
|
||||
$item = end($active);
|
||||
$field = $this->facet['field'];
|
||||
$regex = str_replace(array('^', '$'), '', FACETAPI_REGEX_DATE);
|
||||
$filter = preg_replace_callback($regex, array($this, 'replaceDateString'), $item['value']);
|
||||
$filter = $this->createRangeFilter($item['value']);
|
||||
$this->addFacetFilter($query, $field, $filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites the handler-specific date range syntax to the normal facet syntax.
|
||||
*
|
||||
* @param $value
|
||||
* The user-facing facet value.
|
||||
*
|
||||
* @return string
|
||||
* A facet to add as a filter, in the format used internally in this module.
|
||||
*/
|
||||
protected function createRangeFilter($value) {
|
||||
// Gets the granularity. Ignore any filters passed directly from the server
|
||||
// (range or missing). We always create filters starting with a year.
|
||||
if (!$value || !ctype_digit($value[0])) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$parts = explode('-', $value);
|
||||
$date = new DateTime();
|
||||
switch (count($parts)) {
|
||||
case 1:
|
||||
$date->setDate($parts[0], 1, 1);
|
||||
$date->setTime(0, 0, 0);
|
||||
$lower = $date->format('U');
|
||||
$date->setDate($parts[0] + 1, 1, 1);
|
||||
$date->setTime(0, 0, -1);
|
||||
$upper = $date->format('U');
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Luckily, $month = 13 is treated as January of next year. (The same
|
||||
// goes for all other parameters.) We use the inverse trick for the
|
||||
// seconds of the upper bound, since that's inclusive and we want to
|
||||
// stop at a second before the next segment starts.
|
||||
$date->setDate($parts[0], $parts[1], 1);
|
||||
$date->setTime(0, 0, 0);
|
||||
$lower = $date->format('U');
|
||||
$date->setDate($parts[0], $parts[1] + 1, 1);
|
||||
$date->setTime(0, 0, -1);
|
||||
$upper = $date->format('U');
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$date->setDate($parts[0], $parts[1], $parts[2]);
|
||||
$date->setTime(0, 0, 0);
|
||||
$lower = $date->format('U');
|
||||
$date->setDate($parts[0], $parts[1], $parts[2] + 1);
|
||||
$date->setTime(0, 0, -1);
|
||||
$upper = $date->format('U');
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$date->setDate($parts[0], $parts[1], $parts[2]);
|
||||
$date->setTime($parts[3], 0, 0);
|
||||
$lower = $date->format('U');
|
||||
$date->setTime($parts[3] + 1, 0, -1);
|
||||
$upper = $date->format('U');
|
||||
break;
|
||||
|
||||
case 5:
|
||||
$date->setDate($parts[0], $parts[1], $parts[2]);
|
||||
$date->setTime($parts[3], $parts[4], 0);
|
||||
$lower = $date->format('U');
|
||||
$date->setTime($parts[3], $parts[4] + 1, -1);
|
||||
$upper = $date->format('U');
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$date->setDate($parts[0], $parts[1], $parts[2]);
|
||||
$date->setTime($parts[3], $parts[4], $parts[5]);
|
||||
return $date->format('U');
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
|
||||
return "[$lower TO $upper]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement callback for replacing ISO dates with timestamps.
|
||||
*
|
||||
* Not used anymore, but kept for backwards compatibility with potential
|
||||
* subclasses.
|
||||
*/
|
||||
public function replaceDateString($matches) {
|
||||
return strtotime($matches[0]);
|
||||
@@ -86,15 +166,9 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue
|
||||
$build = array();
|
||||
$search = search_api_current_search($search_id);
|
||||
$results = $search[1];
|
||||
if (!$results['result count']) {
|
||||
return array();
|
||||
}
|
||||
// Gets total number of documents matched in search.
|
||||
$total = $results['result count'];
|
||||
|
||||
// Most of the code below is copied from search_facetapi's implementation of
|
||||
// this method.
|
||||
|
||||
// Executes query, iterates over results.
|
||||
if (isset($results['search_api_facets']) && isset($results['search_api_facets'][$this->facet['name']])) {
|
||||
$values = $results['search_api_facets'][$this->facet['name']];
|
||||
@@ -113,13 +187,6 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue
|
||||
}
|
||||
}
|
||||
else {
|
||||
$filter = substr($value['filter'], 1, -1);
|
||||
$pos = strpos($filter, ' ');
|
||||
if ($pos !== FALSE) {
|
||||
$lower = facetapi_isodate(substr($filter, 0, $pos), FACETAPI_DATE_DAY);
|
||||
$upper = facetapi_isodate(substr($filter, $pos + 1), FACETAPI_DATE_DAY);
|
||||
$filter = '[' . $lower . ' TO ' . $upper . ']';
|
||||
}
|
||||
$build[$filter]['#count'] = $value['count'];
|
||||
}
|
||||
}
|
||||
@@ -128,23 +195,28 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue
|
||||
|
||||
// Get the finest level of detail we're allowed to drill down to.
|
||||
$settings = $facet->getSettings()->settings;
|
||||
$granularity = isset($settings['date_granularity']) ? $settings['date_granularity'] : FACETAPI_DATE_MINUTE;
|
||||
$max_granularity = isset($settings['date_granularity']) ? $settings['date_granularity'] : FACETAPI_DATE_MINUTE;
|
||||
|
||||
// Gets active facets, starts building hierarchy.
|
||||
$parent = $gap = NULL;
|
||||
$parent = $granularity = NULL;
|
||||
$active_items = $this->adapter->getActiveItems($this->facet);
|
||||
foreach ($active_items as $value => $item) {
|
||||
// If the item is active, the count is the result set count.
|
||||
$build[$value] = array('#count' => $total);
|
||||
|
||||
// Gets next "gap" increment.
|
||||
if ($value[0] != '[' || $value[strlen($value) - 1] != ']' || !($pos = strpos($value, ' TO '))) {
|
||||
// Gets next "gap" increment. Ignore any filters passed directly from the
|
||||
// server (range or missing). We always create filters starting with a
|
||||
// year.
|
||||
$value = "$value";
|
||||
if (!$value || !ctype_digit($value[0])) {
|
||||
continue;
|
||||
}
|
||||
$start = substr($value, 1, $pos);
|
||||
$end = substr($value, $pos + 4, -1);
|
||||
$date_gap = facetapi_get_date_gap($start, $end);
|
||||
$gap = facetapi_get_next_date_gap($date_gap, $granularity);
|
||||
|
||||
$granularity = search_api_facetapi_date_get_granularity($value);
|
||||
if (!$granularity) {
|
||||
continue;
|
||||
}
|
||||
$granularity = facetapi_get_next_date_gap($granularity, $max_granularity);
|
||||
|
||||
// If there is a previous item, there is a parent, uses a reference so the
|
||||
// arrays are populated when they are updated.
|
||||
@@ -156,6 +228,7 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue
|
||||
// Stores the last value iterated over.
|
||||
$parent = $value;
|
||||
}
|
||||
|
||||
if (empty($raw_values)) {
|
||||
return $build;
|
||||
}
|
||||
@@ -165,7 +238,7 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue
|
||||
$timestamps = array_keys($raw_values);
|
||||
if (NULL === $parent) {
|
||||
if (count($raw_values) > 1) {
|
||||
$gap = facetapi_get_timestamp_gap(min($timestamps), max($timestamps));
|
||||
$granularity = facetapi_get_timestamp_gap(min($timestamps), max($timestamps), $max_granularity);
|
||||
// Array of numbers used to determine whether the next gap is smaller than
|
||||
// the minimum gap allowed in the drilldown.
|
||||
$gap_numbers = array(
|
||||
@@ -178,36 +251,20 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue
|
||||
);
|
||||
// Gets gap numbers for both the gap and minimum gap, checks if the gap
|
||||
// is within the limit set by the $granularity parameter.
|
||||
if ($gap_numbers[$gap] < $gap_numbers[$granularity]) {
|
||||
$gap = $granularity;
|
||||
if ($gap_numbers[$granularity] < $gap_numbers[$max_granularity]) {
|
||||
$granularity = $max_granularity;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$gap = $granularity;
|
||||
$granularity = $max_granularity;
|
||||
}
|
||||
}
|
||||
|
||||
// Converts all timestamps to dates in ISO 8601 format.
|
||||
$dates = array();
|
||||
foreach ($timestamps as $timestamp) {
|
||||
$dates[$timestamp] = facetapi_isodate($timestamp, $gap);
|
||||
}
|
||||
|
||||
// Treat each date as the range start and next date as the range end.
|
||||
$range_end = array();
|
||||
$previous = NULL;
|
||||
foreach (array_unique($dates) as $date) {
|
||||
if (NULL !== $previous) {
|
||||
$range_end[$previous] = facetapi_get_next_date_increment($previous, $gap);
|
||||
}
|
||||
$previous = $date;
|
||||
}
|
||||
$range_end[$previous] = facetapi_get_next_date_increment($previous, $gap);
|
||||
|
||||
// Groups dates by the range they belong to, builds the $build array
|
||||
// with the facet counts and formatted range values.
|
||||
// Groups dates by the range they belong to, builds the $build array with
|
||||
// the facet counts and formatted range values.
|
||||
$format = search_api_facetapi_date_get_granularity_format($granularity);
|
||||
foreach ($raw_values as $value => $count) {
|
||||
$new_value = '[' . $dates[$value] . ' TO ' . $range_end[$dates[$value]] . ']';
|
||||
$new_value = date($format, $value);
|
||||
if (!isset($build[$new_value])) {
|
||||
$build[$new_value] = array('#count' => $count);
|
||||
}
|
||||
@@ -226,4 +283,5 @@ class SearchApiFacetapiDate extends SearchApiFacetapiTerm implements FacetapiQue
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ class SearchApiFacetapiTerm extends FacetapiQueryType implements FacetapiQueryTy
|
||||
// Return terms for this facet.
|
||||
$this->adapter->addFacet($this->facet, $query);
|
||||
|
||||
$settings = $this->adapter->getFacet($this->facet)->getSettings()->settings;
|
||||
$settings = $this->getSettings()->settings;
|
||||
|
||||
// First check if the facet is enabled for this search.
|
||||
$default_true = isset($settings['default_true']) ? $settings['default_true'] : TRUE;
|
||||
@@ -56,7 +56,12 @@ class SearchApiFacetapiTerm extends FacetapiQueryType implements FacetapiQueryTy
|
||||
$conjunction = 'OR';
|
||||
}
|
||||
else {
|
||||
throw new SearchApiException(t('Unknown facet operator %operator.', array('%operator' => $operator)));
|
||||
$vars = array(
|
||||
'%operator' => $operator,
|
||||
'%facet' => !empty($this->facet['label']) ? $this->facet['label'] : $this->facet['name'],
|
||||
);
|
||||
watchdog('search_api_facetapi', 'Unknown facet operator %operator used for facet %facet.', $vars, WATCHDOG_WARNING);
|
||||
return;
|
||||
}
|
||||
$tags = array('facet:' . $this->facet['field']);
|
||||
$facet_filter = $query->createFilter($conjunction, $tags);
|
||||
@@ -77,7 +82,7 @@ class SearchApiFacetapiTerm extends FacetapiQueryType implements FacetapiQueryTy
|
||||
// Test if this filter should be negated.
|
||||
$settings = $this->adapter->getFacet($this->facet)->getSettings();
|
||||
$exclude = !empty($settings->settings['exclude']);
|
||||
// Integer (or other nun-string) filters might mess up some of the following
|
||||
// Integer (or other non-string) filters might mess up some of the following
|
||||
// comparison expressions.
|
||||
$filter = (string) $filter;
|
||||
if ($filter == '!') {
|
||||
@@ -143,9 +148,15 @@ class SearchApiFacetapiTerm extends FacetapiQueryType implements FacetapiQueryTy
|
||||
return array();
|
||||
}
|
||||
$search_id = $search_ids[$facet['name']];
|
||||
$search = search_api_current_search($search_id);
|
||||
list(, $results) = search_api_current_search($search_id);
|
||||
$build = array();
|
||||
$results = $search[1];
|
||||
|
||||
// Always include the active facet items.
|
||||
foreach ($this->adapter->getActiveItems($this->facet) as $filter) {
|
||||
$build[$filter['value']]['#count'] = $results['result count'];
|
||||
}
|
||||
|
||||
// Then, add the facets returned by the server.
|
||||
if (isset($results['search_api_facets']) && isset($results['search_api_facets'][$this->facet['name']])) {
|
||||
$values = $results['search_api_facets'][$this->facet['name']];
|
||||
foreach ($values as $value) {
|
||||
|
@@ -9,9 +9,9 @@ files[] = plugins/facetapi/adapter.inc
|
||||
files[] = plugins/facetapi/query_type_term.inc
|
||||
files[] = plugins/facetapi/query_type_date.inc
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-25
|
||||
version = "7.x-1.11"
|
||||
; Information added by Drupal.org packaging script on 2014-12-26
|
||||
version = "7.x-1.14"
|
||||
core = "7.x"
|
||||
project = "search_api"
|
||||
datestamp = "1387965506"
|
||||
datestamp = "1419580682"
|
||||
|
||||
|
@@ -53,7 +53,7 @@ function search_api_facetapi_facetapi_searcher_info() {
|
||||
$info = array();
|
||||
$indexes = search_api_index_load_multiple(FALSE);
|
||||
foreach ($indexes as $index) {
|
||||
if ($index->enabled && $index->server()->supportsFeature('search_api_facets')) {
|
||||
if (_search_api_facetapi_index_support_feature($index)) {
|
||||
$searcher_name = 'search_api@' . $index->machine_name;
|
||||
$info[$searcher_name] = array(
|
||||
'label' => t('Search service: @name', array('@name' => $index->name)),
|
||||
@@ -97,7 +97,7 @@ function search_api_facetapi_facetapi_facet_info(array $searcher_info) {
|
||||
'date' => array(
|
||||
'query type' => 'date',
|
||||
'map options' => array(
|
||||
'map callback' => 'facetapi_map_date',
|
||||
'map callback' => 'search_api_facetapi_map_date',
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -116,7 +116,7 @@ function search_api_facetapi_facetapi_facet_info(array $searcher_info) {
|
||||
'description' => t('Filter by @type.', array('@type' => $field['name'])),
|
||||
'allowed operators' => array(
|
||||
FACETAPI_OPERATOR_AND => TRUE,
|
||||
FACETAPI_OPERATOR_OR => $index->server()->supportsFeature('search_api_facets_operator_or'),
|
||||
FACETAPI_OPERATOR_OR => _search_api_facetapi_index_support_feature($index, 'search_api_facets_operator_or'),
|
||||
),
|
||||
'dependency plugins' => array('role'),
|
||||
'facet missing allowed' => TRUE,
|
||||
@@ -218,7 +218,7 @@ function search_api_facetapi_settings($realm_name, SearchApiIndex $index) {
|
||||
if (!$index->enabled) {
|
||||
return array('#markup' => t('Since this index is at the moment disabled, no facets can be activated.'));
|
||||
}
|
||||
if (!$index->server()->supportsFeature('search_api_facets')) {
|
||||
if (!_search_api_facetapi_index_support_feature($index)) {
|
||||
return array('#markup' => t('This index uses a server that does not support facet functionality.'));
|
||||
}
|
||||
$searcher_name = 'search_api@' . $index->machine_name;
|
||||
@@ -226,6 +226,28 @@ function search_api_facetapi_settings($realm_name, SearchApiIndex $index) {
|
||||
return drupal_get_form('facetapi_realm_settings_form', $searcher_name, $realm_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a certain feature is supported for an index.
|
||||
*
|
||||
* @param SearchApiIndex $index
|
||||
* The search index which should be checked.
|
||||
* @param string $feature
|
||||
* (optional) The feature to check for. Defaults to "search_api_facets".
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the feature is supported by the index's server (and the index is
|
||||
* currently enabled), FALSE otherwise.
|
||||
*/
|
||||
function _search_api_facetapi_index_support_feature(SearchApiIndex $index, $feature = 'search_api_facets') {
|
||||
try {
|
||||
$server = $index->server();
|
||||
return $server && $server->supportsFeature($feature);
|
||||
}
|
||||
catch (SearchApiException $e) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets hierarchy information for taxonomy terms.
|
||||
*
|
||||
@@ -366,7 +388,7 @@ function _search_api_facetapi_facet_create_label(array $values, array $options)
|
||||
$entities = entity_load($type, $values);
|
||||
foreach ($entities as $id => $entity) {
|
||||
$label = entity_label($type, $entity);
|
||||
if ($label) {
|
||||
if ($label !== FALSE) {
|
||||
$map[$id] = $label;
|
||||
}
|
||||
}
|
||||
@@ -432,3 +454,131 @@ function search_api_facetapi_search_api_admin_index_fields_submit($form, &$form_
|
||||
$cid = 'facetapi:facet_info:search_api@' . $form_state['index']->machine_name . ':';
|
||||
cache_clear_all($cid, 'cache', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the granularity of a date facet filter.
|
||||
*
|
||||
* @param $filter
|
||||
* The filter value to examine.
|
||||
*
|
||||
* @return string|null
|
||||
* Either one of the FACETAPI_DATE_* constants corresponding to the
|
||||
* granularity of the filter, or NULL if it couldn't be computed.
|
||||
*/
|
||||
function search_api_facetapi_date_get_granularity($filter) {
|
||||
// Granularity corresponds to number of dashes in filter value.
|
||||
$units = array(
|
||||
FACETAPI_DATE_YEAR,
|
||||
FACETAPI_DATE_MONTH,
|
||||
FACETAPI_DATE_DAY,
|
||||
FACETAPI_DATE_HOUR,
|
||||
FACETAPI_DATE_MINUTE,
|
||||
FACETAPI_DATE_SECOND,
|
||||
);
|
||||
$count = substr_count($filter, '-');
|
||||
return isset($units[$count]) ? $units[$count] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date format used for a given granularity.
|
||||
*
|
||||
* @param $granularity
|
||||
* One of the FACETAPI_DATE_* constants.
|
||||
*
|
||||
* @return string
|
||||
* The date format used for the given granularity.
|
||||
*/
|
||||
function search_api_facetapi_date_get_granularity_format($granularity) {
|
||||
$formats = array(
|
||||
FACETAPI_DATE_YEAR => 'Y',
|
||||
FACETAPI_DATE_MONTH => 'Y-m',
|
||||
FACETAPI_DATE_DAY => 'Y-m-d',
|
||||
FACETAPI_DATE_HOUR => 'Y-m-d-H',
|
||||
FACETAPI_DATE_MINUTE => 'Y-m-d-H-i',
|
||||
FACETAPI_DATE_SECOND => 'Y-m-d-H-i-s',
|
||||
);
|
||||
return $formats[$granularity];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs labels for date facet filter values.
|
||||
*
|
||||
* @param array $values
|
||||
* The date facet filter values, as used in URL parameters.
|
||||
* @param array $options
|
||||
* (optional) Options for creating the mapping. The following options are
|
||||
* recognized:
|
||||
* - format callback: A callback for creating a label for a timestamp. The
|
||||
* function signature is like search_api_facetapi_format_timestamp(),
|
||||
* receiving a timestamp and one of the FACETAPI_DATE_* constants as the
|
||||
* parameters and returning a human-readable label.
|
||||
*
|
||||
* @return array
|
||||
* An array of labels for the given facet filters.
|
||||
*/
|
||||
function search_api_facetapi_map_date(array $values, array $options = array()) {
|
||||
$map = array();
|
||||
foreach ($values as $value) {
|
||||
// Ignore any filters passed directly from the server (range or missing). We
|
||||
// always create filters starting with a year.
|
||||
$value = "$value";
|
||||
if (!$value || !ctype_digit($value[0])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the granularity of the filter.
|
||||
$granularity = search_api_facetapi_date_get_granularity($value);
|
||||
if (!$granularity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For years, the URL value is already the label.
|
||||
if ($granularity == FACETAPI_DATE_YEAR) {
|
||||
$map[$value] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, parse the timestamp from the known format and format it as a
|
||||
// label.
|
||||
$format = search_api_facetapi_date_get_granularity_format($granularity);
|
||||
$date = DateTime::createFromFormat($format, $value);
|
||||
if (!$date) {
|
||||
continue;
|
||||
}
|
||||
$format_callback = 'search_api_facetapi_format_timestamp';
|
||||
if (!empty($options['format callback']) && is_callable($options['format callback'])) {
|
||||
$format_callback = $options['format callback'];
|
||||
}
|
||||
$map[$value] = call_user_func($format_callback, $date->format('U'), $granularity);
|
||||
}
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date according to the default timezone and the given precision.
|
||||
*
|
||||
* @param int $timestamp
|
||||
* An integer containing the Unix timestamp being formated.
|
||||
* @param string $precision
|
||||
* A string containing the formatting precision. See the FACETAPI_DATE_*
|
||||
* constants for valid values.
|
||||
*
|
||||
* @return string
|
||||
* A human-readable representation of the timestamp.
|
||||
*/
|
||||
function search_api_facetapi_format_timestamp($timestamp, $precision = FACETAPI_DATE_YEAR) {
|
||||
$formats = array(
|
||||
FACETAPI_DATE_YEAR => 'Y',
|
||||
FACETAPI_DATE_MONTH => 'F Y',
|
||||
FACETAPI_DATE_DAY => 'F j, Y',
|
||||
FACETAPI_DATE_HOUR => 'H:__',
|
||||
FACETAPI_DATE_MINUTE => 'H:i',
|
||||
FACETAPI_DATE_SECOND => 'H:i:s',
|
||||
);
|
||||
|
||||
if (!isset($formats[$precision])) {
|
||||
$precision = FACETAPI_DATE_YEAR;
|
||||
}
|
||||
|
||||
return format_date($timestamp, 'custom', $formats[$precision]);
|
||||
}
|
||||
|
@@ -66,7 +66,13 @@ class SearchApiViewsHandlerArgumentFulltext extends SearchApiViewsHandlerArgumen
|
||||
*/
|
||||
public function query($group_by = FALSE) {
|
||||
if ($this->options['fields']) {
|
||||
$this->query->fields($this->options['fields']);
|
||||
try {
|
||||
$this->query->fields($this->options['fields']);
|
||||
}
|
||||
catch (SearchApiException $e) {
|
||||
$this->query->abort($e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ($this->options['conjunction'] != 'AND') {
|
||||
$this->query->setOption('conjunction', $this->options['conjunction']);
|
||||
|
@@ -62,24 +62,30 @@ class SearchApiViewsHandlerArgumentMoreLikeThis extends SearchApiViewsHandlerArg
|
||||
* The argument sent may be found at $this->argument.
|
||||
*/
|
||||
public function query($group_by = FALSE) {
|
||||
$server = $this->query->getIndex()->server();
|
||||
if (!$server->supportsFeature('search_api_mlt')) {
|
||||
$class = search_api_get_service_info($server->class);
|
||||
watchdog('search_api_views', 'The search service "@class" does not offer "More like this" functionality.',
|
||||
try {
|
||||
$server = $this->query->getIndex()->server();
|
||||
if (!$server->supportsFeature('search_api_mlt')) {
|
||||
$class = search_api_get_service_info($server->class);
|
||||
watchdog('search_api_views', 'The search service "@class" does not offer "More like this" functionality.',
|
||||
array('@class' => $class['name']), WATCHDOG_ERROR);
|
||||
$this->query->abort();
|
||||
return;
|
||||
}
|
||||
$fields = $this->options['fields'] ? $this->options['fields'] : array();
|
||||
if (empty($fields)) {
|
||||
foreach ($this->query->getIndex()->options['fields'] as $key => $field) {
|
||||
$fields[] = $key;
|
||||
$this->query->abort();
|
||||
return;
|
||||
}
|
||||
$fields = $this->options['fields'] ? $this->options['fields'] : array();
|
||||
if (empty($fields)) {
|
||||
foreach ($this->query->getIndex()->options['fields'] as $key => $field) {
|
||||
$fields[] = $key;
|
||||
}
|
||||
}
|
||||
$mlt = array(
|
||||
'id' => $this->argument,
|
||||
'fields' => $fields,
|
||||
);
|
||||
$this->query->getSearchApiQuery()->setOption('search_api_mlt', $mlt);
|
||||
}
|
||||
catch (SearchApiException $e) {
|
||||
$this->query->abort($e->getMessage());
|
||||
}
|
||||
$mlt = array(
|
||||
'id' => $this->argument,
|
||||
'fields' => $fields,
|
||||
);
|
||||
$this->query->getSearchApiQuery()->setOption('search_api_mlt', $mlt);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -90,7 +90,8 @@ abstract class SearchApiViewsHandlerFilterEntity extends SearchApiViewsHandlerFi
|
||||
|
||||
// Set the correct default value in case the admin-set value is used (and a
|
||||
// value is present). The value is used if the form is either not exposed,
|
||||
// or the exposed form wasn't submitted yet (there is
|
||||
// or the exposed form wasn't submitted yet. (There doesn't seem to be an
|
||||
// easier way to check for that.)
|
||||
if ($this->value && (empty($form_state['input']) || !empty($form_state['input']['live_preview']))) {
|
||||
$form['value']['#default_value'] = $this->ids_to_strings($this->value);
|
||||
}
|
||||
@@ -102,11 +103,13 @@ abstract class SearchApiViewsHandlerFilterEntity extends SearchApiViewsHandlerFi
|
||||
public function value_validate($form, &$form_state) {
|
||||
if (!empty($form['value'])) {
|
||||
$value = &$form_state['values']['options']['value'];
|
||||
$values = $this->isMultiValued($form_state['values']['options']) ? drupal_explode_tags($value) : array($value);
|
||||
$ids = $this->validate_entity_strings($form['value'], $values);
|
||||
if (strlen($value)) {
|
||||
$values = $this->isMultiValued($form_state['values']['options']) ? drupal_explode_tags($value) : array($value);
|
||||
$ids = $this->validate_entity_strings($form['value'], $values);
|
||||
|
||||
if ($ids) {
|
||||
$value = $ids;
|
||||
if ($ids) {
|
||||
$value = $ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,6 +138,7 @@ abstract class SearchApiViewsHandlerFilterEntity extends SearchApiViewsHandlerFi
|
||||
return;
|
||||
}
|
||||
|
||||
$this->validated_exposed_input = FALSE;
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
$input = $form_state['values'][$identifier];
|
||||
|
||||
@@ -143,14 +147,14 @@ abstract class SearchApiViewsHandlerFilterEntity extends SearchApiViewsHandlerFi
|
||||
$input = $this->options['group_info']['group_items'][$input]['value'];
|
||||
}
|
||||
|
||||
if (!strlen($input)) {
|
||||
return;
|
||||
}
|
||||
$values = $this->isMultiValued() ? drupal_explode_tags($input) : array($input);
|
||||
|
||||
if (!$this->options['is_grouped'] || ($this->options['is_grouped'] && ($input != 'All'))) {
|
||||
$this->validated_exposed_input = $this->validate_entity_strings($form[$identifier], $values);
|
||||
}
|
||||
else {
|
||||
$this->validated_exposed_input = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,6 +179,9 @@ abstract class SearchApiViewsHandlerFilterEntity extends SearchApiViewsHandlerFi
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function admin_summary() {
|
||||
if (!is_array($this->value)) {
|
||||
$this->value = $this->value ? array($this->value) : array();
|
||||
}
|
||||
$value = $this->value;
|
||||
$this->value = empty($value) ? '' : $this->ids_to_strings($value);
|
||||
$ret = parent::admin_summary();
|
||||
|
@@ -156,8 +156,9 @@ class SearchApiViewsHandlerFilterFulltext extends SearchApiViewsHandlerFilterTex
|
||||
|
||||
if ($filter) {
|
||||
$filter = $this->query->createFilter('OR');
|
||||
$op = $this->operator === 'NOT' ? '<>' : '=';
|
||||
foreach ($fields as $field) {
|
||||
$filter->condition($field, $this->value, $this->operator);
|
||||
$filter->condition($field, $this->value, $op);
|
||||
}
|
||||
$this->query->filter($filter);
|
||||
return;
|
||||
@@ -166,11 +167,18 @@ class SearchApiViewsHandlerFilterFulltext extends SearchApiViewsHandlerFilterTex
|
||||
// If the operator was set to OR or NOT, set OR as the conjunction. (It is
|
||||
// also set for NOT since otherwise it would be "not all of these words".)
|
||||
if ($this->operator != 'AND') {
|
||||
$this->query->setOption('conjunction', $this->operator);
|
||||
$this->query->setOption('conjunction', 'OR');
|
||||
}
|
||||
|
||||
$this->query->fields($fields);
|
||||
$old = $this->query->getOriginalKeys();
|
||||
try {
|
||||
$this->query->fields($fields);
|
||||
}
|
||||
catch (SearchApiException $e) {
|
||||
$this->query->abort($e->getMessage());
|
||||
return;
|
||||
}
|
||||
$old = $this->query->getKeys();
|
||||
$old_original = $this->query->getOriginalKeys();
|
||||
$this->query->keys($this->value);
|
||||
if ($this->operator == 'NOT') {
|
||||
$keys = &$this->query->getKeys();
|
||||
@@ -181,16 +189,44 @@ class SearchApiViewsHandlerFilterFulltext extends SearchApiViewsHandlerFilterTex
|
||||
// We can't know how negation is expressed in the server's syntax.
|
||||
}
|
||||
}
|
||||
|
||||
// If there were fulltext keys set, we take care to combine them in a
|
||||
// meaningful way (especially with negated keys).
|
||||
if ($old) {
|
||||
$keys = &$this->query->getKeys();
|
||||
// Array-valued keys are combined.
|
||||
if (is_array($keys)) {
|
||||
$keys[] = $old;
|
||||
// If the old keys weren't parsed into an array, we instead have to
|
||||
// combine the original keys.
|
||||
if (is_scalar($old)) {
|
||||
$keys = "($old) ({$this->value})";
|
||||
}
|
||||
else {
|
||||
// If the conjunction or negation settings aren't the same, we have to
|
||||
// nest both old and new keys array.
|
||||
if (!empty($keys['#negation']) != !empty($old['#negation']) || $keys['#conjunction'] != $old['#conjunction']) {
|
||||
$keys = array(
|
||||
'#conjunction' => 'AND',
|
||||
$old,
|
||||
$keys,
|
||||
);
|
||||
}
|
||||
// Otherwise, just add all individual words from the old keys to the
|
||||
// new ones.
|
||||
else {
|
||||
foreach (element_children($old) as $i) {
|
||||
$keys[] = $old[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (is_array($old)) {
|
||||
// We don't support such nonsense.
|
||||
}
|
||||
else {
|
||||
$keys = "($old) ($keys)";
|
||||
// If the parse mode was "direct" for both old and new keys, we
|
||||
// concatenate them and set them both via method and reference (to also
|
||||
// update the originalKeys property.
|
||||
elseif (is_scalar($old_original)) {
|
||||
$combined_keys = "($old_original) ($keys)";
|
||||
$this->query->keys($combined_keys);
|
||||
$keys = $combined_keys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,26 +14,14 @@
|
||||
class SearchApiViewsHandlerFilterLanguage extends SearchApiViewsHandlerFilterOptions {
|
||||
|
||||
/**
|
||||
* Provide a form for setting options.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function value_form(&$form, &$form_state) {
|
||||
parent::value_form($form, $form_state);
|
||||
$form['value']['#options'] = array(
|
||||
protected function get_value_options() {
|
||||
parent::get_value_options();
|
||||
$this->value_options = array(
|
||||
'current' => t("Current user's language"),
|
||||
'default' => t('Default site language'),
|
||||
) + $form['value']['#options'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a summary of this filter's value for the admin UI.
|
||||
*/
|
||||
public function admin_summary() {
|
||||
$tmp = $this->definition['options'];
|
||||
$this->definition['options']['current'] = t('current');
|
||||
$this->definition['options']['default'] = t('default');
|
||||
$ret = parent::admin_summary();
|
||||
$this->definition['options'] = $tmp;
|
||||
return $ret;
|
||||
) + $this->value_options;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -28,8 +28,23 @@ class SearchApiViewsHandlerSort extends views_handler_sort {
|
||||
unset($this->query->orderby);
|
||||
$sort = &$this->query->getSort();
|
||||
$sort = array();
|
||||
unset($sort);
|
||||
}
|
||||
|
||||
// If two of the same fields are used for sort, ignore the latter in order
|
||||
// for the prior to take precedence. (Temporary workaround until
|
||||
// https://www.drupal.org/node/2145547 is fixed in Views.)
|
||||
$alreadySorted = $this->query->getSort();
|
||||
if (is_array($alreadySorted) && isset($alreadySorted[$this->real_field])) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->query->sort($this->real_field, $this->options['order']);
|
||||
}
|
||||
catch (SearchApiException $e) {
|
||||
$this->query->abort($e->getMessage());
|
||||
}
|
||||
$this->query->sort($this->real_field, $this->options['order']);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -77,22 +77,24 @@ class SearchApiViewsCache extends views_plugin_cache_time {
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides views_plugin_cache::get_results_key().
|
||||
* Overrides views_plugin_cache::get_cache_key().
|
||||
*
|
||||
* Use the Search API query as the main source for the key.
|
||||
* Use the Search API query as the main source for the key. Note that in
|
||||
* Views < 3.8, this function does not exist.
|
||||
*/
|
||||
public function get_results_key() {
|
||||
public function get_cache_key($key_data = array()) {
|
||||
global $user;
|
||||
|
||||
if (!isset($this->_results_key)) {
|
||||
$query = $this->getSearchApiQuery();
|
||||
$query->preExecute();
|
||||
$key_data = array(
|
||||
$key_data += array(
|
||||
'query' => $query,
|
||||
'roles' => array_keys($user->roles),
|
||||
'super-user' => $user->uid == 1, // special caching for super user.
|
||||
'language' => $GLOBALS['language']->language,
|
||||
'base_url' => $GLOBALS['base_url'],
|
||||
'offset' => $this->view->get_current_page() . '*' . $this->view->get_items_per_page() . '+' . $this->view->get_offset(),
|
||||
);
|
||||
// Not sure what gets passed in exposed_info, so better include it. All
|
||||
// other parameters used in the parent method are already reflected in the
|
||||
@@ -100,8 +102,19 @@ class SearchApiViewsCache extends views_plugin_cache_time {
|
||||
if (isset($_GET['exposed_info'])) {
|
||||
$key_data['exposed_info'] = $_GET['exposed_info'];
|
||||
}
|
||||
}
|
||||
$key = md5(serialize($key_data));
|
||||
return $key;
|
||||
}
|
||||
|
||||
$this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . md5(serialize($key_data));
|
||||
/**
|
||||
* Overrides views_plugin_cache::get_results_key().
|
||||
*
|
||||
* This is unnecessary for Views >= 3.8.
|
||||
*/
|
||||
public function get_results_key() {
|
||||
if (!isset($this->_results_key)) {
|
||||
$this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . $this->get_cache_key();
|
||||
}
|
||||
|
||||
return $this->_results_key;
|
||||
|
@@ -169,7 +169,7 @@ class SearchApiViewsQuery extends views_plugin_query {
|
||||
'#default_value' => $this->options['search_api_bypass_access'],
|
||||
);
|
||||
|
||||
if (entity_get_info($this->index->item_type)) {
|
||||
if ($this->index->getEntityType()) {
|
||||
$form['entity_access'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Additional access checks on result entities'),
|
||||
@@ -342,7 +342,7 @@ class SearchApiViewsQuery extends views_plugin_query {
|
||||
catch (Exception $e) {
|
||||
$this->errors[] = $e->getMessage();
|
||||
// Recursion to get the same error behaviour as above.
|
||||
return $this->execute($view);
|
||||
$this->execute($view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,9 +374,9 @@ class SearchApiViewsQuery extends views_plugin_query {
|
||||
// First off, we try to gather as much field values as possible without
|
||||
// loading any items.
|
||||
foreach ($results as $id => $result) {
|
||||
if (!empty($this->options['entity_access'])) {
|
||||
$entity = entity_load($this->index->item_type, array($id));
|
||||
if (!entity_access('view', $this->index->item_type, $entity[$id])) {
|
||||
if (!empty($this->options['entity_access']) && ($entity_type = $this->index->getEntityType())) {
|
||||
$entity = entity_load($entity_type, array($id));
|
||||
if (!entity_access('view', $entity_type, $entity[$id])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -660,16 +660,18 @@ class SearchApiViewsQuery extends views_plugin_query {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function getOption($name) {
|
||||
public function getOption($name, $default = NULL) {
|
||||
if (!$this->errors) {
|
||||
return $this->query->getOption($name);
|
||||
return $this->query->getOption($name, $default);
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
public function setOption($name, $value) {
|
||||
if (!$this->errors) {
|
||||
return $this->query->setOption($name, $value);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public function &getOptions() {
|
||||
|
@@ -27,9 +27,9 @@ files[] = includes/handler_sort.inc
|
||||
files[] = includes/plugin_cache.inc
|
||||
files[] = includes/query.inc
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-25
|
||||
version = "7.x-1.11"
|
||||
; Information added by Drupal.org packaging script on 2014-12-26
|
||||
version = "7.x-1.14"
|
||||
core = "7.x"
|
||||
project = "search_api"
|
||||
datestamp = "1387965506"
|
||||
datestamp = "1419580682"
|
||||
|
||||
|
@@ -134,8 +134,8 @@ function search_api_views_views_data() {
|
||||
if (isset($field['entity_type']) && $field['entity_type'] === 'taxonomy_term') {
|
||||
$field_id = ($pos = strrpos($key, ':')) ? substr($key, $pos + 1) : $key;
|
||||
$field_info = field_info_field($field_id);
|
||||
if (isset($field_info['settings']['allowed_values'][0]['vocabulary'])) {
|
||||
$vocabulary_fields[$field_info['settings']['allowed_values'][0]['vocabulary']][] = $key;
|
||||
if ($vocabulary = _search_api_views_get_field_vocabulary($field_info)) {
|
||||
$vocabulary_fields[$vocabulary][] = $key;
|
||||
}
|
||||
else {
|
||||
$vocabulary_fields[''][] = $key;
|
||||
@@ -184,7 +184,7 @@ function _search_api_views_add_handlers($id, array $field, EntityMetadataWrapper
|
||||
if ($inner_type == 'text') {
|
||||
$table[$id] += array(
|
||||
'argument' => array(
|
||||
'handler' => 'SearchApiViewsHandlerArgument',
|
||||
'handler' => 'SearchApiViewsHandlerArgumentString',
|
||||
),
|
||||
'filter' => array(
|
||||
'handler' => 'SearchApiViewsHandlerFilterText',
|
||||
@@ -209,7 +209,6 @@ function _search_api_views_add_handlers($id, array $field, EntityMetadataWrapper
|
||||
}
|
||||
elseif (isset($field['entity_type']) && $field['entity_type'] === 'taxonomy_term') {
|
||||
$table[$id]['filter']['handler'] = 'SearchApiViewsHandlerFilterTaxonomyTerm';
|
||||
$info = $wrapper->info();
|
||||
$field_info = field_info_field($info['name']);
|
||||
// For the "Parent terms" and "All parent terms" properties, we can
|
||||
// extrapolate the vocabulary from the parent in the selector. (E.g.,
|
||||
@@ -221,8 +220,8 @@ function _search_api_views_add_handlers($id, array $field, EntityMetadataWrapper
|
||||
$field_info = field_info_field($parts[count($parts) - 2]);
|
||||
}
|
||||
}
|
||||
if (isset($field_info['settings']['allowed_values'][0]['vocabulary'])) {
|
||||
$table[$id]['filter']['vocabulary'] = $field_info['settings']['allowed_values'][0]['vocabulary'];
|
||||
if ($vocabulary = _search_api_views_get_field_vocabulary($field_info)) {
|
||||
$table[$id]['filter']['vocabulary'] = $vocabulary;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -293,3 +292,31 @@ function search_api_views_views_plugins() {
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vocabulary machine name of a term field.
|
||||
*
|
||||
* @param array|null $field_info
|
||||
* The field's field info array, or NULL if the field is not provided by the
|
||||
* Field API. See the return value of field_info_field().
|
||||
*
|
||||
* @return string|null
|
||||
* If the field contains taxonomy terms of a single vocabulary (which could be
|
||||
* determined), that vocabulary's machine name; NULL otherwise.
|
||||
*/
|
||||
function _search_api_views_get_field_vocabulary($field_info) {
|
||||
// Test for "Term reference" fields.
|
||||
if (isset($field_info['settings']['allowed_values'][0]['vocabulary'])) {
|
||||
return $field_info['settings']['allowed_values'][0]['vocabulary'];
|
||||
}
|
||||
// Test for "Entity reference" fields.
|
||||
elseif (isset($field_info['settings']['handler']) && $field_info['settings']['handler'] === 'base') {
|
||||
if (!empty($field_info['settings']['handler_settings']['target_bundles'])) {
|
||||
$bundles = $field_info['settings']['handler_settings']['target_bundles'];
|
||||
if (count($bundles) == 1) {
|
||||
return key($bundles);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
Reference in New Issue
Block a user