Setup

The database adapter is written such that it can be used within a regular Laravel application, as well as outside Laravel.

Inside Laravel Application

Register Service Provider

Register FlysystemDatabaseAdapterServiceProvider inside your config/app.php.

return [

    // ... previous not shown ... //

    /*
    |--------------------------------------------------------------------------
    | Autoloaded Service Providers
    |--------------------------------------------------------------------------
    */

    'providers' => [

        \Aedart\Flysystem\Db\Providers\FlysystemDatabaseAdapterServiceProvider::class

        // ... remaining services not shown ... //
    ],
];

Create custom migration

The database adapter will require two tables to be migrated. To do so, run the following command and follow the on-screen instructions:

php artisan flysystem:make-adapter-migration

The command will generate a new migration file, with the specified table names. Once completed, migrate your database:

php artisan migrate

Add storage disk "profile"

In your config/filesystems.php, add a new storage disk profile, which uses database as its driver: The followings shows a custom disk that uses the database driver and has my_disk as "profile" name.

return [

    // ...previous not shown...

    /*
    |--------------------------------------------------------------------------
    | Filesystem Disks
    |--------------------------------------------------------------------------
    */

    'disks' => [

        // ...previous not shown...

        'my_disk' => [
            'driver' => 'database',
            'connection' => env('DB_CONNECTION', 'mysql'),
            'files_table' => 'files',
            'contents_table' => 'files_contents',
            'hash_algo' => 'sha256',
            'path_prefix' => '',
        ]
    ],
];

Use storage disk

To use the custom disk profile, use the disk() method on the Storage facade.

use Illuminate\Support\Facades\Storage;
 
Storage::disk('my_disk')->put('example.txt', 'Contents');

See Laravel documentationopen in new window for additional examples on how to use custom disk profiles.

Outside Laravel

The database adapter uses Laravel's Database packageopen in new window as means of performing queries. This means that you will need to establish a connection to your database, using Laravel's connection Manager. But before you do that, you will need to create appropriate table schema required by the adapter.

Choose your database driver and create the required tables. Feel free to change the table names to whatever you see fit.

SQL Generator

The shown SQL is generated via a small binary helper in this package.

Run ./vendor/aedart/athenaeum-flysystem-db/bin/table_schemas.

SQLite

create table "files" ("id" integer not null primary key autoincrement, "type" varchar check ("type" in ('dir', 'file')) not null, "path" varchar not null, "level" integer not null default '0', "file_size" integer not null default '0', "mime_type" varchar, "visibility" varchar check ("visibility" in ('public', 'private')) not null default 'private', "content_hash" varchar, "last_modified" integer not null default '0', "extra_metadata" text)

create index "files_path_index" on "files" ("path")

create index "files_path_level_index" on "files" ("path", "level")

create index "files_content_hash_index" on "files" ("content_hash")

create unique index "files_path_unique" on "files" ("path")

create table "file_contents" ("id" integer not null primary key autoincrement, "hash" varchar not null, "reference_count" integer not null default '0', "contents" blob not null)

create index "file_contents_hash_index" on "file_contents" ("hash")

create unique index "file_contents_hash_unique" on "file_contents" ("hash")

MySQL / MariaDB

create table `files` (`id` bigint unsigned not null auto_increment primary key, `type` enum('dir', 'file') not null comment 'Whether this is a file or directory', `path` varchar(255) not null comment 'Unique path of file or directory', `level` smallint unsigned not null default '0' comment 'Depth level', `file_size` bigint not null default '0' comment 'Filesize in bytes', `mime_type` varchar(127) null comment 'File media type / mimetype', `visibility` enum('public', 'private') not null default 'private' comment 'File or directory visibility', `content_hash` varchar(128) null comment 'Hash of file content', `last_modified` bigint not null default '0' comment 'Unix timestamp of when file or directory was last modified', `extra_metadata` json null comment 'Evt. custom extra meta data about file or directory') default character set utf8mb4 collate 'utf8mb4_unicode_ci'

alter table `files` add index `files_path_index`(`path`)

alter table `files` add index `files_path_level_index`(`path`, `level`)

alter table `files` add index `files_content_hash_index`(`content_hash`)

alter table `files` add unique `files_path_unique`(`path`)

create table `file_contents` (`id` bigint unsigned not null auto_increment primary key, `hash` varchar(128) not null comment 'Hash of file content', `reference_count` int not null default '0' comment 'Amount of files that references this content', `contents` blob not null comment 'File contents') default character set utf8mb4 collate 'utf8mb4_unicode_ci'

alter table `file_contents` add index `file_contents_hash_index`(`hash`)

alter table `file_contents` add unique `file_contents_hash_unique`(`hash`)

PostgreSQL

create table "files" ("id" bigserial primary key not null, "type" varchar(255) check ("type" in ('dir', 'file')) not null, "path" varchar(255) not null, "level" smallint not null default '0', "file_size" bigint not null default '0', "mime_type" varchar(127) null, "visibility" varchar(255) check ("visibility" in ('public', 'private')) not null default 'private', "content_hash" varchar(128) null, "last_modified" bigint not null default '0', "extra_metadata" json null)

create index "files_path_index" on "files" ("path")

create index "files_path_level_index" on "files" ("path", "level")

create index "files_content_hash_index" on "files" ("content_hash")

alter table "files" add constraint "files_path_unique" unique ("path")

create table "file_contents" ("id" bigserial primary key not null, "hash" varchar(128) not null, "reference_count" integer not null default '0', "contents" bytea not null)

create index "file_contents_hash_index" on "file_contents" ("hash")

alter table "file_contents" add constraint "file_contents_hash_unique" unique ("hash")

SQL Server

create table "files" ("id" bigint identity primary key not null, "type" nvarchar(255) check ("type" in (N'dir', N'file')) not null, "path" nvarchar(255) not null, "level" smallint not null default '0', "file_size" bigint not null default '0', "mime_type" nvarchar(127) null, "visibility" nvarchar(255) check ("visibility" in (N'public', N'private')) not null default 'private', "content_hash" nvarchar(128) null, "last_modified" bigint not null default '0', "extra_metadata" nvarchar(max) null)

create index "files_path_index" on "files" ("path")

create index "files_path_level_index" on "files" ("path", "level")

create index "files_content_hash_index" on "files" ("content_hash")

create unique index "files_path_unique" on "files" ("path")

create table "file_contents" ("id" bigint identity primary key not null, "hash" nvarchar(128) not null, "reference_count" int not null default '0', "contents" varbinary(max) not null)

create index "file_contents_hash_index" on "file_contents" ("hash")

create unique index "file_contents_hash_unique" on "file_contents" ("hash")

New Adapter Instance

Depending on your database, a different configuration will be required. You can find available connection configuration in Laravel's example configuration fileopen in new window.

use Aedart\Flysystem\Db\Adapters\DatabaseAdapter;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\Flysystem\Filesystem;

// Establish database connection
$capsule = new Capsule;
$capsule->addConnection([
    'driver' => 'mysql',
    'host' => 'localhost',
    'database' => 'database',
    'username' => 'root',
    'password' => 'password',
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix' => '',
]);

$connection = $capsule->getConnection();

// Create Database Adapter instance
$adapter = new DatabaseAdapter(
    filesTable: 'files',
    contentsTable: 'files_contents',
    connection: $connection
);

// Finally, create filesystem instance
$filesystem = new Filesystem($adapter);