Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PL-6 Generalize the Search API fields #39

Merged
merged 13 commits into from
Sep 19, 2018
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ This module facilitates indexing data from multiple Drupal sites into a single S

On each site included in the federated search, you will need to:

1. Install this module
2. Configure a Search API server to connect to the shared Solr index
3. Configure a Search API index according to the [recommended schema](docs/federated_schema.md)
1. Install Fields Search API Module
2. Install this module
3. Configure a Search API server to connect to the shared Solr index
4. Configure a Search API index according to the [recommended schema](docs/federated_schema.md)

In order to display results from the Solr index:

Expand All @@ -26,7 +27,6 @@ When changes to [federated-search-react](https://github.com/palantirnet/federate

## More information

* [How to use this module](docs/usage.md)
* [How to configure a Search API Index for federated search](docs/federated_schema.md)
* [How to theme the ReactJS search app](docs/theme.md)
* [How to add the search form block](docs/block.md)
46 changes: 0 additions & 46 deletions docs/usage.md

This file was deleted.

4 changes: 4 additions & 0 deletions modules/search_api_fields/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node-modules
14 changes: 14 additions & 0 deletions modules/search_api_fields/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Fields Search API Module

This module facilitates indexing data from multiple Drupal sites into a single Solr search index.

On each site included in the mapped field search, you will need to:

1. Install this module
2. Configure a Search API server to connect to the shared Solr index
3. Configure a Search API index according to the [recommended schema](docs/mapped_fields_schema.md)

## More information

* [How to use this module](docs/usage.md)
* [How to configure a Search API Index for federated search](docs/mapped_fields_schema.md)
19 changes: 19 additions & 0 deletions modules/search_api_fields/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "palantirnet/search_api_fields",
"type": "drupal-module",
"description": "Allows indexing multiple Drupal sites into a single Solr search index.",
"keywords": ["Drupal"],
"license": "GPL-2.0+",
"minimum-stability": "dev",
"repositories": [
{
"type": "composer",
"url": "https://packages.drupal.org/8"
}
],
"require": {
"drupal/core": "^8.0",
"drupal/search_api_solr": "^1.2",
"drupal/token": "^1.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
langcode: en
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't directly related to the fields implementation so it should stay in search_api_federated_solr.

status: true
dependencies: { }
name: search_api_fields_image
label: 'Mapped field image'
effects:
53bfd1aa-5a4e-4750-b0d2-1a1ae1f04bce:
uuid: 53bfd1aa-5a4e-4750-b0d2-1a1ae1f04bce
id: image_scale_and_crop
weight: 1
data:
width: 425
height: 239
46 changes: 46 additions & 0 deletions modules/search_api_fields/docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## About this module

This module provides new field options on Search API indexes:

1. The "Mapped field" field can be used to aggregate data from different entity types into the same field in the search index.

This is similar to the "Aggregated field" provided by Search API, but gives more direct, token-based control over the values for different entity types.

See [Using the "Mapped field"](#using-the-mapped-field).
1. The "Mapped terms" field can be used to assign "mapped term" values to any taxonomy term entities within a given site. See [Using the "Mapped terms" field](#using-the-mapped-terms-field).

## Using the "Mapped field"

1. Visit the fields list for your index at _Admin > Configuration > Search API > [your index] > Fields_ (path `/admin/config/search/search-api/index/YOUR_INDEX/fields`)
2. Click "Add fields"
3. Click the "Add" button for the "Mapped Field":

<img src="images/add_mapped_field.png" />

4. Configure field data for each entity type. This field allows token replacement; enter plain text directly or use the token browser to select tokens.

<img src="images/edit_mapped_field.png" />

5. Save your field.
6. Edit the field label, machine name, and type as necessary for your data

## Using the "Mapped terms" field

1. Visit the fields list for your index at _Admin > Configuration > Search API > [your index] > Fields_ (path `/admin/config/search/search-api/index/YOUR_INDEX/fields`)
1. Click "Add fields"
1. Click the "Add" button for the "Mapped terms":
<img src="images/add_mapped_terms.png" />
1. Once you have added the "Mapped terms" field to your search index configuration, you can read through the provided instructions and save the field:
<img src="images/confirmation_added_mapped_terms.png" />
1. Remember to save the index field configuration:
<img src="images/save_index_field_config.png" />
1. Configuration for mapped terms happens within the taxonomy term entity edit UI itself. Browse to a taxonomy vocabulary on your site and add an instance of the "Mapped terms" field type (If you plan on sharing this field among your vocabularies, use something like "Mapped terms" for the field label).
<img src="images/add_mapped_terms_to_vocabulary.png" />
<img src="images/add_mapped_term_field_label.png" />
1. Save the field settings
<img src="images/add_mapped_field_settings_save.png" />
<img src="images/add_mapped_field_save_settings_2.png" />
1. Edit any terms in the vocabularies to which you've just added a "Mapped terms" field instance. On the term edit form, you should now see a "Mapped terms" field instance where you can add one or many "mapped" terms.
<img src="images/add_mapped_term_to_term.png" />
1. Repeat for each term in each vocabulary which should have a mapped term value.
1. Once content which references these terms is indexed, all of their corresponding "mapped terms" will appear in the `mapped_terms` index property field.
9 changes: 9 additions & 0 deletions modules/search_api_fields/search_api_fields.info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: Fields Search API Module
type: module
description: Allows indexing multiple Drupal sites into a single Solr search index by field.
core: 8.x
package: Search
dependencies:
- search_api_solr
- token
- field
24 changes: 24 additions & 0 deletions modules/search_api_fields/search_api_fields.module
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/**
* @file search_api_fields.module
* Contains hook implementations for the Fields Search API Module.
*/

use Drupal\Core\Routing\RouteMatchInterface;

/**
* Implements hook_help().
*/
function search_api_fields_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the search_api_fields module.
case 'help.page.search_api_fields':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Allows indexing into a single Solr search index by field.') . '</p>';
return $output;

default:
}
}
101 changes: 101 additions & 0 deletions modules/search_api_fields/src/Plugin/Field/FieldType/MappedTerms.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php
/**
* @file
* Contains \Drupal\search_api_fields\Plugin\field\field_type\MappedTerms.
*/

namespace Drupal\search_api_fields\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;

/**
* Plugin implementation of the 'mapped_terms' field type.
*
* @FieldType(
* id = "mapped_terms",
* label = @Translation("Mapped terms"),
* description = @Translation("Stores the solr search api mapped term destination value for taxonomy terms."),
* default_widget = "mapped_terms_textfield",
* default_formatter = "string",
* cardinality = -1,
* )
*/
class MappedTerms extends FieldItemBase {
const MAPPED_TERMS_MAXLENGTH = 255;


/**
* {@inheritdoc}
*/
public static function defaultStorageSettings() {
return [
'max_length' => static::MAPPED_TERMS_MAXLENGTH,
'is_ascii' => FALSE,
] + parent::defaultStorageSettings();
}

/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return [
'columns' => [
'value' => [
'type' => $field_definition->getSetting('is_ascii') === TRUE ? 'varchar_ascii' : 'varchar',
'length' => static::MAPPED_TERMS_MAXLENGTH,
'not null' => FALSE,
],
],
];
}

/**
* {@inheritdoc}
*/
public function getConstraints() {
$constraints = parent::getConstraints();

if ($max_length = $this->getSetting('max_length')) {
$constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
$constraints[] = $constraint_manager->create('ComplexData', [
'value' => [
'Length' => [
'max' => static::MAPPED_TERMS_MAXLENGTH,
'maxMessage' => t('%name: may not be longer than @max characters.', ['%name' => $this->getFieldDefinition()->getLabel(), '@max' => static::MAPPED_TERMS_MAXLENGTH]),
],
],
]);
}
return $constraints;
}

/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['value'] = DataDefinition::create('string')->setLabel(t('Mapped terms destination value'));
return $properties;
}

/**
* {@inheritdoc}
*/
public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
$element = [];

$element['max_length'] = [
'#type' => 'number',
'#title' => t('Maximum length'),
'#default_value' => $this->getSetting('max_length'),
'#required' => TRUE,
'#description' => t('The maximum length of the field in characters.'),
'#min' => 1,
'#disabled' => $has_data,
];

return $element;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace Drupal\search_api_fields\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

/**
* Plugin implementation of the 'mapped_terms_textfield' widget.
*
* @FieldWidget(
* id = "mapped_terms_textfield",
* label = @Translation("Mapped Terms Textfield"),
* field_types = {
* "mapped_terms"
* }
* )
*/
class MappedTermsTextfieldWidget extends WidgetBase {

/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'size' => 75,
'placeholder' => '',
] + parent::defaultSettings();
}

/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$element['size'] = [
'#type' => 'number',
'#title' => t('Size of textfield'),
'#default_value' => $this->getSetting('size'),
'#required' => TRUE,
'#min' => 1,
];
$element['placeholder'] = [
'#type' => 'textfield',
'#title' => t('Placeholder'),
'#default_value' => $this->getSetting('placeholder'),
'#description' => t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
];
return $element;
}

/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = [];

$summary[] = t('Textfield size: @size', ['@size' => $this->getSetting('size')]);
$placeholder = $this->getSetting('placeholder');
if (!empty($placeholder)) {
$summary[] = t('Placeholder: @placeholder', ['@placeholder' => $placeholder]);
}

return $summary;
}

/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element['value'] = [
'#type' => 'textfield',
'#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
'#description' => $this->t('This mapped term is used as a facet value in your search application. It should consist of a hierarchy made up of a type (i.e. "Condition") and term (i.e. "Diabetes"), separated by ">". For example: Condition>Diabetes.'),
'#size' => $this->getSetting('size'),
'#placeholder' => $this->getSetting('placeholder'),
'#maxlength' => $this->getFieldSetting('max_length'),
'#attributes' => ['class' => ['js-text-full', 'text-full']],
];

return $element;
}
}
Loading