You are here

class DirectoryDestination in Backup and Migrate 8.4

Class ServerDirectoryDestination.

@package BackupMigrate\Core\Destination

Hierarchy

Expanded class hierarchy of DirectoryDestination

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

File

lib/backup_migrate_core/src/Destination/DirectoryDestination.php, line 18

Namespace

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

  /**
   * {@inheritdoc}
   */
  function saveFile(BackupFileReadableInterface $file) {
    $this
      ->_saveFile($file);
    $this
      ->_saveFileMetadata($file);
  }

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

  /**
   * Get a definition for user-configurable settings.
   *
   * @param array $params
   *
   * @return array
   */
  public function configSchema($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 \BackupMigrate\Core\File\BackupFileReadableInterface $file
   *
   * @throws \BackupMigrate\Core\Exception\BackupMigrateException
   */
  function _saveFile(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 \BackupMigrate\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($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 _deleteFile($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\File\FileSystemInterface $fileSystem */
    $fileSystem = \Drupal::service('file_system');
    $scheme = $fileSystem
      ->uriScheme($dir);

    // Ensure the stream is configured.
    if (!$fileSystem
      ->validScheme($scheme)) {
      drupal_set_message(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. These configuration options can be overriden by the config options but will not be overwritten. If the object is re-configured after construction any missing configuration options will revert to these values.
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::fileExists public function Does the file with the given id (filename) exist in this destination. Overrides ReadableDestinationInterface::fileExists
DirectoryDestination::getFile public function Get a file object representing the file with the given ID from the destination. This file item will not necessarily be readable nor will it have extended metadata loaded. Use loadForReading and loadFileMetadata to get those. Overrides ReadableDestinationInterface::getFile
DirectoryDestination::listFiles public function Return a list of files from the destination. This list should be date ordered from newest to oldest. 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 function Save a file to the destination. Overrides DestinationBase::saveFile
DirectoryDestination::_deleteFile public function Do the actual delete for a file. Overrides DestinationBase::_deleteFile
DirectoryDestination::_getAllFileNames protected function Get the entire file list from this destination.
DirectoryDestination::_idToPath protected function Return a file path for the given file id.
DirectoryDestination::_saveFile function Do the actual file save. This function is called to save the data file AND the metadata sidecar file. Overrides DestinationBase::_saveFile 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::deleteFile public function
SidecarMetadataDestinationTrait::_arrayToINI protected function
SidecarMetadataDestinationTrait::_INIToArray protected function Parse an INI file's contents.
SidecarMetadataDestinationTrait::_loadFileMetadataArray protected function
SidecarMetadataDestinationTrait::_saveFileMetadata 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.