From 702aba79278b11ed55e09c32b79d7108a444bdef Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Fri, 3 Jan 2025 15:00:16 +1000
Subject: [PATCH] Issue #3276845 by shalini_jha, chris burge, smustgrave,
 bramdriesen, larowlan: MediaSourceBase::getSourceFieldName() doesn't check
 character max

---
 core/modules/media/src/MediaSourceBase.php    |  9 ++++-
 .../schema/media_test_source.schema.yml       |  4 ++
 .../Source/TestSourceWithAReallyLongName.php  | 21 +++++++++++
 .../tests/src/Kernel/MediaSourceTest.php      | 37 +++++++++++++++++++
 4 files changed, 70 insertions(+), 1 deletion(-)
 create mode 100644 core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestSourceWithAReallyLongName.php

diff --git a/core/modules/media/src/MediaSourceBase.php b/core/modules/media/src/MediaSourceBase.php
index a07dcc9f59cb..f7197963cca8 100644
--- a/core/modules/media/src/MediaSourceBase.php
+++ b/core/modules/media/src/MediaSourceBase.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
@@ -314,10 +315,16 @@ protected function getSourceFieldName() {
 
     // Iterate at least once, until no field with the generated ID is found.
     do {
-      $id = $base_id;
+      // Limit the base field name to the maximum allowed length.
+      $id = (strlen($base_id) > EntityTypeInterface::ID_MAX_LENGTH) ? substr($base_id, 0, EntityTypeInterface::ID_MAX_LENGTH) : $base_id;
       // If we've tried before, increment and append the suffix.
       if ($tries) {
         $id .= '_' . $tries;
+
+        // Ensure the suffixed field name does not exceed the maximum allowed length.
+        if (strlen($id) > EntityTypeInterface::ID_MAX_LENGTH) {
+          $id = substr($base_id, 0, (EntityTypeInterface::ID_MAX_LENGTH - strlen('_' . $tries))) . '_' . $tries;
+        }
       }
       $field = $storage->load('media.' . $id);
       $tries++;
diff --git a/core/modules/media/tests/modules/media_test_source/config/schema/media_test_source.schema.yml b/core/modules/media/tests/modules/media_test_source/config/schema/media_test_source.schema.yml
index ab025640b400..7acb334ce026 100644
--- a/core/modules/media/tests/modules/media_test_source/config/schema/media_test_source.schema.yml
+++ b/core/modules/media/tests/modules/media_test_source/config/schema/media_test_source.schema.yml
@@ -21,3 +21,7 @@ media.source.test_hidden_source_field:
 media.source.test_different_displays:
   type: media.source.test
   label: 'Test media source with different source field displays'
+
+media.source.test_source_with_a_really_long_name:
+  type: media.source.test
+  label: 'Test source with a really long name'
diff --git a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestSourceWithAReallyLongName.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestSourceWithAReallyLongName.php
new file mode 100644
index 000000000000..1205e0591bfa
--- /dev/null
+++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestSourceWithAReallyLongName.php
@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\media_test_source\Plugin\media\Source;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\media\Attribute\MediaSource;
+
+/**
+ * Provides test media source.
+ */
+#[MediaSource(
+    id: 'test_source_with_a_really_long_name',
+    label: new TranslatableMarkup('Test source with a really long name'),
+    description: new TranslatableMarkup('Test source with a really long name.'),
+    allowed_field_types: ['string'],
+)]
+class TestSourceWithAReallyLongName extends Test {
+
+}
diff --git a/core/modules/media/tests/src/Kernel/MediaSourceTest.php b/core/modules/media/tests/src/Kernel/MediaSourceTest.php
index 012a49d0b220..16bd2102223b 100644
--- a/core/modules/media/tests/src/Kernel/MediaSourceTest.php
+++ b/core/modules/media/tests/src/Kernel/MediaSourceTest.php
@@ -516,6 +516,43 @@ public function testSourceFieldCreation(): void {
     $this->assertEquals('Test source with constraints', $field->label(), 'Incorrect label is used.');
     $this->assertSame('test_constraints_type', $field->getTargetBundle(), 'Field is not targeting correct bundle.');
 
+    // Test a source with a long machine name.
+    $type = MediaType::create([
+      'id' => 'test_type_fail',
+      'label' => 'Test type - Fail',
+      'source' => 'test_source_with_a_really_long_name',
+    ]);
+    $type->save();
+
+    /** @var \Drupal\field\Entity\FieldConfig $field */
+    $field = $type->getSource()->createSourceField($type);
+    /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
+    $field_storage = $field->getFieldStorageDefinition();
+    $field_storage->save();
+    // Field configuration depends on the field storage, which must be saved first.
+    $field->save();
+
+    // Test long field name is truncated.
+    $this->assertSame('field_media_test_source_with_a_r', $field_storage->getName(), 'Incorrect field name is used.');
+
+    $type = MediaType::create([
+      'id' => 'test_type_fail_2',
+      'label' => 'Test type - Fail 2',
+      'source' => 'test_source_with_a_really_long_name',
+    ]);
+    $type->save();
+
+    /** @var \Drupal\field\Entity\FieldConfig $field */
+    $field = $type->getSource()->createSourceField($type);
+    /** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
+    $field_storage = $field->getFieldStorageDefinition();
+    $field_storage->save();
+    // Field configuration depends on the field storage, which must be saved first.
+    $field->save();
+
+    // Test long field name is truncated.
+    $this->assertSame('field_media_test_source_with_a_1', $field_storage->getName(), 'Incorrect field name is used.');
+
     // Test that new source fields respect the configured field prefix, no
     // prefix at all if that's what's configured.
     $this->installConfig('field_ui');
-- 
GitLab