epub_reader_framework-2.0.0-alpha2/src/Epub/ReaderEpubZipExtractor.php

src/Epub/ReaderEpubZipExtractor.php
<?php

namespace Drupal\epub_reader_framework\Epub;

use Drupal\Core\Archiver\Zip;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManager;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\epub_reader_framework\EpubReaderFrameworkHelpers;
use Drupal\file\FileInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Serializer\SerializerInterface;

/**
 * Class ReaderEpubZipExtractor.
 */
class ReaderEpubZipExtractor {

  use StringTranslationTrait;

  /**
   * The file system service.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * The extracted files.
   *
   * @var array
   */
  protected $files;

  /**
   * The stream wrapper.
   *
   * @var Drupal\Core\StreamWrapper\StreamWrapperManager
   */
  protected $streamWrapper;

  /**
   * The serializer.
   *
   * @var Symfony\Component\Serializer\SerializerInterface
   */
  protected $serializer;

  /**
   * Constructor.
   *
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file handler.
   * @param \Drupal\Core\StreamWrapper\StreamWrapperManager $stream_wrapper
   *   The stream wrapper.
   * @param \Symfony\Component\Serializer\SerializerInterface $serializer
   *   The serializer.
   */
  public function __construct(
    FileSystemInterface $file_system,
    StreamWrapperManager $stream_wrapper,
    SerializerInterface $serializer
  ) {
    $this->fileSystem = $file_system;
    $this->streamWrapper = $stream_wrapper;
    $this->serializer = $serializer;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('file_system'),
      $container->get('stream_wrapper_manager'),
      $container->get('serializer')
    );
  }

  /**
   * Callback implementation of hook_form_FORM_ID_alter().
   *
   * @param \Drupal\node\NodeInterface $reader_publication
   *   The reader publication node.
   *
   * @throws \Drupal\Core\Archiver\ArchiverException
   */
  public function extractEpubFiles(NodeInterface $reader_publication) {
    if ($reader_publication->hasField('field_reader_file') && $media_file = $reader_publication->field_reader_file->entity) {
      /** @var \Drupal\media\MediaInterface $media_file */
      if ($media_file->hasField('field_media_file') && $file = $media_file->field_media_file->entity) {
        /** @var \Drupal\file\FileInterface $file */
        $real_path = $this->fileSystem->realpath($file->getFileUri());
        $zip = new Zip($real_path);

        // Build the path per publication, per file.
        $to_path_uri = EpubReaderFrameworkHelpers::getEpubExtractedFilesPath($reader_publication, $file);

        // Create the directory if not yet existing.
        $result = $this->fileSystem->prepareDirectory($to_path_uri, FileSystemInterface::CREATE_DIRECTORY);
        if ($result) {

          // Extract the content.
          $zip->extract($to_path_uri);
        }
        else {
          \Drupal::messenger()->addWarning($this->t('Failed to prepare a directory to store EPUB files in.'));
        }
      }
    }
  }

  /**
   * Get extracted files.
   *
   * @param \Drupal\node\NodeInterface $reader_publication
   *   The reader publication node.
   * @param bool|\Drupal\file\FileInterface $file
   *   The epub file or false.
   *
   * @return array|bool
   *   An array of files or false.
   */
  public function getExtractedFiles(
    NodeInterface $reader_publication,
    $file = FALSE
  ) {
    if ($this->files) {
      return $this->files;
    }

    if (!$file) {
      if ($reader_publication->hasField('field_reader_file') && $media_file = $reader_publication->field_reader_file->entity) {
        /** @var \Drupal\media\MediaInterface $media_file */
        if ($media_file->hasField('field_media_file')) {

          /** @var \Drupal\file\FileInterface $file */
          $file = $media_file->field_media_file->entity;
        }
      }
    }

    if ($file instanceof FileInterface) {
      $directory = EpubReaderFrameworkHelpers::getEpubExtractedFilesPath($reader_publication, $file);
      $this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
      $this->files = $this->fileSystem->scanDirectory(
        $directory,
        '/.*\.(png|jpg|jpeg|gif|xhtml|ncx|opf)$/'
      );
      return $this->files;
    }

    \Drupal::messenger()->addWarning($this->t('Failed to get any extracted files from the EPUB.'));
    return FALSE;
  }

  /**
   * Get extracted files by type.
   *
   * @param \Drupal\node\NodeInterface $reader_publication
   *   The publication reader.
   * @param bool|\Drupal\file\FileInterface $file
   *   The epub file or false.
   * @param array $types
   *   An array of extensions.
   *
   * @return array
   *   The files.
   */
  public function getExtractedFilesByTypes(
    NodeInterface $reader_publication,
    $file,
    array $types
  ) {
    $return = [];
    if ($files = $this->getExtractedFiles($reader_publication, $file)) {
      foreach ($files as $key => $file) {
        $filename_parts = explode('.', $file->filename);
        $extension = end($filename_parts);
        if (in_array($extension, $types)) {
          $return[$key] = $file;
        }
      }
    }
    return $return;
  }

  /**
   * Get extracted files by type.
   *
   * @param \Drupal\node\NodeInterface $reader_publication
   *   The publication reader.
   * @param bool|\Drupal\file\FileInterface $file
   *   The epub file or false.
   *
   * @return array
   *   The files.
   */
  public function getSpineContents(
    NodeInterface $reader_publication,
    $file = FALSE
  ) {
    $return = [];
    if ($files = $this->getExtractedFilesByTypes(
      $reader_publication,
      $file,
      ['opf']
    )) {
      $opf = reset($files);
      $data = file_get_contents($opf->uri);

      /** @var \Symfony\Component\Serializer\SerializerInterface $xml_encoder */
      $xml_encoder = $this->serializer;
      $opf_data = $xml_encoder->decode($data, 'xml');
      if ($opf_data && isset($opf_data['spine']['itemref'])) {

        // Find all spine items.
        foreach ($opf_data['spine']['itemref'] as $spine_item) {
          foreach ($opf_data['manifest']['item'] as $manifest_item) {

            // Skip if this is not the matching manifest item.
            if ($manifest_item['@id'] != $spine_item['@idref']) {
              continue;
            }

            // Skip if non-linear content as we cannot use that.
            if (isset($spine_item['@linear']) && $spine_item['@linear'] === 'no') {
              continue;
            }

            // Add spine item details to the return array.
            $file_details = $this->getFileDetailsByFilename(
              $reader_publication,
              $manifest_item['@href']
            );
            $return[] = array_merge(
              $manifest_item,
              $spine_item,
              $file_details
            );
            break;
          }
        }
      }
    }
    if (!$return) {
      \Drupal::messenger()->addWarning($this->t('Failed to determine EPUB spine contents.'));
    }
    return $return;
  }

  /**
   * Get the file details by filename.
   *
   * @param \Drupal\node\NodeInterface $reader_publication
   *   The publication reader.
   * @param string $filename
   *   The filename.
   *
   * @return array
   *   The file details.
   */
  protected function getFileDetailsByFilename(
    NodeInterface $reader_publication,
    $filename
  ) {
    if ($files = $this->getExtractedFiles($reader_publication)) {
      foreach ($files as $file) {
        if ($file->filename == $filename) {
          return (array) $file;
        }
      }
    }
    return [];
  }

}

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

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