VOOZH about

URL: https://deepwiki.com/hypervel/filesystem/5.1-creating-custom-drivers

⇱ Creating Custom Drivers | hypervel/filesystem | DeepWiki


Loading...
Menu

Creating Custom Drivers

This document explains how to create custom filesystem drivers and register them with the FilesystemManager. It covers implementing the required contracts, integrating with League Flysystem adapters, and optionally enabling connection pooling for custom drivers.

For general driver architecture and the base FilesystemAdapter implementation, see Driver Architecture and FilesystemAdapter. For connection pooling configuration details, see Object Pooling for Cloud Drivers. For comprehensive configuration options, see Configuration Reference.


Driver Architecture Overview

Custom drivers integrate into the system by implementing contracts and registering with the FilesystemManager through the extend() method. The architecture supports two approaches: extending the base FilesystemAdapter class or implementing contracts directly.

Contract and Registration Flow


Sources:


Required Contracts

Filesystem Contract

All drivers must implement the Filesystem interface, which defines the core storage operations. The interface requires implementation of CRUD operations, metadata retrieval, directory management, and streaming capabilities.

Method CategoryRequired MethodsPurpose
Existence Checksexists(), path()Verify file presence and resolve paths
Read Operationsget(), readStream(), readStreamRange()Retrieve file contents and streams
Write Operationsput(), putFile(), putFileAs(), writeStream()Store files and streams
Metadatasize(), lastModified(), getVisibility(), setVisibility()File attributes and permissions
Manipulationcopy(), move(), delete(), prepend(), append()File operations
Directoriesfiles(), allFiles(), directories(), allDirectories(), makeDirectory(), deleteDirectory()Directory operations

Sources:

Cloud Contract (Optional)

Drivers that provide cloud storage features should implement the Cloud interface, which extends Filesystem with URL generation capabilities:

MethodPurposeWhen Required
url()Generate public URL for fileAlways for Cloud drivers
temporaryUrl()Generate time-limited signed URLFor pre-signed download URLs
providesTemporaryUrls()Indicate temporary URL supportImplementation detail

Sources:


Registering Custom Drivers

Using the extend() Method

Custom drivers are registered with FilesystemManager::extend(), which accepts three parameters:


The creator closure receives two parameters:

  • ContainerInterface $app - The Hyperf DI container
  • array $config - Configuration array from filesystems.disks.{name}

Sources:

Registration Implementation

Registration occurs during application bootstrap, typically in a service provider or ConfigProvider. The extend() method stores the creator closure in the customCreators array and optionally adds the driver to the poolables array.

Key Code Locations:

Sources:


Extending FilesystemAdapter

The recommended approach for most custom drivers is to extend FilesystemAdapter, which provides complete implementations of the Filesystem and Cloud contracts. This approach requires only implementing driver-specific functionality.

Constructor Requirements

Custom adapters extending FilesystemAdapter must call the parent constructor with three parameters:

ParameterTypeDescription
$driverFilesystemOperatorLeague Flysystem filesystem instance
$adapterFlysystemAdapterUnderlying Flysystem adapter
$configarrayConfiguration array

Sources:

Overridable Methods

Custom drivers can override specific methods to provide specialized functionality:

MethodDefault BehaviorCommon Overrides
url()Attempts multiple URL strategiesCustom domain logic
temporaryUrl()Delegates to adapter or callbackCloud-specific signed URLs
temporaryUploadUrl()Delegates to adapterPre-signed upload endpoints
readStreamRange()Throws RuntimeExceptionPartial content support

Example: LocalFilesystemAdapter

The LocalFilesystemAdapter extends FilesystemAdapter and adds disk name tracking and signed URL serving for local files:

Example: AwsS3V3Adapter

The AwsS3V3Adapter extends FilesystemAdapter with S3 client access and specialized URL generation:

Sources:


Integration with Flysystem

Custom drivers must integrate with League Flysystem by creating appropriate adapter instances. The FilesystemManager provides the createFlysystem() method to wrap Flysystem adapters with additional functionality.

Creating Flysystem Instances


The createFlysystem() method automatically applies decorators based on configuration:

  • Read-only mode: Wraps adapter with ReadOnlyFilesystemAdapter when read-only is true
  • Path prefixing: Wraps adapter with PathPrefixedAdapter when prefix is set
  • Configuration passthrough: Passes specific config keys to Flysystem constructor

Sources:

Flysystem Adapter Examples

The built-in drivers demonstrate integration patterns:

Local Driver:

1. Create PortableVisibilityConverter with permissions
2. Create LocalAdapter with root path and visibility
3. Call createFlysystem() with adapter and config
4. Wrap in LocalFilesystemAdapter

S3 Driver:

1. Create S3Client with credentials and configuration
2. Create AwsS3PortableVisibilityConverter
3. Create S3Adapter with client, bucket, and options
4. Call createFlysystem() with adapter and config
5. Wrap in AwsS3V3Adapter with client reference

Sources:


Making Drivers Poolable

Drivers that maintain persistent connections to remote services (databases, cloud APIs, network filesystems) benefit from connection pooling in long-running processes like Swoole/Hyperf applications.

Pooling Mechanism


Sources:

Pooling Configuration

When the poolable flag is set to true during registration, the FilesystemManager wraps driver instances in FilesystemPoolProxy. The proxy uses configuration from the disk's pool array:

Configuration KeyDefaultPurpose
min_objects1Minimum pool size
max_objects10Maximum pool size
wait_timeout3.0Seconds to wait for available connection
max_idle_time60.0Seconds before idle connection is closed

Key Implementation Details:

Sources:


Complete Custom Driver Example

Example: Redis Filesystem Driver

This example demonstrates creating a custom driver that stores files in Redis, implements the Cloud contract, and supports connection pooling.


Sources:

Implementation Steps

Step 1: Implement the Flysystem Adapter

Create a Flysystem adapter implementing League\Flysystem\FilesystemAdapter:


Similar to how the S3 driver uses League\Flysystem\AwsS3V3\AwsS3V3Adapter at src/FilesystemManager.php256

Step 2: Extend FilesystemAdapter

Create your driver class that extends FilesystemAdapter and adds driver-specific functionality:


Pattern matches src/AwsS3V3Adapter.php18-31 and src/GoogleCloudStorageAdapter.php21-34

Step 3: Register with FilesystemManager

In your ConfigProvider::__invoke() or a service provider:


Registration pattern follows src/FilesystemManager.php466-479

Step 4: Configure the Disk

Add disk configuration to config/autoload/filesystems.php:


Configuration structure matches src/FilesystemManager.php417-421 and uses pool config at src/FilesystemManager.php136-141

Sources:


Advanced Customization

Custom Temporary URL Generation

Drivers can implement custom temporary URL logic without extending FilesystemAdapter by implementing the temporaryUrl() method directly, or by using the buildTemporaryUrlsUsing() method to set a callback.

The callback approach allows runtime customization:

Sources:

Custom Path Resolution

Override the path() method to customize how relative paths are resolved to absolute paths. The base implementation uses PathPrefixer:

Sources:

Direct Contract Implementation

For drivers with unique requirements that don't fit the FilesystemAdapter pattern, implement the Filesystem and optionally Cloud contracts directly. This approach provides maximum flexibility but requires implementing all contract methods.

Contract Definitions:

Sources:


Testing Custom Drivers

Assertion Methods

The FilesystemAdapter base class provides assertion methods for testing, inherited by custom drivers:

MethodPurpose
assertExists()Verify file/directory exists, optionally check content
assertMissing()Verify file/directory does not exist
assertDirectoryEmpty()Verify directory has no files

These methods use PHPUnit assertions internally and are useful for integration testing custom drivers.

Sources:

Configuration for Testing

The build() method on FilesystemManager creates on-demand disk instances useful for testing:

Sources:


Summary

Custom driver creation involves four main steps:

  1. Implement Storage Logic: Create a Flysystem adapter or extend FilesystemAdapter
  2. Register Driver: Use FilesystemManager::extend() with driver name, creator closure, and optional poolable flag
  3. Configure Disk: Add disk configuration with driver key matching your registered name
  4. Use Driver: Access via disk('name') like any built-in driver

The system automatically handles:

  • Driver resolution from configuration
  • Connection pooling for poolable drivers
  • Path prefixing and read-only decorators
  • Caching of driver instances

For drivers that maintain network connections, enabling pooling significantly improves performance in long-running Hyperf applications by reusing connections across requests.

Sources:

Refresh this wiki

On this page