Example #1
0
 /**
  * Extracts value and original type from a single piece of data.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $data
  *   The piece of data from which to extract information.
  * @param \Drupal\search_api\Item\FieldInterface $field
  *   The field into which to put the extracted data.
  */
 public static function extractField(TypedDataInterface $data, FieldInterface $field)
 {
     $values = static::extractFieldValues($data);
     // If the data type of the field is a custom one, then the value can be
     // altered by the data type plugin.
     $data_type_manager = \Drupal::service('plugin.manager.search_api.data_type');
     if ($data_type_manager->hasDefinition($field->getType())) {
         /** @var \Drupal\search_api\DataType\DataTypeInterface $data_type_plugin */
         $data_type_plugin = $data_type_manager->createInstance($field->getType());
         foreach ($values as $i => $value) {
             $values[$i] = $data_type_plugin->getValue($value);
         }
     }
     $field->setValues($values);
     $field->setOriginalType($data->getDataDefinition()->getDataType());
 }
Example #2
0
 /**
  * {@inheritdoc}
  */
 public function setField($field_id, FieldInterface $field = NULL)
 {
     if ($field) {
         if ($field->getFieldIdentifier() !== $field_id) {
             throw new \InvalidArgumentException('The field identifier passed must be consistent with the identifier set on the field object.');
         }
         // Make sure that the field has the same index object set as we. This
         // might otherwise cause impossibly hard-to-detect bugs.
         $field->setIndex($this->index);
         $this->fields[$field_id] = $field;
     } else {
         unset($this->fields[$field_id]);
     }
     return $this;
 }
Example #3
0
 /**
  * {@inheritdoc}
  */
 public function addField(FieldInterface $field)
 {
     $field_id = $field->getFieldIdentifier();
     if (Utility::isFieldIdReserved($field_id)) {
         $args['%field_id'] = $field_id;
         throw new SearchApiException(new FormattableMarkup('%field_id is a reserved value and cannot be used as the machine name of a normal field.', $args));
     }
     $old_field = $this->getField($field_id);
     if ($old_field && $old_field != $field) {
         $args['%field_id'] = $field_id;
         throw new SearchApiException(new FormattableMarkup('Cannot add field with machine name %field_id: machine name is already taken.', $args));
     }
     $this->fieldInstances[$field_id] = $field;
     return $this;
 }
Example #4
0
  protected function createFieldTable(FieldInterface $field = NULL, $db) {
    $new_table = !$this->database->schema()->tableExists($db['table']);
    if ($new_table) {
      $table = array(
        'name' => $db['table'],
        'module' => 'search_api_db',
        'fields' => array(
          'item_id' => array(
            'type' => 'varchar',
            'length' => 50,
            'description' => 'The primary identifier of the item',
            'not null' => TRUE,
          ),
        ),
      );
      $this->database->schema()->createTable($db['table'], $table);

      // Some DBMSs will need a character encoding and collation set.
      switch ($this->database->databaseType()) {
        case 'mysql':
          $this->database->query("ALTER TABLE {{$db['table']}} CONVERT TO CHARACTER SET 'utf8' COLLATE 'utf8_bin'");
          break;

        // @todo Add fixes for other DBMSs.
        case 'oracle':
        case 'pgsql':
        case 'sqlite':
        case 'sqlsrv':
          break;
      }
    }

    // Stop here if we want to create a table with just the 'item_id' column.
    if (!isset($field)) {
      return;
    }

    $column = isset($db['column']) ? $db['column'] : 'value';
    $db_field = $this->sqlType($field->getType());
    $db_field += array(
      'description' => "The field's value for this item",
    );
    if ($new_table) {
      $db_field['not null'] = TRUE;
    }
    $this->database->schema()->addField($db['table'], $column, $db_field);
    if ($db_field['type'] === 'varchar') {
      $index_spec = array(array($column, 10));
    }
    else {
      $index_spec = array($column);
    }
    // Create a table specification skeleton to pass to addIndex().
    $table_spec = array(
      'fields' => array(
        $column => $db_field,
      ),
      'indexes' => array(
        $column => $index_spec,
      ),
    );
    $this->database->schema()->addIndex($db['table'], $column, $index_spec, $table_spec);

    if ($new_table) {
      // Add a covering index for fields with multiple values.
      if (!isset($db['column'])) {
        $this->database->schema()->addPrimaryKey($db['table'], array('item_id', $column));
      }
      // This is a denormalized table with many columns, where we can't predict
      // the best covering index.
      else {
        $this->database->schema()->addPrimaryKey($db['table'], array('item_id'));
      }
    }
  }
 /**
  * Tests whether a certain field should be processed.
  *
  * @param string $name
  *   The field's ID.
  * @param \Drupal\search_api\Item\FieldInterface $field
  *   The field's information.
  *
  * @return bool
  *   TRUE if the field should be processed, FALSE otherwise.
  */
 protected function testField($name, FieldInterface $field)
 {
     if (!isset($this->configuration['fields'])) {
         return $this->testType($field->getType());
     }
     return !empty($this->configuration['fields'][$name]);
 }
Example #6
0
 protected function createFieldTable(FieldInterface $field = NULL, $db, $type = 'field')
 {
     $new_table = !$this->database->schema()->tableExists($db['table']);
     if ($new_table) {
         $table = array('name' => $db['table'], 'module' => 'search_api_db', 'fields' => array('item_id' => array('type' => 'varchar', 'length' => 50, 'description' => 'The primary identifier of the item', 'not null' => TRUE)));
         $this->database->schema()->createTable($db['table'], $table);
         $this->dbmsCompatibility->alterNewTable($db['table'], $type);
     }
     // Stop here if we want to create a table with just the 'item_id' column.
     if (!isset($field)) {
         return;
     }
     $column = isset($db['column']) ? $db['column'] : 'value';
     $db_field = $this->sqlType($field->getType());
     $db_field += array('description' => "The field's value for this item");
     if ($new_table) {
         $db_field['not null'] = TRUE;
     }
     $this->database->schema()->addField($db['table'], $column, $db_field);
     if ($db_field['type'] === 'varchar') {
         $index_spec = array(array($column, 10));
     } else {
         $index_spec = array($column);
     }
     // Create a table specification skeleton to pass to addIndex().
     $table_spec = array('fields' => array($column => $db_field), 'indexes' => array($column => $index_spec));
     // This is a quick fix for a core bug, so we can run the tests with SQLite
     // until this is fixed.
     //
     // In SQLite, indexes and tables can't have the same name, which is
     // the case for Search API DB. We have following situation:
     //  - a table named search_api_db_default_index_search_api_language
     //  - a table named search_api_db_default_index
     //
     // The last table has an index on the search_api_language column,
     // which results in an index with the same as the first table, which
     // conflicts in SQLite.
     //
     // The core issue addressing this (https://www.drupal.org/node/1008128) was
     // closed as it fixed the PostgresSQL part. The SQLite fix is added in
     // https://www.drupal.org/node/2625664
     // We prevent this by adding an extra underscore (which is also the proposed
     // solution in the original core issue).
     //
     // @todo: Remove when #2625664 lands in Core. See #2625722 for a patch that
     //   implements this.
     try {
         $this->database->schema()->addIndex($db['table'], '_' . $column, $index_spec, $table_spec);
     } catch (\PDOException $e) {
         $variables['%column'] = $column;
         $variables['%table'] = $db['table'];
         watchdog_exception('search_api_db', $e, '%type while trying to add a database index for column %column to table %table: @message in %function (line %line of %file).', $variables, RfcLogLevel::WARNING);
     }
     if ($new_table) {
         // Add a covering index for fields with multiple values.
         if (!isset($db['column'])) {
             $this->database->schema()->addPrimaryKey($db['table'], array('item_id', $column));
         } else {
             $this->database->schema()->addPrimaryKey($db['table'], array('item_id'));
         }
     }
 }
 /**
  * Tests whether a certain field should be processed.
  *
  * @param string $name
  *   The field's ID.
  * @param \Drupal\search_api\Item\FieldInterface $field
  *   The field's information.
  *
  * @return bool
  *   TRUE if the field should be processed, FALSE otherwise.
  */
 protected function testField($name, FieldInterface $field) {
   if (!isset($this->configuration['fields'])) {
     return $this->testType($field->getType());
   }
   return in_array($name, $this->configuration['fields'], TRUE);
 }
 /**
  * Create a single search query string according to the given field, value
  * and operator.
  */
 protected function createFilterQuery($field, $value, $operator, FieldInterface $index_field)
 {
     $field = SearchApiSolrUtility::escapeFieldName($field);
     if ($value === NULL) {
         return ($operator == '=' ? '*:* AND -' : '') . "{$field}:[* TO *]";
     }
     $value = trim($value);
     $value = $this->formatFilterValue($value, $index_field->getType());
     switch ($operator) {
         case '<>':
             return "*:* AND -({$field}:{$value})";
         case '<':
             return "{$field}:{* TO {$value}}";
         case '<=':
             return "{$field}:[* TO {$value}]";
         case '>=':
             return "{$field}:[{$value} TO *]";
         case '>':
             return "{$field}:{{$value} TO *}";
         default:
             return "{$field}:{$value}";
     }
 }