1<?php 2declare(strict_types=1); 3 4namespace ILIAS\Filesystem\Provider\FlySystem; 5 6use ILIAS\Filesystem\Exception\FileAlreadyExistsException; 7use ILIAS\Filesystem\Exception\FileNotFoundException; 8use ILIAS\Filesystem\Exception\IOException; 9use ILIAS\Filesystem\Provider\FileStreamAccess; 10use ILIAS\Filesystem\Stream\FileStream; 11use ILIAS\Filesystem\Stream\Streams; 12use League\Flysystem\FileExistsException; 13use League\Flysystem\FilesystemInterface; 14 15/** 16 * Class FlySystemFileStreamAccess 17 * 18 * Streaming access implementation of the fly system library. 19 * 20 * @author Nicolas Schäfli <ns@studer-raimann.ch> 21 * @since 5.3 22 * @version 1.0.0 23 */ 24final class FlySystemFileStreamAccess implements FileStreamAccess 25{ 26 27 /** 28 * @var FilesystemInterface $flySystemFS 29 */ 30 private $flySystemFS; 31 32 /** 33 * FlySystemFileStreamAccess constructor. 34 * 35 * @param FilesystemInterface $flySystemFS A configured fly system filesystem instance. 36 */ 37 public function __construct(FilesystemInterface $flySystemFS) 38 { 39 $this->flySystemFS = $flySystemFS; 40 } 41 42 /** 43 * Opens a readable stream of the file. 44 * Please make sure to close the stream after the work is done with Stream::close() 45 * 46 * @param string $path The path to the file which should be used to open the new stream. 47 * 48 * @return FileStream The newly created file stream. 49 * 50 * @throws FileNotFoundException If the file could not be found. 51 * @throws IOException If the stream could not be opened. 52 * 53 * @since 5.3 54 * @version 1.0 55 * 56 * @see FileStream::close() 57 */ 58 public function readStream(string $path) : FileStream 59 { 60 try { 61 $resource = $this->flySystemFS->readStream($path); 62 if ($resource === false) { 63 throw new IOException("Could not open stream for file \"$path\""); 64 } 65 66 $stream = Streams::ofResource($resource); 67 return $stream; 68 } catch (\League\Flysystem\FileNotFoundException $ex) { 69 throw new FileNotFoundException("File \"$path\" not found.", 0, $ex); 70 } 71 } 72 73 74 /** 75 * Writes the stream to a new file. 76 * The directory path to the file will be created. 77 * 78 * The stream will be closed after the write operation is done. Please note that the 79 * resource must be detached from the stream in order to write to the file. 80 * 81 * @param string $path The file which should be used to write the stream into. 82 * @param FileStream $stream The stream which should be written into the new file. 83 * 84 * @return void 85 * @throws FileAlreadyExistsException If the file already exists. 86 * @throws IOException If the file could not be written to the filesystem. 87 * @since 5.3 88 * @version 1.0 89 * 90 * @see FileStream::detach() 91 */ 92 public function writeStream(string $path, FileStream $stream) 93 { 94 $resource = $stream->detach(); 95 try { 96 if (!is_resource($resource)) { 97 throw new \InvalidArgumentException('The given stream must not be detached.'); 98 } 99 100 $result = $this->flySystemFS->writeStream($path, $resource); 101 102 if ($result === false) { 103 throw new IOException("Could not write stream to file \"$path\""); 104 } 105 } catch (FileExistsException $ex) { 106 throw new FileAlreadyExistsException("File \"$path\" already exists.", 0, $ex); 107 } finally { 108 if (is_resource($resource)) { 109 fclose($resource); 110 } 111 } 112 } 113 114 115 /** 116 * Creates a new file or updates an existing one. 117 * If the file is updated its content will be truncated before writing the stream. 118 * 119 * The stream will be closed after the write operation is done. Please note that the 120 * resource must be detached from the stream in order to write to the file. 121 * 122 * @param string $path The file which should be used to write the stream into. 123 * @param FileStream $stream The stream which should be written to the file. 124 * 125 * @return void 126 * @throws IOException If the stream could not be written to the file. 127 * @since 5.3 128 * @version 1.0 129 * 130 * @see FileStream::detach() 131 */ 132 public function putStream(string $path, FileStream $stream) 133 { 134 $resource = $stream->detach(); 135 try { 136 if (!is_resource($resource)) { 137 throw new \InvalidArgumentException('The given stream must not be detached.'); 138 } 139 140 $result = $this->flySystemFS->putStream($path, $resource); 141 142 if ($result === false) { 143 throw new IOException("Could not put stream content into \"$path\""); 144 } 145 } finally { 146 if (is_resource($resource)) { 147 fclose($resource); 148 } 149 } 150 } 151 152 153 /** 154 * Updates an existing file. 155 * The file content will be truncated to 0. 156 * 157 * The stream will be closed after the write operation is done. Please note that the 158 * resource must be detached from the stream in order to write to the file. 159 * 160 * @param string $path The path to the file which should be updated. 161 * @param FileStream $stream The stream which should be used to update the file content. 162 * 163 * @return void 164 * @throws FileNotFoundException If the file which should be updated doesn't exist. 165 * @throws IOException If the file could not be updated. 166 * @since 5.3 167 * @version 1.0 168 */ 169 public function updateStream(string $path, FileStream $stream) 170 { 171 $resource = $stream->detach(); 172 try { 173 if (!is_resource($resource)) { 174 throw new \InvalidArgumentException('The given stream must not be detached.'); 175 } 176 177 $result = $this->flySystemFS->updateStream($path, $resource); 178 179 if ($result === false) { 180 throw new IOException("Could not update file \"$path\""); 181 } 182 } catch (\League\Flysystem\FileNotFoundException $ex) { 183 throw new FileNotFoundException("File \"$path\" not found.", 0, $ex); 184 } finally { 185 if (is_resource($resource)) { 186 fclose($resource); 187 } 188 } 189 } 190} 191