You are here

abstract class FileMetadataPluginBase in File metadata manager 8

Same name and namespace in other branches
  1. 8.2 src/Plugin/FileMetadata/FileMetadataPluginBase.php \Drupal\file_mdm\Plugin\FileMetadata\FileMetadataPluginBase

Abstract implementation of a base File Metadata plugin.

Hierarchy

Expanded class hierarchy of FileMetadataPluginBase

2 files declare their use of FileMetadataPluginBase
Exif.php in file_mdm_exif/src/Plugin/FileMetadata/Exif.php
Font.php in file_mdm_font/src/Plugin/FileMetadata/Font.php

File

src/Plugin/FileMetadata/FileMetadataPluginBase.php, line 18

Namespace

Drupal\file_mdm\Plugin\FileMetadata
View source
abstract class FileMetadataPluginBase extends PluginBase implements FileMetadataPluginInterface {

  /**
   * The cache service.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The URI of the file.
   *
   * @var string
   */
  protected $uri;

  /**
   * The local filesystem path to the file.
   *
   * This is used to allow accessing local copies of files stored remotely, to
   * minimise remote calls and allow functions that cannot access remote stream
   * wrappers to operate locally.
   *
   * @var string
   */
  protected $localTempPath;

  /**
   * The hash used to reference the URI.
   *
   * @var string
   */
  protected $hash;

  /**
   * The metadata of the file.
   *
   * @var mixed
   */
  protected $metadata = NULL;

  /**
   * The metadata loading status.
   *
   * @var int
   */
  protected $isMetadataLoaded = FileMetadataInterface::NOT_LOADED;

  /**
   * Track if metadata has been changed from version on file.
   *
   * @var bool
   */
  protected $hasMetadataChangedFromFileVersion = FALSE;

  /**
   * Track if file metadata on cache needs update.
   *
   * @var bool
   */
  protected $hasMetadataChangedFromCacheVersion = FALSE;

  /**
   * Constructs a FileMetadataPluginBase plugin.
   *
   * @param array $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
   *   The plugin implementation definition.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_service
   *   The cache service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   */
  public function __construct(array $configuration, $plugin_id, array $plugin_definition, CacheBackendInterface $cache_service, ConfigFactoryInterface $config_factory) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->cache = $cache_service;
    $this->configFactory = $config_factory;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container
      ->get('cache.file_mdm'), $container
      ->get('config.factory'));
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultConfiguration() {
    return [
      'cache' => [
        'override' => FALSE,
        'settings' => [
          'enabled' => TRUE,
          'expiration' => 172800,
          'disallowed_paths' => [],
        ],
      ],
    ];
  }

  /**
   * Gets the configuration object for this plugin.
   *
   * @param bool $editable
   *   If TRUE returns the editable configuration object.
   *
   * @return \Drupal\Core\Config\ImmutableConfig|\Drupal\Core\Config\Config
   *   The ImmutableConfig of the Config object for this plugin.
   */
  protected function getConfigObject($editable = FALSE) {
    $plugin_definition = $this
      ->getPluginDefinition();
    $config_name = $plugin_definition['provider'] . '.file_metadata_plugin.' . $plugin_definition['id'];
    return $editable ? $this->configFactory
      ->getEditable($config_name) : $this->configFactory
      ->get($config_name);
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form['override'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Override main caching settings'),
      '#default_value' => $this->configuration['cache']['override'],
    ];
    $form['cache_details'] = [
      '#type' => 'details',
      '#open' => TRUE,
      '#collapsible' => FALSE,
      '#title' => $this
        ->t('Metadata caching'),
      '#tree' => TRUE,
      '#states' => [
        'visible' => [
          ':input[name="' . $this
            ->getPluginId() . '[override]"]' => [
            'checked' => TRUE,
          ],
        ],
      ],
    ];
    $form['cache_details']['settings'] = [
      '#type' => 'file_mdm_caching',
      '#default_value' => $this->configuration['cache']['settings'],
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {

    // @codingStandardsIgnoreStart
    $this->configuration['cache']['override'] = (bool) $form_state
      ->getValue([
      $this
        ->getPluginId(),
      'override',
    ]);
    $this->configuration['cache']['settings'] = $form_state
      ->getValue([
      $this
        ->getPluginId(),
      'cache_details',
      'settings',
    ]);

    // @codingStandardsIgnoreEnd
    $config = $this
      ->getConfigObject(TRUE);
    $config
      ->set('configuration', $this->configuration);
    if ($config
      ->getOriginal('configuration') != $config
      ->get('configuration')) {
      $config
        ->save();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function setUri($uri) {
    if (!$uri) {
      throw new FileMetadataException('Missing $uri argument', $this
        ->getPluginId(), __FUNCTION__);
    }
    $this->uri = $uri;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getUri() {
    return $this->uri;
  }

  /**
   * {@inheritdoc}
   */
  public function setLocalTempPath($temp_path) {
    $this->localTempPath = $temp_path;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getLocalTempPath() {
    return $this->localTempPath;
  }

  /**
   * {@inheritdoc}
   */
  public function setHash($hash) {
    if (!$hash) {
      throw new FileMetadataException('Missing $hash argument', $this
        ->getPluginId(), __FUNCTION__);
    }
    $this->hash = $hash;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function isMetadataLoaded() {
    return $this->isMetadataLoaded;
  }

  /**
   * {@inheritdoc}
   */
  public function loadMetadata($metadata) {
    $this->metadata = $metadata;
    $this->hasMetadataChangedFromFileVersion = TRUE;
    $this->hasMetadataChangedFromCacheVersion = TRUE;
    $this
      ->deleteCachedMetadata();
    if ($this->metadata === NULL) {
      $this->isMetadataLoaded = FileMetadataInterface::NOT_LOADED;
    }
    else {
      $this->isMetadataLoaded = FileMetadataInterface::LOADED_BY_CODE;
      $this
        ->saveMetadataToCache();
    }
    return (bool) $this->metadata;
  }

  /**
   * {@inheritdoc}
   */
  public function loadMetadataFromFile() {
    if (!file_exists($this
      ->getLocalTempPath())) {

      // File does not exists.
      throw new FileMetadataException("File at '{$this->getLocalTempPath()}' does not exist", $this
        ->getPluginId(), __FUNCTION__);
    }
    $this->hasMetadataChangedFromFileVersion = FALSE;
    if (($this->metadata = $this
      ->doGetMetadataFromFile()) === NULL) {
      $this->isMetadataLoaded = FileMetadataInterface::NOT_LOADED;
      $this
        ->deleteCachedMetadata();
    }
    else {
      $this->isMetadataLoaded = FileMetadataInterface::LOADED_FROM_FILE;
      $this
        ->saveMetadataToCache();
    }
    return (bool) $this->metadata;
  }

  /**
   * Gets file metadata from the file at URI/local path.
   *
   * @return mixed
   *   The metadata retrieved from the file.
   *
   * @throws \Drupal\file_mdm\FileMetadataException
   *   In case there were significant errors reading from file.
   */
  protected abstract function doGetMetadataFromFile();

  /**
   * {@inheritdoc}
   */
  public function loadMetadataFromCache() {
    $plugin_id = $this
      ->getPluginId();
    $this->hasMetadataChangedFromFileVersion = FALSE;
    $this->hasMetadataChangedFromCacheVersion = FALSE;
    if ($this
      ->isUriFileMetadataCacheable() !== FALSE && ($cache = $this->cache
      ->get("hash:{$plugin_id}:{$this->hash}"))) {
      $this->metadata = $cache->data;
      $this->isMetadataLoaded = FileMetadataInterface::LOADED_FROM_CACHE;
    }
    else {
      $this->metadata = NULL;
      $this->isMetadataLoaded = FileMetadataInterface::NOT_LOADED;
    }
    return (bool) $this->metadata;
  }

  /**
   * Checks if file metadata should be cached.
   *
   * @return array|bool
   *   The caching settings array retrieved from configuration if file metadata
   *   is cacheable, FALSE otherwise.
   */
  protected function isUriFileMetadataCacheable() {

    // Check plugin settings first, if they override general settings.
    if ($this->configuration['cache']['override']) {
      $settings = $this->configuration['cache']['settings'];
      if (!$settings['enabled']) {
        return FALSE;
      }
    }

    // Use general settings if they are not overridden by plugin.
    if (!isset($settings)) {
      $settings = $this->configFactory
        ->get('file_mdm.settings')
        ->get('metadata_cache');
      if (!$settings['enabled']) {
        return FALSE;
      }
    }

    // URIs without valid scheme, and temporary:// URIs are not cached.
    if (!file_valid_uri($this
      ->getUri()) || file_uri_scheme($this
      ->getUri()) === 'temporary') {
      return FALSE;
    }

    // URIs falling into disallowed paths are not cached.
    foreach ($settings['disallowed_paths'] as $pattern) {
      $p = "#^" . strtr(preg_quote($pattern, '#'), [
        '\\*' => '.*',
        '\\?' => '.',
      ]) . "\$#i";
      if (preg_match($p, $this
        ->getUri())) {
        return FALSE;
      }
    }
    return $settings;
  }

  /**
   * {@inheritdoc}
   */
  public function getMetadata($key = NULL) {
    if (!$this
      ->getUri()) {
      throw new FileMetadataException("No URI specified", $this
        ->getPluginId(), __FUNCTION__);
    }
    if (!$this->hash) {
      throw new FileMetadataException("No hash specified", $this
        ->getPluginId(), __FUNCTION__);
    }
    if ($this->metadata === NULL) {

      // Metadata has not been loaded yet. Try loading it from cache first.
      $this
        ->loadMetadataFromCache();
    }
    if ($this->metadata === NULL && $this->isMetadataLoaded !== FileMetadataInterface::LOADED_FROM_FILE) {

      // Metadata has not been loaded yet. Try loading it from file if URI is
      // defined and a read attempt was not made yet.
      $this
        ->loadMetadataFromFile();
    }
    return $this
      ->doGetMetadata($key);
  }

  /**
   * Gets a metadata element.
   *
   * @param mixed|null $key
   *   A key to determine the metadata element to be returned. If NULL, the
   *   entire metadata will be returned.
   *
   * @return mixed|null
   *   The value of the element specified by $key. If $key is NULL, the entire
   *   metadata. If no metadata is available, return NULL.
   */
  protected abstract function doGetMetadata($key = NULL);

  /**
   * {@inheritdoc}
   */
  public function setMetadata($key, $value) {
    if ($key === NULL) {
      throw new FileMetadataException("No metadata key specified for file at '{$this->getUri()}'", $this
        ->getPluginId(), __FUNCTION__);
    }
    if (!$this->metadata && !$this
      ->getMetadata()) {
      throw new FileMetadataException("No metadata loaded for file at '{$this->getUri()}'", $this
        ->getPluginId(), __FUNCTION__);
    }
    if ($this
      ->doSetMetadata($key, $value)) {
      $this->hasMetadataChangedFromFileVersion = TRUE;
      if ($this->isMetadataLoaded === FileMetadataInterface::LOADED_FROM_CACHE) {
        $this->hasMetadataChangedFromCacheVersion = TRUE;
      }
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Sets a metadata element.
   *
   * @param mixed $key
   *   A key to determine the metadata element to be changed.
   * @param mixed $value
   *   The value to change the metadata element to.
   *
   * @return bool
   *   TRUE if metadata was changed successfully, FALSE otherwise.
   */
  protected abstract function doSetMetadata($key, $value);

  /**
   * {@inheritdoc}
   */
  public function removeMetadata($key) {
    if ($key === NULL) {
      throw new FileMetadataException("No metadata key specified for file at '{$this->getUri()}'", $this
        ->getPluginId(), __FUNCTION__);
    }
    if (!$this->metadata && !$this
      ->getMetadata()) {
      throw new FileMetadataException("No metadata loaded for file at '{$this->getUri()}'", $this
        ->getPluginId(), __FUNCTION__);
    }
    if ($this
      ->doRemoveMetadata($key)) {
      $this->hasMetadataChangedFromFileVersion = TRUE;
      if ($this->isMetadataLoaded === FileMetadataInterface::LOADED_FROM_CACHE) {
        $this->hasMetadataChangedFromCacheVersion = TRUE;
      }
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Removes a metadata element.
   *
   * @param mixed $key
   *   A key to determine the metadata element to be removed.
   *
   * @return bool
   *   TRUE if metadata was removed successfully, FALSE otherwise.
   */
  protected abstract function doRemoveMetadata($key);

  /**
   * {@inheritdoc}
   */
  public function isSaveToFileSupported() {
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function saveMetadataToFile() {
    if (!$this
      ->isSaveToFileSupported()) {
      throw new FileMetadataException('Write metadata to file is not supported', $this
        ->getPluginId(), __FUNCTION__);
    }
    if ($this->metadata === NULL) {
      return FALSE;
    }
    if ($this->hasMetadataChangedFromFileVersion) {

      // Clears cache so that next time metadata will be fetched from file.
      $this
        ->deleteCachedMetadata();
      return $this
        ->doSaveMetadataToFile();
    }
    return FALSE;
  }

  /**
   * Saves metadata to file at URI.
   *
   * @return bool
   *   TRUE if metadata was saved successfully, FALSE otherwise.
   */
  protected function doSaveMetadataToFile() {
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function saveMetadataToCache(array $tags = []) {
    if ($this->metadata === NULL) {
      return FALSE;
    }
    if (($cache_settings = $this
      ->isUriFileMetadataCacheable()) === FALSE) {
      return FALSE;
    }
    if ($this->isMetadataLoaded !== FileMetadataInterface::LOADED_FROM_CACHE || $this->isMetadataLoaded === FileMetadataInterface::LOADED_FROM_CACHE && $this->hasMetadataChangedFromCacheVersion) {
      $tags = Cache::mergeTags($tags, $this
        ->getConfigObject()
        ->getCacheTags());
      $tags = Cache::mergeTags($tags, $this->configFactory
        ->get('file_mdm.settings')
        ->getCacheTags());
      $expire = $cache_settings['expiration'] === -1 ? Cache::PERMANENT : time() + $cache_settings['expiration'];
      $this->cache
        ->set("hash:{$this->getPluginId()}:{$this->hash}", $this
        ->getMetadataToCache(), $expire, $tags);
      $this->hasMetadataChangedFromCacheVersion = FALSE;
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Gets metadata to save to cache.
   *
   * @return mixed
   *   The metadata to be cached.
   */
  protected function getMetadataToCache() {
    return $this->metadata;
  }

  /**
   * {@inheritdoc}
   */
  public function deleteCachedMetadata() {
    if ($this
      ->isUriFileMetadataCacheable() === FALSE) {
      return FALSE;
    }
    $plugin_id = $this
      ->getPluginId();
    $this->cache
      ->delete("hash:{$plugin_id}:{$this->hash}");
    $this->hasMetadataChangedFromCacheVersion = FALSE;
    return TRUE;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FileMetadataPluginBase::$cache protected property The cache service.
FileMetadataPluginBase::$configFactory protected property The config factory.
FileMetadataPluginBase::$hash protected property The hash used to reference the URI.
FileMetadataPluginBase::$hasMetadataChangedFromCacheVersion protected property Track if file metadata on cache needs update.
FileMetadataPluginBase::$hasMetadataChangedFromFileVersion protected property Track if metadata has been changed from version on file.
FileMetadataPluginBase::$isMetadataLoaded protected property The metadata loading status.
FileMetadataPluginBase::$localTempPath protected property The local filesystem path to the file.
FileMetadataPluginBase::$metadata protected property The metadata of the file.
FileMetadataPluginBase::$uri protected property The URI of the file.
FileMetadataPluginBase::buildConfigurationForm public function Form constructor. Overrides PluginFormInterface::buildConfigurationForm
FileMetadataPluginBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 1
FileMetadataPluginBase::defaultConfiguration public static function Gets default configuration for this plugin. Overrides FileMetadataPluginInterface::defaultConfiguration
FileMetadataPluginBase::deleteCachedMetadata public function Removes cached metadata for file at URI. Overrides FileMetadataPluginInterface::deleteCachedMetadata
FileMetadataPluginBase::doGetMetadata abstract protected function Gets a metadata element. 3
FileMetadataPluginBase::doGetMetadataFromFile abstract protected function Gets file metadata from the file at URI/local path. 3
FileMetadataPluginBase::doRemoveMetadata abstract protected function Removes a metadata element. 3
FileMetadataPluginBase::doSaveMetadataToFile protected function Saves metadata to file at URI. 1
FileMetadataPluginBase::doSetMetadata abstract protected function Sets a metadata element. 3
FileMetadataPluginBase::getConfigObject protected function Gets the configuration object for this plugin.
FileMetadataPluginBase::getLocalTempPath public function Gets the local filesystem path to the file. Overrides FileMetadataPluginInterface::getLocalTempPath
FileMetadataPluginBase::getMetadata public function Gets a metadata element. Overrides FileMetadataPluginInterface::getMetadata
FileMetadataPluginBase::getMetadataToCache protected function Gets metadata to save to cache.
FileMetadataPluginBase::getUri public function Gets the URI of the file. Overrides FileMetadataPluginInterface::getUri
FileMetadataPluginBase::isMetadataLoaded public function Checks if file metadata has been already loaded. Overrides FileMetadataPluginInterface::isMetadataLoaded
FileMetadataPluginBase::isSaveToFileSupported public function Determines if plugin is capable of writing metadata to files. Overrides FileMetadataPluginInterface::isSaveToFileSupported 1
FileMetadataPluginBase::isUriFileMetadataCacheable protected function Checks if file metadata should be cached.
FileMetadataPluginBase::loadMetadata public function Loads file metadata from an in-memory object/array. Overrides FileMetadataPluginInterface::loadMetadata
FileMetadataPluginBase::loadMetadataFromCache public function Loads file metadata from a cache entry. Overrides FileMetadataPluginInterface::loadMetadataFromCache
FileMetadataPluginBase::loadMetadataFromFile public function Loads file metadata from the file at URI/local path. Overrides FileMetadataPluginInterface::loadMetadataFromFile
FileMetadataPluginBase::removeMetadata public function Removes a metadata element. Overrides FileMetadataPluginInterface::removeMetadata
FileMetadataPluginBase::saveMetadataToCache public function Caches metadata for file at URI. Overrides FileMetadataPluginInterface::saveMetadataToCache
FileMetadataPluginBase::saveMetadataToFile public function Saves metadata to file at URI. Overrides FileMetadataPluginInterface::saveMetadataToFile
FileMetadataPluginBase::setHash public function Sets the hash used to reference the URI by the metadata manager. Overrides FileMetadataPluginInterface::setHash
FileMetadataPluginBase::setLocalTempPath public function Sets the local filesystem path to the file. Overrides FileMetadataPluginInterface::setLocalTempPath
FileMetadataPluginBase::setMetadata public function Sets a metadata element. Overrides FileMetadataPluginInterface::setMetadata
FileMetadataPluginBase::setUri public function Sets the URI of the file. Overrides FileMetadataPluginInterface::setUri
FileMetadataPluginBase::submitConfigurationForm public function Form submission handler. Overrides PluginFormInterface::submitConfigurationForm
FileMetadataPluginBase::validateConfigurationForm public function Form validation handler. Overrides PluginFormInterface::validateConfigurationForm
FileMetadataPluginBase::__construct public function Constructs a FileMetadataPluginBase plugin. Overrides PluginBase::__construct 1
FileMetadataPluginInterface::getSupportedKeys public function Returns a list of metadata keys supported by the plugin. 3
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.