external_entities-8.x-2.x-dev/src/Plugin/ExternalEntities/DataProcessor/DateTime.php

src/Plugin/ExternalEntities/DataProcessor/DateTime.php
<?php

namespace Drupal\external_entities\Plugin\ExternalEntities\DataProcessor;

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\TypedData\Plugin\DataType\DateTimeIso8601;
use Drupal\Core\TypedData\PrimitiveInterface;
use Drupal\Core\TypedData\Type\DateTimeInterface;
use Drupal\Core\TypedData\Type\IntegerInterface;
use Drupal\Core\TypedData\Type\StringInterface;
use Drupal\Core\TypedData\TypedDataManagerInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\external_entities\DataProcessor\DataProcessorBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * This plugin handles date and time pre-processing.
 *
 * @DataProcessor(
 *   id = "datetime",
 *   label = @Translation("Date and time"),
 *   description = @Translation("Converts a date and time format into another.")
 * )
 *
 * @package Drupal\external_entities\Plugin\ExternalEntities\DataProcessor
 */
class DateTime extends DataProcessorBase {

  /**
   * The typed data manager.
   *
   * @var \Drupal\Core\TypedData\TypedDataManagerInterface
   */
  protected TypedDataManagerInterface $typedDataManager;

  /**
   * Constructs a DateTime processor object.
   *
   * The configuration parameters is expected to contain the external entity
   * type (key ExternalEntityTypeInterface::XNTT_TYPE_PROP), the field name
   * (key 'field_name') and the property name (key 'property_name') this data
   * processor will work on.
   *
   * @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\TypedData\TypedDataManagerInterface $typed_data_manager
   *   The typed data manager.
   */
  public function __construct(
    array $configuration,
    string $plugin_id,
    $plugin_definition,
    TranslationInterface $string_translation,
    LoggerChannelFactoryInterface $logger_factory,
    TypedDataManagerInterface $typed_data_manager,
  ) {
    parent::__construct(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $string_translation,
      $logger_factory
    );
    $this->typedDataManager = $typed_data_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('typed_data_manager')
    );
  }

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

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(
    array $form,
    FormStateInterface $form_state,
  ) {
    $form = parent::buildConfigurationForm($form, $form_state);
    $config = $this->getConfiguration();
    $datetime_id = ($form['#attributes']['id'] ??= uniqid('dt', TRUE));
    $form['source_format'] = [
      '#type' => 'radios',
      '#title' => $this->t('Source date format'),
      '#description' => $this->t('If not set to "auto", values that do not match the selected format will be considered empty (NULL).'),
      '#options' => [
        'timestamp' => $this->t('Unix timestamp'),
        'iso8601' => $this->t('ISO 8601'),
        'auto' => $this->t('Auto-detect'),
      ],
      '#default_value' => $config['source_format'] ?? 'auto',
      '#attributes' => [
        'data-xntt-datetime-selector' => $datetime_id . 'sf',
      ],
    ];
    $form['save_format'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Save format'),
      '#description' => $this->t(
        'Specify a date and time format using the <a href="https://www.php.net/manual/en/datetime.format.php">PHP DateTime format</a>. Leave empty if you do not need to save data.'
      ),
      '#default_value' => $config['save_format'] ?? '',
      '#attributes' => [
        'placeholder' => $this->t('ex.: YmdHis'),
      ],
      '#states' => [
        'visible' => [
          'input[data-xntt-datetime-selector="' . $datetime_id . 'sf"]' => [
            'value' => 'auto',
          ],
        ],
      ],
    ];
    // @todo When using auto-detect, provide a setting to choose save format.
    $form['drupal_format'] = [
      '#type' => 'radios',
      '#title' => $this->t('Drupal date format to use'),
      '#description' => $this->t('Only used for non-date-time field property types.'),
      '#options' => [
        'timestamp' => $this->t('Unix timestamp'),
        'iso8601' => $this->t('ISO 8601'),
        'auto' => $this->t('Auto-detect'),
      ],
      '#default_value' => $config['drupal_format'] ?? 'auto',
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function processData(
    array $raw_data,
    FieldDefinitionInterface $field_definition,
    string $property_name,
  ) :array {
    $data = [];

    // Create the typed data instance.
    $config = $this->getConfiguration();
    $property_definition = $field_definition
      ->getFieldStorageDefinition()
      ->getPropertyDefinition($property_name);
    $typed_data = $this->typedDataManager->create($property_definition);

    // We work with timestamp values.
    foreach ($raw_data as $index => $datetime_data) {
      $timestamp = NULL;

      if (isset($datetime_data)) {
        switch ($config['source_format']) {
          case 'timestamp':
            if (is_numeric($datetime_data)) {
              $timestamp = $datetime_data;
            }
            break;

          case 'iso8601':
            $timestamp = strtotime($datetime_data) ?: NULL;
            break;

          case 'auto':
          default:
            $timestamp = !is_numeric($datetime_data)
              ? strtotime($datetime_data)
              : $datetime_data;
            $timestamp = $timestamp ?: NULL;
            break;
        }
      }

      // Add processed data.
      if (isset($timestamp)) {
        // Check requested type.
        // We discard processor settings for datetime properties.
        if ($typed_data instanceof DateTimeIso8601) {
          $datetime_type = $field_definition
            ->getFieldStorageDefinition()
            ->getSetting('datetime_type');

          if ($datetime_type === DateTimeItem::DATETIME_TYPE_DATE) {
            $storage_format = DateTimeItemInterface::DATE_STORAGE_FORMAT;
          }
          else {
            $storage_format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
          }

          // Use setValue so timezone is not set.
          $typed_data->setValue(gmdate($storage_format, $timestamp));
        }
        elseif ($typed_data instanceof DateTimeInterface) {
          // Works for Timestamp and DateTimeIso8601.
          $typed_data->setDateTime(
            DrupalDateTime::createFromTimestamp($timestamp)
          );
        }
        // For non-datetime properties, we follow processor settings.
        elseif (('iso8601' == $config['drupal_format'])
          || (('auto' == $config['drupal_format']) && ($typed_data instanceof StringInterface))
        ) {
          // Return iso8601 strings.
          $typed_data->setValue(gmdate('Y-m-d\TH:i:s', $timestamp));
        }
        elseif (('timestamp' == $config['drupal_format'])
          || (('auto' == $config['drupal_format']) && ($typed_data instanceof IntegerInterface))
        ) {
          // Return timestamps.
          $typed_data->setValue($timestamp);
        }
        else {
          // Unsupported properties.
          $typed_data->setValue($datetime_data);
        }

        // Convert the property value to the correct PHP type as expected by
        // this specific property type.
        if ($typed_data instanceof PrimitiveInterface) {
          $processed_datetime = $typed_data->getCastedValue();
        }
        else {
          $processed_datetime = $typed_data->getValue();
        }

        $data[] = $processed_datetime;
      }
      else {
        // Not able to parse date.
        $data[] = NULL;
      }
      if (2 <= $this->getDebugLevel()) {
        if (isset($datetime_data)) {
          $this->logger->debug(
            "Extracted timestamp value for '@original_value' (#@index): '@timestamp'",
            [
              '@original_value' => $datetime_data,
              '@index' => $index,
              '@timestamp' => $timestamp ?? 'NULL',
            ]
          );
        }
        else {
          $this->logger->debug(
            "No extracted timestamp value from empty value #@index",
            [
              '@index' => $index,
            ]
          );
        }
      }
    }
    if (empty($data) || empty($data[0])) {
      // Drupal DateTimePlus component does not like empty data.
      $data = [0];
    }
    return $data;
  }

  /**
   * {@inheritdoc}
   */
  public function reverseDataProcessing(
    array $data,
    array $original_data,
    FieldDefinitionInterface $field_definition,
    string $property_name,
  ) :array|null {
    // @todo Test code.
    $raw_data = [];
    $config = $this->getConfiguration();
    $property_definition = $field_definition
      ->getFieldStorageDefinition()
      ->getPropertyDefinition($property_name);
    $typed_data = $this->typedDataManager->create($property_definition);

    foreach ($data as $datetime_data) {
      $timestamp = NULL;
      if ($typed_data instanceof DateTimeInterface) {
        // Check that given value is a timestamp.
        if (is_numeric($datetime_data)) {
          $timestamp = $datetime_data;
        }
        // Or an ISO string.
        elseif (is_string($datetime_data)) {
          $timestamp = strtotime($datetime_data) ?: NULL;
        }
        else {
          $timestamp = NULL;
        }
      }
      elseif ($typed_data instanceof StringInterface) {
        if (isset($datetime_data)) {
          $timestamp = strtotime($datetime_data) ?: NULL;
        }
      }
      elseif ($typed_data instanceof IntegerInterface) {
        if (is_numeric($datetime_data)) {
          $timestamp = $datetime_data;
        }
        else {
          $timestamp = NULL;
        }
      }
      else {
        if (is_numeric($datetime_data)) {
          $timestamp = $datetime_data;
        }
        else {
          $timestamp = NULL;
        }
      }

      if (isset($timestamp)) {
        switch ($config['source_format']) {
          case 'timestamp':
            $raw_data[] = $timestamp;
            break;

          case 'iso8601':
            $raw_data[] = gmdate('Y-m-d\TH:i:s', $timestamp);
            break;

          case 'auto':
          default:
            if (!empty($config['save_format'])) {
              $raw_data[] = gmdate($config['save_format'], $timestamp);
            }
            else {
              $raw_data[] = NULL;
            }
            break;
        }
      }
      else {
        $raw_data[] = NULL;
      }
    }
    return $raw_data;
  }

  /**
   * {@inheritdoc}
   */
  public function couldReverseDataProcessing() :bool {
    return TRUE;
  }

}

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

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