crossword-8.x-1.x-dev/modules/crossword_image/src/CrosswordImageService.php

modules/crossword_image/src/CrosswordImageService.php
<?php

namespace Drupal\crossword_image;

use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\File\FileSystemInterface;
use Drupal\crossword\CrosswordDataServiceInterface;
use Drupal\file\FileInterface;
use Drupal\Core\File\FileSystem;
use Drupal\file\FileUsage\DatabaseFileUsageBackend;

/**
 * CrosswordImageService creates images from crossword files.
 *
 * This service takes a Crossword file and uses a specified crossword_image
 * plugin to generate and/or retrieve an image that represents the crossword.
 */
class CrosswordImageService implements CrosswordImageServiceInterface {

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

  /**
   * Crossword image plugin manager.
   *
   * @var \Drupal\crossword_image\CrosswordImageManager
   */
  protected $crosswordImageManager;

  /**
   * File usage.
   *
   * @var \Drupal\file\FileUsage\DatabaseFileUsageBackend
   */
  protected $fileUsage;

  /**
   * File storage.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $fileStorage;

  /**
   * The database connection used to store file usage information.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $connection;

  /**
   * The crossword data service.
   *
   * @var \Drupal\crossword\CrosswordDataServiceInterface
   */
  protected $crosswordDataService;

  /**
   * Construct the Crossword Image Service.
   *
   * @param \Drupal\Core\File\FileSystem $file_system
   *   The file system.
   * @param \Drupal\file\FileUsage\DatabaseFileUsageBackend $file_usage
   *   File usage service.
   * @param \Drupal\crossword_image\CrosswordImageManager $crossword_image_manager
   *   Crossword image plugin manager.
   * @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
   *   Entity type manager.
   * @param \Drupal\Core\Database\Connection $connection
   *   Database connection.
   */
  public function __construct(FileSystem $file_system, DatabaseFileUsageBackend $file_usage, CrosswordImageManager $crossword_image_manager, EntityTypeManager $entity_type_manager, Connection $connection, CrosswordDataServiceInterface $crossword_data_service) {
    $this->fileSystem = $file_system;
    $this->fileUsage = $file_usage;
    $this->crosswordImageManager = $crossword_image_manager;
    $this->fileStorage = $entity_type_manager->getStorage('file');
    $this->connection = $connection;
    $this->crosswordDataService = $crossword_data_service;
  }

  /**
   * {@inheritdoc}
   */
  public function getImageUri(FileInterface $file, string $plugin_id) {
    if (empty($this->crosswordDataService->getData($file))) {
      return NULL;
    }
    $plugin = $this->getCrosswordImagePlugin($plugin_id);
    if (empty($plugin)) {
      return NULL;
    }
    $destination_uri = $this->getDestinationUri($file, $plugin);
    if (file_exists($destination_uri)) {
      // Check if the existing image is older than the file itself.
      if (filemtime($file->getFileUri()) <= filemtime($destination_uri)) {
        // The existing image can be used, nothing to do.
        return $destination_uri;
      }
      else {
        // Delete the existing but out-of-date image.
        $this->fileSystem->delete($destination_uri);
        image_path_flush($destination_uri);
      }
    }
    if ($this->saveNewImageResource($file, $plugin, $destination_uri)) {
      return $destination_uri;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getImageEntity(FileInterface $file, string $plugin_id) {
    if (empty($this->crosswordDataService->getData($file))) {
      return NULL;
    }
    $destination_uri = $this->getImageUri($file, $plugin_id);
    $values = [
      'uri' => $destination_uri,
    ];
    $existing = $this->fileStorage->loadByProperties($values);
    if ($existing) {
      return reset($existing);
    }
    else {
      return $this->saveImageEntity($file, $destination_uri);
    }
  }

  /**
   * Creates and saves image representation of the crossword file.
   *
   * @param \Drupal\file\FileInterface $file
   *   The file from which the image is to be created.
   * @param CrosswordImagePluginInterface $plugin
   *   The loaded crossword_image plugin.
   * @param string $destination_uri
   *   The destination of the new file.
   *
   * @return bool
   *   Returns TRUE upon success, FALSE upon failure.
   */
  protected function saveNewImageResource(FileInterface $file, CrosswordImagePluginInterface $plugin, $destination_uri) {
    $toolkit = $plugin->getToolkit();
    $toolkit->setType($plugin->getType());
    $toolkit->setImage($plugin->createImageResource($file));
    $directory = $this->fileSystem->dirname($destination_uri);
    $this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
    $success = $toolkit->save($destination_uri);
    if ($success) {
      $this->saveImageEntity($file, $destination_uri);
    }
    return $success;
  }

  /**
   * Gets the destination URI of the file.
   *
   * By default the image is saved in a subdirectory of the directory that
   * holds the crossword file itself.
   *
   * @param \Drupal\file\FileInterface $file
   *   The file that is being converted.
   * @param CrosswordImagePluginInterface $plugin
   *   The loaded crossword_image plugin.
   *
   * @return string
   *   The destination URI.
   */
  protected function getDestinationUri(FileInterface $file, CrosswordImagePluginInterface $plugin) {
    $file_dir = dirname($file->getFileUri());
    if ($file_dir == 'public:') {
      $output_path = 'public://crossword';
    }
    else {
      $output_path = $file_dir . '/crossword';
    }
    $extension = image_type_to_extension($plugin->getType(), FALSE);
    $filename = "{$file->id()}-{$plugin->getPluginId()}.$extension";
    return $output_path . '/' . $filename;
  }

  /**
   * Save a file entity for the image file (a managed file).
   *
   * @param \Drupal\file\FileInterface $file
   *   The file from which the image is to be created.
   * @param string $destination_uri
   *   The destination of the new file.
   *
   * @return \Drupal\file\FileInterface
   *   The file entity of the image.
   */
  protected function saveImageEntity(FileInterface $file, $destination_uri) {
    // Manage the newly saved image file.
    $values = [
      'uri' => $destination_uri,
    ];
    $existing = $this->fileStorage->loadByProperties($values);
    if ($existing) {
      $image = reset($existing);
      $image->save();
      return $image;
    }
    else {
      /** @var \Drupal\file\FileInterface $image */
      $image = $this->fileStorage->create($values);
      $image->setPermanent();
      $image->save();
      $this->fileUsage->add($image, 'crossword', 'file', $file->id());
      return $image;
    }
  }

  /**
   * Loads a plugin if it exists.
   *
   * @param string $plugin_id
   *   Crossword Image plugin id.
   *
   * @return CrosswordImagePluginInterface|null
   *   The plugin or null.
   */
  protected function getCrosswordImagePlugin(string $plugin_id) {
    try {
      $plugin = $this->crosswordImageManager->createInstance($plugin_id);
    }
    catch (PluginNotFoundException $e) {
      return NULL;
    }
    return $plugin;
  }

  /**
   * {@inheritdoc}
   *
   * Terribly brute force and should be used sparingly!
   */
  public function regenerateCrosswordImages(array $crossword_image_plugin_ids = []) {
    // 1. Get all images registered by crossword module.
    // Then for each image...
    // 2. Parse name to find fid of crossword and crossword_image_plugin id.
    // 3. Delete the image.
    // 4. Generate new image from info in step 2.
    // Steps 2-4 happen in a batch.
    $query = $this->connection->select('file_usage', 'f')
      ->fields('f', ['fid'])
      ->condition('module', 'crossword');
    $usage = $query->execute()->fetchAll();
    $image_fids = array_column($usage, 'fid');

    $chunk_size = 10;
    $chunks = array_chunk($image_fids, $chunk_size);
    $batch = [
      'title' => 'Regenerating Crossword Images',
      'finished' => '\Drupal\crossword_image\CrosswordImageService::crosswordImageRegenerateBatchFinished',
      'operations' => [],
    ];
    foreach ($chunks as $chunk) {
      $batch['operations'][] = [
        '\Drupal\crossword_image\CrosswordImageService::crosswordImageRegenerateBatchOp',
        [$chunk, $crossword_image_plugin_ids],
      ];
    }
    batch_set($batch);
  }

  /**
   * Batch op function for regenerating images.
   *
   * See function regenerateAllImages().
   */
  public static function crosswordImageRegenerateBatchOp(array $image_fids, array $crossword_image_plugin_ids, &$context) {
    $crossword_image_service = \Drupal::service('crossword.image_service');
    $file_storage = \Drupal::service('entity_type.manager')->getStorage('file');
    // Parse image file names.
    $items = [];
    foreach ($image_fids as $fid) {
      if ($image = $file_storage->load($fid)) {
        $image_filename = $image->getFilename();
        $crossword_fid = explode("-", $image_filename)[0];
        $crossword_image_plugin = explode(".", explode("-", $image_filename)[1])[0];
        $items[] = [
          'image' => $fid,
          'image_uri' => $image->getFileUri(),
          'crossword_fid' => $crossword_fid,
          'crossword_image_plugin' => $crossword_image_plugin,
        ];
      }
    }
    // Delete and regenerate.
    foreach ($items as $item) {
      if (empty($crossword_image_plugin_ids) || in_array($item['crossword_image_plugin'], $crossword_image_plugin_ids, TRUE)) {
        if ($crossword_file = $file_storage->load($item['crossword_fid'])) {
          // Step 3.
          $crossword_image_service->fileSystem->delete($item['image_uri']);
          image_path_flush($item['image_uri']);
          // Step 4.
          $plugin = $crossword_image_service->getCrosswordImagePlugin($item['crossword_image_plugin']);
          $crossword_image_service->saveNewImageResource($crossword_file, $plugin, $item['image_uri']);
        }
      }
    }
  }

  /**
   * Finished callback.
   */
  public static function crosswordImageRegenerateBatchFinished($success, array $results, array $operations) {
    \Drupal::messenger()->addStatus(t('Crossword Image Regeneration is complete. Check the <a href="@url">files overview page</a> to see updates.', ['@url' => '/admin/content/files']));
  }

}

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

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