data_pipelines-1.x-dev/src/Plugin/DatasetDestination/FileDestinationBase.php

src/Plugin/DatasetDestination/FileDestinationBase.php
<?php

declare(strict_types=1);

namespace Drupal\data_pipelines\Plugin\DatasetDestination;

use Drupal\Component\Utility\Unicode;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\data_pipelines\Destination\DatasetDestinationPluginBase;
use Drupal\data_pipelines\Entity\DatasetInterface;
use Drupal\data_pipelines\Entity\DestinationInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a base class for file destination plugins.
 */
abstract class FileDestinationBase extends DatasetDestinationPluginBase implements ContainerFactoryPluginInterface {

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

  /**
   * The stream wrapper manager.
   *
   * @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
   */
  protected $streamWrapperManager;

  /**
   * Constructs a new FileDestinationBase.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\File\FileSystemInterface $fileSystem
   *   The file system service.
   * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $streamWrapperManager
   *   The stream wrapper manager.
   */
  final public function __construct(array $configuration, $plugin_id, $plugin_definition, FileSystemInterface $fileSystem, StreamWrapperManagerInterface $streamWrapperManager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->fileSystem = $fileSystem;
    $this->streamWrapperManager = $streamWrapperManager;
  }

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

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration(): array {
    return [
      'scheme' => 'public',
      'dir' => '',
    ] + parent::defaultConfiguration();
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
    $options = $this->streamWrapperManager->getDescriptions(StreamWrapperInterface::WRITE_VISIBLE);
    if (!empty($options)) {
      $form['scheme'] = [
        '#type' => 'radios',
        '#title' => $this->t('File scheme'),
        '#default_value' => $this->configuration['scheme'],
        '#options' => $options,
        '#description' => $this->t('The file scheme to use.'),
        '#required' => TRUE,
      ];
    }
    $form['dir'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Sub-directory path'),
      '#description' => $this->t('(optional) The sub-directory to write files to.'),
      '#default_value' => $this->configuration['dir'],
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function viewSettings(): array {
    return [
      'data' => [
        '#markup' => new TranslatableMarkup("Path: %path", [
          '%path' => $this->getDirPath(),
        ]),
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state): void {
    $scheme = $form_state->getValue('scheme');
    $path = $form_state->getValue('dir');
    $fullPath = $scheme . '://' . ltrim($path, '/');
    $dirname = $this->fileSystem->dirname($fullPath);
    if (!$this->fileSystem->prepareDirectory($dirname, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
      $form_state->setErrorByName('dir', $this->t("Destination path is not writable."));
    }
    $basename = $this->fileSystem->basename($fullPath);
    if (!Unicode::validateUtf8($basename)) {
      $form_state->setErrorByName('dir', $this->t("Filename must contain valid UTF-8 characters."));
    }
  }

  /**
   * Gets the dir.
   *
   * @return string
   *   The file path.
   */
  public function getDir(): string {
    $dir = $this->configuration['dir'];
    if (empty($dir)) {
      return $dir;
    }
    // Remove leading slash.
    $dir = ltrim($dir, '/');
    // Add trailing slash.
    return rtrim($dir, '/') . '/';
  }

  /**
   * Gets the file scheme.
   *
   * @return string|null
   *   The file scheme.
   */
  public function getScheme(): ?string {
    return $this->configuration['scheme'];
  }

  /**
   * Gets the file path.
   *
   * @return string|null
   *   The file path.
   */
  public function getDirPath(): ?string {
    if ($this->getScheme()) {
      return $this->getScheme() . '://' . $this->getDir();
    }
    return NULL;
  }

  /**
   * Gets the file path for the dataset.
   *
   * @param \Drupal\data_pipelines\Entity\DatasetInterface $dataset
   *   The dataset.
   *
   * @return string
   *   The file path.
   */
  public function getFilePath(DatasetInterface $dataset): string {
    return $this->getDirPath() . $this->getFilename($dataset);
  }

  /**
   * Get the Url object for the file of the dataset.
   *
   * @param \Drupal\data_pipelines\Entity\DatasetInterface $dataset
   *   The dataset.
   *
   * @return \Drupal\Core\Url
   *   File Url.
   */
  public function getFileUrl(DatasetInterface $dataset): Url {
    $fileUri = $this->getFilePath($dataset);
    $filePath = $this->fileSystem->realpath($fileUri);
    // Add the timestamp as a cache-bursting parameter.
    $timestamp = file_exists($filePath) ? filemtime($filePath) : time();
    return Url::fromUri($fileUri, [
      'query' => [
        't' => $timestamp,
      ],
    ]);
  }

  /**
   * Get the dataset filename.
   *
   * @param \Drupal\data_pipelines\Entity\DatasetInterface $dataset
   *   The dataset.
   *
   * @return string
   *   The filename.
   */
  protected function getFilename(DatasetInterface $dataset): string {
    return $dataset->getMachineName() . '.' . $this->getFileExtension();
  }

  /**
   * {@inheritdoc}
   */
  public function deleteDataSet(DatasetInterface $dataset, DestinationInterface $destination): bool {
    $filePath = $this->getFilePath($dataset);
    try {
      $this->fileSystem->delete($filePath);
    }
    catch (FileException $e) {
      $this->messenger()
        ->addError($this->t("Error deleting '%path': %error", [
          '%path' => $filePath,
          '%error' => $e->getMessage(),
        ]));
      return FALSE;
    }
    return TRUE;
  }

  /**
   * Serialize the chunk for writing to file.
   *
   * @param \Drupal\data_pipelines\DatasetData[] $chunk
   *   Chunk data.
   *
   * @return string
   *   The serialized chunk.
   */
  abstract protected function serializeChunk(array $chunk): string;

  /**
   * Gets the file extension.
   *
   * @return string
   *   The file extension.
   */
  abstract protected function getFileExtension(): string;

  /**
   * {@inheritdoc}
   */
  public function beginProcessing(DatasetInterface $dataset): bool {
    parent::beginProcessing($dataset);
    $dirPath = $this->getDirPath();
    if (!$this->fileSystem->prepareDirectory($dirPath, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
      $this->messenger()
        ->addError($this->t("Could not create directory '%dirname'", [
          '%dirname' => $dirPath,
        ]));
      return FALSE;
    }
    $filePath = $this->getFilePath($dataset);
    $this->fileSystem->delete($filePath);
    touch($filePath);
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function processChunk(DatasetInterface $dataset, array $chunk): bool {
    parent::processChunk($dataset, $chunk);
    $data = $this->serializeChunk($chunk);
    $filepath = $this->getFilePath($dataset);
    $file = fopen($filepath, 'a');
    try {
      fwrite($file, $data);
      fclose($file);
    }
    catch (\Exception $e) {
      $this->messenger()
        ->addError($this->t("Error saving to destination '%path': %error", [
          '%path' => $this->getDir(),
          '%error' => $e->getMessage(),
        ]));
      return FALSE;
    }
    return TRUE;
  }

}

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

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