FilePostDump.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <?php
  2. namespace Drupal\reinstall\EventSubscriber;
  3. use Drupal\Component\Utility\Unicode;
  4. use Drupal\Core\File\FileSystem;
  5. use Drupal\Core\File\FileSystemInterface;
  6. use Drupal\file\Entity\File;
  7. use Drupal\reinstall\DumperEvent;
  8. use Drupal\reinstall\DumperEvents;
  9. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  10. /**
  11. * Class FilePostDump performs physical file copy on file dump.
  12. */
  13. class FilePostDump implements EventSubscriberInterface {
  14. /**
  15. * The file_system service.
  16. *
  17. * @var \Drupal\Core\File\FileSystemInterface
  18. */
  19. protected $fileSystem;
  20. /**
  21. * The export/import path.
  22. *
  23. * @var string
  24. */
  25. protected $importPath;
  26. /**
  27. * FilePostDump constructor.
  28. *
  29. * @param string $importPath
  30. * The reinstall.path parameter.
  31. */
  32. public function __construct(FileSystemInterface $fileSystem, string $importPath) {
  33. $this->fileSystem = $fileSystem;
  34. $this->importPath = $importPath;
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public static function getSubscribedEvents() {
  40. return [
  41. DumperEvents::POST_DUMP => 'onDumpPost',
  42. ];
  43. }
  44. public function onDumpPost(DumperEvent $event) {
  45. if ($event->storage->getEntityTypeId() !== 'file') {
  46. return;
  47. }
  48. $this->dumpFiles($event->bundleName, $event->entities);
  49. }
  50. public function dumpFiles(string $bundleName, array $files) {
  51. $importPath = $this->importPath;
  52. $dir = "$importPath/$bundleName";
  53. $usedNamespaces = array_keys(array_reduce($files, [__CLASS__, 'namespacesReducer'], []));
  54. $lists = [];
  55. foreach ($usedNamespaces as $ns) {
  56. // XXX Consider using \0 to support xargs: file names MAY contain spaces.
  57. $path = "$dir/$ns.list.txt";
  58. $nsDir = "$dir/$ns";
  59. if (!is_dir($nsDir)) {
  60. echo "Creating $nsDir\n";
  61. mkdir($nsDir, 0777, TRUE);
  62. }
  63. // fopen() is in text mode by default.
  64. $lists[$ns] = [
  65. 'dir' => $nsDir,
  66. 'handle' => fopen($path, 'w'),
  67. ];
  68. }
  69. /**
  70. * @var int $fid
  71. * @var \Drupal\file\Entity\File $file
  72. */
  73. foreach ($files as $fid => $file) {
  74. $uri = $file->getFileUri();
  75. $target = file_uri_target($uri);
  76. $ns = $this->fileSystem->uriScheme($uri);
  77. fputs($lists[$ns]['handle'], $target . "\n");
  78. $dest = $lists[$ns]['dir'] . '/' . $target;
  79. $dir = dirname($dest);
  80. if (!is_dir($dir)) {
  81. mkdir($dir, 0777, TRUE);
  82. }
  83. file_unmanaged_copy($uri, $dest, FILE_EXISTS_REPLACE);
  84. }
  85. foreach ($lists as $list) {
  86. fclose($list['handle']);
  87. }
  88. }
  89. /**
  90. * array_reduce() callback to collect namespaces from file entities.
  91. *
  92. * @param string[] $accu
  93. * @param \Drupal\file\Entity\File $fileItem
  94. *
  95. * @return string[]
  96. *
  97. * @see \Drupal\reinstall\Dumper::dumpFiles()
  98. */
  99. protected static function namespacesReducer(array $accu, File $fileItem) {
  100. $uri = $fileItem->getFileUri();
  101. // Plain filenames without a namespace. Should not happen, but...
  102. if (FALSE === ($len = Unicode::strpos($uri, '://'))) {
  103. return $accu;
  104. };
  105. $namespace = Unicode::substr($uri, 0, $len);
  106. $accu[$namespace] = TRUE;
  107. return $accu;
  108. }
  109. }