PageRenderTime 48ms CodeModel.GetById 4ms RepoModel.GetById 1ms app.codeStats 0ms

/src/File/Writer/DefaultWriter.php

http://github.com/josegonzalez/upload
PHP | 193 lines | 100 code | 21 blank | 72 comment | 4 complexity | f469cf699a20dbcf17b205a98e058923 MD5 | raw file
  1. <?php
  2. declare(strict_types=1);
  3. namespace Josegonzalez\Upload\File\Writer;
  4. use Cake\Datasource\EntityInterface;
  5. use Cake\ORM\Table;
  6. use Cake\Utility\Hash;
  7. use League\Flysystem\Filesystem;
  8. use League\Flysystem\FilesystemAdapter;
  9. use League\Flysystem\FilesystemException;
  10. use League\Flysystem\FilesystemOperator;
  11. use League\Flysystem\Local\LocalFilesystemAdapter;
  12. use League\Flysystem\Visibility;
  13. use Psr\Http\Message\UploadedFileInterface;
  14. use UnexpectedValueException;
  15. class DefaultWriter implements WriterInterface
  16. {
  17. /**
  18. * Table instance.
  19. *
  20. * @var \Cake\ORM\Table
  21. */
  22. protected $table;
  23. /**
  24. * Entity instance.
  25. *
  26. * @var \Cake\Datasource\EntityInterface
  27. */
  28. protected $entity;
  29. /**
  30. * Array of uploaded data for this field
  31. *
  32. * @var \Psr\Http\Message\UploadedFileInterface|null
  33. */
  34. protected $data;
  35. /**
  36. * Name of field
  37. *
  38. * @var string
  39. */
  40. protected $field;
  41. /**
  42. * Settings for processing a path
  43. *
  44. * @var array
  45. */
  46. protected $settings;
  47. /**
  48. * Constructs a writer
  49. *
  50. * @param \Cake\ORM\Table $table the instance managing the entity
  51. * @param \Cake\Datasource\EntityInterface $entity the entity to construct a path for.
  52. * @param \Psr\Http\Message\UploadedFileInterface|null $data the data being submitted for a save
  53. * @param string $field the field for which data will be saved
  54. * @param array $settings the settings for the current field
  55. */
  56. public function __construct(
  57. Table $table,
  58. EntityInterface $entity,
  59. ?UploadedFileInterface $data = null,
  60. string $field,
  61. array $settings
  62. ) {
  63. $this->table = $table;
  64. $this->entity = $entity;
  65. $this->data = $data;
  66. $this->field = $field;
  67. $this->settings = $settings;
  68. }
  69. /**
  70. * Writes a set of files to an output
  71. *
  72. * @param array $files the files being written out
  73. * @return array array of results
  74. */
  75. public function write(array $files): array
  76. {
  77. $filesystem = $this->getFilesystem($this->field, $this->settings);
  78. $results = [];
  79. foreach ($files as $file => $path) {
  80. $results[] = $this->writeFile($filesystem, $file, $path);
  81. }
  82. return $results;
  83. }
  84. /**
  85. * Deletes a set of files to an output
  86. *
  87. * @param array $files the files being written out
  88. * @return array array of results
  89. */
  90. public function delete(array $files): array
  91. {
  92. $filesystem = $this->getFilesystem($this->field, $this->settings);
  93. $results = [];
  94. foreach ($files as $path) {
  95. $results[] = $this->deletePath($filesystem, $path);
  96. }
  97. return $results;
  98. }
  99. /**
  100. * Writes a set of files to an output
  101. *
  102. * @param \League\Flysystem\FilesystemOperator $filesystem a filesystem wrapper
  103. * @param string $file a full path to a temp file
  104. * @param string $path that path to which the file should be written
  105. * @return bool
  106. */
  107. public function writeFile(FilesystemOperator $filesystem, $file, $path): bool
  108. {
  109. // phpcs:ignore
  110. $stream = @fopen($file, 'r');
  111. if ($stream === false) {
  112. return false;
  113. }
  114. $success = false;
  115. $tempPath = $path . '.temp';
  116. $this->deletePath($filesystem, $tempPath);
  117. try {
  118. $filesystem->writeStream($tempPath, $stream);
  119. $this->deletePath($filesystem, $path);
  120. try {
  121. $filesystem->move($tempPath, $path);
  122. $success = true;
  123. } catch (FilesystemException $e) {
  124. // noop
  125. }
  126. } catch (FilesystemException $e) {
  127. // noop
  128. }
  129. $this->deletePath($filesystem, $tempPath);
  130. is_resource($stream) && fclose($stream);
  131. return $success;
  132. }
  133. /**
  134. * Deletes a path from a filesystem
  135. *
  136. * @param \League\Flysystem\FilesystemOperator $filesystem a filesystem writer
  137. * @param string $path the path that should be deleted
  138. * @return bool
  139. */
  140. public function deletePath(FilesystemOperator $filesystem, string $path): bool
  141. {
  142. $success = true;
  143. try {
  144. $filesystem->delete($path);
  145. } catch (FilesystemException $e) {
  146. $success = false;
  147. // TODO: log this?
  148. }
  149. return $success;
  150. }
  151. /**
  152. * Retrieves a configured filesystem for the given field
  153. *
  154. * @param string $field the field for which data will be saved
  155. * @param array $settings the settings for the current field
  156. * @return \League\Flysystem\FilesystemOperator
  157. */
  158. public function getFilesystem(string $field, array $settings = []): FilesystemOperator
  159. {
  160. $adapter = new LocalFilesystemAdapter(Hash::get($settings, 'filesystem.root', ROOT . DS));
  161. $adapter = Hash::get($settings, 'filesystem.adapter', $adapter);
  162. if (is_callable($adapter)) {
  163. $adapter = $adapter();
  164. }
  165. if ($adapter instanceof FilesystemAdapter) {
  166. return new Filesystem($adapter, Hash::get($settings, 'filesystem.options', [
  167. 'visibility' => Visibility::PUBLIC,
  168. ]));
  169. }
  170. throw new UnexpectedValueException(sprintf('Invalid Adapter for field %s', $field));
  171. }
  172. }