1<?php 2 3namespace League\Flysystem; 4 5use InvalidArgumentException; 6use League\Flysystem\Adapter\CanOverwriteFiles; 7use League\Flysystem\Plugin\PluggableTrait; 8use League\Flysystem\Util\ContentListingFormatter; 9 10/** 11 * @method array getWithMetadata(string $path, array $metadata) 12 * @method bool forceCopy(string $path, string $newpath) 13 * @method bool forceRename(string $path, string $newpath) 14 * @method array listFiles(string $path = '', boolean $recursive = false) 15 * @method array listPaths(string $path = '', boolean $recursive = false) 16 * @method array listWith(array $keys = [], $directory = '', $recursive = false) 17 */ 18class Filesystem implements FilesystemInterface 19{ 20 use PluggableTrait; 21 use ConfigAwareTrait; 22 23 /** 24 * @var AdapterInterface 25 */ 26 protected $adapter; 27 28 /** 29 * Constructor. 30 * 31 * @param AdapterInterface $adapter 32 * @param Config|array $config 33 */ 34 public function __construct(AdapterInterface $adapter, $config = null) 35 { 36 $this->adapter = $adapter; 37 $this->setConfig($config); 38 } 39 40 /** 41 * Get the Adapter. 42 * 43 * @return AdapterInterface adapter 44 */ 45 public function getAdapter() 46 { 47 return $this->adapter; 48 } 49 50 /** 51 * @inheritdoc 52 */ 53 public function has($path) 54 { 55 $path = Util::normalizePath($path); 56 57 return strlen($path) === 0 ? false : (bool) $this->getAdapter()->has($path); 58 } 59 60 /** 61 * @inheritdoc 62 */ 63 public function write($path, $contents, array $config = []) 64 { 65 $path = Util::normalizePath($path); 66 $this->assertAbsent($path); 67 $config = $this->prepareConfig($config); 68 69 return (bool) $this->getAdapter()->write($path, $contents, $config); 70 } 71 72 /** 73 * @inheritdoc 74 */ 75 public function writeStream($path, $resource, array $config = []) 76 { 77 if ( ! is_resource($resource)) { 78 throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.'); 79 } 80 81 $path = Util::normalizePath($path); 82 $this->assertAbsent($path); 83 $config = $this->prepareConfig($config); 84 85 Util::rewindStream($resource); 86 87 return (bool) $this->getAdapter()->writeStream($path, $resource, $config); 88 } 89 90 /** 91 * @inheritdoc 92 */ 93 public function put($path, $contents, array $config = []) 94 { 95 $path = Util::normalizePath($path); 96 $config = $this->prepareConfig($config); 97 98 if ( ! $this->adapter instanceof CanOverwriteFiles && $this->has($path)) { 99 return (bool) $this->getAdapter()->update($path, $contents, $config); 100 } 101 102 return (bool) $this->getAdapter()->write($path, $contents, $config); 103 } 104 105 /** 106 * @inheritdoc 107 */ 108 public function putStream($path, $resource, array $config = []) 109 { 110 if ( ! is_resource($resource)) { 111 throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.'); 112 } 113 114 $path = Util::normalizePath($path); 115 $config = $this->prepareConfig($config); 116 Util::rewindStream($resource); 117 118 if ( ! $this->adapter instanceof CanOverwriteFiles &&$this->has($path)) { 119 return (bool) $this->getAdapter()->updateStream($path, $resource, $config); 120 } 121 122 return (bool) $this->getAdapter()->writeStream($path, $resource, $config); 123 } 124 125 /** 126 * @inheritdoc 127 */ 128 public function readAndDelete($path) 129 { 130 $path = Util::normalizePath($path); 131 $this->assertPresent($path); 132 $contents = $this->read($path); 133 134 if ($contents === false) { 135 return false; 136 } 137 138 $this->delete($path); 139 140 return $contents; 141 } 142 143 /** 144 * @inheritdoc 145 */ 146 public function update($path, $contents, array $config = []) 147 { 148 $path = Util::normalizePath($path); 149 $config = $this->prepareConfig($config); 150 151 $this->assertPresent($path); 152 153 return (bool) $this->getAdapter()->update($path, $contents, $config); 154 } 155 156 /** 157 * @inheritdoc 158 */ 159 public function updateStream($path, $resource, array $config = []) 160 { 161 if ( ! is_resource($resource)) { 162 throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.'); 163 } 164 165 $path = Util::normalizePath($path); 166 $config = $this->prepareConfig($config); 167 $this->assertPresent($path); 168 Util::rewindStream($resource); 169 170 return (bool) $this->getAdapter()->updateStream($path, $resource, $config); 171 } 172 173 /** 174 * @inheritdoc 175 */ 176 public function read($path) 177 { 178 $path = Util::normalizePath($path); 179 $this->assertPresent($path); 180 181 if ( ! ($object = $this->getAdapter()->read($path))) { 182 return false; 183 } 184 185 return $object['contents']; 186 } 187 188 /** 189 * @inheritdoc 190 */ 191 public function readStream($path) 192 { 193 $path = Util::normalizePath($path); 194 $this->assertPresent($path); 195 196 if ( ! $object = $this->getAdapter()->readStream($path)) { 197 return false; 198 } 199 200 return $object['stream']; 201 } 202 203 /** 204 * @inheritdoc 205 */ 206 public function rename($path, $newpath) 207 { 208 $path = Util::normalizePath($path); 209 $newpath = Util::normalizePath($newpath); 210 $this->assertPresent($path); 211 $this->assertAbsent($newpath); 212 213 return (bool) $this->getAdapter()->rename($path, $newpath); 214 } 215 216 /** 217 * @inheritdoc 218 */ 219 public function copy($path, $newpath) 220 { 221 $path = Util::normalizePath($path); 222 $newpath = Util::normalizePath($newpath); 223 $this->assertPresent($path); 224 $this->assertAbsent($newpath); 225 226 return $this->getAdapter()->copy($path, $newpath); 227 } 228 229 /** 230 * @inheritdoc 231 */ 232 public function delete($path) 233 { 234 $path = Util::normalizePath($path); 235 $this->assertPresent($path); 236 237 return $this->getAdapter()->delete($path); 238 } 239 240 /** 241 * @inheritdoc 242 */ 243 public function deleteDir($dirname) 244 { 245 $dirname = Util::normalizePath($dirname); 246 247 if ($dirname === '') { 248 throw new RootViolationException('Root directories can not be deleted.'); 249 } 250 251 return (bool) $this->getAdapter()->deleteDir($dirname); 252 } 253 254 /** 255 * @inheritdoc 256 */ 257 public function createDir($dirname, array $config = []) 258 { 259 $dirname = Util::normalizePath($dirname); 260 $config = $this->prepareConfig($config); 261 262 return (bool) $this->getAdapter()->createDir($dirname, $config); 263 } 264 265 /** 266 * @inheritdoc 267 */ 268 public function listContents($directory = '', $recursive = false) 269 { 270 $directory = Util::normalizePath($directory); 271 $contents = $this->getAdapter()->listContents($directory, $recursive); 272 273 return (new ContentListingFormatter($directory, $recursive))->formatListing($contents); 274 } 275 276 /** 277 * @inheritdoc 278 */ 279 public function getMimetype($path) 280 { 281 $path = Util::normalizePath($path); 282 $this->assertPresent($path); 283 284 if ( ! $object = $this->getAdapter()->getMimetype($path)) { 285 return false; 286 } 287 288 return $object['mimetype']; 289 } 290 291 /** 292 * @inheritdoc 293 */ 294 public function getTimestamp($path) 295 { 296 $path = Util::normalizePath($path); 297 $this->assertPresent($path); 298 299 if ( ! $object = $this->getAdapter()->getTimestamp($path)) { 300 return false; 301 } 302 303 return $object['timestamp']; 304 } 305 306 /** 307 * @inheritdoc 308 */ 309 public function getVisibility($path) 310 { 311 $path = Util::normalizePath($path); 312 $this->assertPresent($path); 313 314 if (($object = $this->getAdapter()->getVisibility($path)) === false) { 315 return false; 316 } 317 318 return $object['visibility']; 319 } 320 321 /** 322 * @inheritdoc 323 */ 324 public function getSize($path) 325 { 326 $path = Util::normalizePath($path); 327 328 if (($object = $this->getAdapter()->getSize($path)) === false || ! isset($object['size'])) { 329 return false; 330 } 331 332 return (int) $object['size']; 333 } 334 335 /** 336 * @inheritdoc 337 */ 338 public function setVisibility($path, $visibility) 339 { 340 $path = Util::normalizePath($path); 341 342 return (bool) $this->getAdapter()->setVisibility($path, $visibility); 343 } 344 345 /** 346 * @inheritdoc 347 */ 348 public function getMetadata($path) 349 { 350 $path = Util::normalizePath($path); 351 $this->assertPresent($path); 352 353 return $this->getAdapter()->getMetadata($path); 354 } 355 356 /** 357 * @inheritdoc 358 */ 359 public function get($path, Handler $handler = null) 360 { 361 $path = Util::normalizePath($path); 362 363 if ( ! $handler) { 364 $metadata = $this->getMetadata($path); 365 $handler = $metadata['type'] === 'file' ? new File($this, $path) : new Directory($this, $path); 366 } 367 368 $handler->setPath($path); 369 $handler->setFilesystem($this); 370 371 return $handler; 372 } 373 374 /** 375 * Assert a file is present. 376 * 377 * @param string $path path to file 378 * 379 * @throws FileNotFoundException 380 * 381 * @return void 382 */ 383 public function assertPresent($path) 384 { 385 if ($this->config->get('disable_asserts', false) === false && ! $this->has($path)) { 386 throw new FileNotFoundException($path); 387 } 388 } 389 390 /** 391 * Assert a file is absent. 392 * 393 * @param string $path path to file 394 * 395 * @throws FileExistsException 396 * 397 * @return void 398 */ 399 public function assertAbsent($path) 400 { 401 if ($this->config->get('disable_asserts', false) === false && $this->has($path)) { 402 throw new FileExistsException($path); 403 } 404 } 405} 406