Skip to content
Snippets Groups Projects

Issue #2877319: Integrate database backend with Search API Location

1 file
+ 81
0
Compare changes
  • Side-by-side
  • Inline
@@ -16,11 +16,13 @@ use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
@@ -16,11 +16,13 @@ use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Element;
 
use Drupal\Core\TypedData\DataDefinition;
use Drupal\search_api\Backend\BackendPluginBase;
use Drupal\search_api\Backend\BackendPluginBase;
use Drupal\search_api\Contrib\AutocompleteBackendInterface;
use Drupal\search_api\Contrib\AutocompleteBackendInterface;
use Drupal\search_api\DataType\DataTypePluginManager;
use Drupal\search_api\DataType\DataTypePluginManager;
use Drupal\search_api\Entity\Index;
use Drupal\search_api\Entity\Index;
use Drupal\search_api\IndexInterface;
use Drupal\search_api\IndexInterface;
 
use Drupal\search_api\Item\Field;
use Drupal\search_api\Item\FieldInterface;
use Drupal\search_api\Item\FieldInterface;
use Drupal\search_api\Item\ItemInterface;
use Drupal\search_api\Item\ItemInterface;
use Drupal\search_api\Plugin\PluginFormTrait;
use Drupal\search_api\Plugin\PluginFormTrait;
@@ -602,6 +604,13 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
@@ -602,6 +604,13 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
];
];
}
}
 
/**
 
* {@inheritdoc}
 
*/
 
public function supportsDataType($type) {
 
return $type === 'location';
 
}
 
/**
/**
* {@inheritdoc}
* {@inheritdoc}
*/
*/
@@ -919,6 +928,18 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
@@ -919,6 +928,18 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
case 'boolean':
case 'boolean':
return ['type' => 'int', 'size' => 'tiny'];
return ['type' => 'int', 'size' => 'tiny'];
 
case 'location':
 
// @todo #2877319 Find good way to index geo data so it can later be
 
// queried. Could also depend on DBMS used – in that case, add to
 
// \Drupal\search_api_db\DatabaseCompatibility\DatabaseCompatibilityHandlerInterface.
 
// E.g., for MySQL, see
 
// https://www.percona.com/sites/default/files/presentations/webinar-gis-03-15.pdf.
 
// If you need two columns (which is likely, I guess), you'll need to
 
// do some refactoring, though, or come up with another clever
 
// solution. But you could also add conditional support based on DBMS
 
// (and version).
 
return ['type' => 'varchar', 'length' => 255];
 
default:
default:
throw new SearchApiException("Unknown field type '$type'.");
throw new SearchApiException("Unknown field type '$type'.");
}
}
@@ -1539,6 +1560,8 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
@@ -1539,6 +1560,8 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
case 'boolean':
case 'boolean':
return $value ? 1 : 0;
return $value ? 1 : 0;
 
case 'location':
 
return $value;
default:
default:
throw new SearchApiException("Unknown field type '$type'.");
throw new SearchApiException("Unknown field type '$type'.");
}
}
@@ -1784,6 +1807,12 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
@@ -1784,6 +1807,12 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
$condition_group = $query->getConditionGroup();
$condition_group = $query->getConditionGroup();
$this->addLanguageConditions($condition_group, $query);
$this->addLanguageConditions($condition_group, $query);
 
// @todo #2877319 Maybe, like addLanguageConditions(), add a method here
 
// checking for the "search_api_location" option on the query and, if
 
// present, add new conditions based on the option(s) to the query.
 
// Or place the conditions directly on the query below this if block -
 
// in that case, you might need to remove any conditions on those fields
 
// from the query.
if ($condition_group->getConditions()) {
if ($condition_group->getConditions()) {
$condition = $this->createDbCondition($condition_group, $fields, $db_query, $query->getIndex());
$condition = $this->createDbCondition($condition_group, $fields, $db_query, $query->getIndex());
if ($condition) {
if ($condition) {
@@ -2260,6 +2289,11 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
@@ -2260,6 +2289,11 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
$method = $not_equals ? 'isNotNull' : 'isNull';
$method = $not_equals ? 'isNotNull' : 'isNull';
$db_condition->$method($column);
$db_condition->$method($column);
}
}
 
elseif ($field_info['type'] === 'location') {
 
// @todo #2877319 Place filter on query, possibly also taking the
 
// options into account. Or, if this is handled somewhere else,
 
// simply ignore this condition.
 
}
elseif ($not_between) {
elseif ($not_between) {
$nested_condition = $db_query->conditionGroupFactory('OR');
$nested_condition = $db_query->conditionGroupFactory('OR');
$nested_condition->condition($column, $value[0], '<');
$nested_condition->condition($column, $value[0], '<');
@@ -2425,6 +2459,8 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
@@ -2425,6 +2459,8 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
}
}
$index_table = $this->getIndexDbInfo($query->getIndex())['index_table'];
$index_table = $this->getIndexDbInfo($query->getIndex())['index_table'];
$alias = $this->getTableAlias(['table' => $index_table], $db_query);
$alias = $this->getTableAlias(['table' => $index_table], $db_query);
 
// @todo #2877319 Add special case for sorts on location fields, to sort
 
// by distance.
$db_query->orderBy($alias . '.' . $fields[$field_name]['column'], $order);
$db_query->orderBy($alias . '.' . $fields[$field_name]['column'], $order);
// PostgreSQL automatically adds a field to the SELECT list when
// PostgreSQL automatically adds a field to the SELECT list when
// sorting on it. Therefore, if we have aggregations present we also
// sorting on it. Therefore, if we have aggregations present we also
@@ -2473,6 +2509,9 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
@@ -2473,6 +2509,9 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
}
}
$field = $fields[$facet['field']];
$field = $fields[$facet['field']];
 
// @todo #2877319 This would most likely also need a special case for
 
// location fields.
 
if (($facet['operator'] ?? 'and') != 'or') {
if (($facet['operator'] ?? 'and') != 'or') {
// First, check whether this can even possibly have any results.
// First, check whether this can even possibly have any results.
if ($result_count !== NULL && $result_count < $facet['min_count']) {
if ($result_count !== NULL && $result_count < $facet['min_count']) {
@@ -2841,6 +2880,48 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
@@ -2841,6 +2880,48 @@ class Database extends BackendPluginBase implements AutocompleteBackendInterface
return $db_info;
return $db_info;
}
}
 
/**
 
* {@inheritdoc}
 
*
 
* @throws \Drupal\search_api\SearchApiException
 
*/
 
public function getBackendDefinedFields(IndexInterface $index) {
 
$backend_defined_fields = [];
 
 
foreach ($index->getFields() as $field) {
 
if ($field->getType() === 'location') {
 
$distance_field_name = $field->getFieldIdentifier() . '__distance';
 
$property_path_name = $field->getPropertyPath() . '__distance';
 
$distance_field = new Field($index, $distance_field_name);
 
$distance_field->setLabel($field->getLabel() . ' (distance)');
 
$distance_field->setDataDefinition(DataDefinition::create('decimal'));
 
$distance_field->setType('decimal');
 
$distance_field->setDatasourceId($field->getDatasourceId());
 
$distance_field->setPropertyPath($property_path_name);
 
 
$backend_defined_fields[$distance_field_name] = $distance_field;
 
}
 
}
 
 
// @todo #2877319 fix why getType() return 'string' and not 'location'?
 
foreach ($index->getFields() as $field) {
 
if ($field->getFieldIdentifier() === 'field_geofield') {
 
$distance_field_name = $field->getFieldIdentifier() . '__distance';
 
$property_path_name = $field->getPropertyPath() . '__distance';
 
$distance_field = new Field($index, $distance_field_name);
 
$distance_field->setLabel($field->getLabel() . ' (distance)');
 
$distance_field->setDataDefinition(DataDefinition::create('decimal'));
 
$distance_field->setType('decimal');
 
$distance_field->setDatasourceId($field->getDatasourceId());
 
$distance_field->setPropertyPath($property_path_name);
 
 
$backend_defined_fields[$distance_field_name] = $distance_field;
 
}
 
}
 
 
return $backend_defined_fields;
 
}
 
/**
/**
* Implements the magic __sleep() method.
* Implements the magic __sleep() method.
*
*
Loading