migrate_media_handler-8.x-1.0-rc4/src/MediaMaker.php

src/MediaMaker.php
<?php

namespace Drupal\migrate_media_handler;

use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * MediaMaker takes file paths and makes file & media entities if possible.
 *
 * Requires the presence of a text field on all destination media entities
 * named `field_original_ref`. This allows for lookup by file hash to avoid
 * duplication. This field can be deleted after migration is complete.
 */
class MediaMaker implements ContainerInjectionInterface {

  /**
   * Entity Type Manager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManager
   */
  protected $entityTypeManager;

  /**
   * ConfigFactory service.
   *
   * @var \Drupal\Core\Config\ConfigFactory
   */
  protected $configFactory;

  /**
   * Config variable.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $config;

  /**
   * {@inheritdoc}
   */
  public function __construct(EntityTypeManager $entity_manager, ConfigFactory $config_factory) {
    $this->entityTypeManager = $entity_manager;
    $this->configFactory = $config_factory;

    // Pull media setting from config. Can be overridden if necessary.
    $this->config = $this->configFactory->get('migrate_media_handler.settings');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('config.factory')
    );
  }

  /**
   * Find hash of file contents.
   *
   * @param string $filepath
   *   Filepath of file to hash.
   *
   * @return bool|string
   *   Return hashed file contents or FALSE.
   */
  public function getFileHash(string $filepath) {
    $path_info = parse_url($filepath);
    // Function sha1_file works for local and http/s filepaths.
    $hash = sha1_file($filepath);
    // Hash da39a... is the hash of an empty string.
    if ($hash == 'da39a3ee5e6b4b0d3255bfef95601890afd80709') {
      // Possible @TODO here for AWS S3 buckets, as sha1_file doesn't work.
      return FALSE;
    }
    return $hash;
  }

  /**
   * Find existing media by file hash.
   *
   * @param string $hash
   *   File hash to lookup in field_original_ref.
   *
   * @return bool|\Drupal\media\Entity\Media
   *   Return media entity or FALSE
   */
  public function findExistingMediaByHash(string $hash) {
    $media = FALSE;
    // Lookup the media entity by hash of file data in field_original_ref.
    $query = $this->entityTypeManager->getStorage('media')->getQuery()
      ->condition('status', 1)
      ->accessCheck(FALSE)
      ->condition('field_original_ref', $hash, '=');
    $mids = $query->execute();
    // If found, `mid` is the reference for the content.
    if (!empty($mids)) {
      $mid = array_pop($mids);
      // This check is to make sure that the media /actually/ exists.
      $media = $this->entityTypeManager->getStorage('media')->load($mid);
    }
    return $media;
  }

  /**
   * Find existing media by file path, using the hash.
   *
   * @param string $path
   *   Path from which to generate hash for comparison.
   *
   * @return bool|\Drupal\media\Entity\Media
   *   Return media entity or FALSE
   */
  public function findExistingMediaByPath(string $path) {
    // Hash file, then find by stored hash.
    $hash = $this->getFileHash($path);
    return $this->findExistingMediaByHash($hash);
  }

  /**
   * Make a file entity out of a file path. Move file to current file directory.
   *
   * @param string $path
   *   File path of existing legacy file.
   *
   * @return bool|\Drupal\file\Entity\File
   *   File entity or FALSE
   */
  public function makeFileEntity(string $path) {
    $clean_path = strtok($path, '?');
    $destination = str_ireplace($this->config->get('file_source'), $this->config->get('file_dest'), $clean_path);
    $filename = pathinfo($clean_path, PATHINFO_BASENAME);

    if (file_exists($path)) {
      // Create file entity.
      $file = $this->entityTypeManager->getStorage('file')->create();
      $file->setFileUri($destination);
      $file->setFilename($filename);
      $file->setMimeType(mime_content_type($path));
      $file->setSize(filesize($path));
      $file->setOwnerId($this->config->get('file_owner'));
      $file->setPermanent();
      $file->save();

      // Copy file to permanent destination.
      $dir = dirname($destination);
      if (!file_exists($dir)) {
        mkdir($dir, 0770, TRUE);
      }
      file_put_contents($destination, file_get_contents($path));
      $file->save();
      return $file;
    }
    return FALSE;
  }

  /**
   * Make an image media entity out of a file. Add alt, title if avail.
   *
   * @param int $file_id
   *   ID of existing file entity.
   * @param Drupal\migrate\Row $row
   *   Migration row, used for getting data.
   * @param array $configuration
   *   Config of process plugin.
   *
   * @return bool|\Drupal\media\Entity\Media
   *   Return media entity or FALSE
   */
  public function makeImageEntity(int $file_id, Row $row, array $configuration) {
    $media = FALSE;
    // Load file entity.
    $file = $this->entityTypeManager->getStorage('file')->load($file_id);
    // If that's successful, carry on.
    if ($file) {
      // Hash file for overlap lookup.
      $hash = $this->getFileHash($file->getFileUri());

      // Lookup media entity by file hash.
      $media = $this->findExistingMediaByHash($hash);

      // If it wasn't found, make it!
      if (!$media) {
        if (isset($configuration['source_field'])) {
          $field_source = $row->getSourceProperty($configuration['source_field']);
          $alt = $field_source[0]['alt'] ?? "";
          $title = $field_source[0]['title'] ?? "";
        } else {
          $alt = $title = $file->getFilename();
        }

        // Create media entity with saved file.
        $bundle = $configuration['target_bundle'] ?? 'image';
        $langcode = $row->getSourceProperty('language');

        // Please note accessibility concerns around empty alt & title.
        $media = $this->entityTypeManager->getStorage('media')->create([
          'bundle' => $bundle,
          'field_original_ref' => $hash,
          $this->config->get('image_field_name') => [
            'target_id' => $file_id,
            'alt' => $alt,
            'title' => $title,
          ],
          'langcode' => $langcode ?? 'und',
        ]);
        $owner = $file->getOwnerId();
        $filename = $file->getFilename();
        $media->setOwnerId($owner);
        $media->setName($filename);
        $media->save();
      }
    }
    return $media;
  }

  /**
   * Make a document media entity out of a file.
   *
   * @param string $file_id
   *   ID of existing file entity.
   * @param Drupal\migrate\Row $row
   *   Migration row, used for getting data.
   * @param array $configuration
   *   Config of process plugin.
   *
   * @return bool|\Drupal\media\Entity\Media
   *   Return media entity or FALSE
   */
  public function makeDocumentEntity(int $file_id, Row $row, array $configuration) {
    $media = FALSE;
    // Load file entity.
    $file = $this->entityTypeManager->getStorage('file')->load($file_id);
    // If that's successful, carry on.
    if ($file) {
      $hash = $this->getFileHash($file->getFileUri());
      // Lookup media entity by file hash.
      $media = $this->findExistingMediaByHash($hash);

      // If it wasn't found, make it!
      if (!$media) {
        $display = $description = '';
        if (isset($configuration['source_field'])) {
          $field_source = $row->getSourceProperty($configuration['source_field']);
          $display = $field_source[0]['display'] ?? "";
          $description = $field_source[0]['description'] ?? "";
        }

        // Create media entity with saved file.
        $bundle = $configuration['target_bundle'] ?? 'document';
        $langcode = $row->getSourceProperty('language');

        $media = $this->entityTypeManager->getStorage('media')->create([
          'bundle' => $bundle,
          'field_original_ref' => $hash,
          $this->config->get('document_field_name') => [
            'target_id' => $file_id,
            'display' => $display,
            'description' => $description,
          ],
          'langcode' => $langcode ?? 'und',
        ]);
        // Get additional media properties.
        $owner = $file->getOwnerId();
        $filename = $file->getFilename();
        // Set additional media properties.
        $media->setOwnerId($owner);
        $media->setName($filename);

        $media->save();

      }
    }
    return $media;
  }

  /**
   * Make a video media entity out of a url.
   *
   * @param array $field_data
   *   Array of data from the D7 video embed field.
   * @param Drupal\migrate\Row $row
   *   Migration row, used for getting data.
   * @param array $configuration
   *   Config of process plugin.
   *
   * @return bool|\Drupal\media\Entity\Media
   *   Return media entity or FALSE
   */
  public function makeVideoLinkEntity(array $field_data, Row $row, $configuration = []) {
    $media = FALSE;
    if (!empty($field_data['video_url'])) {
      $hash = $this->getFileHash($field_data['video_url']);
      // Lookup media entity by hash.
      $media = $this->findExistingMediaByHash($hash);
      // If it wasn't found, make it!
      if (!$media) {
        $title = $row->getSourceProperty('title');
        $langcode = $row->getSourceProperty('language');
        // Create media entity with url.
        $bundle = $configuration['target_bundle'] ?? 'remote_video';
        $media = $this->entityTypeManager->getStorage('media')->create([
          'name' => $title,
          'bundle' => $bundle,
          'field_original_ref' => $hash,
          $this->config->get('video_field_name') => $field_data['video_url'],
          'langcode' => $langcode ?? 'und',
        ]);

        $media->save();

      }
    }
    return $media;
  }

  /**
   * Make an audio media entity out of a file.
   *
   * @param string $file_id
   *   ID of existing file entity.
   * @param Drupal\migrate\Row $row
   *   Migration row, used for getting data.
   * @param array $configuration
   *   Config of process plugin.
   *
   * @return bool|\Drupal\media\Entity\Media
   *   Return media entity or FALSE
   */
  public function makeAudioEntity(int $file_id, Row $row, array $configuration) {
    $media = FALSE;
    // Load file entity.
    $file = $this->entityTypeManager->getStorage('file')->load($file_id);
    // If that's successful, carry on.
    if ($file) {
      // Lookup media entity by file hash.
      $hash = $this->getFileHash($file->getFileUri());
      $media = $this->findExistingMediaByHash($hash);

      // If it wasn't found, make it!
      if (!$media) {
        $display = $description = '';
        if (isset($configuration['source_field'])) {
          $field_source = $row->getSourceProperty($configuration['source_field']);
          $display = $field_source[0]['display'] ?? "";
          $description = $field_source[0]['description'] ?? "";
        }
        // Create media entity with saved file.
        $bundle = $configuration['target_bundle'] ?? 'audio';
        $langcode = $row->getSourceProperty('language');

        // Create media entity with saved file.
        $media = $this->entityTypeManager->getStorage('media')->create([
          'bundle' => $bundle,
          'field_original_ref' => $hash,
          $this->config->get('audio_field_name') => [
            'target_id' => $file_id,
            'display' => $display,
            'description' => $description,
          ],
          'langcode' => $langcode ?? 'und',
        ]);
        // Get additional media properties.
        $owner = $file->getOwnerId();
        $filename = $file->getFilename();
        // Set additional media properties.
        $media->setOwnerId($owner);
        $media->setName($filename);

        $media->save();

      }
    }
    return $media;
  }

  /**
   * Utility function to get source file repository filepath.
   *
   * @param string $path
   *   Path from which to generate hash for comparison.
   * @param bool $find_in_store
   *   Replace "public://" with file_source variable.
   *
   * @return string
   *   Modified file path.
   */
  public function getSourceFilePath($path = '', $find_in_store = FALSE) {
    $file_path = strtok($path, '?');
    // If link is full-path (contains http:// or https://).
    if (preg_match('/https?:\/\//', $path) !== 0) {
      // If link is full-path to *this* site.
      if (preg_match($this->config->get('site_uri'), $path) !== 0) {
        // Swap out full path for public://, and remove sites/default/files.
        $file_path = preg_replace($this->config->get('site_uri'), $this->config->get('file_source'), $path);
        $file_path = str_ireplace("/sites/default/files", "", $file_path);
      }
    }
    // If file path is in the VFSStream protocol, skip.
    elseif (preg_match('/vfs:\/\//', $path) !== 0) {
      // Do nothing - this is an internal file path that works out of the box.
    }
    // If this is a relative filepath, swap out sites/default/files.
    else {
      $file_path = str_ireplace("/sites/default/files", $this->config->get('file_source'), $file_path);
    }
    return $file_path;
  }

  /**
   * Record a file hash for later usage.
   *
   * @param int $file_id
   *   ID of existing file entity.
   * @param Drupal\migrate\Row $row
   *   Migration row, used for getting data.
   * @param array $configuration
   *   Config of process plugin.
   *
   * @return string
   *   Return hashed file path.
   */
  public function recordMediaRef(int $file_id, Row $row, array $configuration) {
    $hash = FALSE;
    // Load file entity.
    $file = $this->entityTypeManager->getStorage('file')->load($file_id);
    // If that's successful, carry on.
    if ($file) {
      // Hash file for overlap lookup.
      $hash = $this->getFileHash($file->getFileUri());
    }
    return $hash;
  }

}

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

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