You are here

class DirectoryDestination in Backup and Migrate 5.0.x

@package Drupal\backup_migrate\Core\Destination

Hierarchy

Expanded class hierarchy of DirectoryDestination

1 file declares its use of DirectoryDestination
DrupalDirectoryDestination.php in src/Drupal/Destination/DrupalDirectoryDestination.php

File

src/Core/Destination/DirectoryDestination.php, line 18

Namespace

Drupal\backup_migrate\Core\Destination
View source
class DirectoryDestination extends DestinationBase implements ListableDestinationInterface, ReadableDestinationInterface, ConfigurableInterface, FileProcessorInterface {
  use SidecarMetadataDestinationTrait;

  /**
   * {@inheritdoc}
   */
  public function saveFile(BackupFileReadableInterface $file) {
    $this
      ->saveTheFile($file);
    $this
      ->saveTheFileMetadata($file);
  }

  /**
   * {@inheritdoc}
   */
  public function checkWritable() {
    $this
      ->checkDirectory();
  }

  /**
   * Get a definition for user-configurable settings.
   *
   * @param array $params
   *
   * @return array
   */
  public function configSchema(array $params = []) {
    $schema = [];

    // Init settings.
    if ($params['operation'] == 'initialize') {
      $schema['fields']['directory'] = [
        'type' => 'text',
        'title' => $this
          ->t('Directory Path'),
      ];
    }
    return $schema;
  }

  /**
   * Do the actual file save.
   *
   * This function is called to save the data file AND the metadata sidecar
   * file.
   *
   * @param \Drupal\backup_migrate\Core\File\BackupFileReadableInterface $file
   *
   * @throws \Drupal\backup_migrate\Core\Exception\BackupMigrateException
   */
  public function saveTheFile(BackupFileReadableInterface $file) {

    // Check if the directory exists.
    $this
      ->checkDirectory();
    copy($file
      ->realpath(), $this
      ->idToPath($file
      ->getFullName()));

    // @todo Use copy/unlink if the temp file and the destination do not share
    // a stream wrapper.
  }

  /**
   * Check that the directory can be used for backup.
   *
   * @throws \Drupal\backup_migrate\Core\Exception\BackupMigrateException
   */
  protected function checkDirectory() {
    $dir = $this
      ->confGet('directory');

    // Check if the directory exists.
    if (!file_exists($dir)) {
      throw new DestinationNotWritableException("The backup file could not be saved to '%dir' because it does not exist.", [
        '%dir' => $dir,
      ]);
    }

    // Check if the directory is writable.
    if (!is_writable($this
      ->confGet('directory'))) {
      throw new DestinationNotWritableException("The backup file could not be saved to '%dir' because Backup and Migrate does not have write access to that directory.", [
        '%dir' => $dir,
      ]);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getFile($id) {
    if ($this
      ->fileExists($id)) {
      $out = new BackupFile();
      $out
        ->setMeta('id', $id);
      $out
        ->setFullName($id);
      return $out;
    }
    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function loadFileForReading(BackupFileInterface $file) {

    // If this file is already readable, simply return it.
    if ($file instanceof BackupFileReadableInterface) {
      return $file;
    }
    $id = $file
      ->getMeta('id');
    if ($this
      ->fileExists($id)) {
      return new ReadableStreamBackupFile($this
        ->idToPath($id));
    }
    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function listFiles() {
    $dir = $this
      ->confGet('directory');
    $out = [];

    // Get the entire list of filenames.
    $files = $this
      ->getAllFileNames();
    foreach ($files as $file) {
      $filepath = $dir . '/' . $file;
      $out[$file] = new ReadableStreamBackupFile($filepath);
    }
    return $out;
  }

  /**
   * {@inheritdoc}
   */
  public function queryFiles(array $filters = [], $sort = 'datestamp', $sort_direction = SORT_DESC, $count = 100, $start = 0) {

    // Get the full list of files.
    $out = $this
      ->listFiles($count + $start);
    foreach ($out as $key => $file) {
      $out[$key] = $this
        ->loadFileMetadata($file);
    }

    // Filter the output.
    if ($filters) {
      $out = array_filter($out, function ($file) use ($filters) {
        foreach ($filters as $key => $value) {
          if ($file
            ->getMeta($key) !== $value) {
            return FALSE;
          }
        }
        return TRUE;
      });
    }

    // Sort the files.
    if ($sort && $sort_direction) {
      uasort($out, function ($a, $b) use ($sort, $sort_direction) {
        if ($sort_direction == SORT_DESC) {
          return $b
            ->getMeta($sort) < $b
            ->getMeta($sort);
        }
        else {
          return $b
            ->getMeta($sort) > $b
            ->getMeta($sort);
        }
      });
    }

    // Slice the return array.
    if ($count || $start) {
      $out = array_slice($out, $start, $count);
    }
    return $out;
  }

  /**
   * @return int
   *   The number of files in the destination.
   */
  public function countFiles() {
    $files = $this
      ->getAllFileNames();
    return count($files);
  }

  /**
   * {@inheritdoc}
   */
  public function fileExists($id) {
    return file_exists($this
      ->idToPath($id));
  }

  /**
   * {@inheritdoc}
   */
  public function deleteTheFile($id) {
    if ($file = $this
      ->getFile($id)) {
      if ($file = $this
        ->loadFileForReading($file)) {
        return unlink($file
          ->realpath());
      }
    }
    return FALSE;
  }

  /**
   * Return a file path for the given file id.
   *
   * @param $id
   *
   * @return string
   */
  protected function idToPath($id) {
    return rtrim($this
      ->confGet('directory'), '/') . '/' . $id;
  }

  /**
   * Get the entire file list from this destination.
   *
   * @return array
   */
  protected function getAllFileNames() {
    $files = [];

    // Read the list of files from the directory.
    $dir = $this
      ->confGet('directory');

    /** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
    $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
    $scheme = $stream_wrapper_manager
      ->getScheme($dir);

    // Ensure the stream is configured.
    if (!$stream_wrapper_manager
      ->isValidScheme($scheme)) {
      \Drupal::messenger()
        ->addMessage($this
        ->t('Your @scheme stream is not configured.', [
        '@scheme' => $scheme . '://',
      ]), 'warning');
      return $files;
    }
    if ($handle = opendir($dir)) {
      while (FALSE !== ($file = readdir($handle))) {
        $filepath = $dir . '/' . $file;

        // Don't show hidden, unreadable or metadata files.
        if (substr($file, 0, 1) !== '.' && is_readable($filepath) && substr($file, strlen($file) - 5) !== '.info') {
          $files[] = $file;
        }
      }
    }
    return $files;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ConfigurableTrait::$config protected property The object's configuration object.
ConfigurableTrait::$init protected property The initial configuration.
ConfigurableTrait::confGet public function Get a specific value from the configuration.
ConfigurableTrait::config public function Get the configuration object for this item.
ConfigurableTrait::configDefaults public function Get the default values for the plugin. 10
ConfigurableTrait::configErrors public function Get any validation errors in the config.
ConfigurableTrait::setConfig public function Set the configuration for all plugins. 1
ConfigurableTrait::__construct public function 2
DestinationBase::isRemote public function
DestinationBase::loadFileMetadata public function Load the metadata for the given file however it may be stored. Overrides ReadableDestinationInterface::loadFileMetadata
DestinationBase::supportedOps public function Get a list of supported operations and their weight. Overrides PluginBase::supportedOps
DirectoryDestination::checkDirectory protected function Check that the directory can be used for backup. 1
DirectoryDestination::checkWritable public function Overrides DestinationBase::checkWritable
DirectoryDestination::configSchema public function Get a definition for user-configurable settings. Overrides ConfigurableTrait::configSchema
DirectoryDestination::countFiles public function Overrides ListableDestinationInterface::countFiles
DirectoryDestination::deleteTheFile public function Do the actual delete for a file. Overrides DestinationBase::deleteTheFile
DirectoryDestination::fileExists public function Does the file with the given id (filename) exist in this destination. Overrides ReadableDestinationInterface::fileExists
DirectoryDestination::getAllFileNames protected function Get the entire file list from this destination.
DirectoryDestination::getFile public function Get a file object representing the file with the given ID from the dest. Overrides ReadableDestinationInterface::getFile
DirectoryDestination::idToPath protected function Return a file path for the given file id.
DirectoryDestination::listFiles public function Return a list of files from the destination. Overrides ListableDestinationInterface::listFiles
DirectoryDestination::loadFileForReading public function Load the file with the given ID from the destination. Overrides ReadableDestinationInterface::loadFileForReading
DirectoryDestination::queryFiles public function Run a basic query with sort on the list of files. Overrides ListableDestinationInterface::queryFiles 1
DirectoryDestination::saveFile public function Save a file to the destination. Overrides DestinationBase::saveFile
DirectoryDestination::saveTheFile public function Do the actual file save. Overrides DestinationBase::saveTheFile 1
FileProcessorTrait::$tempfilemanager protected property
FileProcessorTrait::alterMime public function Provide the file mime for the given file extension if known.
FileProcessorTrait::getTempFileManager public function Get the temp file manager.
FileProcessorTrait::setTempFileManager public function Inject the temp file manager.
PluginBase::opWeight public function What is the weight of the given operation for this plugin. Overrides PluginInterface::opWeight
PluginBase::supportsOp public function Does this plugin implement the given operation. Overrides PluginInterface::supportsOp
SidecarMetadataDestinationTrait::arrayToIni protected function
SidecarMetadataDestinationTrait::deleteFile public function
SidecarMetadataDestinationTrait::iniToArray protected function Parse an INI file's contents.
SidecarMetadataDestinationTrait::loadFileMetadataArray protected function
SidecarMetadataDestinationTrait::saveTheFileMetadata protected function
TranslatableTrait::$translator protected property
TranslatableTrait::setTranslator public function
TranslatableTrait::t public function Translate the given string if there is a translator service available.