From 70aa24c341ee003a0f0eeaf214bd987d5345c0cb Mon Sep 17 00:00:00 2001
From: Aurora Norris <AuroraNorris@numiko.com>
Date: Fri, 10 Jan 2025 15:18:59 +0000
Subject: [PATCH 1/7] Hook to modify oEmbed resource data for 11.x branch using
 OOP hooks in tests

---
 core/misc/cspell/dictionary.txt                  |  2 ++
 core/modules/media/media.api.php                 | 15 +++++++++++++++
 core/modules/media/media.services.yml            |  2 +-
 .../modules/media/src/OEmbed/ResourceFetcher.php | 11 +++++++++++
 .../src/Hook/MediaTestOembedHooks.php            | 10 ++++++++++
 .../tests/src/Functional/ResourceFetcherTest.php | 16 ++++++++++++++++
 .../media/tests/src/Unit/ResourceFetcherTest.php |  8 +++++++-
 7 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/core/misc/cspell/dictionary.txt b/core/misc/cspell/dictionary.txt
index 076d0372fe45..09f2d67068ac 100644
--- a/core/misc/cspell/dictionary.txt
+++ b/core/misc/cspell/dictionary.txt
@@ -230,6 +230,7 @@ hrefs
 htmlcorrector
 httpheader
 httponly
+hqdefault
 icann
 iconwrap
 idekey
@@ -285,6 +286,7 @@ mainpage
 maryjane
 maximumred
 maxlifetime
+maxresdefault
 maynot
 mbytes
 mediumint
diff --git a/core/modules/media/media.api.php b/core/modules/media/media.api.php
index 1a1700596134..b0ca8d3e382a 100644
--- a/core/modules/media/media.api.php
+++ b/core/modules/media/media.api.php
@@ -26,6 +26,21 @@ function hook_media_source_info_alter(array &$sources) {
   $sources['youtube']['label'] = t('Youtube rocks!');
 }
 
+/**
+ * Alters the information provided by the oEmbed resource url.
+ *
+ * @param array $data
+ *   Data provided by the oEmbed resource.
+ * @param $url
+ *   The oEmbed resource URL.
+ */
+function hook_oembed_resource_data_alter(array &$data, $url) {
+  if (str_contains($url, 'youtube.com/oembed')) {
+    // Get the maximum resolution thumbnail from YouTube.
+    $data['thumbnail_url'] = str_replace('hqdefault', 'maxresdefault', $data['thumbnail_url']);
+  }
+}
+
 /**
  * Alters an oEmbed resource URL before it is fetched.
  *
diff --git a/core/modules/media/media.services.yml b/core/modules/media/media.services.yml
index 0f3aeb6822e8..9be700e140ed 100644
--- a/core/modules/media/media.services.yml
+++ b/core/modules/media/media.services.yml
@@ -17,7 +17,7 @@ services:
   Drupal\media\OEmbed\ProviderRepositoryInterface: '@media.oembed.provider_repository'
   media.oembed.resource_fetcher:
     class: Drupal\media\OEmbed\ResourceFetcher
-    arguments: ['@http_client', '@media.oembed.provider_repository', '@cache.default', '%media.resource_fetcher_timeout%']
+    arguments: ['@http_client', '@media.oembed.provider_repository', '@cache.default', '@module_handler', '%media.resource_fetcher_timeout%']
   Drupal\media\OEmbed\ResourceFetcherInterface: '@media.oembed.resource_fetcher'
   media.oembed.iframe_url_helper:
     class: Drupal\media\IFrameUrlHelper
diff --git a/core/modules/media/src/OEmbed/ResourceFetcher.php b/core/modules/media/src/OEmbed/ResourceFetcher.php
index 4b482cbbc24e..52231dee8ce7 100644
--- a/core/modules/media/src/OEmbed/ResourceFetcher.php
+++ b/core/modules/media/src/OEmbed/ResourceFetcher.php
@@ -4,6 +4,7 @@
 
 use Drupal\Component\Serialization\Json;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use GuzzleHttp\ClientInterface;
 use GuzzleHttp\RequestOptions;
 use Psr\Http\Client\ClientExceptionInterface;
@@ -24,6 +25,8 @@ class ResourceFetcher implements ResourceFetcherInterface {
    *   The oEmbed provider repository service.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cacheBackend
    *   The cache backend.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface|null $moduleHandler
+   *   The module handler service.
    * @param int $timeout
    *   The length of time to wait for the request before the request
    *   should time out.
@@ -32,8 +35,14 @@ public function __construct(
     protected ClientInterface $httpClient,
     protected ProviderRepositoryInterface $providers,
     protected CacheBackendInterface $cacheBackend,
+    protected ModuleHandlerInterface $moduleHandler,
     protected int $timeout = 5,
   ) {
+    if (empty($moduleHandler)) {
+      $moduleHandler = \Drupal::moduleHandler();
+      @trigger_error('Passing NULL as the $module_handler parameter to ' . __METHOD__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3042423', E_USER_DEPRECATED);
+    }
+    $this->moduleHandler = $moduleHandler;
   }
 
   /**
@@ -74,6 +83,8 @@ public function fetchResource($url) {
       throw new ResourceException('The oEmbed resource could not be decoded.', $url);
     }
 
+    $this->moduleHandler->alter('oembed_resource_data', $data, $url);
+
     $this->cacheBackend->set($cache_id, $data);
 
     return $this->createResource($data, $url);
diff --git a/core/modules/media/tests/modules/media_test_oembed/src/Hook/MediaTestOembedHooks.php b/core/modules/media/tests/modules/media_test_oembed/src/Hook/MediaTestOembedHooks.php
index 4ed572a82ae5..1c455065bfb6 100644
--- a/core/modules/media/tests/modules/media_test_oembed/src/Hook/MediaTestOembedHooks.php
+++ b/core/modules/media/tests/modules/media_test_oembed/src/Hook/MediaTestOembedHooks.php
@@ -22,4 +22,14 @@ public function oembedResourceUrlAlter(array &$parsed_url, Provider $provider):
     }
   }
 
+  /**
+  * Implements hook_oembed_resource_data_alter().
+  */
+  #[Hook('oembed_resource_data_alter')]
+  function oembedResourceDataAlter(array &$data, $url) {
+    if (str_contains($url, 'twitter.com/oembed')) {
+      // Change the width property.
+      $data['width'] = 600;
+    }
+  }
 }
diff --git a/core/modules/media/tests/src/Functional/ResourceFetcherTest.php b/core/modules/media/tests/src/Functional/ResourceFetcherTest.php
index ec327a73ac73..5ad7d6364fb7 100644
--- a/core/modules/media/tests/src/Functional/ResourceFetcherTest.php
+++ b/core/modules/media/tests/src/Functional/ResourceFetcherTest.php
@@ -38,6 +38,7 @@ protected function setUp(): void {
    * Data provider for testFetchResource().
    *
    * @return array
+   *   Resources data provider.
    */
   public static function providerFetchResource() {
     return [
@@ -78,4 +79,19 @@ public function testFetchResource($resource_url, $provider_name, $title): void {
     $this->assertSame($title, $resource->getTitle());
   }
 
+  /**
+   * Tests that hook_oembed_resource_data_alter() is invoked.
+   */
+  public function testResourceDataAlter(): void {
+    $this->container->get('module_installer')->install(['media_test_oembed']);
+
+    // Get the resource.
+    $resource_url = $this->container->get('media.oembed.resource_fetcher')
+      ->fetchResource('https://publish.twitter.com/oembed?url=https://twitter.com/Dries/status/999985431595880448');
+
+    // Check media_test_oembed_oembed_resource_data_alter
+    // to see the hook implementation.
+    $this->assertEquals(600, $resource_url->getWidth());
+  }
+
 }
diff --git a/core/modules/media/tests/src/Unit/ResourceFetcherTest.php b/core/modules/media/tests/src/Unit/ResourceFetcherTest.php
index e05aaa06b55d..b55d5201a6cf 100644
--- a/core/modules/media/tests/src/Unit/ResourceFetcherTest.php
+++ b/core/modules/media/tests/src/Unit/ResourceFetcherTest.php
@@ -47,6 +47,7 @@ public function testFetchTimeout(): void {
       $client->reveal(),
       $this->createMock('\Drupal\media\OEmbed\ProviderRepositoryInterface'),
       new NullBackend('default'),
+      $this->createMock('\Drupal\Core\Extension\ModuleHandlerInterface'),
       $non_default_timeout
     );
     $fetcher->fetchResource($url);
@@ -84,7 +85,12 @@ public function testUnknownContentTypeHeader(): void {
     ]);
     $providers = $this->createMock('\Drupal\media\OEmbed\ProviderRepositoryInterface');
 
-    $fetcher = new ResourceFetcher($client, $providers, new NullBackend('default'));
+    $fetcher = new ResourceFetcher(
+      $client,
+      $providers,
+      new NullBackend('default'),
+      $this->createMock('\Drupal\Core\Extension\ModuleHandlerInterface')
+    );
     /** @var \Drupal\media\OEmbed\Resource $resource */
     $resource = $fetcher->fetchResource('valid');
     // The resource should have been successfully decoded as JSON.
-- 
GitLab


From bfaf0475f31fc95c93129d043c9f897e892db57d Mon Sep 17 00:00:00 2001
From: Aurora Norris <AuroraNorris@numiko.com>
Date: Fri, 10 Jan 2025 15:25:45 +0000
Subject: [PATCH 2/7] Increment major Drupal version in the deprecation hook

---
 core/modules/media/src/OEmbed/ResourceFetcher.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/modules/media/src/OEmbed/ResourceFetcher.php b/core/modules/media/src/OEmbed/ResourceFetcher.php
index 52231dee8ce7..aa9ceb4a6349 100644
--- a/core/modules/media/src/OEmbed/ResourceFetcher.php
+++ b/core/modules/media/src/OEmbed/ResourceFetcher.php
@@ -40,7 +40,7 @@ public function __construct(
   ) {
     if (empty($moduleHandler)) {
       $moduleHandler = \Drupal::moduleHandler();
-      @trigger_error('Passing NULL as the $module_handler parameter to ' . __METHOD__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3042423', E_USER_DEPRECATED);
+      @trigger_error('Passing NULL as the $module_handler parameter to ' . __METHOD__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:12.0.0. See https://www.drupal.org/node/3042423', E_USER_DEPRECATED);
     }
     $this->moduleHandler = $moduleHandler;
   }
-- 
GitLab


From d845049c2d142317d79bd99a25082178d420f594 Mon Sep 17 00:00:00 2001
From: Aurora Norris <AuroraNorris@numiko.com>
Date: Fri, 10 Jan 2025 15:43:33 +0000
Subject: [PATCH 3/7] Update Drupal version in deprecation message and make the
 moduleHandler as maybe null

---
 core/modules/media/src/OEmbed/ResourceFetcher.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/modules/media/src/OEmbed/ResourceFetcher.php b/core/modules/media/src/OEmbed/ResourceFetcher.php
index aa9ceb4a6349..9dba1eccec79 100644
--- a/core/modules/media/src/OEmbed/ResourceFetcher.php
+++ b/core/modules/media/src/OEmbed/ResourceFetcher.php
@@ -35,12 +35,12 @@ public function __construct(
     protected ClientInterface $httpClient,
     protected ProviderRepositoryInterface $providers,
     protected CacheBackendInterface $cacheBackend,
-    protected ModuleHandlerInterface $moduleHandler,
+    protected ?ModuleHandlerInterface $moduleHandler,
     protected int $timeout = 5,
   ) {
     if (empty($moduleHandler)) {
       $moduleHandler = \Drupal::moduleHandler();
-      @trigger_error('Passing NULL as the $module_handler parameter to ' . __METHOD__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:12.0.0. See https://www.drupal.org/node/3042423', E_USER_DEPRECATED);
+      @trigger_error('Passing NULL as the $module_handler parameter to ' . __METHOD__ . '() is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. See https://www.drupal.org/node/3042423', E_USER_DEPRECATED);
     }
     $this->moduleHandler = $moduleHandler;
   }
-- 
GitLab


From c93f8327d74705039babe7e11169286fad3aa56d Mon Sep 17 00:00:00 2001
From: Aurora Norris <AuroraNorris@numiko.com>
Date: Fri, 10 Jan 2025 15:43:57 +0000
Subject: [PATCH 4/7] Stick to phpcs rules

---
 .../media_test_oembed/src/Hook/MediaTestOembedHooks.php        | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/core/modules/media/tests/modules/media_test_oembed/src/Hook/MediaTestOembedHooks.php b/core/modules/media/tests/modules/media_test_oembed/src/Hook/MediaTestOembedHooks.php
index 1c455065bfb6..b09d5a22460a 100644
--- a/core/modules/media/tests/modules/media_test_oembed/src/Hook/MediaTestOembedHooks.php
+++ b/core/modules/media/tests/modules/media_test_oembed/src/Hook/MediaTestOembedHooks.php
@@ -26,10 +26,11 @@ public function oembedResourceUrlAlter(array &$parsed_url, Provider $provider):
   * Implements hook_oembed_resource_data_alter().
   */
   #[Hook('oembed_resource_data_alter')]
-  function oembedResourceDataAlter(array &$data, $url) {
+  public function oembedResourceDataAlter(array &$data, $url): void {
     if (str_contains($url, 'twitter.com/oembed')) {
       // Change the width property.
       $data['width'] = 600;
     }
   }
+
 }
-- 
GitLab


From 4ffd8dddeba4bf270920191dadee2877e8c63ce6 Mon Sep 17 00:00:00 2001
From: Aurora Norris <AuroraNorris@numiko.com>
Date: Fri, 10 Jan 2025 16:21:38 +0000
Subject: [PATCH 5/7] Fix dictionary issues

---
 core/misc/cspell/dictionary.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/misc/cspell/dictionary.txt b/core/misc/cspell/dictionary.txt
index 09f2d67068ac..8ba56793e004 100644
--- a/core/misc/cspell/dictionary.txt
+++ b/core/misc/cspell/dictionary.txt
@@ -226,11 +226,11 @@ hhvm
 hilited
 hmac
 hookname
+hqdefault
 hrefs
 htmlcorrector
 httpheader
 httponly
-hqdefault
 icann
 iconwrap
 idekey
-- 
GitLab


From d6a3ddb0ead1874101f379333a3a539568546af5 Mon Sep 17 00:00:00 2001
From: Aurora Norris <AuroraNorris@numiko.com>
Date: Fri, 10 Jan 2025 16:28:04 +0000
Subject: [PATCH 6/7] The container now needs to be rebuilt after a module is
 installed

---
 .../modules/media/tests/src/Functional/ResourceFetcherTest.php | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/core/modules/media/tests/src/Functional/ResourceFetcherTest.php b/core/modules/media/tests/src/Functional/ResourceFetcherTest.php
index 5ad7d6364fb7..4c09b2e871e9 100644
--- a/core/modules/media/tests/src/Functional/ResourceFetcherTest.php
+++ b/core/modules/media/tests/src/Functional/ResourceFetcherTest.php
@@ -86,6 +86,9 @@ public function testResourceDataAlter(): void {
     $this->container->get('module_installer')->install(['media_test_oembed']);
 
     // Get the resource.
+    // Much like FunctionalTestSetupTrait::installModulesFromClassProperty()
+    // after module install the rebuilt container needs to be used.
+    $this->container = \Drupal::getContainer();
     $resource_url = $this->container->get('media.oembed.resource_fetcher')
       ->fetchResource('https://publish.twitter.com/oembed?url=https://twitter.com/Dries/status/999985431595880448');
 
-- 
GitLab


From 9cb53f9bbd6535459345e81ee9d0b05ff5261fe8 Mon Sep 17 00:00:00 2001
From: Aurora Norris <69621-aurora-norris@users.noreply.drupalcode.org>
Date: Mon, 13 Jan 2025 08:56:58 +0000
Subject: [PATCH 7/7] Apply 1 suggestion(s) to 1 file(s)

Co-authored-by: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
---
 core/modules/media/src/OEmbed/ResourceFetcher.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/modules/media/src/OEmbed/ResourceFetcher.php b/core/modules/media/src/OEmbed/ResourceFetcher.php
index 9dba1eccec79..74925d996a1f 100644
--- a/core/modules/media/src/OEmbed/ResourceFetcher.php
+++ b/core/modules/media/src/OEmbed/ResourceFetcher.php
@@ -40,7 +40,7 @@ public function __construct(
   ) {
     if (empty($moduleHandler)) {
       $moduleHandler = \Drupal::moduleHandler();
-      @trigger_error('Passing NULL as the $module_handler parameter to ' . __METHOD__ . '() is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. See https://www.drupal.org/node/3042423', E_USER_DEPRECATED);
+      @trigger_error('Passing NULL as the $module_handler parameter to ' . __METHOD__ . '() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. See https://www.drupal.org/node/3042423', E_USER_DEPRECATED);
     }
     $this->moduleHandler = $moduleHandler;
   }
-- 
GitLab