Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / file_mdm / file_mdm_exif / src / ExifTagMapper.php
diff --git a/web/modules/contrib/file_mdm/file_mdm_exif/src/ExifTagMapper.php b/web/modules/contrib/file_mdm/file_mdm_exif/src/ExifTagMapper.php
new file mode 100644 (file)
index 0000000..c7b39cc
--- /dev/null
@@ -0,0 +1,350 @@
+<?php
+
+namespace Drupal\file_mdm_exif;
+
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\file_mdm\FileMetadataException;
+use Psr\Log\LoggerInterface;
+use lsolesen\pel\PelIfd;
+use lsolesen\pel\PelTag;
+
+/**
+ * Provides a mapping service for EXIF ifds and tags.
+ */
+class ExifTagMapper implements ExifTagMapperInterface {
+
+  /**
+   * The cache service.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $cache;
+
+  /**
+   * The file_mdm logger.
+   *
+   * @var \Psr\Log\LoggerInterface
+   */
+  protected $logger;
+
+  /**
+   * The config factory service.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The string to IFD map.
+   *
+   * Maps IFDs or their aliases expressed as literals to the EXIF integer
+   * identifier.
+   *
+   * @var array
+   */
+  protected $stringToIfdMap;
+
+  /**
+   * The string to TAG map.
+   *
+   * Maps TAGs expressed as literals to the EXIF integer IFD/TAG identifiers.
+   *
+   * @var array
+   */
+  protected $stringToTagMap;
+
+  /**
+   * The supported metadata 'keys'.
+   *
+   * A simple array of IFD/TAG combinations, expressed as literals.
+   *
+   * @var array
+   */
+  protected $supportedKeysMap;
+
+  /**
+   * The supported IFDs.
+   *
+   * A simple array of IFDs, expressed as literal/integer combinations.
+   *
+   * @var array
+   */
+  protected $supportedIfdsMap;
+
+  /**
+   * Constructs a ExifTagMapper object.
+   *
+   * @param \Psr\Log\LoggerInterface $logger
+   *   The file_mdm logger.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_service
+   *   The cache service.
+   */
+  public function __construct(LoggerInterface $logger, ConfigFactoryInterface $config_factory, CacheBackendInterface $cache_service) {
+    $this->logger = $logger;
+    $this->configFactory = $config_factory;
+    $this->cache = $cache_service;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function resolveKeyToIfdAndTag($key) {
+    if ($key === NULL) {
+      throw new FileMetadataException('Missing $key argument', NULL, __METHOD__);
+    }
+    if (is_string($key)) {
+      $tag = $this->stringToTag($key);
+      return ['ifd' => $tag[0], 'tag' => $tag[1]];
+    }
+    if (is_array($key)) {
+      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];
+      }
+      elseif (is_string($key[0])) {
+        $ifd = $this->stringToIfd($key[0]);
+      }
+      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];
+      }
+      elseif (is_int($key[1])) {
+        $tag = $key[1];
+      }
+      else {
+        throw new FileMetadataException('Invalid EXIF TAG specified, must be a string or an integer', NULL, __METHOD__);
+      }
+      return ['ifd' => $ifd, 'tag' => $tag];
+    }
+    throw new FileMetadataException('Invalid $key argument, must be a string or an array', NULL, __METHOD__);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSupportedKeys(array $options = NULL) {
+    if (isset($options['ifds'])) {
+      return $this->getSupportedIfdsMap();
+    }
+    elseif (isset($options['ifd'])) {
+      return array_filter($this->getSupportedKeysMap(), function ($a) use ($options) {
+        return strtolower($options['ifd']) === strtolower($a[0]);
+      });
+    }
+    else {
+      return $this->getSupportedKeysMap();
+    }
+  }
+
+  /**
+   * Returns the list of supported IFDs.
+   *
+   * Builds and caches the list as needed.
+   *
+   * @return array
+   *   A simple array of IFDs, expressed as literal/integer combinations.
+   */
+  protected function getSupportedIfdsMap() {
+    if (!$this->supportedIfdsMap) {
+      $cache_id = 'supportedIfds';
+      if ($cache = $this->getCache($cache_id)) {
+        $this->supportedIfdsMap = $cache->data;
+      }
+      else {
+        $this->supportedIfdsMap = [];
+        $ifd_types = [
+          PelIfd::IFD0,
+          PelIfd::IFD1,
+          PelIfd::EXIF,
+          PelIfd::GPS,
+          PelIfd::INTEROPERABILITY,
+        ];
+        foreach ($ifd_types as $type) {
+          $this->supportedIfdsMap[] = [PelIfd::getTypeName($type), $type];
+        }
+        $this->setCache($cache_id, $this->supportedIfdsMap);
+      }
+    }
+    return $this->supportedIfdsMap;
+  }
+
+  /**
+   * Returns the list of supported metadata 'keys'.
+   *
+   * Builds and caches the list as needed.
+   *
+   * @return array
+   *   A simple array of IFD/TAG combinations, expressed as literals.
+   */
+  protected function getSupportedKeysMap() {
+    if (!$this->supportedKeysMap) {
+      $cache_id = 'supportedKeys';
+      if ($cache = $this->getCache($cache_id)) {
+        $this->supportedKeysMap = $cache->data;
+      }
+      else {
+        $this->supportedKeysMap = [];
+        foreach ($this->getSupportedIfdsMap() as $ifd) {
+          $ifd_obj = new PelIfd($ifd[1]);
+          $valid_tags = $ifd_obj->getValidTags();
+          foreach ($valid_tags as $tag) {
+            $this->supportedKeysMap[] = [
+              $ifd[0],
+              PelTag::getName($ifd[1], $tag),
+            ];
+          }
+        }
+        $this->setCache($cache_id, $this->supportedKeysMap);
+      }
+    }
+    return $this->supportedKeysMap;
+  }
+
+  /**
+   * Returns the IFD/TAG integers for a TAG literal.
+   *
+   * @param string $value
+   *   A TAG literal.
+   *
+   * @return array
+   *   A simple array of with IFD and TAG, expressed as integers.
+   *
+   * @throws \Drupal\file_mdm\FileMetadataException
+   *   When the IFD/TAG combination could not be found.
+   */
+  protected function stringToTag($value) {
+    $v = strtolower($value);
+    $tag = isset($this->getStringToTagMap()[$v]) ? $this->getStringToTagMap()[$v] : NULL;
+    if ($tag) {
+      return $tag;
+    }
+    throw new FileMetadataException("No EXIF TAG found for key '{$value}'", "EXIF");
+  }
+
+  /**
+   * Returns the map of TAG strings to IFD/TAG integers.
+   *
+   * Builds and caches the list as needed.
+   *
+   * @return array
+   *   An associative array where keys are TAG literals, and values a simple
+   *   array of IFD/TAG integer identifiers.
+   */
+  protected function getStringToTagMap() {
+    if (!$this->stringToTagMap) {
+      $cache_id = 'stringToTag';
+      if ($cache = $this->getCache($cache_id)) {
+        $this->stringToTagMap = $cache->data;
+      }
+      else {
+        foreach ($this->getSupportedIfdsMap() as $ifd) {
+          $ifd_obj = new PelIfd($ifd[1]);
+          $valid_tags = $ifd_obj->getValidTags();
+          foreach ($valid_tags as $tag) {
+            $tag_name = strtolower(PelTag::getName($ifd[1], $tag));
+            if (!isset($this->stringToTagMap[$tag_name])) {
+              $this->stringToTagMap[$tag_name] = [$ifd[1], $tag];
+            }
+          }
+        }
+        $this->setCache($cache_id, $this->stringToTagMap);
+      }
+    }
+    return $this->stringToTagMap;
+  }
+
+  /**
+   * Returns the IFD integer for an IFD literal.
+   *
+   * @param string $value
+   *   An IFD literal.
+   *
+   * @return int
+   *   The IFD identifier.
+   *
+   * @throws \Drupal\file_mdm\FileMetadataException
+   *   When the IFD could not be found.
+   */
+  protected function stringToIfd($value) {
+    $v = strtolower($value);
+    if (isset($this->getStringToIfdMap()[$v])) {
+      return $this->getStringToIfdMap()[$v];
+    }
+    throw new FileMetadataException("Invalid EXIF IFD '{$value}' specified", "EXIF");
+  }
+
+  /**
+   * Returns the map of IFD strings to IFD integers.
+   *
+   * Builds and caches the list as needed.
+   *
+   * @return array
+   *   An associative array where keys are IFD literals, and values the IFD
+   *   integer identifiers.
+   */
+  protected function getStringToIfdMap() {
+    if (!$this->stringToIfdMap) {
+      $cache_id = 'stringToIfd';
+      if ($cache = $this->getCache($cache_id)) {
+        $this->stringToIfdMap = $cache->data;
+      }
+      else {
+        $config_map = $this->configFactory->get('file_mdm_exif.file_metadata_plugin.exif')->get('ifd_map');
+        $this->stringToIfdMap = [];
+        foreach ($config_map as $value) {
+          foreach ($value['aliases'] as $alias) {
+            $k = strtolower($alias);
+            $this->stringToIfdMap[$k] = $value['type'];
+          }
+        }
+        $this->setCache($cache_id, $this->stringToIfdMap);
+      }
+    }
+    return $this->stringToIfdMap;
+  }
+
+  /**
+   * Gets a cache entry.
+   *
+   * @param string $id
+   *   The cache id to get.
+   *
+   * @return object|null
+   *   The cache item or NULL on failure.
+   */
+  protected function getCache($id) {
+    if ($cache = $this->cache->get("map:exif:{$id}")) {
+      return $cache;
+    }
+    else {
+      return NULL;
+    }
+  }
+
+  /**
+   * Sets a cache entry.
+   *
+   * @param string $id
+   *   The cache id to set.
+   * @param mixed $value
+   *   The value to cache.
+   *
+   * @return $this
+   */
+  protected function setCache($id, $value) {
+    $config = $this->configFactory->get('file_mdm_exif.file_metadata_plugin.exif');
+    $this->cache->set("map:exif:{$id}", $value, Cache::PERMANENT, $config->getCacheTags());
+    return $this;
+  }
+
+}