Commit 329dac1e authored by Naveen Valecha's avatar Naveen Valecha Committed by Thomas Seidl
Browse files

Issue #3273159 by naveenvalecha, drunken monkey: Added the "Custom value" processor property.

parent 53e59ba8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
Search API 1.x, dev (xxxx-xx-xx):
---------------------------------
- #3273159 by naveenvalecha, drunken monkey: Added the "Custom value" processor
  property.
- #3296477 by abramm, drunken monkey: Fixed results when only one value is
  entered in a Views date range filter.
- #2855447 by edurenye, drunken monkey, alexdoma: Added option to customize the
+8 −0
Original line number Diff line number Diff line
@@ -272,3 +272,11 @@ search_api.property_configuration.search_api_url:
    absolute:
      type: boolean
      label: 'Whether to generate an absolute URL'

search_api.property_configuration.custom_value:
  type: mapping
  label: Custom value
  mapping:
    value:
      type: string
      label: 'The field value'
+123 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\search_api\Plugin\search_api\processor;

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Utility\Token;
use Drupal\search_api\Datasource\DatasourceInterface;
use Drupal\search_api\Item\ItemInterface;
use Drupal\search_api\Plugin\search_api\processor\Property\CustomValueProperty;
use Drupal\search_api\Processor\ProcessorPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Allows adding custom tokenized text values to the index.
 *
 * @SearchApiProcessor(
 *   id = "custom_value",
 *   label = @Translation("Custom value"),
 *   description = @Translation("Allows adding custom tokenized text values to the index."),
 *   stages = {
 *     "add_properties" = 0,
 *   },
 *   locked = true,
 *   hidden = true,
 * )
 */
class CustomValue extends ProcessorPluginBase {

  /**
   * The token service.
   *
   * @var \Drupal\Core\Utility\Token|null
   */
  protected $token;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
    $processor = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $processor->setToken($container->get('token'));
    return $processor;
  }

  /**
   * Retrieves the token service.
   *
   * @return \Drupal\Core\Utility\Token
   *   The token service.
   */
  public function getToken(): Token {
    return $this->token ?: \Drupal::token();
  }

  /**
   * Sets the token service.
   *
   * @param \Drupal\Core\Utility\Token $token
   *   The new token service.
   *
   * @return $this
   */
  public function setToken(Token $token): self {
    $this->token = $token;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getPropertyDefinitions(DatasourceInterface $datasource = NULL) {
    $properties = [];

    if (!$datasource) {
      $definition = [
        'label' => $this->t('Custom value'),
        'description' => $this->t('Index a custom value with replacement tokens.'),
        'type' => 'string',
        'processor_id' => $this->getPluginId(),
      ];
      $properties['custom_value'] = new CustomValueProperty($definition);
    }

    return $properties;
  }

  /**
   * {@inheritdoc}
   */
  public function addFieldValues(ItemInterface $item) {
    // Get all of the "custom_value" fields on this item.
    $fields = $this->getFieldsHelper()
      ->filterForPropertyPath($item->getFields(), NULL, 'custom_value');
    // If the indexed item is an entity, we can pass that as data to the token
    // service. Otherwise, only global tokens are available.
    $entity = $item->getOriginalObject()->getValue();
    if ($entity instanceof EntityInterface) {
      $data = [$entity->getEntityTypeId() => $entity];
    }
    else {
      $data = [];
    }

    $token = $this->getToken();
    foreach ($fields as $field) {
      $config = $field->getConfiguration();
      if (empty($config['value'])) {
        continue;
      }
      // Check if there are any tokens to replace.
      if (preg_match_all('/\[[-\w]++(?::[-\w]++)++]/', $config['value'], $matches)) {
        $field_value = $token->replacePlain($config['value'], $data);
        // Make sure there are no left-over tokens.
        $field_value = str_replace($matches[0], '', $field_value);
        $field_value = trim($field_value);
      }
      if ($field_value !== '') {
        $field->addValue($field_value);
      }
    }
  }

}
+44 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\search_api\Plugin\search_api\processor\Property;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\search_api\Item\FieldInterface;
use Drupal\search_api\Processor\ConfigurablePropertyBase;

/**
 * Defines a "custom value" property.
 *
 * @see \Drupal\search_api\Plugin\search_api\processor\CustomValue
 */
class CustomValueProperty extends ConfigurablePropertyBase {

  use StringTranslationTrait;

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'value' => '',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(FieldInterface $field, array $form, FormStateInterface $form_state) {
    $configuration = $field->getConfiguration();

    $form['value'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Field value'),
      '#description' => $this->t('Use this field to set the data to be sent to the index. You can use replacement tokens depending on the type of item being indexed.'),
      '#default_value' => $configuration['value'] ?? '',
    ];

    return $form;
  }

}
+16 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ class ProcessorIntegrationTest extends SearchApiBrowserTestBase {
    $enabled = [
      'add_url',
      'aggregated_field',
      'custom_value',
      'entity_type',
      'language_with_fallback',
      'rendered_item',
@@ -230,6 +231,10 @@ class ProcessorIntegrationTest extends SearchApiBrowserTestBase {
    // locked.
    $this->checkUrlFieldIntegration();

    // The 'custom_value' processor is not available to be removed because it's
    // locked.
    $this->checkCustomValueIntegration();

    // Check the order of the displayed processors.
    $stages = [
      ProcessorInterface::STAGE_PREPROCESS_INDEX,
@@ -745,6 +750,17 @@ TAGS
    $this->assertTrue($this->loadIndex()->isValidProcessor('add_url'), 'The "Add URL" processor cannot be disabled.');
  }

  /**
   * Tests the integration of the "Custom value" processor.
   */
  public function checkCustomValueIntegration() {
    $index = $this->loadIndex();
    $index->removeProcessor('custom_value');
    $index->save();

    $this->assertTrue($this->loadIndex()->isValidProcessor('custom_value'), 'The "Custom value" processor cannot be disabled.');
  }

  /**
   * Tests that a processor can be enabled.
   *
Loading