"Fossies" - the Fresh Open Source Software Archive

Member "drupal-9.1.0-rc1/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php" (18 Nov 2020, 8637 Bytes) of package /linux/www/drupal-9.1.0-rc1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "FileCopy.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 namespace Drupal\migrate\Plugin\migrate\process;
    4 
    5 use Drupal\Core\File\Exception\FileException;
    6 use Drupal\Core\File\FileSystemInterface;
    7 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
    8 use Drupal\Core\StreamWrapper\LocalStream;
    9 use Drupal\Core\StreamWrapper\StreamWrapperManager;
   10 use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
   11 use Drupal\migrate\MigrateException;
   12 use Drupal\migrate\MigrateExecutableInterface;
   13 use Drupal\migrate\Plugin\MigrateProcessInterface;
   14 use Drupal\migrate\Row;
   15 use Symfony\Component\DependencyInjection\ContainerInterface;
   16 
   17 /**
   18  * Copies or moves a local file from one place into another.
   19  *
   20  * The file can be moved, reused, or set to be automatically renamed if a
   21  * duplicate exists.
   22  *
   23  * The source value is an indexed array of two values:
   24  * - The source path or URI, e.g. '/path/to/foo.txt' or 'public://bar.txt'.
   25  * - The destination URI, e.g. 'public://foo.txt'.
   26  *
   27  * Available configuration keys:
   28  * - move: (optional) Boolean, if TRUE, move the file, otherwise copy the file.
   29  *   Defaults to FALSE.
   30  * - file_exists: (optional) Replace behavior when the destination file already
   31  *   exists:
   32  *   - 'replace' - (default) Replace the existing file.
   33  *   - 'rename' - Append _{incrementing number} until the filename is
   34  *       unique.
   35  *   - 'use existing' - Do nothing and return FALSE.
   36  *
   37  * Examples:
   38  *
   39  * @code
   40  * process:
   41  *   path_to_file:
   42  *     plugin: file_copy
   43  *     source:
   44  *       - /path/to/file.png
   45  *       - public://new/path/to/file.png
   46  * @endcode
   47  *
   48  * @see \Drupal\migrate\Plugin\MigrateProcessInterface
   49  *
   50  * @MigrateProcessPlugin(
   51  *   id = "file_copy"
   52  * )
   53  */
   54 class FileCopy extends FileProcessBase implements ContainerFactoryPluginInterface {
   55 
   56   /**
   57    * The stream wrapper manager service.
   58    *
   59    * @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
   60    */
   61   protected $streamWrapperManager;
   62 
   63   /**
   64    * The file system service.
   65    *
   66    * @var \Drupal\Core\File\FileSystemInterface
   67    */
   68   protected $fileSystem;
   69 
   70   /**
   71    * An instance of the download process plugin.
   72    *
   73    * @var \Drupal\migrate\Plugin\MigrateProcessInterface
   74    */
   75   protected $downloadPlugin;
   76 
   77   /**
   78    * Constructs a file_copy process plugin.
   79    *
   80    * @param array $configuration
   81    *   The plugin configuration.
   82    * @param string $plugin_id
   83    *   The plugin ID.
   84    * @param mixed $plugin_definition
   85    *   The plugin definition.
   86    * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrappers
   87    *   The stream wrapper manager service.
   88    * @param \Drupal\Core\File\FileSystemInterface $file_system
   89    *   The file system service.
   90    * @param \Drupal\migrate\Plugin\MigrateProcessInterface $download_plugin
   91    *   An instance of the download plugin for handling remote URIs.
   92    */
   93   public function __construct(array $configuration, $plugin_id, array $plugin_definition, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system, MigrateProcessInterface $download_plugin) {
   94     $configuration += [
   95       'move' => FALSE,
   96     ];
   97     parent::__construct($configuration, $plugin_id, $plugin_definition);
   98     $this->streamWrapperManager = $stream_wrappers;
   99     $this->fileSystem = $file_system;
  100     $this->downloadPlugin = $download_plugin;
  101   }
  102 
  103   /**
  104    * {@inheritdoc}
  105    */
  106   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
  107     return new static(
  108       $configuration,
  109       $plugin_id,
  110       $plugin_definition,
  111       $container->get('stream_wrapper_manager'),
  112       $container->get('file_system'),
  113       $container->get('plugin.manager.migrate.process')->createInstance('download', $configuration)
  114     );
  115   }
  116 
  117   /**
  118    * {@inheritdoc}
  119    */
  120   public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
  121     // If we're stubbing a file entity, return a URI of NULL so it will get
  122     // stubbed by the general process.
  123     if ($row->isStub()) {
  124       return NULL;
  125     }
  126     list($source, $destination) = $value;
  127 
  128     // If the source path or URI represents a remote resource, delegate to the
  129     // download plugin.
  130     if (!$this->isLocalUri($source)) {
  131       return $this->downloadPlugin->transform($value, $migrate_executable, $row, $destination_property);
  132     }
  133 
  134     // Ensure the source file exists, if it's a local URI or path.
  135     if (!file_exists($source)) {
  136       throw new MigrateException("File '$source' does not exist");
  137     }
  138 
  139     // If the start and end file is exactly the same, there is nothing to do.
  140     if ($this->isLocationUnchanged($source, $destination)) {
  141       return $destination;
  142     }
  143 
  144     // Check if a writable directory exists, and if not try to create it.
  145     $dir = $this->getDirectory($destination);
  146     // If the directory exists and is writable, avoid
  147     // \Drupal\Core\File\FileSystemInterface::prepareDirectory() call and write
  148     // the file to destination.
  149     if (!is_dir($dir) || !is_writable($dir)) {
  150       if (!$this->fileSystem->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
  151         throw new MigrateException("Could not create or write to directory '$dir'");
  152       }
  153     }
  154 
  155     $final_destination = $this->writeFile($source, $destination, $this->configuration['file_exists']);
  156     if ($final_destination) {
  157       return $final_destination;
  158     }
  159     throw new MigrateException("File $source could not be copied to $destination");
  160   }
  161 
  162   /**
  163    * Tries to move or copy a file.
  164    *
  165    * @param string $source
  166    *   The source path or URI.
  167    * @param string $destination
  168    *   The destination path or URI.
  169    * @param int $replace
  170    *   (optional) FileSystemInterface::EXISTS_REPLACE (default) or
  171    *   FileSystemInterface::EXISTS_RENAME.
  172    *
  173    * @return string|bool
  174    *   File destination on success, FALSE on failure.
  175    */
  176   protected function writeFile($source, $destination, $replace = FileSystemInterface::EXISTS_REPLACE) {
  177     // Check if there is a destination available for copying. If there isn't,
  178     // it already exists at the destination and the replace flag tells us to not
  179     // replace it. In that case, return the original destination.
  180     if ($this->fileSystem->getDestinationFilename($destination, $replace) === FALSE) {
  181       return $destination;
  182     }
  183     try {
  184       if ($this->configuration['move']) {
  185         return $this->fileSystem->move($source, $destination, $replace);
  186       }
  187       else {
  188         return $this->fileSystem->copy($source, $destination, $replace);
  189       }
  190     }
  191     catch (FileException $e) {
  192       return FALSE;
  193     }
  194   }
  195 
  196   /**
  197    * Returns the directory component of a URI or path.
  198    *
  199    * For URIs like public://foo.txt, the full physical path of public://
  200    * will be returned, since a scheme by itself will trip up certain file
  201    * API functions (such as
  202    * \Drupal\Core\File\FileSystemInterface::prepareDirectory()).
  203    *
  204    * @param string $uri
  205    *   The URI or path.
  206    *
  207    * @return string|false
  208    *   The directory component of the path or URI, or FALSE if it could not
  209    *   be determined.
  210    */
  211   protected function getDirectory($uri) {
  212     $dir = $this->fileSystem->dirname($uri);
  213     if (substr($dir, -3) == '://') {
  214       return $this->fileSystem->realpath($dir);
  215     }
  216     return $dir;
  217   }
  218 
  219   /**
  220    * Determines if the source and destination URIs represent identical paths.
  221    *
  222    * @param string $source
  223    *   The source URI.
  224    * @param string $destination
  225    *   The destination URI.
  226    *
  227    * @return bool
  228    *   TRUE if the source and destination URIs refer to the same physical path,
  229    *   otherwise FALSE.
  230    */
  231   protected function isLocationUnchanged($source, $destination) {
  232     return $this->fileSystem->realpath($source) === $this->fileSystem->realpath($destination);
  233   }
  234 
  235   /**
  236    * Determines if the given URI or path is considered local.
  237    *
  238    * A URI or path is considered local if it either has no scheme component,
  239    * or the scheme is implemented by a stream wrapper which extends
  240    * \Drupal\Core\StreamWrapper\LocalStream.
  241    *
  242    * @param string $uri
  243    *   The URI or path to test.
  244    *
  245    * @return bool
  246    */
  247   protected function isLocalUri($uri) {
  248     $scheme = StreamWrapperManager::getScheme($uri);
  249 
  250     // The vfs scheme is vfsStream, which is used in testing. vfsStream is a
  251     // simulated file system that exists only in memory, but should be treated
  252     // as a local resource.
  253     if ($scheme == 'vfs') {
  254       $scheme = FALSE;
  255     }
  256     return $scheme === FALSE || $this->streamWrapperManager->getViaScheme($scheme) instanceof LocalStream;
  257   }
  258 
  259 }