custom_field-1.0.x-dev/src/Plugin/CustomField/FieldWidget/TimeRangeWidget.php

src/Plugin/CustomField/FieldWidget/TimeRangeWidget.php
<?php

declare(strict_types=1);

namespace Drupal\custom_field\Plugin\CustomField\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\custom_field\Attribute\CustomFieldWidget;
use Drupal\custom_field\Plugin\CustomFieldTypeInterface;
use Drupal\custom_field\Plugin\CustomFieldWidgetBase;
use Drupal\custom_field\Time;

/**
 * Plugin implementation of the 'time_range' custom field widget.
 */
#[CustomFieldWidget(
  id: 'time_range',
  label: new TranslatableMarkup('Time range'),
  category: new TranslatableMarkup('Time'),
  field_types: [
    'time_range',
  ],
)]
class TimeRangeWidget extends CustomFieldWidgetBase {

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings(): array {
    return [
      'start_label' => 'Start time',
      'end_label' => 'End time',
      'time_end_required' => FALSE,
    ] + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function widgetSettingsForm(FormStateInterface $form_state, CustomFieldTypeInterface $field): array {
    $element = parent::widgetSettingsForm($form_state, $field);
    $settings = $this->getSettings() + static::defaultSettings();

    $element['start_label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Start time label'),
      '#default_value' => $settings['start_label'],
      '#description' => $this->t('The label for the start time field.'),
      '#required' => TRUE,
      '#maxlength' => 255,
    ];
    $element['end_label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('End time label'),
      '#default_value' => $settings['end_label'],
      '#description' => $this->t('The label for the end time field.'),
      '#required' => TRUE,
      '#maxlength' => 255,
    ];
    $element['time_end_required'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Require end time'),
      '#description' => $this->t('If checked, the end time field will be required if the start time is provided.'),
      '#default_value' => $settings['time_end_required'],
    ];

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function widget(FieldItemListInterface $items, int $delta, array $element, array &$form, FormStateInterface $form_state, CustomFieldTypeInterface $field): array {
    $element = parent::widget($items, $delta, $element, $form, $form_state, $field);
    $field_settings = $field->getFieldSettings();
    $settings = $this->getSettings() + static::defaultSettings();
    // Determine if we're showing seconds in the widget.
    $show_seconds = (bool) $field_settings['seconds_enabled'];
    $item = $items[$delta];
    $name = $field->getName();
    $time_start = $item->{$name} ?? NULL;
    $time_end = $item->{$name . '__end'} ?? NULL;

    $element['#theme'] = 'custom_field_time_range';
    $element['#theme_wrappers'] = ['fieldset', 'container'];
    $element['#element_validate'][] = [$this, 'validateStartEnd'];

    $element['value']['#title'] = $this->t('@label', ['@label' => $settings['start_label']]);
    $element['value']['#description'] = NULL;
    $element['value'] += [
      '#type' => 'time_cf',
      '#default_value' => Time::createFromTimestamp($time_start)?->formatForWidget($show_seconds),
    ];
    if ($show_seconds) {
      // Add the step attribute if we're showing seconds in the widget.
      $element['value']['#attributes']['step'] = $field_settings['seconds_step'];
      // Set a property to determine the format in TimeElement::preRenderTime().
      $element['value']['#show_seconds'] = TRUE;
    }

    $element['end_value'] = [
      '#title' => $this->t('@label', ['@label' => $settings['end_label']]),
      '#default_value' => $time_end ? Time::createFromTimestamp($time_end)?->formatForWidget($show_seconds) : NULL,
    ] + $element['value'];

    return $element;
  }

  /**
   * An #element_validate callback to ensure the start time < the end time.
   *
   * @param array $element
   *   An associative array containing the properties and children of the
   *   generic form element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param array $complete_form
   *   The complete form structure.
   */
  public function validateStartEnd(array &$element, FormStateInterface $form_state, array &$complete_form): void {
    // Only validate if the start and end date fields are present.
    $require_end_time = $this->getSetting('time_end_required');

    $start_value = $element['value']['#value'];
    $end_value = $element['end_value']['#value'];

    // If both values are empty, just return.
    if (Time::isEmpty($start_value) && Time::isEmpty($end_value)) {
      return;
    }

    try {
      $start_time = Time::createFromTimestamp($start_value);
      $end_time = Time::createFromTimestamp($end_value);
    }
    catch (\InvalidArgumentException $exception) {
      $start_time = FALSE;
      $end_time = FALSE;
    }

    // Validate the end time is after the start time.
    if ($start_time && $end_time) {
      $start_timestamp = $start_time->getTimestamp();
      $end_timestamp = $end_time->getTimestamp();
      if ($start_timestamp >= $end_timestamp) {
        $form_state->setError($element, t('The @title end time must be after the start time.', ['@title' => $element['#title']]));
      }
    }

    // Validate the end time is required.
    elseif ($start_time && $require_end_time && !$end_time) {
      $form_state->setError($element['end_value'], $this->t('The @title end time is required.', ['@title' => $element['#title']]));
    }
    // Validate the end date requires a start date.
    elseif ($end_time && !$start_time) {
      $form_state->setError($element['value'], $this->t('The @title cannot have an end time with no start time', ['@title' => $element['#title']]));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function massageFormValue(mixed $value, $column): ?array {
    $start = $value['value'] ?? NULL;
    $end = $value['end_value'] ?? NULL;
    if (!is_numeric($start)) {
      return NULL;
    }

    return [
      'value' => (int) $start,
      'end_value' => is_numeric($end) ? (int) $end : NULL,
    ];
  }

}

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

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