From dfa8da607aeaaa4ed055ca21c773237f09dff285 Mon Sep 17 00:00:00 2001
From: Kunal Sachdev <kunal.sachdev@acquia.com>
Date: Tue, 14 Nov 2023 12:31:59 +0530
Subject: [PATCH] apply
 https://git.drupalcode.org/issue/drupal-2794481/-/merge_requests/2.diff

---
 .../config/schema/datetime_range.schema.yml   |  8 +--
 .../Plugin/Field/FieldType/DateRangeItem.php  | 60 +++++++++++++------
 .../Field/FieldWidget/DateRangeWidgetBase.php |  4 +-
 .../tests/src/Kernel/DateRangeItemTest.php    |  4 +-
 4 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/core/modules/datetime_range/config/schema/datetime_range.schema.yml b/core/modules/datetime_range/config/schema/datetime_range.schema.yml
index 921010b2bb74..7900a35ce5d2 100644
--- a/core/modules/datetime_range/config/schema/datetime_range.schema.yml
+++ b/core/modules/datetime_range/config/schema/datetime_range.schema.yml
@@ -7,12 +7,12 @@ field.storage_settings.daterange:
   label: 'Date range settings'
 
 field.field_settings.daterange:
-  type: field.field_settings.datetime
+  type: mapping
   label: 'Date range settings'
   mapping:
-    optional_end_date:
-      type: boolean
-      label: 'Optional end date'
+    optional_values:
+      type: integer
+      label: 'Optional values'
 
 field.value.daterange:
   type: mapping
diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php b/core/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php
index 9c5184ddcad3..18bc48834ece 100644
--- a/core/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php
+++ b/core/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php
@@ -29,7 +29,7 @@ class DateRangeItem extends DateTimeItem {
    */
   public static function defaultFieldSettings() {
     return [
-      'optional_end_date' => FALSE,
+      'optional_values' => FALSE,
     ] + parent::defaultFieldSettings();
   }
 
@@ -38,6 +38,16 @@ public static function defaultFieldSettings() {
    */
   const DATETIME_TYPE_ALLDAY = 'allday';
 
+  /**
+   * Optional values setting, require a bounded datetime range.
+   */
+  const OPTIONAL_NONE = 0x01;
+
+  /**
+   * Optional values setting, do not require an end date.
+   */
+  const OPTIONAL_END = 0x02;
+
   /**
    * {@inheritdoc}
    */
@@ -89,11 +99,15 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
    */
   public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
     $element = [];
-    $element['optional_end_date'] = [
-      '#type' => 'checkbox',
-      '#title' => $this->t('Optional end date'),
-      '#description' => $this->t('Allow end date to be optional opposed to the default behaviour where end date is required when "Required field" is checked.'),
-      '#default_value' => $this->getSetting('optional_end_date'),
+    $element['optional_values'] = [
+      '#type' => 'radios',
+      '#title' => $this->t('End date'),
+      '#description' => $this->t('Applies regardless of whether the whole field is required'),
+      '#default_value' => $this->getSetting('optional_values'),
+      '#options' => [
+        static::OPTIONAL_NONE => $this->t('Required'),
+        static::OPTIONAL_END => $this->t('Optional end date'),
+      ],
     ];
 
     return $element;
@@ -151,19 +165,29 @@ public function getConstraints() {
       ->getValidationConstraintManager();
     $constraints = parent::getConstraints();
 
-    if (!empty($this->getSetting('optional_end_date'))) {
-      return $constraints;
-    }
-
-    $label = $this->getFieldDefinition()->getLabel();
-    $constraints[] = $constraint_manager
-      ->create('ComplexData', [
-        'end_value' => [
-          'NotNull' => [
-            'message' => $this->t('The @title end date is required', ['@title' => $label]),
+    if (!$this->getFieldDefinition()->isRequired()) {
+      $label = $this->getFieldDefinition()->getLabel();
+      // If the end date triggers constraint validation then test the start date.
+      $constraints[] = $constraint_manager
+        ->create('ComplexData', [
+          'value' => [
+            'NotNull' => [
+              'message' => $this->t('The @title start date is required', ['@title' => $label]),
+            ],
           ],
-        ],
-      ]);
+        ]);
+      // Testing the end date is only needed if not required and not optional.
+      if ($this->getSetting('optional_values') == static::OPTIONAL_NONE) {
+        $constraints[] = $constraint_manager
+          ->create('ComplexData', [
+            'end_value' => [
+              'NotNull' => [
+                'message' => $this->t('The @title end date is required', ['@title' => $label]),
+              ],
+            ],
+          ]);
+      }
+    }
 
     return $constraints;
   }
diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php
index ee894f56da49..a5de90790394 100644
--- a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php
+++ b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php
@@ -19,7 +19,7 @@ class DateRangeWidgetBase extends DateTimeWidgetBase {
    */
   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $element = parent::formElement($items, $delta, $element, $form, $form_state);
-    $optional_end_date = $this->getFieldSetting('optional_end_date');
+    $optional_values = $this->getFieldSetting('optional_values');
 
     // Wrap all of the select elements with a fieldset.
     $element['#theme_wrappers'][] = 'fieldset';
@@ -31,7 +31,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       '#title' => $this->t('End date'),
     ] + $element['value'];
 
-    if ($element['#required'] && $optional_end_date) {
+    if ($element['#required'] && $optional_values == DateRangeItem::OPTIONAL_END) {
       $element['end_value']['#required'] = FALSE;
       $element['#required'] = FALSE;
     }
diff --git a/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php b/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php
index 4a8cb5801579..a7e5b1749973 100644
--- a/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php
+++ b/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php
@@ -110,7 +110,7 @@ public function testOptionalEndDate() {
     $field_name = $this->fieldStorage->getName();
 
     $this->field->setSettings([
-      'optional_end_date' => FALSE,
+      'optional_values' => DateRangeItem::OPTIONAL_NONE,
     ])
       ->save();
 
@@ -126,7 +126,7 @@ public function testOptionalEndDate() {
     $this->assertNotEquals(count($entity->validate()), 0);
 
     // Verify entity with the optional_end_date enabled.
-    $this->field->setSetting('optional_end_date', TRUE)
+    $this->field->setSetting('optional_values', DateRangeItem::OPTIONAL_END)
       ->save();
     $entity = EntityTest::create([
       'name' => $this->randomString(),
-- 
GitLab