コード例 #1
0
  /**
   * Tests whether overriding of testType() works correctly.
   */
  public function testTestTypeOverride() {
    $override = function ($type) {
      return Utility::isTextType($type, array('string', 'integer'));
    };
    $this->processor->setMethodOverride('testType', $override);

    $items = $this->getTestItem();
    $this->processor->preprocessIndexItems($items);
    $this->assertFieldsProcessed($items, array('string_field', 'integer_field'));
  }
コード例 #2
0
 /**
  * {@inheritdoc}
  */
 protected function testType($type)
 {
     return Utility::isTextType($type, array('text', 'tokenized_text'));
 }
コード例 #3
0
ファイル: HtmlFilter.php プロジェクト: jkyto/agolf
 /**
  * {@inheritdoc}
  */
 protected function processFieldValue(&$value, &$type) {
   // Remove invisible content.
   $text = preg_replace('@<(applet|audio|canvas|command|embed|iframe|map|menu|noembed|noframes|noscript|script|style|svg|video)[^>]*>.*</\1>@siU', ' ', $value);
   // Let removed tags still delimit words.
   $is_text_type = Utility::isTextType($type, array('text', 'tokenized_text'));
   if ($is_text_type) {
     $text = str_replace(array('<', '>'), array(' <', '> '), $text);
     if ($this->configuration['title']) {
       $text = preg_replace('/(<[-a-z_]+[^>]*["\s])title\s*=\s*("([^"]+)"|\'([^\']+)\')([^>]*>)/i', '$1 $5 $3$4 ', $text);
     }
     if ($this->configuration['alt']) {
       $text = preg_replace('/<[-a-z_]+[^>]*["\s]alt\s*=\s*("([^"]+)"|\'([^\']+)\')[^>]*>/i', ' <img>$2$3</img> ', $text);
     }
   }
   if ($this->configuration['tags'] && $is_text_type) {
     $text = strip_tags($text, '<' . implode('><', array_keys($this->configuration['tags'])) . '>');
     $value = $this->parseHtml($text);
     $type = 'tokenized_text';
   }
   else {
     $text = strip_tags($text);
     $value = $this->normalizeText(trim($text));
   }
 }
コード例 #4
0
ファイル: Highlight.php プロジェクト: curveagency/intranet
 /**
  * Retrieves the fulltext fields of the given result items.
  *
  * @param \Drupal\search_api\Item\ItemInterface[] $result_items
  *   The results for which fulltext data should be extracted, keyed by item
  *   ID.
  * @param bool $load
  *   (optional) If FALSE, only field values already present will be returned.
  *   Otherwise, fields will be loaded if necessary.
  *
  * @return \Drupal\search_api\Item\FieldInterface[][]
  *   An two-dimensional array of fulltext fields, keyed first by item ID and
  *   then field ID.
  */
 protected function getFulltextFields(array $result_items, $load = TRUE)
 {
     // @todo Add some caching, since this will sometimes be called twice for the
     //   same result set.
     $items = array();
     // All the index's fulltext fields, grouped by datasource.
     $fulltext_fields = array();
     foreach ($this->index->getFields() as $field_id => $field) {
         if (Utility::isTextType($field->getType())) {
             $fulltext_fields[$field->getDatasourceId()][$field_id] = $field;
         }
     }
     $needs_extraction = array();
     foreach ($result_items as $item_id => $result_item) {
         $datasource_id = $result_item->getDatasourceId();
         // Make sure this datasource even has any indexed fulltext fields.
         if (empty($fulltext_fields[$datasource_id])) {
             continue;
         }
         /** @var \Drupal\search_api\Item\FieldInterface $field */
         foreach ($fulltext_fields[$datasource_id] as $field_id => $field) {
             if ($result_item->getField($field_id, FALSE)) {
                 $items[$item_id][$field_id] = $result_item->getField($field_id, FALSE);
             } elseif ($load) {
                 $needs_extraction[$item_id][$field->getPropertyPath()] = clone $field;
             }
         }
     }
     $needs_load = array();
     foreach ($needs_extraction as $item_id => $fields) {
         if (!$result_items[$item_id]->getOriginalObject(FALSE)) {
             $needs_load[$item_id] = $item_id;
         }
     }
     if ($needs_load) {
         foreach ($this->index->loadItemsMultiple($needs_load) as $item_id => $object) {
             $result_items[$item_id]->setOriginalObject($object);
             unset($needs_load[$item_id]);
         }
     }
     // Remove the fields for all items that couldn't be loaded.
     $needs_extraction = array_diff_key($needs_extraction, $needs_load);
     foreach ($needs_extraction as $item_id => $fields) {
         try {
             Utility::extractFields($result_items[$item_id]->getOriginalObject(), $fields);
             foreach ($fields as $field) {
                 $field_id = $field->getFieldIdentifier();
                 $result_items[$item_id]->setField($field_id, $field);
                 $items[$item_id][$field_id] = $field;
             }
         } catch (SearchApiException $e) {
             // Missing highlighting will be the least problem in this case – just
             // ignore it.
         }
     }
     return $items;
 }
コード例 #5
0
 /**
  * Implements the magic __toString() method to simplify debugging.
  */
 public function __toString()
 {
     $out = $this->getLabel() . ' [' . $this->getFieldIdentifier() . ']: ';
     if ($this->isIndexed()) {
         $out .= 'indexed as type ' . $this->getType();
         if (Utility::isTextType($this->getType())) {
             $out .= ' (boost ' . $this->getBoost() . ')';
         }
     } else {
         $out .= 'not indexed';
     }
     if ($this->getValues()) {
         $out .= "\nValues:";
         foreach ($this->getValues() as $value) {
             $value = str_replace("\n", "\n  ", "{$value}");
             $out .= "\n- " . $value;
         }
     }
     return $out;
 }
コード例 #6
0
ファイル: Index.php プロジェクト: curveagency/intranet
 /**
  * {@inheritdoc}
  */
 public function getFulltextFields()
 {
     $fulltext_fields = array();
     foreach ($this->getFields() as $key => $field) {
         if (Utility::isTextType($field->getType())) {
             $fulltext_fields[] = $key;
         }
     }
     return $fulltext_fields;
 }
コード例 #7
0
ファイル: Index.php プロジェクト: jkyto/agolf
 /**
  * {@inheritdoc}
  */
 public function getFulltextFields($only_indexed = TRUE) {
   $i = $only_indexed ? 1 : 0;
   if (!isset($this->fulltextFields[$i])) {
     $this->fulltextFields[$i] = array();
     if ($only_indexed) {
       if (isset($this->options['fields'])) {
         foreach ($this->options['fields'] as $key => $field) {
           if (Utility::isTextType($field['type'])) {
             $this->fulltextFields[$i][] = $key;
           }
         }
       }
     }
     else {
       foreach ($this->getFields(FALSE) as $key => $field) {
         if (Utility::isTextType($field->getType())) {
           $this->fulltextFields[$i][] = $key;
         }
       }
     }
   }
   return $this->fulltextFields[$i];
 }
コード例 #8
0
ファイル: Database.php プロジェクト: jkyto/agolf
  /**
   * Implements SearchApiAutocompleteInterface::getAutocompleteSuggestions().
   */
  public function getAutocompleteSuggestions(QueryInterface $query, SearchApiAutocompleteSearch $search, $incomplete_key, $user_input) {
    $settings = isset($this->configuration['autocomplete']) ? $this->configuration['autocomplete'] : array();
    $settings += array(
      'suggest_suffix' => TRUE,
      'suggest_words' => TRUE,
    );
    // If none of these options is checked, the user apparently chose a very
    // roundabout way of telling us he doesn't want autocompletion.
    if (!array_filter($settings)) {
      return array();
    }

    $index = $query->getIndex();
    $db_info = $this->getIndexDbInfo($index);
    if (empty($db_info['field_tables'])) {
      throw new SearchApiException(new FormattableMarkup('Unknown index @id.', array('@id' => $index->id())));
    }
    $fields = $this->getFieldInfo($index);

    $suggestions = array();
    $passes = array();
    $incomplete_like = NULL;

    // Make the input lowercase as the indexed data is (usually) also all
    // lowercase.
    $incomplete_key = Unicode::strtolower($incomplete_key);
    $user_input = Unicode::strtolower($user_input);

    // Decide which methods we want to use.
    if ($incomplete_key && $settings['suggest_suffix']) {
      $passes[] = 1;
      $incomplete_like = $this->database->escapeLike($incomplete_key) . '%';
    }
    if ($settings['suggest_words'] && (!$incomplete_key || strlen($incomplete_key) >= $this->configuration['min_chars'])) {
      $passes[] = 2;
    }

    if (!$passes) {
      return array();
    }

    // We want about half of the suggestions from each enabled method.
    $limit = $query->getOption('limit', 10);
    $limit /= count($passes);
    $limit = ceil($limit);

    // Also collect all keywords already contained in the query so we don't
    // suggest them.
    $keys = preg_split('/[^\p{L}\p{N}]+/u', $user_input, -1, PREG_SPLIT_NO_EMPTY);
    $keys = array_combine($keys, $keys);
    if ($incomplete_key) {
      $keys[$incomplete_key] = $incomplete_key;
    }

    foreach ($passes as $pass) {
      if ($pass == 2 && $incomplete_key) {
        $query->keys($user_input);
      }
      // To avoid suggesting incomplete words, we have to temporarily disable
      // the "partial_matches" option. (There should be no way we'll save the
      // server during the createDbQuery() call, so this should be safe.)
      $options = $this->options;
      $this->options['partial_matches'] = FALSE;
      $db_query = $this->createDbQuery($query, $fields);
      $this->options = $options;

      // We need a list of all current results to match the suggestions against.
      // However, since MySQL doesn't allow using a temporary table multiple
      // times in one query, we regrettably have to do it this way.
      $fulltext_fields = $this->getQueryFulltextFields($query);
      if (count($fulltext_fields) > 1) {
        $all_results = $db_query->execute()->fetchCol();
        // Compute the total number of results so we can later sort out matches
        // that occur too often.
        $total = count($all_results);
      }
      else {
        $table = $this->getTemporaryResultsTable($db_query);
        if (!$table) {
          return array();
        }
        $all_results = $this->database->select($table, 't')
          ->fields('t', array('item_id'));
        $total = $this->database->query("SELECT COUNT(item_id) FROM {{$table}}")->fetchField();
      }
      $max_occurrences = $this->getConfigFactory()->get('search_api_db.settings')->get('autocomplete_max_occurrences');
      $max_occurrences = max(1, floor($total * $max_occurrences));

      if (!$total) {
        if ($pass == 1) {
          return NULL;
        }
        continue;
      }

      /** @var \Drupal\Core\Database\Query\SelectInterface|null $word_query */
      $word_query = NULL;
      foreach ($fulltext_fields as $field) {
        if (!isset($fields[$field]) || !Utility::isTextType($fields[$field]['type'])) {
          continue;
        }
        $field_query = $this->database->select($fields[$field]['table'], 't');
        $field_query->fields('t', array('word', 'item_id'))
          ->condition('item_id', $all_results, 'IN');
        if ($pass == 1) {
          $field_query->condition('word', $incomplete_like, 'LIKE')
            ->condition('word', $keys, 'NOT IN');
        }
        if (!isset($word_query)) {
          $word_query = $field_query;
        }
        else {
          $word_query->union($field_query);
        }
      }
      if (!$word_query) {
        return array();
      }
      $db_query = $this->database->select($word_query, 't');
      $db_query->addExpression('COUNT(DISTINCT item_id)', 'results');
      $db_query->fields('t', array('word'))
        ->groupBy('word')
        ->having('results <= :max', array(':max' => $max_occurrences))
        ->orderBy('results', 'DESC')
        ->range(0, $limit);
      $incomp_len = strlen($incomplete_key);
      foreach ($db_query->execute() as $row) {
        $suffix = ($pass == 1) ? substr($row->word, $incomp_len) : ' ' . $row->word;
        $suggestions[] = array(
          'suggestion_suffix' => $suffix,
          'results' => $row->results,
        );
      }
    }

    return $suggestions;
  }
コード例 #9
0
ファイル: SolrHelper.php プロジェクト: curveagency/intranet
 public function setGrouping(Query $solarium_query, QueryInterface $query, $grouping_options = array(), $index_fields = array(), $field_names = array())
 {
     $group_params['group'] = 'true';
     // We always want the number of groups returned so that we get pagers done
     // right.
     $group_params['group.ngroups'] = 'true';
     if (!empty($grouping_options['truncate'])) {
         $group_params['group.truncate'] = 'true';
     }
     if (!empty($grouping_options['group_facet'])) {
         $group_params['group.facet'] = 'true';
     }
     foreach ($grouping_options['fields'] as $collapse_field) {
         $type = $index_fields[$collapse_field]['type'];
         // Only single-valued fields are supported.
         if ($this->getSolrVersion() < 4) {
             // For Solr 3.x, only string and boolean fields are supported.
             if (!SearchApiUtility::isTextType($type, array('string', 'boolean', 'uri'))) {
                 $warnings[] = $this->t('Grouping is not supported for field @field. ' . 'Only single-valued fields of type "String", "Boolean" or "URI" are supported.', array('@field' => $index_fields[$collapse_field]['name']));
                 continue;
             }
         } else {
             if (SearchApiUtility::isTextType($type)) {
                 $warnings[] = $this->t('Grouping is not supported for field @field. ' . 'Only single-valued fields not indexed as "Fulltext" are supported.', array('@field' => $index_fields[$collapse_field]['name']));
                 continue;
             }
         }
         $group_params['group.field'][] = $field_names[$collapse_field];
     }
     if (empty($group_params['group.field'])) {
         unset($group_params);
     } else {
         if (!empty($grouping_options['group_sort'])) {
             foreach ($grouping_options['group_sort'] as $group_sort_field => $order) {
                 if (isset($fields[$group_sort_field])) {
                     $f = $fields[$group_sort_field];
                     if (substr($f, 0, 3) == 'ss_') {
                         $f = 'sort_' . substr($f, 3);
                     }
                     $order = strtolower($order);
                     $group_params['group.sort'][] = $f . ' ' . $order;
                 }
             }
             if (!empty($group_params['group.sort'])) {
                 $group_params['group.sort'] = implode(', ', $group_params['group.sort']);
             }
         }
         if (!empty($grouping_options['group_limit']) && $grouping_options['group_limit'] != 1) {
             $group_params['group.limit'] = $grouping_options['group_limit'];
         }
     }
     foreach ($group_params as $param_id => $param_value) {
         $solarium_query->addParam($param_id, $param_value);
     }
 }
コード例 #10
0
ファイル: Field.php プロジェクト: curveagency/intranet
 /**
  * Implements the magic __toString() method to simplify debugging.
  */
 public function __toString()
 {
     $label = $this->getLabel();
     $field_id = $this->getFieldIdentifier();
     $type = $this->getType();
     $out = "{$label} [{$field_id}]: indexed as type {$type}";
     if (Utility::isTextType($type)) {
         $out .= ' (boost ' . $this->getBoost() . ')';
     }
     if ($this->getValues()) {
         $out .= "\nValues:";
         foreach ($this->getValues() as $value) {
             $value = str_replace("\n", "\n  ", "{$value}");
             $out .= "\n- " . $value;
         }
     }
     return $out;
 }