From 4ca91e3c82c937b523e8f18b4d821d3c978d0138 Mon Sep 17 00:00:00 2001
From: mondrake <28163-mondrake@users.noreply.drupalcode.org>
Date: Tue, 7 Jan 2025 20:04:05 +0000
Subject: [PATCH 01/11] Update composer.json

---
 composer.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/composer.json b/composer.json
index 6e69b0d..62ba674 100644
--- a/composer.json
+++ b/composer.json
@@ -5,7 +5,7 @@
     "require": {
         "drupal/core": "^10.3 | ^11",
         "dompdf/php-font-lib": "^1",
-        "fileeye/pel": "^0.10.0"
+        "fileeye/pel": "dev-master"
     },
     "require-dev": {
         "drupal/vendor_stream_wrapper": "^2.0.4",
-- 
GitLab


From 3f49e9adab932513ca76a5281eada172813455fc Mon Sep 17 00:00:00 2001
From: mondrake <28163-mondrake@users.noreply.drupalcode.org>
Date: Tue, 7 Jan 2025 20:07:02 +0000
Subject: [PATCH 02/11] Update .gitlab-ci.yml

---
 .gitlab-ci.yml | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3f30e91..960e093 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -49,8 +49,9 @@ include:
 # Docs at https://git.drupalcode.org/project/gitlab_templates/-/blob/1.0.x/includes/include.drupalci.variables.yml
 ################
 variables:
-  _PHPUNIT_CONCURRENT: '1'
-#  _PHPUNIT_EXTRA: '-c $CI_PROJECT_DIR/$_WEB_ROOT/core --testdox --colors=always'
+  _PHPUNIT_CONCURRENT: '0'
+  _PHPUNIT_EXTRA: '-c $CI_PROJECT_DIR/$_WEB_ROOT/core --testdox --colors=always'
+  OPT_IN_TEST_PREVIOUS_MAJOR: '01'
   OPT_IN_TEST_PREVIOUS_MINOR: '0'
   OPT_IN_TEST_NEXT_MINOR: '1'
   OPT_IN_TEST_NEXT_MAJOR: '1'
-- 
GitLab


From d138ee5eb25ff3760a863c0d85ba2be60465197f Mon Sep 17 00:00:00 2001
From: mondrake <28163-mondrake@users.noreply.drupalcode.org>
Date: Wed, 8 Jan 2025 19:45:54 +0000
Subject: [PATCH 03/11] fix test

---
 .../tests/src/Kernel/FileMetadataExifTest.php         |  2 +-
 phpstan-baseline.neon                                 | 11 -----------
 phpstan.neon                                          |  1 -
 3 files changed, 1 insertion(+), 13 deletions(-)
 delete mode 100644 phpstan-baseline.neon

diff --git a/file_mdm_exif/tests/src/Kernel/FileMetadataExifTest.php b/file_mdm_exif/tests/src/Kernel/FileMetadataExifTest.php
index 4dfd64b..9dce7b1 100644
--- a/file_mdm_exif/tests/src/Kernel/FileMetadataExifTest.php
+++ b/file_mdm_exif/tests/src/Kernel/FileMetadataExifTest.php
@@ -381,7 +381,7 @@ class FileMetadataExifTest extends FileMetadataManagerTestBase {
     $this->assertEquals([8, 8, 8, 8], $file_metadata->getMetadata('exif', 'BitsPerSample')['value']);
     $data['BitsPerSample'] = [7, 6, 5, 4];
     $bps_tag = $this->container->get(ExifTagMapperInterface::class)->resolveKeyToIfdAndTag('BitsPerSample');
-    $bps = new PelEntryShort($bps_tag['tag'], $data['BitsPerSample']);
+    $bps = new PelEntryShort($bps_tag['tag'], ...$data['BitsPerSample']);
     $this->assertTrue($file_metadata->setMetadata('exif', 'BitsPerSample', $bps));
     $this->assertEquals($data['BitsPerSample'], $file_metadata->getMetadata('exif', 'BitsPerSample')['value']);
 
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
deleted file mode 100644
index f7df7af..0000000
--- a/phpstan-baseline.neon
+++ /dev/null
@@ -1,11 +0,0 @@
-parameters:
-	ignoreErrors:
-		-
-			message: "#^Parameter \\#2 \\$value of class lsolesen\\\\pel\\\\PelEntryShort constructor expects int\\|null, array\\<int, int\\> given\\.$#"
-			count: 1
-			path: file_mdm_exif/tests/src/Kernel/FileMetadataExifTest.php
-
-		-
-			message: "#^Parameter \\#2 \\$message of method Drupal\\\\Core\\\\Form\\\\FormStateInterface\\:\\:setError\\(\\) expects string, Drupal\\\\Core\\\\StringTranslation\\\\TranslatableMarkup given\\.$#"
-			count: 1
-			path: src/Element/FileMetadataCaching.php
diff --git a/phpstan.neon b/phpstan.neon
index db8cf58..f55fa8a 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,7 +1,6 @@
 # Configuration file for PHPStan static code checking, see https://phpstan.org .
 
 includes:
-  - phpstan-baseline.neon
   - phar://phpstan.phar/conf/bleedingEdge.neon
 
 parameters:
-- 
GitLab


From 365bb21d2698a91be1044c117c5167e4edd81fb3 Mon Sep 17 00:00:00 2001
From: mondrake <28163-mondrake@users.noreply.drupalcode.org>
Date: Wed, 8 Jan 2025 19:58:01 +0000
Subject: [PATCH 04/11] Update 2 files

- /.gitlab-ci.yml
- /phpstan.neon
---
 .gitlab-ci.yml | 3 ++-
 phpstan.neon   | 3 ---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 960e093..636cdb9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -51,10 +51,11 @@ include:
 variables:
   _PHPUNIT_CONCURRENT: '0'
   _PHPUNIT_EXTRA: '-c $CI_PROJECT_DIR/$_WEB_ROOT/core --testdox --colors=always'
-  OPT_IN_TEST_PREVIOUS_MAJOR: '01'
+  OPT_IN_TEST_PREVIOUS_MAJOR: '1'
   OPT_IN_TEST_PREVIOUS_MINOR: '0'
   OPT_IN_TEST_NEXT_MINOR: '1'
   OPT_IN_TEST_NEXT_MAJOR: '1'
+  BROWSERTEST_OUTPUT_VERBOSE: false
 
 phpunit:
   extends: .phpunit-base
diff --git a/phpstan.neon b/phpstan.neon
index f55fa8a..a2ecf67 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,8 +1,5 @@
 # Configuration file for PHPStan static code checking, see https://phpstan.org .
 
-includes:
-  - phar://phpstan.phar/conf/bleedingEdge.neon
-
 parameters:
 
   level: 5
-- 
GitLab


From 33857bbcaca29997602b156ab6be4d0b850fdd8c Mon Sep 17 00:00:00 2001
From: mondrake <28163-mondrake@users.noreply.drupalcode.org>
Date: Wed, 8 Jan 2025 21:25:03 +0000
Subject: [PATCH 05/11] Update .gitlab-ci.yml

---
 .gitlab-ci.yml | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 636cdb9..40b752e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -49,12 +49,13 @@ include:
 # Docs at https://git.drupalcode.org/project/gitlab_templates/-/blob/1.0.x/includes/include.drupalci.variables.yml
 ################
 variables:
-  _PHPUNIT_CONCURRENT: '0'
-  _PHPUNIT_EXTRA: '-c $CI_PROJECT_DIR/$_WEB_ROOT/core --testdox --colors=always'
+  SKIP_CSPELL: '1'
   OPT_IN_TEST_PREVIOUS_MAJOR: '1'
   OPT_IN_TEST_PREVIOUS_MINOR: '0'
   OPT_IN_TEST_NEXT_MINOR: '1'
   OPT_IN_TEST_NEXT_MAJOR: '1'
+  _PHPUNIT_CONCURRENT: '0'
+  _PHPUNIT_EXTRA: '-c $CI_PROJECT_DIR/$_WEB_ROOT/core --testdox --colors=always'
   BROWSERTEST_OUTPUT_VERBOSE: false
 
 phpunit:
-- 
GitLab


From ccf9b46ed4aa3e8c26dbc88b2019cfd93b42ae16 Mon Sep 17 00:00:00 2001
From: mondrake <mondrake.org@gmail.com>
Date: Sat, 18 Jan 2025 18:16:35 +0100
Subject: [PATCH 06/11] fix

---
 .gitlab-ci.yml                 |  2 +-
 file_mdm.module                | 31 ---------------------------
 src/Hook/FileMetadataHooks.php | 38 ++++++++++++++++++++++++++++++++++
 3 files changed, 39 insertions(+), 32 deletions(-)
 delete mode 100644 file_mdm.module
 create mode 100644 src/Hook/FileMetadataHooks.php

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 40b752e..bde71f4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -50,7 +50,7 @@ include:
 ################
 variables:
   SKIP_CSPELL: '1'
-  OPT_IN_TEST_PREVIOUS_MAJOR: '1'
+  OPT_IN_TEST_PREVIOUS_MAJOR: '0'
   OPT_IN_TEST_PREVIOUS_MINOR: '0'
   OPT_IN_TEST_NEXT_MINOR: '1'
   OPT_IN_TEST_NEXT_MAJOR: '1'
diff --git a/file_mdm.module b/file_mdm.module
deleted file mode 100644
index 28f673c..0000000
--- a/file_mdm.module
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-/**
- * @file
- * Provides a service to manage file metadata.
- */
-
-declare(strict_types=1);
-
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\file\FileInterface;
-use Drupal\file_mdm\FileMetadataManagerInterface;
-
-/**
- * Implements hook_cache_flush().
- */
-function file_mdm_cache_flush(): array {
-  return ['file_mdm'];
-}
-
-/**
- * Implements hook_file_delete().
- */
-function file_mdm_file_delete(EntityInterface $entity): void {
-  // Deletes any cached file metadata information upon deletion of a file
-  // entity.
-  assert($entity instanceof FileInterface);
-  $fmdm = \Drupal::service(FileMetadataManagerInterface::class);
-  $fmdm->deleteCachedMetadata($entity->getFileUri());
-  $fmdm->release($entity->getFileUri());
-}
diff --git a/src/Hook/FileMetadataHooks.php b/src/Hook/FileMetadataHooks.php
new file mode 100644
index 0000000..75f2a6b
--- /dev/null
+++ b/src/Hook/FileMetadataHooks.php
@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\file_mdm\Hook;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\file\FileInterface;
+use Drupal\file_mdm\FileMetadataManagerInterface;
+
+/**
+ * Hook implementations for file_mdm.
+ */
+class FileMetadataHooks {
+
+  /**
+   * Implements hook_cache_flush().
+   */
+  #[Hook('cache_flush')]
+  function cacheFlush(): void {
+    // @todo this needs to delete the cache.
+  }
+
+  /**
+   * Implements hook_file_delete().
+   */
+  #[Hook('file_delete')]
+  function fileDelete(EntityInterface $entity): void {
+    // Deletes any cached file metadata information upon deletion of a file
+    // entity.
+    assert($entity instanceof FileInterface);
+    $fmdm = \Drupal::service(FileMetadataManagerInterface::class);
+    $fmdm->deleteCachedMetadata($entity->getFileUri());
+    $fmdm->release($entity->getFileUri());
+  }
+
+}
-- 
GitLab


From 3c7058a1ca35c658be59349c3a22da2d1562791c Mon Sep 17 00:00:00 2001
From: mondrake <mondrake.org@gmail.com>
Date: Sat, 18 Jan 2025 18:50:14 +0100
Subject: [PATCH 07/11] array definitions

---
 file_mdm.install                             |  4 ++--
 file_mdm_exif/src/ExifTagMapper.php          | 16 ++++++++--------
 file_mdm_exif/src/ExifTagMapperInterface.php |  8 ++++----
 src/Hook/FileMetadataHooks.php               |  4 ++--
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/file_mdm.install b/file_mdm.install
index d3186a5..63ff95e 100644
--- a/file_mdm.install
+++ b/file_mdm.install
@@ -12,14 +12,14 @@ use Drupal\Core\Logger\RfcLogLevel;
 /**
  * Clear caches to discover service changes.
  */
-function file_mdm_update_8200() {
+function file_mdm_update_8200(): void {
   // Empty function.
 }
 
 /**
  * Set a default for the 'Log level to use if a file does not exist' setting.
  */
-function file_mdm_update_8201() {
+function file_mdm_update_8201(): void {
   $config = \Drupal::configFactory()->getEditable('file_mdm.settings');
   if ($config->get('missing_file_log_level') !== NULL) {
     return;
diff --git a/file_mdm_exif/src/ExifTagMapper.php b/file_mdm_exif/src/ExifTagMapper.php
index 68eed0d..4683c9d 100644
--- a/file_mdm_exif/src/ExifTagMapper.php
+++ b/file_mdm_exif/src/ExifTagMapper.php
@@ -115,8 +115,8 @@ class ExifTagMapper implements ExifTagMapperInterface {
    *
    * Builds and caches the list as needed.
    *
-   * @return array
-   *   A simple array of IFDs, expressed as literal/integer combinations.
+   * @return list<array{0: string, 1: int}>
+   *   A list of IFDs, expressed as literal/integer combinations.
    */
   protected function getSupportedIfdsMap(): array {
     if (!isset($this->supportedIfdsMap)) {
@@ -147,8 +147,8 @@ class ExifTagMapper implements ExifTagMapperInterface {
    *
    * Builds and caches the list as needed.
    *
-   * @return array
-   *   A simple array of IFD/TAG combinations, expressed as literals.
+   * @return list<array{0: string, 1: string}>
+   *   A list of IFD/TAG combinations, expressed as literals.
    */
   protected function getSupportedKeysMap(): array {
     if (!isset($this->supportedKeysMap)) {
@@ -180,8 +180,8 @@ class ExifTagMapper implements ExifTagMapperInterface {
    * @param string $value
    *   A TAG literal.
    *
-   * @return array
-   *   A simple array of with IFD and TAG, expressed as integers.
+   * @return array{0: int, 1: int}
+   *   An array with IFD and TAG, expressed as integers.
    *
    * @throws \Drupal\file_mdm\FileMetadataException
    *   When the IFD/TAG combination could not be found.
@@ -199,7 +199,7 @@ class ExifTagMapper implements ExifTagMapperInterface {
    *
    * Builds and caches the list as needed.
    *
-   * @return array
+   * @return array<string, array{0: int, 1: int}>
    *   An associative array where keys are TAG literals, and values a simple
    *   array of IFD/TAG integer identifiers.
    */
@@ -251,7 +251,7 @@ class ExifTagMapper implements ExifTagMapperInterface {
    *
    * Builds and caches the list as needed.
    *
-   * @return array
+   * @return array<string,int>
    *   An associative array where keys are IFD literals, and values the IFD
    *   integer identifiers.
    */
diff --git a/file_mdm_exif/src/ExifTagMapperInterface.php b/file_mdm_exif/src/ExifTagMapperInterface.php
index 60484f8..ea9d114 100644
--- a/file_mdm_exif/src/ExifTagMapperInterface.php
+++ b/file_mdm_exif/src/ExifTagMapperInterface.php
@@ -12,7 +12,7 @@ interface ExifTagMapperInterface {
   /**
    * Resolves a metadata 'key' to the default EXIF IFD and TAG.
    *
-   * @param string|array $key
+   * @param string|array{0: int|string, 1: int|string} $key
    *   A metadata 'key' as passed in by the file metadata manager. It can be a
    *   string, in which case the default IFD and TAG are returned. If it is an
    *   array, then the first and the second array elements define respectively
@@ -20,7 +20,7 @@ interface ExifTagMapperInterface {
    *   they are converted to EXIF integer identifiers, or integers, in which
    *   case they are returned as such.
    *
-   * @return array
+   * @return array{'ifd': int, 'tag': int}
    *   An associative array with the following keys:
    *     'ifd' - the IFD EXIF integer identifier.
    *     'tag' - the TAG EXIF integer identifier.
@@ -33,7 +33,7 @@ interface ExifTagMapperInterface {
   /**
    * Returns a list of default metadata 'keys' supported.
    *
-   * @param array|null $options
+   * @param array{'ifds'?: bool, 'ifd'?: int}|null $options
    *   (optional) If specified, restricts the results returned. By default, all
    *   the available EXIF IFD/TAG combinations for any IFD are returned.
    *   If $options contains ['ifds' => TRUE], the supported IFDs are returned.
@@ -41,7 +41,7 @@ interface ExifTagMapperInterface {
    *   supported by the IFD specified by $value are returned.
    *   If $options is NULL, no restrictions are applied.
    *
-   * @return array
+   * @return list<array{0: string, 1: int|string}>
    *   A simple array.
    *   When returning a list of supported IFDs, each array element is a simple
    *   array with:
diff --git a/src/Hook/FileMetadataHooks.php b/src/Hook/FileMetadataHooks.php
index 75f2a6b..a0975b9 100644
--- a/src/Hook/FileMetadataHooks.php
+++ b/src/Hook/FileMetadataHooks.php
@@ -18,7 +18,7 @@ class FileMetadataHooks {
    * Implements hook_cache_flush().
    */
   #[Hook('cache_flush')]
-  function cacheFlush(): void {
+  public function cacheFlush(): void {
     // @todo this needs to delete the cache.
   }
 
@@ -26,7 +26,7 @@ class FileMetadataHooks {
    * Implements hook_file_delete().
    */
   #[Hook('file_delete')]
-  function fileDelete(EntityInterface $entity): void {
+  public function fileDelete(EntityInterface $entity): void {
     // Deletes any cached file metadata information upon deletion of a file
     // entity.
     assert($entity instanceof FileInterface);
-- 
GitLab


From 1edc7a115874b0e6d77c0bb02e3a4a6deecd90ba Mon Sep 17 00:00:00 2001
From: mondrake <mondrake.org@gmail.com>
Date: Sun, 19 Jan 2025 09:49:56 +0100
Subject: [PATCH 08/11] phpstan

---
 file_mdm_exif/src/ExifTagMapper.php            | 18 +++++++++++++-----
 file_mdm_exif/src/ExifTagMapperInterface.php   |  2 +-
 file_mdm_exif/src/Plugin/FileMetadata/Exif.php |  8 ++++++++
 src/Plugin/FileMetadataPluginInterface.php     |  6 +++---
 4 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/file_mdm_exif/src/ExifTagMapper.php b/file_mdm_exif/src/ExifTagMapper.php
index 4683c9d..bbcb820 100644
--- a/file_mdm_exif/src/ExifTagMapper.php
+++ b/file_mdm_exif/src/ExifTagMapper.php
@@ -23,6 +23,8 @@ class ExifTagMapper implements ExifTagMapperInterface {
    *
    * Maps IFDs or their aliases expressed as literals to the EXIF integer
    * identifier.
+   *
+   * @var array<string,int>
    */
   protected array $stringToIfdMap;
 
@@ -30,13 +32,17 @@ class ExifTagMapper implements ExifTagMapperInterface {
    * The string to TAG map.
    *
    * Maps TAGs expressed as literals to the EXIF integer IFD/TAG identifiers.
+   *
+   * @var array<string, array{0: int, 1: int}>
    */
   protected array $stringToTagMap;
 
   /**
    * The supported metadata 'keys'.
    *
-   * A simple array of IFD/TAG combinations, expressed as literals.
+   * A list of IFD/TAG combinations, expressed as literals.
+   *
+   * @var list<array{0: string, 1: string}>
    */
   protected array $supportedKeysMap;
 
@@ -44,6 +50,8 @@ class ExifTagMapper implements ExifTagMapperInterface {
    * The supported IFDs.
    *
    * A simple array of IFDs, expressed as literal/integer combinations.
+   *
+   * @var list<array{0: string, 1: int}>
    */
   protected array $supportedIfdsMap;
 
@@ -70,9 +78,7 @@ class ExifTagMapper implements ExifTagMapperInterface {
       $tag = $this->stringToTag($key);
       return ['ifd' => $tag[0], 'tag' => $tag[1]];
     }
-    if (!isset($key[0]) || !isset($key[1])) {
-      throw new FileMetadataException('Invalid $key array specified, must have two values', NULL, __METHOD__);
-    }
+
     // Deal with ifd.
     if (is_int($key[0])) {
       $ifd = $key[0];
@@ -83,6 +89,7 @@ class ExifTagMapper implements ExifTagMapperInterface {
     else {
       throw new FileMetadataException('Invalid EXIF IFD specified, must be a string or an integer', NULL, __METHOD__);
     }
+
     // Deal with tag.
     if (is_string($key[1])) {
       $tag = $this->stringToTag($key[1])[1];
@@ -93,6 +100,7 @@ class ExifTagMapper implements ExifTagMapperInterface {
     else {
       throw new FileMetadataException('Invalid EXIF TAG specified, must be a string or an integer', NULL, __METHOD__);
     }
+
     return ['ifd' => $ifd, 'tag' => $tag];
   }
 
@@ -101,7 +109,7 @@ class ExifTagMapper implements ExifTagMapperInterface {
       return $this->getSupportedIfdsMap();
     }
     elseif (isset($options['ifd'])) {
-      return array_filter($this->getSupportedKeysMap(), function ($a) use ($options) {
+      return array_filter($this->getSupportedKeysMap(), function ($a) use ($options): bool {
         return strtolower($options['ifd']) === strtolower($a[0]);
       });
     }
diff --git a/file_mdm_exif/src/ExifTagMapperInterface.php b/file_mdm_exif/src/ExifTagMapperInterface.php
index ea9d114..c14a78c 100644
--- a/file_mdm_exif/src/ExifTagMapperInterface.php
+++ b/file_mdm_exif/src/ExifTagMapperInterface.php
@@ -33,7 +33,7 @@ interface ExifTagMapperInterface {
   /**
    * Returns a list of default metadata 'keys' supported.
    *
-   * @param array{'ifds'?: bool, 'ifd'?: int}|null $options
+   * @param array{'ifds'?: bool, 'ifd'?: string}|null $options
    *   (optional) If specified, restricts the results returned. By default, all
    *   the available EXIF IFD/TAG combinations for any IFD are returned.
    *   If $options contains ['ifds' => TRUE], the supported IFDs are returned.
diff --git a/file_mdm_exif/src/Plugin/FileMetadata/Exif.php b/file_mdm_exif/src/Plugin/FileMetadata/Exif.php
index b8c943c..0993a39 100644
--- a/file_mdm_exif/src/Plugin/FileMetadata/Exif.php
+++ b/file_mdm_exif/src/Plugin/FileMetadata/Exif.php
@@ -42,6 +42,14 @@ class Exif extends FileMetadataPluginBase {
    */
   protected PelJpeg|PelTiff|false $pelFile;
 
+  /**
+   * @param array<mixed> $configuration
+   *   The plugin configuration.
+   * @param string $plugin_id
+   *   The plugin id.
+   * @param array<mixed> $plugin_definition
+   *   The plugin definition.
+   */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
     $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
     $instance->mimeTypeGuesser = $container->get('file.mime_type.guesser');
diff --git a/src/Plugin/FileMetadataPluginInterface.php b/src/Plugin/FileMetadataPluginInterface.php
index 7464e64..6130ee5 100644
--- a/src/Plugin/FileMetadataPluginInterface.php
+++ b/src/Plugin/FileMetadataPluginInterface.php
@@ -84,12 +84,12 @@ interface FileMetadataPluginInterface extends ContainerFactoryPluginInterface, P
   /**
    * Returns a list of metadata keys supported by the plugin.
    *
-   * @param array|null $options
+   * @param array<mixed>|null $options
    *   (optional) Allows specifying additional options to control the list of
    *   metadata keys returned. If NULL, no additional options are applied.
    *
-   * @return array
-   *   A simple array of metadata keys supported.
+   * @return list<mixed>
+   *   A list of metadata keys supported.
    */
   public function getSupportedKeys(?array $options = NULL): array;
 
-- 
GitLab


From 85317c579687c037d11be5c1ac334cbaf8068f54 Mon Sep 17 00:00:00 2001
From: mondrake <mondrake.org@gmail.com>
Date: Sun, 19 Jan 2025 10:18:37 +0100
Subject: [PATCH 09/11] cacheFlush hook is irrelevant

---
 file_mdm_exif/src/ExifTagMapper.php | 2 +-
 src/Hook/FileMetadataHooks.php      | 8 --------
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/file_mdm_exif/src/ExifTagMapper.php b/file_mdm_exif/src/ExifTagMapper.php
index bbcb820..e3985bc 100644
--- a/file_mdm_exif/src/ExifTagMapper.php
+++ b/file_mdm_exif/src/ExifTagMapper.php
@@ -49,7 +49,7 @@ class ExifTagMapper implements ExifTagMapperInterface {
   /**
    * The supported IFDs.
    *
-   * A simple array of IFDs, expressed as literal/integer combinations.
+   * A list of IFDs, expressed as literal/integer combinations.
    *
    * @var list<array{0: string, 1: int}>
    */
diff --git a/src/Hook/FileMetadataHooks.php b/src/Hook/FileMetadataHooks.php
index a0975b9..d6f365e 100644
--- a/src/Hook/FileMetadataHooks.php
+++ b/src/Hook/FileMetadataHooks.php
@@ -14,14 +14,6 @@ use Drupal\file_mdm\FileMetadataManagerInterface;
  */
 class FileMetadataHooks {
 
-  /**
-   * Implements hook_cache_flush().
-   */
-  #[Hook('cache_flush')]
-  public function cacheFlush(): void {
-    // @todo this needs to delete the cache.
-  }
-
   /**
    * Implements hook_file_delete().
    */
-- 
GitLab


From e6493692550de7adb436722013198c1e07db30f5 Mon Sep 17 00:00:00 2001
From: mondrake <mondrake.org@gmail.com>
Date: Sun, 19 Jan 2025 14:11:20 +0100
Subject: [PATCH 10/11] phpstan

---
 file_mdm_exif/src/ExifTagMapper.php                |  3 +++
 file_mdm_font/src/Plugin/FileMetadata/Font.php     |  3 +++
 phpstan.neon                                       |  2 ++
 src/Element/FileMetadataCaching.php                | 10 +++++-----
 src/FileMetadataInterface.php                      |  8 ++++----
 src/Plugin/FileMetadata/FileMetadataPluginBase.php | 14 +++++++++++---
 src/Plugin/FileMetadataPluginInterface.php         |  4 ++--
 7 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/file_mdm_exif/src/ExifTagMapper.php b/file_mdm_exif/src/ExifTagMapper.php
index e3985bc..b129314 100644
--- a/file_mdm_exif/src/ExifTagMapper.php
+++ b/file_mdm_exif/src/ExifTagMapper.php
@@ -78,6 +78,9 @@ class ExifTagMapper implements ExifTagMapperInterface {
       $tag = $this->stringToTag($key);
       return ['ifd' => $tag[0], 'tag' => $tag[1]];
     }
+    if (!isset($key[0]) || !isset($key[1])) {
+      throw new FileMetadataException('Invalid $key array specified, must have two values', NULL, __METHOD__);
+    }
 
     // Deal with ifd.
     if (is_int($key[0])) {
diff --git a/file_mdm_font/src/Plugin/FileMetadata/Font.php b/file_mdm_font/src/Plugin/FileMetadata/Font.php
index be4e079..7865ccd 100644
--- a/file_mdm_font/src/Plugin/FileMetadata/Font.php
+++ b/file_mdm_font/src/Plugin/FileMetadata/Font.php
@@ -23,6 +23,9 @@ use FontLib\Table\Type\name;
 )]
 class Font extends FileMetadataPluginBase {
 
+  /**
+   * @return list<string>
+   */
   public function getSupportedKeys(?array $options = NULL): array {
     return array_merge(['FontType', 'FontWeight'], array_values(name::$nameIdCodes));
   }
diff --git a/phpstan.neon b/phpstan.neon
index 89cb2bc..3badf19 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -7,6 +7,8 @@ parameters:
   paths:
     - .
 
+  treatPhpDocTypesAsCertain: false
+
   ignoreErrors:
     # Ignore common errors for now.
     - "#^Class .* has an uninitialized readonly property .*\\. Assign it in the constructor\\.#"
diff --git a/src/Element/FileMetadataCaching.php b/src/Element/FileMetadataCaching.php
index a99382e..6a268b9 100644
--- a/src/Element/FileMetadataCaching.php
+++ b/src/Element/FileMetadataCaching.php
@@ -45,14 +45,14 @@ class FileMetadataCaching extends FormElementBase {
   /**
    * Processes a 'file_mdm_caching' form element.
    *
-   * @param array $element
+   * @param array<mixed> $element
    *   The form element to process.
    * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the form.
-   * @param array $complete_form
+   * @param array<mixed> $complete_form
    *   The complete form structure.
    *
-   * @return array
+   * @return array<mixed>
    *   The processed element.
    */
   public static function processCaching(array &$element, FormStateInterface $form_state, array &$complete_form): array {
@@ -96,11 +96,11 @@ class FileMetadataCaching extends FormElementBase {
   /**
    * Form element validation handler.
    *
-   * @param array $element
+   * @param array<mixed> $element
    *   The form element to process.
    * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the form.
-   * @param array $complete_form
+   * @param array<mixed> $complete_form
    *   The complete form structure.
    */
   public static function validateCaching(array &$element, FormStateInterface $form_state, array &$complete_form): void {
diff --git a/src/FileMetadataInterface.php b/src/FileMetadataInterface.php
index a3aa16c..9946c69 100644
--- a/src/FileMetadataInterface.php
+++ b/src/FileMetadataInterface.php
@@ -100,8 +100,8 @@ interface FileMetadataInterface {
    *   (optional) Allows specifying additional options to control the list of
    *   metadata keys returned.
    *
-   * @return array
-   *   A simple array of metadata keys supported.
+   * @return list<string|int>
+   *   A list of metadata keys supported.
    */
   public function getSupportedKeys(string $metadataId, mixed $options = NULL): array;
 
@@ -190,8 +190,8 @@ interface FileMetadataInterface {
    *
    * @param string $metadataId
    *   The id of the FileMetadata plugin.
-   * @param array $tags
-   *   (optional) An array of cache tags to save to cache.
+   * @param list<string> $tags
+   *   (optional) A list of cache tags to save to cache.
    *
    * @return bool
    *   TRUE if metadata was saved successfully, FALSE otherwise.
diff --git a/src/Plugin/FileMetadata/FileMetadataPluginBase.php b/src/Plugin/FileMetadata/FileMetadataPluginBase.php
index abbd6da..df09307 100644
--- a/src/Plugin/FileMetadata/FileMetadataPluginBase.php
+++ b/src/Plugin/FileMetadata/FileMetadataPluginBase.php
@@ -65,11 +65,11 @@ abstract class FileMetadataPluginBase extends PluginBase implements FileMetadata
   /**
    * Constructs a FileMetadataPluginBase plugin.
    *
-   * @param array $configuration
+   * @param array<mixed> $configuration
    *   A configuration array containing information about the plugin instance.
    * @param string $plugin_id
    *   The plugin_id for the plugin instance.
-   * @param array $plugin_definition
+   * @param array<mixed> $plugin_definition
    *   The plugin implementation definition.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache
    *   The cache service.
@@ -89,6 +89,14 @@ abstract class FileMetadataPluginBase extends PluginBase implements FileMetadata
     parent::__construct($configuration, $plugin_id, $plugin_definition);
   }
 
+  /**
+   * @param array<mixed> $configuration
+   *   The plugin configuration.
+   * @param string $plugin_id
+   *   The plugin id.
+   * @param array<mixed> $plugin_definition
+   *   The plugin definition.
+   */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
     return new static(
       $configuration,
@@ -261,7 +269,7 @@ abstract class FileMetadataPluginBase extends PluginBase implements FileMetadata
   /**
    * Checks if file metadata should be cached.
    *
-   * @return array|bool
+   * @return array<mixed>|false
    *   The caching settings array retrieved from configuration if file metadata
    *   is cacheable, FALSE otherwise.
    */
diff --git a/src/Plugin/FileMetadataPluginInterface.php b/src/Plugin/FileMetadataPluginInterface.php
index 6130ee5..06f73f0 100644
--- a/src/Plugin/FileMetadataPluginInterface.php
+++ b/src/Plugin/FileMetadataPluginInterface.php
@@ -16,7 +16,7 @@ interface FileMetadataPluginInterface extends ContainerFactoryPluginInterface, P
   /**
    * Gets default configuration for this plugin.
    *
-   * @return array
+   * @return array<mixed>
    *   An associative array with the default configuration.
    */
   public static function defaultConfiguration(): array;
@@ -192,7 +192,7 @@ interface FileMetadataPluginInterface extends ContainerFactoryPluginInterface, P
    *
    * Uses the 'file_mdm' cache bin.
    *
-   * @param array $tags
+   * @param list<string> $tags
    *   (optional) An array of cache tags to save to cache.
    *
    * @return bool
-- 
GitLab


From dfbef69ade88ee54a56e6bf3c85d9646c0cdeea5 Mon Sep 17 00:00:00 2001
From: mondrake <mondrake.org@gmail.com>
Date: Sun, 19 Jan 2025 14:30:47 +0100
Subject: [PATCH 11/11] phpstan baseline

---
 phpstan-baseline.neon | 115 ++++++++++++++++++++++++++++++++++++++++++
 phpstan.neon          |   3 ++
 2 files changed, 118 insertions(+)
 create mode 100644 phpstan-baseline.neon

diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 0000000..32e2fd4
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,115 @@
+parameters:
+	ignoreErrors:
+		-
+			message: '#^Method Drupal\\file_mdm\\Element\\FileMetadataCaching\:\:getInfo\(\) return type has no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Element/FileMetadataCaching.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Element\\FileMetadataCaching\:\:valueCallback\(\) has parameter \$element with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Element/FileMetadataCaching.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Form\\SettingsForm\:\:buildForm\(\) has parameter \$form with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Form/SettingsForm.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Form\\SettingsForm\:\:buildForm\(\) return type has no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Form/SettingsForm.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Form\\SettingsForm\:\:create\(\) has no return type specified\.$#'
+			identifier: missingType.return
+			count: 1
+			path: src/Form/SettingsForm.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Form\\SettingsForm\:\:getEditableConfigNames\(\) return type has no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Form/SettingsForm.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Form\\SettingsForm\:\:submitForm\(\) has no return type specified\.$#'
+			identifier: missingType.return
+			count: 1
+			path: src/Form/SettingsForm.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Form\\SettingsForm\:\:submitForm\(\) has parameter \$form with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Form/SettingsForm.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Form\\SettingsForm\:\:validateForm\(\) has no return type specified\.$#'
+			identifier: missingType.return
+			count: 1
+			path: src/Form/SettingsForm.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Form\\SettingsForm\:\:validateForm\(\) has parameter \$form with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Form/SettingsForm.php
+
+		-
+			message: '#^\\Drupal calls should be avoided in classes, use dependency injection instead$#'
+			identifier: globalDrupalDependencyInjection.useDependencyInjection
+			count: 1
+			path: src/Hook/FileMetadataHooks.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Plugin\\FileMetadata\\FileMetadataPluginBase\:\:buildConfigurationForm\(\) has parameter \$form with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Plugin/FileMetadata/FileMetadataPluginBase.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Plugin\\FileMetadata\\FileMetadataPluginBase\:\:buildConfigurationForm\(\) return type has no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Plugin/FileMetadata/FileMetadataPluginBase.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Plugin\\FileMetadata\\FileMetadataPluginBase\:\:submitConfigurationForm\(\) has no return type specified\.$#'
+			identifier: missingType.return
+			count: 1
+			path: src/Plugin/FileMetadata/FileMetadataPluginBase.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Plugin\\FileMetadata\\FileMetadataPluginBase\:\:submitConfigurationForm\(\) has parameter \$form with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Plugin/FileMetadata/FileMetadataPluginBase.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Plugin\\FileMetadata\\FileMetadataPluginBase\:\:validateConfigurationForm\(\) has no return type specified\.$#'
+			identifier: missingType.return
+			count: 1
+			path: src/Plugin/FileMetadata/FileMetadataPluginBase.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Plugin\\FileMetadata\\FileMetadataPluginBase\:\:validateConfigurationForm\(\) has parameter \$form with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Plugin/FileMetadata/FileMetadataPluginBase.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Plugin\\FileMetadataPluginManager\:\:__construct\(\) has parameter \$namespaces with no value type specified in iterable type Traversable\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Plugin/FileMetadataPluginManager.php
+
+		-
+			message: '#^Method Drupal\\file_mdm\\Plugin\\FileMetadataPluginManager\:\:createInstance\(\) has parameter \$configuration with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/Plugin/FileMetadataPluginManager.php
diff --git a/phpstan.neon b/phpstan.neon
index 3badf19..0c74ecc 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,5 +1,8 @@
 # Configuration file for PHPStan static code checking, see https://phpstan.org .
 
+includes:
+  - phpstan-baseline.neon
+
 parameters:
 
   level: 6
-- 
GitLab