countdown-8.x-1.8/modules/countdown_field/src/Plugin/Field/FieldType/CountdownItem.php

modules/countdown_field/src/Plugin/Field/FieldType/CountdownItem.php
<?php

declare(strict_types=1);

namespace Drupal\countdown_field\Plugin\Field\FieldType;

use Drupal\Component\Utility\Random;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TypedData\DataDefinition;

/**
 * Plugin implementation of the 'countdown' field type.
 *
 * Stores countdown timer configurations with library support. The target date
 * is stored as a UTC UNIX timestamp for consistency and validation simplicity.
 *
 * @FieldType(
 *   id = "countdown",
 *   label = @Translation("Countdown"),
 *   description = @Translation("Field for countdown timers with library support"),
 *   default_widget = "countdown_default",
 *   default_formatter = "countdown_default",
 * )
 */
class CountdownItem extends FieldItemBase {

  use StringTranslationTrait;

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

  /**
   * {@inheritdoc}
   */
  public static function defaultFieldSettings() {
    return [
      'allowed_libraries' => [],
      'allow_event_details' => TRUE,
      'require_future_date' => TRUE,
    ] + parent::defaultFieldSettings();
  }

  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    // Define the library property.
    $properties['library'] = DataDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Library'))
      ->setDescription(new TranslatableMarkup('The countdown library to use'))
      ->setRequired(FALSE);

    // Define the target date as a timestamp (integer).
    $properties['target_date'] = DataDefinition::create('integer')
      ->setLabel(new TranslatableMarkup('Target date'))
      ->setDescription(new TranslatableMarkup('The target date/time as a UTC UNIX timestamp'))
      ->setRequired(FALSE);

    // Define the event name property.
    $properties['event_name'] = DataDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Event name'))
      ->setDescription(new TranslatableMarkup('Optional name of the event'))
      ->setRequired(FALSE);

    // Define the event URL property.
    $properties['event_url'] = DataDefinition::create('uri')
      ->setLabel(new TranslatableMarkup('Event URL'))
      ->setDescription(new TranslatableMarkup('Optional URL for event details'))
      ->setRequired(FALSE);

    // Define the finish message property.
    $properties['finish_message'] = DataDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Finish message'))
      ->setDescription(new TranslatableMarkup('Message to display when countdown completes'))
      ->setRequired(FALSE);

    // Define library_settings as any type to support arrays.
    $properties['library_settings'] = DataDefinition::create('any')
      ->setLabel(new TranslatableMarkup('Library settings'))
      ->setDescription(new TranslatableMarkup('Library-specific configuration'))
      ->setRequired(FALSE);

    return $properties;
  }

  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    return [
      'columns' => [
        'library' => [
          'type' => 'varchar',
          'length' => 32,
        ],
        'target_date' => [
          'type' => 'int',
          'size' => 'big',
          'not null' => FALSE,
        ],
        'event_name' => [
          'type' => 'varchar',
          'length' => 255,
        ],
        'event_url' => [
          'type' => 'varchar',
          'length' => 2048,
        ],
        'finish_message' => [
          'type' => 'varchar',
          'length' => 255,
        ],
        'library_settings' => [
          'type' => 'blob',
          'size' => 'normal',
          'serialize' => TRUE,
        ],
      ],
      'indexes' => [
        'target_date' => ['target_date'],
        'library' => ['library'],
      ],
    ];
  }

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

    // Get available libraries from the manager service.
    /** @var \Drupal\countdown\Service\CountdownLibraryManagerInterface $library_manager */
    $library_manager = \Drupal::service('countdown.library_manager');
    $libraries = $library_manager->getAvailableLibraryOptions();

    $element['default_library'] = [
      '#type' => 'select',
      '#title' => $this->t('Default library'),
      '#description' => $this->t('The default countdown library for new fields.'),
      '#options' => ['' => $this->t('- Use global default -')] + $libraries,
      '#default_value' => $this->getSetting('default_library'),
      '#disabled' => $has_data,
    ];

    return $element;
  }

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

    // Get available libraries from the manager service.
    /** @var \Drupal\countdown\Service\CountdownLibraryManagerInterface $library_manager */
    $library_manager = \Drupal::service('countdown.library_manager');
    $libraries = $library_manager->getAvailableLibraryOptions();

    $element['allowed_libraries'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Allowed libraries'),
      '#description' => $this->t('Select which countdown libraries can be used. If none are selected, all available libraries are allowed.'),
      '#options' => $libraries,
      '#default_value' => $this->getSetting('allowed_libraries') ?: [],
    ];

    $element['allow_event_details'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Allow event details'),
      '#description' => $this->t('Allow users to add event name and URL to countdown timers.'),
      '#default_value' => $this->getSetting('allow_event_details'),
    ];

    $element['require_future_date'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Require future date for countdown'),
      '#description' => $this->t('When counting down, require the target date to be in the future.'),
      '#default_value' => $this->getSetting('require_future_date'),
    ];

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function isEmpty() {
    // Field is empty if target_date is not set or is zero.
    $value = $this->get('target_date')->getValue();
    return $value === NULL || $value === '' || $value === 0;
  }

  /**
   * {@inheritdoc}
   */
  public function preSave() {
    // Ensure library is set.
    if (empty($this->library)) {
      $this->library = $this->getDefaultLibrary();
    }

    // Ensure finish_message has a default value.
    if (empty($this->finish_message)) {
      $this->finish_message = (string) $this->t("Time's up!");
    }

    // Ensure target_date is properly formatted if set.
    if (!empty($this->target_date) && !is_numeric($this->target_date)) {
      if ($this->target_date instanceof DrupalDateTime) {
        $this->target_date = $this->target_date->getTimestamp();
      }
      elseif (is_string($this->target_date)) {
        $this->setTargetDateFromIso($this->target_date);
      }
    }

    // Log what we're saving.
    \Drupal::logger('countdown_field')->debug('preSave - library_settings value: @settings', [
      '@settings' => json_encode($this->get('library_settings')->getValue()),
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function setValue($values, $notify = TRUE) {
    // Handle DrupalDateTime objects for target_date.
    if (isset($values['target_date']) && $values['target_date'] instanceof DrupalDateTime) {
      $values['target_date'] = $values['target_date']->getTimestamp();
    }

    // Log incoming values for debugging.
    if (isset($values['library_settings'])) {
      \Drupal::logger('countdown_field')->debug('setValue called with library_settings: @settings', [
        '@settings' => json_encode($values['library_settings']),
      ]);
    }

    parent::setValue($values, $notify);
  }

  /**
   * Get allowed libraries for this field.
   *
   * @return array
   *   Array of allowed library IDs.
   */
  public function getAllowedLibraries(): array {
    $allowed = $this->getFieldDefinition()->getSetting('allowed_libraries');

    if (empty($allowed)) {
      // If no restrictions, all libraries are allowed.
      /** @var \Drupal\countdown\Service\CountdownLibraryManagerInterface $library_manager */
      $library_manager = \Drupal::service('countdown.library_manager');
      $method = $library_manager->getLoadingMethod();
      return array_keys($library_manager->getAvailableLibraryOptions($method));
    }

    // Filter out unchecked options (value = 0).
    return array_values(array_filter($allowed));
  }

  /**
   * Get the default library for this field.
   *
   * @return string
   *   The default library ID.
   */
  protected function getDefaultLibrary(): string {
    // Check field storage settings first.
    $default = $this->getFieldDefinition()
      ->getFieldStorageDefinition()
      ->getSetting('default_library');

    if (!empty($default)) {
      return $default;
    }

    // Fall back to global default.
    /** @var \Drupal\countdown\Service\CountdownLibraryManagerInterface $library_manager */
    $library_manager = \Drupal::service('countdown.library_manager');
    return $library_manager->getActiveLibrary();
  }

  /**
   * Get library-specific settings.
   *
   * @return array
   *   The library settings array.
   */
  public function getLibrarySettings(): array {
    // Use the proper get() method with property name.
    $settings = $this->get('library_settings')->getValue();

    // The value is automatically unserialized by Drupal.
    return is_array($settings) ? $settings : [];
  }

  /**
   * Set library-specific settings.
   *
   * @param array $settings
   *   The settings array to store.
   */
  public function setLibrarySettings(array $settings): void {
    // Use the proper set() method with property name.
    $this->set('library_settings', $settings);
  }

  /**
   * Get the effective loading method for this field.
   *
   * @return string
   *   The loading method ('local' or 'cdn').
   */
  public function getEffectiveMethod(): string {
    /** @var \Drupal\countdown\Service\CountdownLibraryManagerInterface $library_manager */
    $library_manager = \Drupal::service('countdown.library_manager');
    return $library_manager->getLoadingMethod();
  }

  /**
   * Get the target date as an ISO-8601 string.
   *
   * Converts the stored UTC timestamp to ISO-8601 format for JavaScript
   * consumption and display purposes.
   *
   * @return string|null
   *   The ISO-8601 formatted date string, or NULL if no date is set.
   */
  public function getTargetDateIso(): ?string {
    $timestamp = $this->get('target_date')->getValue();

    if (empty($timestamp) || !is_numeric($timestamp) || $timestamp <= 0) {
      return NULL;
    }

    // Format timestamp as ISO-8601 in UTC.
    return gmdate('Y-m-d\TH:i:s\Z', (int) $timestamp);
  }

  /**
   * Set the target date from an ISO-8601 string.
   *
   * Converts an ISO-8601 date string to a UTC timestamp for storage.
   *
   * @param string $iso_date
   *   The ISO-8601 formatted date string.
   */
  public function setTargetDateFromIso(string $iso_date): void {
    try {
      $datetime = new \DateTime($iso_date);
      $this->set('target_date', $datetime->getTimestamp());
    }
    catch (\Exception $e) {
      // Invalid date format, set to NULL.
      $this->set('target_date', NULL);
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
    $random = new Random();

    // Generate a future timestamp between 1 hour and 1 year from now.
    $timestamp = \Drupal::time()->getRequestTime() + rand(3600, 31536000);

    $values = [
      'target_date' => $timestamp,
      'event_name' => $random->sentences(mt_rand(1, 3)),
      'finish_message' => $random->sentences(1),
    ];

    // Set a default library.
    /** @var \Drupal\countdown\Service\CountdownLibraryManagerInterface $library_manager */
    $library_manager = \Drupal::service('countdown.library_manager');
    $values['library'] = $library_manager->getActiveLibrary();

    return $values;
  }

}

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

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