Storage¶
Note
Not part of core. Install it separately:
composer require kinetis/storage
File storage against League\Flysystem’s FilesystemOperator interface —
read, write, delete, and list files through one interface, swappable to a
different backend with no application-code changes. The local backend
runs every operation without blocking the rest of your application. S3
(and S3-compatible services) is a second, equally non-blocking backend —
see Storage (S3).
use Kinetis\Storage\FilesystemFactory;
$storage = FilesystemFactory::fromConfig($config);
$storage->write('avatars/user-42.png', $imageContents);
$contents = $storage->read('avatars/user-42.png');
$storage->delete('avatars/user-42.png');
$storage is a plain League\Flysystem\FilesystemOperator — any
existing Flysystem knowledge or tooling applies directly; there’s no
Kinetis-specific interface wrapping it.
Configuring¶
FILESYSTEM_DRIVER=local
FILESYSTEM_ROOT=/var/app/storage
FILESYSTEM_DRIVER defaults to local — the only driver this package
implements. FILESYSTEM_ROOT is required; there’s no sane default to
guess, since a wrong one could write files somewhere unintended.
Named connections¶
$backups = FilesystemFactory::fromConfig($config, 'backups');
FILESYSTEM_BACKUPS_DRIVER=local
FILESYSTEM_BACKUPS_ROOT=/var/app/backups
Following Configuration’s named-connection convention: 'default' reads
the plain FILESYSTEM_* keys above; any other name reads
FILESYSTEM_{NAME}_* instead. A named filesystem is never autowired by
type — resolve it explicitly, or construct it directly, wherever it’s
needed.
Streaming an upload¶
Dispatcher already resolves UploadedFileInterface parameters (see
Routing & Validation); its stream feeds writeStream() directly:
use Kinetis\Http\Attributes\Post;
use League\Flysystem\FilesystemOperator;
use Psr\Http\Message\UploadedFileInterface;
final readonly class AvatarController
{
public function __construct(private FilesystemOperator $storage) {}
#[Post('/avatar')]
public function store(UploadedFileInterface $avatar): array
{
$this->storage->writeStream(
"avatars/{$avatar->getClientFilename()}",
$avatar->getStream()->detach(),
);
return ['status' => 'stored'];
}
}
Metadata and visibility¶
use League\Flysystem\Visibility;
$storage->fileExists('avatars/user-42.png');
$storage->fileSize('avatars/user-42.png');
$storage->lastModified('avatars/user-42.png');
$storage->mimeType('avatars/user-42.png');
$storage->setVisibility('avatars/user-42.png', Visibility::PUBLIC);
listContents($path, deep: true) walks a directory tree, yielding
FileAttributes/DirectoryAttributes for each entry:
foreach ($storage->listContents('avatars', deep: true) as $item) {
$item->path();
$item->isFile();
}
See also¶
Storage (S3) — the S3-backed driver, plugged in via the same
FilesystemFactory.Configuration — the named-connection convention
FilesystemFactorybuilds on.Persistence — MySQL, Postgres, and Redis, which run the same way: without blocking the rest of your application.
Routing & Validation —
UploadedFileInterfaceparameter binding.