external_entities-8.x-2.x-dev/src/PropertyMapper/PropertyMapperBase.php

src/PropertyMapper/PropertyMapperBase.php
<?php

namespace Drupal\external_entities\PropertyMapper;

use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Plugin\PluginDependencyTrait;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\external_entities\Entity\ExternalEntityTypeInterface;
use Drupal\external_entities\Form\XnttSubformState;
use Drupal\external_entities\Plugin\PluginDebugTrait;
use Drupal\external_entities\Plugin\PluginFormTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * A base class for property mappers.
 */
abstract class PropertyMapperBase extends PluginBase implements PropertyMapperInterface, ConfigurableInterface, PluginFormInterface {

  use PluginDependencyTrait;
  use PluginFormTrait;
  use PluginDebugTrait;

  /**
   * Max length for mapping expressions.
   */
  public const MAPPING_FIELD_MAX_LENGTH = 2048;

  /**
   * Default property mapper plugin id to use.
   */
  const DEFAULT_DATA_PROCESSOR = '';

  /**
   * The external entity type this property mapper is configured for.
   *
   * @var \Drupal\external_entities\Entity\ExternalEntityTypeInterface
   */
  protected $externalEntityType;

  /**
   * The field name this property mapper is configured for.
   *
   * @var string
   */
  protected $fieldName;

  /**
   * The property name this property mapper is configured for.
   *
   * @var string
   */
  protected $propertyName;

  /**
   * The entity field manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

  /**
   * The data processor manager.
   *
   * @var \Drupal\Component\Plugin\PluginManagerInterface
   */
  protected $dataProcessorManager;

  /**
   * The logger channel factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerChannelFactory;

  /**
   * The property mapper plugin logger channel.
   *
   * @var \Drupal\Core\Logger\LoggerChannel
   */
  protected $logger;

  /**
   * The property mapper form element base identifier.
   *
   * @var string
   */
  protected $formElementBaseId;

  /**
   * Constructs a PropertyMapperBase object.
   *
   * The configuration parameters is expected to contain the external entity
   * type (key ExternalEntityTypeInterface::XNTT_TYPE_PROP), the field name
   * (key 'field_name'), the property name (key 'property_name'), the
   * requirement status of this property field as a boolean value (key
   * 'required_field') and if this property is the main property (key
   * 'main_property') of its field.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The identifier for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
   *   The string translation service.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger channel factory.
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
   *   The entity field manager.
   * @param \Drupal\Component\Plugin\PluginManagerInterface $data_processor_manager
   *   The data processor plugin manager.
   */
  public function __construct(
    array $configuration,
    string $plugin_id,
    $plugin_definition,
    TranslationInterface $string_translation,
    LoggerChannelFactoryInterface $logger_factory,
    EntityFieldManagerInterface $entity_field_manager,
    PluginManagerInterface $data_processor_manager,
  ) {
    $this->debugLevel = $configuration['debug_level'] ?? NULL;
    $this->setConfiguration($configuration);
    $configuration = $this->getConfiguration();
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->setStringTranslation($string_translation);
    $this->loggerChannelFactory = $logger_factory;
    $this->logger = $this->loggerChannelFactory->get('xntt_property_mapper_' . $plugin_id);
    $this->entityFieldManager = $entity_field_manager;
    $this->dataProcessorManager = $data_processor_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition,
  ) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('string_translation'),
      $container->get('logger.factory'),
      $container->get('entity_field.manager'),
      $container->get('plugin.manager.external_entities.data_processor')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    $dependencies = [];
    $config = $this->getConfiguration();
    foreach ($config['data_processors'] ?? [] as $data_processor_setting) {
      if (!empty($data_processor_setting['id'])) {
        $data_processor_id = $data_processor_setting['id'];
        $config = NestedArray::mergeDeep(
          $this->getDataProcessorDefaultConfiguration(),
          ($data_processor_setting['config'] ?? [])
        );
        try {
          $data_processor = $this->dataProcessorManager->createInstance(
            $data_processor_id,
            $config
          );
          $dependencies = NestedArray::mergeDeep(
            $dependencies,
            $this->getPluginDependencies($data_processor)
          );
        }
        catch (PluginNotFoundException $e) {
          $this->logger->warning(
            "Data processor plugin not found '$data_processor_id'.\n" . $e
          );
        }
      }
    }
    return $dependencies;
  }

  /**
   * {@inheritdoc}
   */
  public function getLabel() :string {
    $plugin_definition = $this->getPluginDefinition();
    return $plugin_definition['label'];
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription() :string {
    $plugin_definition = $this->getPluginDefinition();
    return $plugin_definition['description'] ?? '';
  }

  /**
   * {@inheritdoc}
   */
  public function getConfiguration() {
    return $this->configuration;
  }

  /**
   * {@inheritdoc}
   */
  public function setConfiguration(array $configuration) {
    $configuration = NestedArray::mergeDeep(
      $this->defaultConfiguration(),
      $configuration
    );
    if (!empty($configuration[ExternalEntityTypeInterface::XNTT_TYPE_PROP])
        && $configuration[ExternalEntityTypeInterface::XNTT_TYPE_PROP] instanceof ExternalEntityTypeInterface
    ) {
      $this->externalEntityType = $configuration[ExternalEntityTypeInterface::XNTT_TYPE_PROP];
    }
    unset($configuration[ExternalEntityTypeInterface::XNTT_TYPE_PROP]);
    if (!empty($configuration['field_name'])) {
      $this->fieldName = $configuration['field_name'];
      unset($configuration['field_name']);
    }
    if (!empty($configuration['property_name'])) {
      $this->propertyName = $configuration['property_name'];
      unset($configuration['property_name']);
    }
    $this->configuration = $configuration;
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'mapping' => '',
      'required_field' => FALSE,
      'main_property' => FALSE,
      'data_processors' => [],
    ];
  }

  /**
   * Returns default values for a data processor.
   *
   * @return array
   *   The data processor default configuration.
   */
  protected function getDataProcessorDefaultConfiguration() :array {
    $external_entity_type = $this->getExternalEntityType();
    return [
      ExternalEntityTypeInterface::XNTT_TYPE_PROP => $external_entity_type,
      'field_name' => $this->fieldName,
      'property_name' => $this->propertyName,
      'debug_level' => $this->getDebugLevel(),
    ];
  }

  /**
   * Get the external entity type being operated for.
   *
   * @return \Drupal\external_entities\Entity\ExternalEntityTypeInterface
   *   The external entity type definition.
   */
  protected function getExternalEntityType() :ExternalEntityTypeInterface {
    return $this->externalEntityType;
  }

  /**
   * {@inheritdoc}
   */
  public function isProcessed() :bool {
    $is_processed = FALSE;
    $config = $this->getConfiguration();
    // Check if a data processor may alter data.
    foreach ($config['data_processors'] ?? [] as $data_processor_setting) {
      if (!empty($data_processor_setting['id'])) {
        $dp_config = NestedArray::mergeDeep(
          $this->getDataProcessorDefaultConfiguration(),
          ($data_processor_setting['config'] ?? [])
        );
        try {
          $data_processor = $this->dataProcessorManager->createInstance(
            $data_processor_setting['id'],
            $dp_config
          );
          if ($data_processor->mayAlterData()) {
            $is_processed = TRUE;
            break;
          }
        }
        catch (PluginNotFoundException $e) {
          $this->logger->warning(
            "Data processor plugin not found '"
            . $data_processor_setting['id']
            . "'.\n"
            . $e
          );
        }
      }
    }
    return $is_processed;
  }

  /**
   * Calls data processors on each raw data item.
   *
   * @param array $raw_data
   *   An array of raw data item to process.
   * @param bool $return_intermediates
   *   If TRUE, the returned array will be an array of array of processed items,
   *   each corresponding to the results of each processor in the same order as
   *   set for the property mapper. Default: FALSE.
   *
   * @return array
   *   The array of processed data items.
   */
  public function processData(
    array $raw_data,
    bool $return_intermediates = FALSE,
  ) :array {
    $config = $this->getConfiguration();
    $processed_data = $raw_data;
    if ($return_intermediates) {
      $stepped_processed_data = [$processed_data];
    }
    foreach ($config['data_processors'] ?? [] as $data_processor_setting) {
      if (!empty($data_processor_setting['id'])) {
        $data_processor_id = $data_processor_setting['id'];
        $dp_config = NestedArray::mergeDeep(
          $this->getDataProcessorDefaultConfiguration(),
          ($data_processor_setting['config'] ?? [])
        );
        try {
          $data_processor = $this->dataProcessorManager->createInstance(
            $data_processor_id,
            $dp_config
          );
          if ($debug_level = $this->getDebugLevel()) {
            $data_processor->setDebugLevel($debug_level);
          }
          $xntt_type_id = $this->externalEntityType->getDerivedEntityTypeId();
          $field_definition = $this
            ->entityFieldManager
            ->getFieldDefinitions($xntt_type_id, $xntt_type_id)[$this->fieldName]
            ?? NULL;

          $processed_data = $data_processor->processData(
            $processed_data,
            $field_definition,
            $this->propertyName
          );
        }
        catch (PluginNotFoundException $e) {
          $this->logger->warning(
            "Data processor plugin not found '$data_processor_id'.\n" . $e
          );
        }
      }
      if ($return_intermediates) {
        $stepped_processed_data[] = $processed_data;
      }
    }
    if ($return_intermediates) {
      return $stepped_processed_data;
    }
    return $processed_data;
  }

  /**
   * Calls data processors on each processed data item to revert the process.
   *
   * Note: if a data processor can not reverse the given dataitem, NULL will be
   * returned for that data item.
   *
   * @param array $new_data
   *   An array of new data item.
   * @param array $original_data
   *   An array of original processed data item.
   *
   * @return array
   *   The array of reverse-processed data items.
   */
  public function reverseDataProcessing(
    array $new_data,
    array $original_data,
  ) :array {
    $config = $this->getConfiguration();
    $raw_data = $new_data;
    $stepped_original_data = array_reverse(
      $this->processData($original_data, TRUE)
    );
    // Process in reverse order.
    $data_processors = array_reverse($config['data_processors'] ?? []);
    foreach ($data_processors as $step => $data_processor_setting) {
      if (!empty($data_processor_setting['id'])) {
        $data_processor_id = $data_processor_setting['id'];
        $config = NestedArray::mergeDeep(
          $this->getDataProcessorDefaultConfiguration(),
          ($data_processor_setting['config'] ?? [])
        );
        try {
          $data_processor = $this->dataProcessorManager->createInstance(
            $data_processor_id,
            $config
          );
          if ($debug_level = $this->getDebugLevel()) {
            $data_processor->setDebugLevel($debug_level);
          }
          $xntt_type_id = $this->externalEntityType->getDerivedEntityTypeId();
          $field_definition = $this
            ->entityFieldManager
            ->getFieldDefinitions($xntt_type_id, $xntt_type_id)[$this->fieldName]
            ?? NULL;
          $raw_data = $data_processor->reverseDataProcessing(
            $raw_data,
            $stepped_original_data[$step],
            $field_definition,
            $this->propertyName
          ) ?? [];
        }
        catch (PluginNotFoundException $e) {
          $this->logger->warning(
            "Data processor plugin not found '$data_processor_id'.\n" . $e
          );
        }
      }
    }
    return $raw_data;
  }

  /**
   * {@inheritdoc}
   */
  public function couldReversePropertyMapping() :bool {
    $could_reverse = TRUE;
    $config = $this->getConfiguration();
    foreach ($config['data_processors'] ?? [] as $data_processor_setting) {
      if (!empty($data_processor_setting['id'])) {
        $data_processor_id = $data_processor_setting['id'];
        $config = NestedArray::mergeDeep(
          $this->getDataProcessorDefaultConfiguration(),
          ($data_processor_setting['config'] ?? [])
        );
        try {
          $data_processor = $this->dataProcessorManager->createInstance(
            $data_processor_id,
            $config
          );
          if ($debug_level = $this->getDebugLevel()) {
            $data_processor->setDebugLevel($debug_level);
          }
          if (!$data_processor->couldReverseDataProcessing()) {
            $could_reverse = FALSE;
            break;
          }
        }
        catch (PluginNotFoundException $e) {
          $this->logger->warning(
            "Data processor plugin not found '$data_processor_id'.\n" . $e
          );
        }
      }
    }
    return $could_reverse;
  }

  /**
   * Provide an unique identifier string for this property mapper.
   *
   * @param array &$form
   *   The form containing the property mapper form with an eventual identifier.
   *
   * @return string
   *   A unique identifier for this property mapper.
   */
  protected function getPropertyMapperFormIdentifier(array &$form = []): string {
    if (empty($this->formElementBaseId)) {
      $this->formElementBaseId =
        $form['#attributes']['id']
        ??= (($this->externalEntityType ? $this->externalEntityType->id() : uniqid('x'))
          . '_'
          . ($this->fieldName ?? uniqid('f'))
          . '_'
          . ($this->propertyName ?? uniqid('p'))
          . '_pm'
        );
    }
    return $this->formElementBaseId;
  }

  /**
   * Return current form number of data processors.
   *
   * @param array $form
   *   An associative array containing the initial structure of the plugin form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return int
   *   Number of data processors.
   */
  protected function getCurrentDataProcessorCount(
    array $form,
    FormStateInterface $form_state,
  ): int {
    $config = $this->getConfiguration();
    $state_id = $this->getPropertyMapperFormIdentifier($form) . '_processor_count';
    $processor_count =
      $form_state->get($state_id)
      ?? count($config['data_processors'] ?? []);
    return $processor_count;
  }

  /**
   * Set current form number of data processors.
   *
   * @param array $form
   *   An associative array containing the initial structure of the plugin form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param int $processor_count
   *   Number of data processor to use.
   */
  protected function setCurrentDataProcessorCount(
    array $form,
    FormStateInterface $form_state,
    int $processor_count,
  ) {
    $state_id = $this->getPropertyMapperFormIdentifier($form) . '_processor_count';
    if (!$processor_count || ($processor_count < 0)) {
      $processor_count = 0;
    }
    $form_state->set($state_id, $processor_count);
  }

  /**
   * Form constructor.
   *
   * @param array $form
   *   An associative array containing the initial structure of the plugin form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form. Calling code should pass on a subform
   *   state created through
   *   \Drupal\Core\Form\SubformState::createForSubform().
   *
   * @return array
   *   The form structure.
   */
  public function buildConfigurationForm(
    array $form,
    FormStateInterface $form_state,
  ) {
    $config = $this->getConfiguration();
    $form['description'] = [
      '#type' => 'item',
      '#description' => $this->getDescription(),
    ];
    $form['mapping'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Mapping:'),
      '#maxlength' => static::MAPPING_FIELD_MAX_LENGTH,
      '#default_value' => $config['mapping'] ?? '',
      '#required' => $config['required_field'] && $config['main_property'],
      '#wrapper_attributes' => ['class' => ['xntt-inline']],
      '#attributes' => ['class' => ['xntt-field']],
      '#label_attributes' => ['class' => ['xntt-label']],
    ];
    // Data processors.
    $dp_container_id = $this->getPropertyMapperFormIdentifier($form) . '_dp';
    $processor_count = $this->getCurrentDataProcessorCount($form, $form_state);
    $form['data_processors'] = [
      '#type' => 'container',
      // If #parents is not set here, sub-element names will not follow the tree
      // structure.
      '#parents' => [...($form['#parents'] ?? []), 'data_processors'],
      '#attributes' => [
        'id' => $dp_container_id,
      ],
    ];

    for ($index = 0; $index < $processor_count; ++$index) {
      $form['data_processors'][$index] = [
        '#type' => 'fieldset',
        '#attributes' => [
          'id' => $this->getPropertyMapperFormIdentifier($form)
          . '_'
          . $index,
        ],
        '#weight' => 100,
      ];
      $this->buildDataProcessorSelectForm($form, $form_state, $index);
      $this->buildDataProcessorConfigForm($form, $form_state, $index);
    }
    // @todo Improve name to include identifier.
    $form['data_processors']['remove_processor'] = [
      '#type' => 'submit',
      '#value' => $this->t(
        'Remove last data processor',
      ),
      // Match this name with self::validateConfigurationForm().
      '#name' => 'rempm_' . $this->getPropertyMapperFormIdentifier($form),
      '#disabled' => ($processor_count ? NULL : TRUE),
      '#ajax' => [
        'callback' => [get_class($this), 'buildAjaxParentSubForm'],
        'wrapper' => $dp_container_id,
        'method' => 'replaceWith',
        'effect' => 'fade',
      ],
    ];
    $form['data_processors']['add_processor'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add a data processor'),
      // Match this name with self::validateConfigurationForm().
      '#name' => 'addpm_' . $this->getPropertyMapperFormIdentifier($form),
      '#ajax' => [
        'callback' => [get_class($this), 'buildAjaxParentSubForm'],
        'wrapper' => $dp_container_id,
        'method' => 'replaceWith',
        'effect' => 'fade',
      ],
    ];

    return $form;
  }

  /**
   * Build a form element for selecting a data processor.
   *
   * @todo API: Return $form array instead of using reference &$form.
   *
   * @param array &$form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param int $index
   *   Index of the current data processor.
   */
  public function buildDataProcessorSelectForm(
    array &$form,
    FormStateInterface $form_state,
    int $index = 0,
  ) {
    $data_processors = $this->dataProcessorManager->getDefinitions();
    if (empty($data_processors)) {
      return;
    }

    $current_data_processor_id =
      $form_state->getValue(['data_processors', $index, 'id'])
      ?? $this->getConfiguration()['data_processors'][$index]['id']
      ?? static::DEFAULT_DATA_PROCESSOR;
    $data_processor_options = [];
    foreach ($data_processors as $data_processor_id => $definition) {
      $config = $this->getDataProcessorDefaultConfiguration();
      $data_processor = $this->dataProcessorManager->createInstance($data_processor_id, $config);
      $data_processor_options[$data_processor_id] = $data_processor->getLabel();
    }

    $form['data_processors'][$index]['id'] = [
      '#type' => 'select',
      '#title' => $this->t('Data processor:'),
      '#default_value' => $current_data_processor_id,
      '#empty_value' => '',
      '#options' => $data_processor_options,
      '#sort_options' => TRUE,
      '#wrapper_attributes' => ['class' => ['xntt-inline']],
      '#attributes' => [
        'class' => ['xntt-field'],
        'autocomplete' => 'off',
      ],
      '#label_attributes' => ['class' => ['xntt-label']],
      '#ajax' => [
        'callback' => [get_class($this), 'buildAjaxParentSubForm'],
        'wrapper' => $this->getPropertyMapperFormIdentifier($form)
        . '_'
        . $index,
        'method' => 'replaceWith',
        'effect' => 'fade',
      ],
    ];
  }

  /**
   * Build a form element for configuring a field property mapping.
   *
   * @todo API: Return $form array instead of using reference &$form.
   *
   * @param array &$form
   *   The form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param int $index
   *   Index of the current data processor.
   */
  public function buildDataProcessorConfigForm(
    array &$form,
    FormStateInterface $form_state,
    int $index = 0,
  ) {
    $config = $this->getConfiguration();
    $data_processor_id =
      $form_state->getValue(['data_processors', $index, 'id'])
      ?? $config['data_processors'][$index]['id']
      ?? '';

    if (empty($data_processor_id)) {
      // No data processor selected, stop here.
      return;
    }
    // Check if config correspond to selected data processor.
    $dp_config = [];
    if ($data_processor_id == ($config['data_processors'][$index]['id'] ?? '-')) {
      $dp_config = $config['data_processors'][$index]['config'] ?? [];
    }
    $dp_config += $this->getDataProcessorDefaultConfiguration();

    // Generate a new property mapper instance.
    $data_processor = $this->dataProcessorManager->createInstance($data_processor_id, $dp_config);
    $data_processor_form_state = XnttSubformState::createForSubform(['data_processors', $index, 'config'], $form, $form_state);
    $form['data_processors'][$index]['config'] = $data_processor->buildConfigurationForm(
      $form['data_processors'][$index]['config'],
      $data_processor_form_state
    );
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {

    // Check for Ajax events.
    if ($trigger = $form_state->getTriggeringElement()) {
      $pm_id = $this->getPropertyMapperFormIdentifier($form);
      if ("addpm_$pm_id" == $trigger['#name']) {
        $processor_count = $this->getCurrentDataProcessorCount($form, $form_state) + 1;
        $this->setCurrentDataProcessorCount($form, $form_state, $processor_count);
        $form_state->setRebuild(TRUE);
      }
      elseif ("rempm_$pm_id" == $trigger['#name']) {
        $processor_count = $this->getCurrentDataProcessorCount($form, $form_state) - 1;
        $this->setCurrentDataProcessorCount($form, $form_state, $processor_count);
        $form_state->setRebuild(TRUE);
      }
    }

    // Validate data processor settings.
    $data_processors = array_filter(
      $form_state->getValue('data_processors', []),
      'is_numeric',
      ARRAY_FILTER_USE_KEY
    );
    foreach ($data_processors as $index => $data_processor_setting) {
      $data_processor_id = $data_processor_setting['id'];
      if ($data_processor_id) {
        $config = $this->getDataProcessorDefaultConfiguration();
        $data_processor = $this->dataProcessorManager->createInstance($data_processor_id, $config);
        if ($data_processor instanceof PluginFormInterface) {
          $data_processor_form_state = XnttSubformState::createForSubform(['data_processors', $index, 'config'], $form, $form_state);
          $data_processor->validateConfigurationForm($form['data_processors'][$index]['config'], $data_processor_form_state);
        }
      }
    }

    // If rebuild needed, ignore validation.
    if ($form_state->isRebuilding()) {
      $form_state->clearErrors();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    // Validate data processor settings.
    $data_processors = $form_state->getValue('data_processors');
    if (isset($data_processors)) {
      $data_processors = array_filter(
        $data_processors,
        'is_numeric',
        ARRAY_FILTER_USE_KEY
      );
      foreach ($data_processors as $index => $data_processor_setting) {
        $data_processors[$index] = NULL;
        $data_processor_id = $data_processor_setting['id'];
        if ($data_processor_id) {
          $config = $this->getDataProcessorDefaultConfiguration();
          $data_processor = $this->dataProcessorManager->createInstance($data_processor_id, $config);
          if ($data_processor instanceof PluginFormInterface) {
            $data_processor_form_state = XnttSubformState::createForSubform(['data_processors', $index, 'config'], $form, $form_state);
            $data_processor->submitConfigurationForm($form['data_processors'][$index]['config'], $data_processor_form_state);
            $data_processors[$index] = [
              'id' => $data_processor_id,
              'config' => $data_processor->getConfiguration(),
            ];
          }
        }
      }
      $form_state->setValue(
        'data_processors',
        array_values(array_filter($data_processors))
      );
    }

    $config = $this->getConfiguration();
    $form_state->setValue('required_field', $config['required_field'] ?? FALSE);
    $form_state->setValue('main_property', $config['main_property'] ?? FALSE);
    $this->setConfiguration($form_state->getValues());
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc