Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/filesystems.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'driver' => 'local',
'root' => storage_path('app'),
'throw' => false,
'report' => false,
],

'public' => [
Expand All @@ -42,6 +43,7 @@
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
'report' => false,
],

's3' => [
Expand All @@ -54,6 +56,7 @@
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
'report' => false,
],

],
Expand Down
49 changes: 49 additions & 0 deletions src/Illuminate/Filesystem/FilesystemAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Illuminate\Filesystem;

use Closure;
use Illuminate\Container\Container;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Filesystem\Cloud as CloudFilesystemContract;
use Illuminate\Contracts\Filesystem\Filesystem as FilesystemContract;
use Illuminate\Http\File;
Expand Down Expand Up @@ -35,6 +37,7 @@
use Psr\Http\Message\StreamInterface;
use RuntimeException;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Throwable;

/**
* @mixin \League\Flysystem\FilesystemOperator
Expand Down Expand Up @@ -288,6 +291,8 @@ public function get($path)
return $this->driver->read($path);
} catch (UnableToReadFile $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);
}
}

Expand Down Expand Up @@ -417,6 +422,8 @@ public function put($path, $contents, $options = [])
} catch (UnableToWriteFile|UnableToSetVisibility $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

return false;
}

Expand Down Expand Up @@ -502,6 +509,8 @@ public function setVisibility($path, $visibility)
} catch (UnableToSetVisibility $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

return false;
}

Expand Down Expand Up @@ -560,6 +569,8 @@ public function delete($paths)
} catch (UnableToDeleteFile $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

$success = false;
}
}
Expand All @@ -581,6 +592,8 @@ public function copy($from, $to)
} catch (UnableToCopyFile $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

return false;
}

Expand All @@ -601,6 +614,8 @@ public function move($from, $to)
} catch (UnableToMoveFile $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

return false;
}

Expand Down Expand Up @@ -632,6 +647,8 @@ public function checksum(string $path, array $options = [])
} catch (UnableToProvideChecksum $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

return false;
}
}
Expand All @@ -648,6 +665,8 @@ public function mimeType($path)
return $this->driver->mimeType($path);
} catch (UnableToRetrieveMetadata $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);
}

return false;
Expand All @@ -673,6 +692,8 @@ public function readStream($path)
return $this->driver->readStream($path);
} catch (UnableToReadFile $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);
}
}

Expand All @@ -686,6 +707,8 @@ public function writeStream($path, $resource, array $options = [])
} catch (UnableToWriteFile|UnableToSetVisibility $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

return false;
}

Expand Down Expand Up @@ -918,6 +941,8 @@ public function makeDirectory($path)
} catch (UnableToCreateDirectory|UnableToSetVisibility $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

return false;
}

Expand All @@ -937,6 +962,8 @@ public function deleteDirectory($directory)
} catch (UnableToDeleteDirectory $e) {
throw_if($this->throwsExceptions(), $e);

$this->report($e);

return false;
}

Expand Down Expand Up @@ -1026,6 +1053,28 @@ protected function throwsExceptions(): bool
return (bool) ($this->config['throw'] ?? false);
}

/**
* @param Throwable $exception
* @return void
* @throws Throwable
*/
protected function report($exception)
{
if ($this->shouldReport() && Container::getInstance()->bound(ExceptionHandler::class)) {
Container::getInstance()->make(ExceptionHandler::class)->report($exception);
}
}

/**
* Determine if Flysystem exceptions should be reported.
*
* @return bool
*/
protected function shouldReport(): bool
{
return (bool) ($this->config['report'] ?? false);
}

/**
* Pass dynamic methods call onto Flysystem.
*
Expand Down
122 changes: 122 additions & 0 deletions tests/Filesystem/FilesystemAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Carbon\Carbon;
use GuzzleHttp\Psr7\Stream;
use Illuminate\Container\Container;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Filesystem\FilesystemManager;
use Illuminate\Foundation\Application;
Expand Down Expand Up @@ -545,6 +547,126 @@ public function testThrowExceptionsForMimeType()
$this->fail('Exception was not thrown.');
}

public function testReportExceptionsForGet()
{
$container = Container::getInstance();

$exceptionHandler = m::mock(ExceptionHandler::class);

$exceptionHandler->shouldReceive('report')
->once()
->andReturnUsing(function (UnableToReadFile $e) {
self::assertStringContainsString(
'Unable to read file from location: foo.txt.',
$e->getMessage(),
);
});

$container->bind(ExceptionHandler::class, function () use ($exceptionHandler) {
return $exceptionHandler;
});

$adapter = new FilesystemAdapter($this->filesystem, $this->adapter, ['report' => true]);

try {
$adapter->get('/foo.txt');
} catch (UnableToReadFile) {
$this->fail('Exception was thrown.');
}
}

public function testReportExceptionsForReadStream()
{
$container = Container::getInstance();

$exceptionHandler = m::mock(ExceptionHandler::class);

$exceptionHandler->shouldReceive('report')
->once()
->andReturnUsing(function (UnableToReadFile $e) {
self::assertStringContainsString(
'Unable to read file from location: foo.txt.',
$e->getMessage(),
);
});

$container->bind(ExceptionHandler::class, function () use ($exceptionHandler) {
return $exceptionHandler;
});

$adapter = new FilesystemAdapter($this->filesystem, $this->adapter, ['report' => true], $exceptionHandler);

try {
$adapter->readStream('/foo.txt');
} catch (UnableToReadFile) {
$this->fail('Exception was thrown.');
}
}

public function testReportExceptionsForPut()
{
$container = Container::getInstance();

$exceptionHandler = m::mock(ExceptionHandler::class);

$exceptionHandler->shouldReceive('report')
->once()
->andReturnUsing(function (UnableToWriteFile $e) {
self::assertStringContainsString(
'Unable to write file at location: foo.txt.',
$e->getMessage(),
);
});

$container->bind(ExceptionHandler::class, function () use ($exceptionHandler) {
return $exceptionHandler;
});

$this->filesystem->write('foo.txt', 'Hello World');

chmod(__DIR__.'/tmp/foo.txt', 0400);

$adapter = new FilesystemAdapter($this->filesystem, $this->adapter, ['report' => true], $exceptionHandler);

try {
$adapter->put('/foo.txt', 'Hello World!');
} catch (UnableToWriteFile) {
$this->fail('Exception was thrown.');
} finally {
chmod(__DIR__.'/tmp/foo.txt', 0600);
}
}

public function testReportExceptionsForMimeType()
{
$container = Container::getInstance();

$exceptionHandler = m::mock(ExceptionHandler::class);

$exceptionHandler->shouldReceive('report')
->once()
->andReturnUsing(function (UnableToRetrieveMetadata $e) {
self::assertStringContainsString(
'Unable to retrieve the mime_type for file at location: unknown.mime-type.',
$e->getMessage(),
);
});

$container->bind(ExceptionHandler::class, function () use ($exceptionHandler) {
return $exceptionHandler;
});

$this->filesystem->write('unknown.mime-type', '');

$adapter = new FilesystemAdapter($this->filesystem, $this->adapter, ['report' => true], $exceptionHandler);

try {
$adapter->mimeType('unknown.mime-type');
} catch (UnableToRetrieveMetadata) {
$this->fail('Exception was thrown.');
}
}

public function testGetAllFiles()
{
$this->filesystem->write('body.txt', 'Hello World');
Expand Down
3 changes: 3 additions & 0 deletions tests/Filesystem/FilesystemManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

namespace Illuminate\Tests\Filesystem;

use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Filesystem\FilesystemManager;
use Illuminate\Foundation\Application;
use InvalidArgumentException;
use Mockery as m;
use PHPUnit\Framework\Attributes\RequiresOperatingSystem;
use PHPUnit\Framework\TestCase;
use Throwable;

class FilesystemManagerTest extends TestCase
{
Expand Down