toolshed-8.x-1.x-dev/modules/toolshed_media/src/Utility/FileHelper.php

modules/toolshed_media/src/Utility/FileHelper.php
<?php

namespace Drupal\toolshed_media\Utility;

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\file\Entity\File;
use Drupal\media\MediaInterface;
use Psr\Log\LoggerInterface;

/**
 * Helper class for getting the URI or info of file from media or file entities.
 */
class FileHelper {

  const DEFAULT_VIEW_MODE = EntityDisplayRepositoryInterface::DEFAULT_DISPLAY_MODE;

  /**
   * Get the toolshed logger.
   *
   * @return \Psr\Log\LoggerInterface
   *   Logger for toolshed logging messages.
   */
  protected static function getLogger(): LoggerInterface {
    return \Drupal::logger('toolshed');
  }

  /**
   * Get the file URL generator service.
   *
   * @return \Drupal\Core\File\FileUrlGeneratorInterface
   *   The file URL generator.
   */
  protected static function getFileUrlGenerator(): FileUrlGeneratorInterface {
    return \Drupal::service('file_url_generator');
  }

  /**
   * Get the entity type manager.
   *
   * @return \Drupal\Core\Entity\EntityTypeManagerInterface
   *   The entity type manager service.
   */
  protected static function getEntityTypeManager(): EntityTypeManagerInterface {
    return \Drupal::entityTypeManager();
  }

  /**
   * Get the field which contains the media file, for a media entity.
   *
   * Every media entity type can utilize a different field for its file, this
   * method helps to determine which field was used.
   *
   * @param \Drupal\media\MediaInterface $media
   *   The media entity being to test for the field information. We don't
   *   use the \Drupal\media_entity\Entity\Media class directly because it
   *   may not exists if the media entity module is not install (allowes it
   *   to be not required).
   *
   * @return string|false
   *   The machine name of the media that contains the media file. Returns
   *   FALSE if the field can't be determined for this media entity type.
   */
  protected static function getMediaField(MediaInterface $media) {
    static $fields;

    $bundle = $media->bundle();
    if (!isset($fields[$bundle])) {
      $mediaConfig = $media->getSource()->getConfiguration();
      $fields[$bundle] = $mediaConfig['source_field'] ?? FALSE;
    }

    return $fields[$bundle];
  }

  /**
   * Create a FileHelper from an entity field.
   *
   * This method will try to capture a file object referenced by an
   * entity field. The method is able to resolve the nested file entity from
   * fields referencing a Media or file entity.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   A fieldable entity containing the file to get the URL for as a field.
   * @param string $field_name
   *   Name of the field to try to extract the File object from.
   * @param string $view_mode
   *   The view mode to use when rendering the entity. This can help determine
   *   if any image styles or other settings that might affect the final URL.
   * @param int $delta
   *   The field delta to extract the file from. Assumes the first field.
   *
   * @return \Drupal\toolshed_media\Utility\FileHelper|null
   *   An instance of the FileHelper or NULL if the file entity could
   *   not be resolved.
   */
  public static function fromEntityField(ContentEntityInterface $entity, $field_name, $view_mode = self::DEFAULT_VIEW_MODE, $delta = 0): ?FileHelper {
    $entityType = $entity->getEntityTypeId();
    $bundle = $entity->bundle();

    // Since this is mostly an internal / developer helper utility, we'll
    // reduce the number of checks and fallback to exception handling to handle
    // the missing field, missing values or wrong entity type referenced issues.
    // It's unlikely wrong fields, or entities are passed, but just in case.
    try {
      /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $field */
      $field = $entity->get($field_name);
      $item = $field->get($delta);

      // No entity? No service, that's just how it is.
      if (!($targetEnt = $item->entity)) {
        return NULL;
      }

      // Load the display configurations and get the field display settings.
      $fieldDisplay = \Drupal::service('entity_display.repository')
        ->getViewDisplay($entityType, $bundle, $view_mode)
        ->getComponent($field_name);

      $displaySettings = $fieldDisplay['settings'] ?? [];

      if ($targetEnt instanceof File) {
        $data = $item->getValue();
        unset($data['target_id']);

        return new static($targetEnt, $displaySettings, $data);
      }
      elseif ($targetEnt->getEntityType()->id() === 'media') {
        /** @var \Drupal\media\MediaInterface $targetEnt */
        $mediaViewMode = $displaySettings['view_mode'] ?? 'default';
        $srcField = static::getMediaField($targetEnt);
        return $srcField ? static::fromEntityField($targetEnt, $srcField, $mediaViewMode) : NULL;
      }
      else {
        throw new \InvalidArgumentException(sprintf(
          'Only file and media entities are supported, %s entity field %s value is of type %s',
          $entityType,
          $field_name,
          $targetEnt->getEntityTypeId()
        ));
      }
    }
    catch (\InvalidArgumentException $e) {
      // Field doesn't exist, or "entity" property doesn't exists all throw
      // InvalidArgumentException. This reduces the number of individual checks
      // and handling of the separate issues.
      static::getLogger()->error('Unable fetch file information for %entity_type %bundle: @message', [
        '%entity_type' => $entityType,
        '%bundle' => $bundle,
        '@message' => $e->getMessage(),
      ]);
    }

    return NULL;
  }

  /**
   * Create a file helper from either a File or Media entity.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   The file or media entity to create a new instance of the FileHelper
   *   from. The instance (if it can be created) will be for the real file.
   * @param string $view_mode
   *   View mode to use when determining the display of the file.
   *
   * @return \Drupal\toolshed_media\Utility\FileHelper|null
   *   An instance of the FileHelper.
   */
  public static function fromEntity(ContentEntityInterface $entity, $view_mode = self::DEFAULT_VIEW_MODE): ?FileHelper {
    if ($entity instanceof File) {
      return new static($entity, []);
    }
    elseif ($entity->getEntityTypeId() === 'media') {
      /** @var \Drupal\media\MediaInterface $entity */
      $srcField = static::getMediaField($entity);
      return empty($srcField) ? NULL : static::fromEntityField($entity, $srcField, $view_mode);
    }

    // Unsupported entity type.
    static::getLogger()->error('Unable fetch file information for %entity_type %bundle.', [
      '%entity_type' => $entity->getEntityTypeId(),
      '%bundle' => $entity->bundle(),
    ]);

    return NULL;
  }

  /**
   * The file to generate the URL for.
   *
   * @var \Drupal\file\Entity\File
   */
  protected $file;

  /**
   * Display settings for the file.
   *
   * This can contain `image_style` or other settings that may control
   * the style of URL that gets generated.
   *
   * @var array
   */
  protected $displaySettings;

  /**
   * Additional data to use with the file entity.
   *
   * @var array
   */
  protected $data;

  /**
   * Create a new instance of the FileHelper with the provided file.
   *
   * @param \Drupal\file\Entity\File $file
   *   File entity to track and create the URL for.
   * @param array $display
   *   Display settings for this file entity. Mostly we will be looking
   *   for an image style or view mode.
   * @param array $data
   *   Additional field data that may have been stored with this file, such
   *   as image files which have the alt and width / height information.
   */
  public function __construct(File $file, array $display = [], array $data = []) {
    $this->file = $file;
    $this->displaySettings = $display;
    $this->data = $data;
  }

  /**
   * Retrieve file specific data.
   *
   * @return array
   *   Array of additional data that was stored with this file. Usually comes
   *   from the field it was extracted from, such as the alt or width / height
   *   information for image files.
   */
  public function getData(): array {
    return $this->data;
  }

  /**
   * Get the file name of the referenced file.
   *
   * @return string
   *   The name of the underlying file.
   */
  public function getFilename(): string {
    return $this->file->getFilename();
  }

  /**
   * Get the URI of the file.
   *
   * @return string
   *   Get the URI to the file.
   */
  public function getUri(): string {
    return $this->file->getFileUri();
  }

  /**
   * Get the file mime for the file.
   *
   * @return string
   *   The file mime for the file, or an empty string if it can't be determined.
   */
  public function getMime(): string {
    return $this->file->filemime->isEmpty() ? '' : $this->file->getMimeType();
  }

  /**
   * Get the size of the file in bytes.
   *
   * @return int
   *   The size of the file in bytes.
   */
  public function getSize(): int {
    return $this->file->getSize();
  }

  /**
   * Build the URL of the file, paying attention to display settings.
   *
   * @param array $settings
   *   Any rendering overrides to provide for rendering this URL.
   *   The most common things to override would be either 'absolute'
   *   for 'image_style'.
   *
   * @return string
   *   The URL of the file, and will include any view or field settings
   *   applied. This is mostly for `image_style` at this point.
   */
  public function buildUrl(array $settings = []): string {
    $settings += $this->displaySettings + ['absolute' => TRUE];

    if (!empty($settings['image_style'])) {
      /** @var \Drupal\image\ImageStyleInterface $imageStyle */
      $imageStyle = static::getEntityTypeManager()
        ->getStorage('image_style')
        ->load($settings['image_style']);

      if ($imageStyle) {
        return $imageStyle->buildUrl($this->getUri());
      }
    }

    // No image style, just return the path directly to the file.
    return $this->buildRawUrl();
  }

  /**
   * Create a URL to the file directly, without applying any display or views.
   *
   * @param bool $absolute
   *   TRUE if the resulting URL should be made absolute.
   *
   * @return string
   *   The URL path to the file set in this URL helper.
   */
  public function buildRawUrl($absolute = TRUE): string {
    $urlGenerator = static::getFileUrlGenerator();

    return $absolute
      ? $urlGenerator->generateAbsoluteString($this->getUri())
      : $urlGenerator->generateString($this->getUri());
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc