diff plugins/facetapi/query_type_integer.inc @ 0:a2b4f67e73dc default tip

initial
author Dirk Wintergruen <dwinter@mpiwg-berlin.mpg.de>
date Mon, 08 Jun 2015 10:21:54 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/facetapi/query_type_integer.inc	Mon Jun 08 10:21:54 2015 +0200
@@ -0,0 +1,223 @@
+<?php
+
+/**
+ * @file
+ * Date query type plugin for the Apache Solr adapter.
+ * @author dwinter
+ *
+ */
+
+
+/**
+ * Regex pattern for integer ranges.
+ */
+define('REGEX_INTEGER_RANGE', '/^\[(\d*) TO (\d*)\]$/');
+
+
+/**
+ * Plugin for "Integer" query types.
+ */
+class solrsearchFacetapiInteger extends FacetapiQueryType implements FacetapiQueryTypeInterface {
+
+  /**
+   * Overrides FacetapiQueryType::extract().
+   *
+   * Adds the "start" and "end" values for the integer range.
+   */
+  public function extract(array $item) {
+    $return = array();
+    if (preg_match(REGEX_INTEGER_RANGE, $item['value'], $matches)) {
+
+      $return['start'] = $matches[1];
+      $return['end'] = $matches[2];
+    }
+    return $return;
+  }
+
+
+  /**
+   * Returns the query type associated with the plugin.
+   *
+   * @return string
+   *   The query type.
+   */
+  static public function getType() {
+    return 'integer';
+  }
+
+  /**
+   * Adds the filter to the query object.
+   *
+   * @param DrupalSolrQueryInterface $query
+   *   An object containing the query in the backend's native API.
+   */
+  public function execute($query) {
+    // Gets the data range in formats that Solr understands.
+
+    $integer_range = $this->getIntegerRange($query);
+
+    if (empty($integer_range)) {
+      return NULL;
+    }
+    list($start, $end, $gap) = $integer_range;
+    $query->addParam('facet.range', $this->facet['field']);
+    $query->addParam('f.' . $this->facet['field'] . '.facet.range.start', $start);
+    $query->addParam('f.' . $this->facet['field'] . '.facet.range.end', $end);
+    $query->addParam('f.' . $this->facet['field'] . '.facet.range.gap', $gap);
+
+    // Adds "hard limit" parameter to prevent too many return values.
+    $settings = $this->adapter->getFacet($this->facet)->getSettings();
+    $limit = empty($settings->settings['hard_limit']) ? 20 : (int) $settings->settings['hard_limit'];
+    $query->addParam('f.' . $this->facet['field'] . '.facet.limit', $limit);
+
+    $active = $this->adapter->getActiveItems($this->facet);
+    // Date filters don't support OR operator.
+    foreach ($active as $value => $item) {
+      $query->addFilter($this->facet['field'], $value);
+    }
+  }
+
+  /**
+   * Gets the range of integer rage we are using.
+   *
+   * @param DrupalSolrQueryInterface $query
+   *   A SolrBaseQuery object.
+   *
+   * @return bool|array
+   *   An array containing the gap and range information or false if not present
+   */
+  function getIntegerRange(DrupalSolrQueryInterface $query) {
+
+    $return = NULL;
+    $gap = NULL;
+
+    // Attempts to get next gap from passed date filters.
+    foreach ($this->adapter->getActiveItems($this->facet) as $item) {
+
+      if ($gap = ($item['end'] - $item['start'])) {
+        //$next_gap = facetapi_get_next_date_gap($gap, FACETAPI_DATE_SECOND);
+        //TODO: is something similar needed for integer range?
+        $next_gap =$gap;
+        if ($next_gap == $gap) {
+          $next_gap = NULL;
+          return NULL;
+        }
+        $return = array(
+          $item['start'],
+          $item['end'],
+          $next_gap,
+        );
+      }
+    }
+
+    // If no filters were passed, get default range.
+    if (NULL === $return) {
+
+      // Builds SQL that gets minimum and maximum values from node table.
+      $minimum = $maximum =$gap = FALSE;
+      if ($this->facet['min callback'] && is_callable($this->facet['min callback'])) {
+        $minimum = $this->facet['min callback']($this->facet);
+      }
+      if ($this->facet['max callback'] && is_callable($this->facet['max callback'])) {
+        $maximum = $this->facet['max callback']($this->facet);
+      }
+
+      if ($this->facet['gap callback'] && is_callable($this->facet['gap callback'])) {
+        $gap = $this->facet['gap callback']($this->facet);
+      }
+
+
+      // Gets the default gap.
+      //$gap = FACETAPI_DATE_YEAR;
+      if ($minimum && $maximum && $gap) {
+
+        //$minimum = facetapi_isodate($minimum, $gap);
+        //$maximum = facetapi_isodate($maximum, $gap);
+        $return = array(
+          $minimum,
+          $maximum,
+          $gap ,
+        );
+      }
+    }
+    // Returns the range information.
+    return $return;
+  }
+
+  /**
+   * Initializes the facet's build array.
+   *
+   * @return array
+   *   The initialized render array.
+   */
+  public function build() {
+
+    // Initializes build and gets static response.
+    if (!$response = solrsearch_static_response_cache($this->adapter->getSearcher())) {
+      return array();
+    }
+    $build = array();
+
+    // Gets total number of documents matched in search.
+    $total = $response->response->numFound;
+
+    // Gets the active date facets, starts to builds the "parent - child"
+    // relationships.
+    $parent = NULL;
+    foreach ($this->adapter->getActiveItems($this->facet) as $value => $item) {
+      // Builds the raw facet "value", the count for selected items will be the
+      // total number of rows returned in the query.
+      $build[$value] = array('#count' => $total);
+
+      // If there is a previous item, there is a parent, uses a reference so the
+      // arrays are populated when they are updated.
+      if (NULL !== $parent) {
+        $build[$parent]['#item_children'][$value] = &$build[$value];
+        $build[$value]['#item_parents'][$parent] = $parent;
+      }
+
+      // Stores the last value iterated over.
+      $parent = $value;
+    }
+
+    // Gets raw facet data from the Solr server.
+    if (isset($response->facet_counts->facet_ranges) && isset($response->facet_counts->facet_ranges->{$this->facet['field']})) {
+      $raw_data = (array) $response->facet_counts->facet_ranges->{$this->facet['field']};
+    }
+    else {
+      $raw_data = array();
+    }
+    //$end = (!empty($raw_data['end'])) ? $raw_data['end'] : '';
+    //$start = (!empty($raw_data['start'])) ? $raw_data['start'] : '';
+    $gap = (!empty($raw_data['gap'])) ? $raw_data['gap'] : '';
+
+    // We cannot list anything below a minute (range of 00 seconds till 59
+    // seconds. Milliseconds are not possible)
+
+      unset($raw_data['start']);
+      unset($raw_data['end']);
+      unset($raw_data['gap']);
+
+      // Treat each date facet as a range start, and use the next date facet
+      // as range end.  Use 'end' for the final end.
+      $previous = NULL;
+
+      // Builds facet counts object used by the server.
+
+      foreach ($raw_data as $value => $counts) {
+        foreach($counts as $val => $count){
+        if ($count) {
+                  $from = $val;
+          $to = $val+$gap;
+          $new_value = '[' . $from . ' TO ' . $to . ']';
+          $build[$new_value] = array('#count' => $count, '#active' => 0);
+          if (NULL !== $parent) {
+            $build[$parent]['#item_children'][$new_value] = &$build[$new_value];
+            $build[$new_value]['#item_parents'][$parent] = $parent;
+          }
+        }
+      }
+      }
+    return $build;
+  }
+}