marktaborosi/storage-navigator

A simple lightweight universal storage/file browser and navigator library with rendering options.

2.1.0 2025-01-05 17:34 UTC

This package is auto-updated.

Last update: 2025-03-05 17:59:54 UTC


README

Author Latest Version Software License Downloads php 8.2+

Table of Contents

Storage Navigator

A simple, lightweight, and universal storage/file browser and navigator library with rendering options.

This library allows accessing various storage systems via adapters and rendering their contents using different renderers. It supports navigating and displaying storage contents across various platforms, including FTP, SFTP, local filesystems, and more.

Supported Adapters

Adapters are the backbone of the Storage Navigator library, enabling seamless integration with various storage systems. They act as abstraction layers that standardize communication with diverse storage backends, such as local file systems, cloud storage, FTP servers, and more. By decoupling the specific implementation details of storage systems, adapters ensure a unified interface for interacting with files and directories, regardless of the underlying storage type.

Adapters allow developers to effortlessly navigate, manage, and interact with storage systems, making the library versatile and adaptable to a wide range of use cases.

For advanced requirements, custom adapters can be implemented using the StorageNavigatorAdapterInterface, providing the flexibility to extend functionality and support additional storage platforms while maintaining compatibility with the library's architecture.

  • Flysystem: Provides integration with the League\Flysystem library for a unified filesystem interface. The following Flysystem adapters are currently available:

    • Local: Accesses and interacts with local file systems.
    • Dropbox: Provides access to Dropbox storage.
    • Amazon S3 (AWS): Enables integration with Amazon S3 for cloud storage. Has AsyncAws too.
    • Azure Blob: Provides access to Microsoft Azure Blob Storage, allowing interaction with objects stored in Azure's cloud-based storage service.
    • FTP: Allows FTP connections for navigating and managing files on FTP servers using the built-in PHP ftp_connect function.
    • SFTP: Secure FTP connections to remote servers via SSH, utilizing the phpseclib3\Net\SFTP library for advanced secure file transfers.
    • MongoDB GridFS: Allows interaction with MongoDB's GridFS, a specification for storing large files in MongoDB, enabling streaming of large files.
    • Rackspace: Connects with Rackspace cloud storage for file management in cloud environments.
    • Google Drive: Provides access to Google Drive for cloud file management, allowing seamless interaction with Google’s storage.
    • GitLab: Accesses files stored on GitLab, a web-based Git repository manager, for managing repository data and artifacts.
    • WebDAV: Enables file interactions with WebDAV-compatible servers for remote file management.
    • InMemory: This adapter keeps the filesystem completely in memory, which is useful when you need a filesystem without persistence.
  • FTP Adapter: Uses PHP's built-in ftp_connect function for connecting and navigating FTP servers. Ideal for legacy FTP setups.

  • SFTP Adapter: Establishes secure FTP connections to remote servers using the phpseclib3\Net\SFTP class, supporting robust SSH-based file transfers.

  • Native Adapter: Leverages PHP's built-in scandir function for accessing and interacting with local file systems. Suitable for basic filesystem navigation.

  • Unified Archive Adapter: Provides access to various archive types using the wapmorgan\UnifiedArchive library. This includes support for:

    • .zip
    • .tar
    • .tar.gz
    • .tar.bz2
    • .tar.xz
    • .rar
    • .7z
    • .gzip
    • .xz
    • .lzma
    • .iso
    • .ar
    • .cpio
  • ZIP Archive Adapter: Utilizes PHP's ZipArchive class to interact with and manage .zip archives, offering a convenient way to work with compressed files.

  • Null Adapter: A placeholder adapter that does nothing, useful for debugging or testing without requiring actual storage interactions.

Supported Renderers

A Renderer is a crucial component in the Storage Navigator library, responsible for transforming the raw data collected by the adapters into a visually interpretable format. Renderers determine how the storage contents, such as files and directories, are displayed to the user, whether in a web browser, a command-line interface, or a debugging environment. Each renderer is tailored to a specific context, providing the necessary features and styling to meet diverse usage scenarios. By decoupling the rendering logic from data retrieval, Storage Navigator ensures maximum flexibility and adaptability across different platforms and environments.

For advanced scenarios, you can implement a custom renderer by utilizing the StorageNavigatorRendererInterface, which defines the necessary methods and structure for creating a tailored rendering solution. This allows developers to seamlessly integrate unique rendering logic that aligns with their application's requirements, while maintaining compatibility with the Storage Navigator ecosystem.

  • HTML Renderer: A fully-featured renderer designed for browsers, with support for various themes and file navigation options.
  • Console Renderer: A simple CLI-based renderer for listing files, without navigation support.
  • Null Renderer: A placeholder renderer, useful for debugging or specific use cases.

Installation

You can install Storage Navigator via Composer:

composer require marktaborosi/storage-navigator

Usage

Below are examples of how to use Storage Navigator with different adapters and renderers.

Native Adapter Example

use Marktaborosi\StorageNavigator\Adapters\PHPNativeAdapter;
use Marktaborosi\StorageNavigator\Builders\FileStructureFilterBuilder;
use Marktaborosi\StorageNavigator\Renderers\Config\HtmlRendererConfig;
use Marktaborosi\StorageNavigator\Renderers\HtmlRenderer;
use Marktaborosi\StorageNavigator\StorageNavigator;

// Create a native PHP adapter for filesystem operations
$adapter = new PHPNativeAdapter();

// Configure HTML renderer settings
$config = new HtmlRendererConfig([
    'date_format' => "Y-m-d H:i:s", // Set the format for displaying timestamps
]);

// Create an HTML renderer with a custom theme and options
$renderer = new HtmlRenderer(
    themePath: "basic-mac", // Set the theme path for styling
    config: $config, // Pass the renderer configuration
    disableNavigation: false, // Enable directory navigation
    disableFileDownload: false, // Allow file downloads
);

// Configure a filter to display only files
// Note: Additional filters can be applied using methods on $filterBuilder if needed
$filterBuilder = new FileStructureFilterBuilder();
$filterBuilder
    ->isFile() // Filter entries to include only files
    ->nameContains("my_name"); // Match files containing the specified name 

// Initialize the StorageNavigator with the configured components
$navigator = new StorageNavigator(
    adapter: $adapter, // Pass the PHP native filesystem adapter
    renderer: $renderer, // Pass the HTML renderer
    rootPath: __DIR__ . "/storage/", // Set the root directory to browse
    filterBuilder: $filterBuilder, // Apply the configured file filter
);

// Display the file structure in the browser
$navigator->display();

Flysystem Adapter with Local Adapter Example

For detailed information on Flysystem, its adapters, and usage, please refer to the Flysystem Documentation.

// Define the local filesystem adapter from league for the storage directory. 
$localAdapter = new LocalFilesystemAdapter(__DIR__ . "/storage/");
$filesystem = new Filesystem($localAdapter);

// Create a Flysystem adapter for use with StorageNavigator
$adapter = new FlysystemAdapter($filesystem);

// Configure the HTML renderer with specific settings
$config = new HtmlRendererConfig([
    'date_format' => "M d Y H:i", // Define date format for file timestamps
]);

// Create the HTML renderer with a specific theme and options
$renderer = new HtmlRenderer(
    themePath: 'console-midnight-commander2', // Set theme path
    config: $config, // Pass configuration
    disableNavigation: false, // Enable navigation
    disableFileDownload: false // Enable file downloads
);

// Configure filtering options for the file structure
// Note: Additional filters can be applied using methods on $filterBuilder if needed
$filterBuilder = new FileStructureFilterBuilder();
$filterBuilder
    ->isFile() // Filter to include only file entries
    ->nameContains('my_name.pdf'); // Match files containing the specified name

// Initialize the StorageNavigator with configured components
$navigator = new StorageNavigator(
    adapter: $adapter, // Pass the filesystem adapter
    renderer: $renderer, // Pass the HTML renderer
    rootPath: "", // Set the root path for the navigator
    filterBuilder: $filterBuilder, // Apply the configured filter builder
);

// Display the file structure in the browser
$navigator->display();

FTP Adapter Example

use Marktaborosi\StorageNavigator\Adapters\FTP\FtpConnection;
use Marktaborosi\StorageNavigator\Adapters\FtpAdapter;
use Marktaborosi\StorageNavigator\Builders\FileStructureFilterBuilder;
use Marktaborosi\StorageNavigator\Renderers\Config\HtmlRendererConfig;
use Marktaborosi\StorageNavigator\Renderers\HtmlRenderer;
use Marktaborosi\StorageNavigator\StorageNavigator;

// Create an FTP adapter for connecting to the FTP server
$adapter = new FtpAdapter(new FtpConnection());
$adapter->initialize(
    'test.rebex.net', // FTP server host
    'demo', // Username for authentication
    'password', // Password for authentication
    21, // FTP server port
    "/" // Initial directory path on the FTP server
);

// Configure HTML renderer settings
$config = new HtmlRendererConfig([
    'date_format' => "Y-m-d H:i:s", // Set the format for displaying file timestamps
]);

// Create an HTML renderer with a custom theme and options
$renderer = new HtmlRenderer(
    themePath: "basic-norton", // Set the theme path for styling
    config: $config, // Pass the renderer configuration
    disableNavigation: false, // Enable directory navigation
    disableFileDownload: false // Allow file downloads
);

// Configure filtering options for the file structure (optional)
// Note: Additional filters can be applied using methods on $filterBuilder if needed
$filterBuilder = new FileStructureFilterBuilder();
$filterBuilder->isFile(); // Shows only files

// Initialize the StorageNavigator with the configured components
$navigator = new StorageNavigator(
    adapter: $adapter, // Pass the FTP adapter
    renderer: $renderer, // Pass the HTML renderer
    rootPath: "", // Set the root directory to browse
    filterBuilder: $filterBuilder, // Apply the configured file filter
);

// Display the file structure in the browser
$navigator->display();

SFTP Adapter Example

use Marktaborosi\StorageNavigator\Adapters\SftpAdapter;
use Marktaborosi\StorageNavigator\Builders\FileStructureFilterBuilder;
use Marktaborosi\StorageNavigator\Renderers\Config\HtmlRendererConfig;
use Marktaborosi\StorageNavigator\Renderers\HtmlRenderer;
use Marktaborosi\StorageNavigator\StorageNavigator;

// Create an SFTP adapter for connecting to the SFTP server
$adapter = new SftpAdapter(
    'test.rebex.net',   // SFTP server address
    'demo',             // SFTP username
    'password',         // SFTP password
    22,                 // SFTP port (default 22)
    ""                  // Initial directory to browse
);

// Configure HTML renderer settings
$config = new HtmlRendererConfig([
    'date_format' => "Y-m-d H:i:s", // Define the date format for displaying timestamps
]);

// Create an HTML renderer with a custom theme and options
$renderer = new HtmlRenderer(
    themePath: "basic-norton", // Specify the theme path for styling
    config: $config, // Apply the renderer configuration
    disableNavigation: false, // Allow navigation between directories
    disableFileDownload: false // Enable file downloads
);

// Configure filtering options for the file structure (optional)
// Note: Additional filters can be applied using methods on $filterBuilder if needed
$filterBuilder = new FileStructureFilterBuilder();
$filterBuilder->isFile(); // Include only files in the displayed structure

// Initialize the StorageNavigator with the configured components
$navigator = new StorageNavigator(
    adapter: $adapter, // Pass the SFTP adapter
    renderer: $renderer, // Pass the HTML renderer
    rootPath: "", // Set the root directory to browse
    filterBuilder: $filterBuilder, // Apply the configured file filter
);

// Display the file structure in the browser
$navigator->display();

Unified Archive Adapter Example

use Marktaborosi\StorageNavigator\Adapters\UnifiedArchiveAdapter;
use Marktaborosi\StorageNavigator\Builders\FileStructureFilterBuilder;
use Marktaborosi\StorageNavigator\Renderers\Config\HtmlRendererConfig;
use Marktaborosi\StorageNavigator\Renderers\HtmlRenderer;
use Marktaborosi\StorageNavigator\StorageNavigator;

// Create a ZIP archive adapter to interact with the specified archive
$adapter = new UnifiedArchiveAdapter(__DIR__ . "/storage/zips/1mb-fake-sample.zip");

// Configure HTML renderer settings
$config = new HtmlRendererConfig([
    'date_format' => "Y-m-d H:i:s", // Define the format for displaying timestamps
]);

// Create an HTML renderer with a custom theme and options
$renderer = new HtmlRenderer(
    themePath: "basic-mac", // Specify the theme path for styling
    config: $config, // Apply the renderer configuration
    disableNavigation: false, // Allow directory navigation
    disableFileDownload: false // Enable file downloads
);

// Configure a filter to display only files
// Note: Additional filters can be applied using methods on $filterBuilder if needed
$filterBuilder = new FileStructureFilterBuilder();
$filterBuilder
    ->isFile(); // Include only files in the displayed structure

// Initialize the StorageNavigator with the configured components
$navigator = new StorageNavigator(
    adapter: $adapter, // Pass the archive adapter
    renderer: $renderer, // Pass the HTML renderer
    rootPath: "", // Set the root directory to browse
    filterBuilder: $filterBuilder, // Apply the configured file filter
);

// Display the file structure in the browser
$navigator->display();

ZIP Archive Adapter Example

use Marktaborosi\StorageNavigator\Adapters\ZipArchiveAdapter;
use Marktaborosi\StorageNavigator\Builders\FileStructureFilterBuilder;
use Marktaborosi\StorageNavigator\Renderers\Config\HtmlRendererConfig;
use Marktaborosi\StorageNavigator\Renderers\HtmlRenderer;
use Marktaborosi\StorageNavigator\StorageNavigator;

// Create a ZIP archive adapter to interact with the specified archive
try {
    $adapter = new ZipArchiveAdapter(__DIR__ . "/storage/zips/1mb-fake-sample.zip");
} catch (Exception $e) {
    die($e); // Terminate execution if the ZIP archive cannot be accessed
}

// Configure HTML renderer settings
$config = new HtmlRendererConfig([
    'date_format' => "Y-m-d H:i:s", // Define the format for displaying timestamps
]);

// Create an HTML renderer with a custom theme and options
$renderer = new HtmlRenderer(
    themePath: "basic-mac", // Specify the theme path for styling
    config: $config, // Apply the renderer configuration
    disableNavigation: false, // Allow directory navigation
    disableFileDownload: false // Enable file downloads
);

// Configure a filter to display only files
// Additional filters can be applied using methods on $filterBuilder if needed
$filterBuilder = new FileStructureFilterBuilder();
$filterBuilder
    ->isFile(); // Include only files in the displayed structure

// Initialize the StorageNavigator with the configured components
// Note: Additional filters can be applied using methods on $filterBuilder if needed
$navigator = new StorageNavigator(
    adapter: $adapter, // Pass the archive adapter
    renderer: $renderer, // Pass the HTML renderer
    rootPath: "", // Set the root directory to browse
    filterBuilder: $filterBuilder, // Apply the configured file filter
);

// Display the file structure in the browser
$navigator->display();

Renderers

HTML Renderer

Configuration

You can configure various options for the file browser, such as:

  • date_format: The format for displaying file modification dates. This follows the same format as PHP's date() function. For example, Y-m-d H:i:s would display dates as 2024-01-01 15:30:00.

Themes

HTML Renderer has navigation and file download support. Each theme provides a different look and feel for the file browser.

Below are some screenshots of the available themes:

basic-dark

basic-dark

basic-light

basic-light

basic-mac

basic-mac

basic-norton

basic-norton

basic-terminal

basic-terminal

console-hacker

console-hacker

console-midnight-commander

console-midnight-commander

console-norton-commander

console-norton-commander

console-norton-commander

bootstrap-mason-light

Console Renderer

Important! The Console renderer does not have navigation functionality.

To use the Console Renderer in a CLI environment, you can instantiate it as follows:

// Create renderer
$renderer = new \Marktaborosi\StorageNavigator\Renderers\ConsoleRenderer();

It looks structurally similar to a Windows DIR command:

console-renderer

File Structure Filtering

The FileStructureFilterBuilder class is a utility for constructing filters to navigate and filter file and directory structures. It allows fine-grained control over what files or directories are displayed by applying various filtering criteria.

Usage

The FileStructureFilterBuilder provides a fluent interface to add filters. Each filter can narrow down the results based on file or directory attributes such as name, type, or extension.

Note: Currently, all filters are combined using a logical "AND" operation. Logical expressions such as "OR" or grouped conditions are under development.

Filtering Options

1. Filter by Type

  • isFile()

    • Includes only files in the results.
    • Example:
      $filterBuilder->isFile();
  • isDirectory()

    • Includes only directories in the results.
    • Example:
      $filterBuilder->isDirectory();

2. Filter by Name

  • nameEquals(string|array $filenames)

    • Includes files or directories whose names match the given values exactly.
    • Example:
      $filterBuilder->nameEquals(['file1.txt', 'file2.log']);
  • nameNotEquals(string|array $filenames)

    • Excludes files or directories whose names match the given values.
    • Example:
      $filterBuilder->nameNotEquals('example.txt');
  • nameContains(string|array $substrings)

    • Includes files or directories whose names contain any of the specified substrings.
    • Example:
      $filterBuilder->nameContains(['log', 'data']);
  • nameNotContains(string|array $substrings)

    • Excludes files or directories whose names contain any of the specified substrings.
    • Example:
      $filterBuilder->nameNotContains(['tmp', 'backup']);

3. Filter by File Extension

(Applies only to files.)

  • extensionEquals(string|array $extensions)

    • Includes files whose extensions match the given values.
    • Example:
      $filterBuilder->extensionEquals(['txt', 'log']);
  • extensionNotEquals(string|array $extensions)

    • Excludes files whose extensions match the given values.
    • Example:
      $filterBuilder->extensionNotEquals('exe');
  • extensionContains(string|array $substrings)

    • Includes files whose extensions contain any of the specified substrings.
    • Example:
      $filterBuilder->extensionContains('gz');
  • extensionNotContains(string|array $substrings)

    • Excludes files whose extensions contain any of the specified substrings.
    • Example:
      $filterBuilder->extensionNotContains('tmp');

4. Combining Filters

All filters are combined with a logical "AND" operation. This means that only files or directories that meet all the specified conditions will be included.

Example:

To include only .txt files whose names contain log:

$filterBuilder
    ->isFile()
    ->nameContains('log')
    ->extensionEquals('txt');

Retrieving the Filters

Once all filters are configured, you can retrieve them using the getFilters() method. The filters are returned as an array of callables that can be applied to entries in the file structure.

$filters = $filterBuilder->getFilters();

Creating Your Own Adapter

The StorageNavigatorAdapterInterface provides a contract for creating custom adapters in the Storage Navigator library. Adapters are responsible for interacting with various storage backends, such as local file systems, SFTP servers, or cloud storage solutions, and translating their structure and operations into a standardized format for the Storage Navigator.

This guide outlines the steps to implement your own adapter.

1. Understanding the StorageNavigatorAdapterInterface

The StorageNavigatorAdapterInterface defines three core methods:

  • fileOrDirectoryExists(string $location): bool
    Checks if a file or directory exists at the specified location.

  • getFileStructure(string $location): FileStructure
    Retrieves the structure of files and directories at a given location, returning a FileStructure object.

  • downloadFile(string $filePath): void
    Handles the downloading of a specified file, typically sending it to the client.

2. Steps to Implement a Custom Adapter

Step 1: Create a New Class

Start by creating a class that implements the StorageNavigatorAdapterInterface.

namespace YourNamespace;

use Marktaborosi\StorageNavigator\Entities\FileStructure;
use Marktaborosi\StorageNavigator\Interfaces\StorageNavigatorAdapterInterface;

class YourCustomAdapter implements StorageNavigatorAdapterInterface
{
    public function fileOrDirectoryExists(string $location): bool
    {
        // Implement your logic here
    }

    public function getFileStructure(string $location): FileStructure
    {
        // Implement your logic here
    }

    public function downloadFile(string $filePath): void
    {
        // Implement your logic here
    }
}

Step 2: Implement the fileOrDirectoryExists Method

This method determines if a file or directory exists at the specified location.
For example, in a cloud storage adapter, you might query the storage API:

public function fileOrDirectoryExists(string $location): bool
{
    // Example: Check existence in a cloud storage system
    return $this->apiClient->exists($location);
}

For local file systems, you can use PHP's file_exists function:

public function fileOrDirectoryExists(string $location): bool
{
    return file_exists($location);
}

Step 3: Implement the getFileStructure Method

This method retrieves the structure of a directory and returns it as a FileStructure object. You can use the FileStructureBuilder class to construct the structure.

Example for a local file system:

use Marktaborosi\StorageNavigator\Builders\FileStructureBuilder;
use Marktaborosi\StorageNavigator\Entities\DirectoryAttribute;
use Marktaborosi\StorageNavigator\Entities\FileAttribute;
use Marktaborosi\StorageNavigator\Entities\FileStructure;

public function getFileStructure(string $location): FileStructure
{
    $entries = scandir($location);
    $structureBuilder = new FileStructureBuilder();

    foreach ($entries as $entry) {
        $path = $location . DIRECTORY_SEPARATOR . $entry;

        if ($entry === '.' || $entry === '..') {
            continue;
        }

        if (is_dir($path)) {
            $structureBuilder->addDirectory(new DirectoryAttribute(
                name: $entry,
                path: $path,
                lastModified: filemtime($path)
            ));
        } else {
            $structureBuilder->addFile(new FileAttribute(
                directoryPath: dirname($path),
                filename: $entry,
                extension: pathinfo($path, PATHINFO_EXTENSION),
                byteSize: filesize($path),
                lastModified: filemtime($path)
            ));
        }
    }

    return $structureBuilder->sortByAZ()->build();
}

Step 4: Implement the downloadFile Method

The downloadFile method handles file downloading. This typically involves sending the file's contents to the client with appropriate HTTP headers.

Example:

public function downloadFile(string $filePath): void
{
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
    header('Content-Length: ' . filesize($filePath));
    readfile($filePath);
}

3. Example: Minimal Adapter

Here's a minimal example of an adapter for a custom storage system:

namespace YourNamespace;

use Marktaborosi\StorageNavigator\Entities\FileStructure;
use Marktaborosi\StorageNavigator\Interfaces\StorageNavigatorAdapterInterface;

class CustomStorageAdapter implements StorageNavigatorAdapterInterface
{
    public function fileOrDirectoryExists(string $location): bool
    {
        // Example logic to check existence
        return true;
    }

    public function getFileStructure(string $location): FileStructure
    {
        // Example: Return an empty FileStructure
        return new FileStructure([]);
    }

    public function downloadFile(string $filePath): void
    {
        // Example: Serve a static file
        header('Content-Type: text/plain');
        echo "File contents for {$filePath}";
    }
}

4. Advanced Customization

For complex storage systems, consider:

  • Using APIs: Integrate with APIs provided by cloud storage platforms like AWS S3, Google Drive, or Azure Blob Storage.
  • Authentication: Implement secure connections using authentication tokens, SSH keys, or API keys.
  • Error Handling: Handle cases where files or directories are missing, permissions are restricted, or connections fail.

5. Testing Your Adapter

Test your adapter thoroughly with:

  • Different file structures, including deeply nested directories.
  • Edge cases like empty directories or invalid paths.
  • File downloads of various sizes and types.

By following these steps, you can create a custom adapter that integrates seamlessly with the Storage Navigator library and provides access to your desired storage backend.

Creating Your Own Renderer

The StorageNavigatorRendererInterface defines a flexible and extensible contract for creating custom renderers in the Storage Navigator library. Renderers are responsible for displaying the data fetched by adapters in a desired format, whether as an HTML page, CLI output, or any other custom view.

This guide walks you through the process of implementing your own custom renderer.

1. Understanding the StorageNavigatorRendererInterface

The StorageNavigatorRendererInterface contains two core methods you need to implement:

  • render(RenderData $data): void
    This method is responsible for generating and displaying the output based on the provided RenderData. You can customize the way data is displayed, such as creating HTML pages, console output, or even JSON responses.

  • navigationHandler(): StorageNavigatorNavigationHandlerInterface
    This method provides a navigation handler to process navigation-related actions, like changing directories or downloading files.

2. Steps to Implement a Custom Renderer

Step 1: Create a New Class

Start by creating a class that implements the StorageNavigatorRendererInterface.

namespace YourNamespace;

use Marktaborosi\StorageNavigator\Interfaces\StorageNavigatorRendererInterface;
use Marktaborosi\StorageNavigator\Interfaces\StorageNavigatorNavigationHandlerInterface;
use Marktaborosi\StorageNavigator\Renderers\Entities\RenderData;

class YourCustomRenderer implements StorageNavigatorRendererInterface
{
    public function render(RenderData $data): void
    {
        // Implement the rendering logic here
    }

    public function navigationHandler(): StorageNavigatorNavigationHandlerInterface
    {
        // Return your custom navigation handler
    }
}

Step 2: Implement the render Method

The render method receives a RenderData object, which contains the current file structure, navigation paths, and other data needed for rendering. Customize this method to output the data in your desired format.

For example, to render as JSON:

public function render(RenderData $data): void
{
    header('Content-Type: application/json');
    echo json_encode($data->getStructure()->toArray(), JSON_PRETTY_PRINT);
}

Step 3: Implement the navigationHandler Method

The navigationHandler method returns a StorageNavigatorNavigationHandlerInterface implementation. This handles navigation actions like changing directories or downloading files.

If no navigation logic is needed, you can return a NullNavigationHandler:

public function navigationHandler(): StorageNavigatorNavigationHandlerInterface
{
    return new NullNavigationHandler();
}

For custom navigation handling, create a new class implementing StorageNavigatorNavigationHandlerInterface:

use Marktaborosi\StorageNavigator\Interfaces\StorageNavigatorNavigationHandlerInterface;

class CustomNavigationHandler implements StorageNavigatorNavigationHandlerInterface
{
    public function isChangePathRequest(): bool { /* Your logic */ }
    public function isDownloadFileRequest(): bool { /* Your logic */ }
    public function changeToPath(): string { /* Your logic */ }
    public function downloadFilePath(): string { /* Your logic */ }
}

Step 4: Register and Use Your Renderer

Instantiate your custom renderer and pass it to the StorageNavigator:

use Marktaborosi\StorageNavigator\StorageNavigator;
use YourNamespace\YourCustomRenderer;

$renderer = new YourCustomRenderer();
$navigator = new StorageNavigator(
    adapter: $yourAdapter,
    renderer: $renderer,
    rootPath: '/path/to/root'
);

$navigator->display();

3. Example: Minimal Renderer

Here's a minimal example of a renderer that outputs a plain-text file list:

namespace YourNamespace;

use Marktaborosi\StorageNavigator\Interfaces\StorageNavigatorRendererInterface;
use Marktaborosi\StorageNavigator\Interfaces\StorageNavigatorNavigationHandlerInterface;
use Marktaborosi\StorageNavigator\Renderers\Entities\RenderData;
use Marktaborosi\StorageNavigator\Renderers\Navigators\NullNavigationHandler;

class PlainTextRenderer implements StorageNavigatorRendererInterface
{
    public function render(RenderData $data): void
    {
        foreach ($data->getStructure()->toArray() as $file) {
            echo $file['name'] . PHP_EOL;
        }
    }

    public function navigationHandler(): StorageNavigatorNavigationHandlerInterface
    {
        return new NullNavigationHandler();
    }
}

4. Advanced Customization

You can leverage additional tools or libraries, like Twig for templating, or integrate third-party APIs for advanced rendering. For instance:

  • Use Twig for creating dynamic and styled HTML outputs.
  • Generate downloadable CSV or PDF reports using libraries like FPDF or PhpSpreadsheet.
  • Create a REST API endpoint to serve the file structure in JSON or XML formats.

5. Testing Your Renderer

Before integrating your renderer, test it with different data sets to ensure it handles various file structures, edge cases, and error scenarios. Use the RenderData class to simulate test inputs.

By following these steps, you can create a custom renderer tailored to your application's needs while maintaining compatibility with the Storage Navigator's architecture.

Contributing

If you'd like to contribute to the project, feel free to fork the repository and submit a pull request.