Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Vfs Laravel Package

adlawson/vfs

Virtual file system for PHP using the stream wrapper API. Mount a vfs:// scheme and use built-in functions (fopen, require, file_get_contents) or filesystem libraries like Symfony/Laravel. Emulates real streams, including PHP warnings and edge cases.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package via Composer:
    composer require adlawson/vfs
    
  2. Mount the virtual filesystem in your test setup:
    use Vfs\FileSystem;
    
    $fs = FileSystem::factory('vfs://');
    $fs->mount();
    
  3. Use vfs:// as a prefix for all filesystem operations:
    file_put_contents('vfs://test.txt', 'Hello, VFS!');
    $content = file_get_contents('vfs://test.txt');
    

First Use Case: Testing File Uploads

Replace disk I/O in Laravel tests with VFS to avoid filesystem pollution:

public function test_file_upload()
{
    $fs = FileSystem::factory('vfs://');
    $fs->mount();

    Storage::fake('local');
    Storage::disk('local')->put('uploaded.txt', 'Test content');

    // Assert using VFS
    $this->assertEquals('Test content', file_get_contents('vfs://uploaded.txt'));
}

Implementation Patterns

Core Workflows

1. Node-Based Manipulation

Use Vfs\Node\Directory and Vfs\Node\File for programmatic filesystem setup:

$fs = FileSystem::factory('vfs://');
$fs->mount();

// Create a directory with files
$root = $fs->get('/');
$root->addChild(new Directory(['subdir' => new Directory(['file.txt' => new File('Content')])]));

// Access via PHP functions
file_put_contents('vfs://subdir/file.txt', 'Updated content');

2. Laravel Storage Integration

Extend Laravel’s Storage facade to use VFS:

Storage::extend('vfs', function ($app, $config) {
    $fs = FileSystem::factory('vfs://');
    $fs->mount();
    return new \Illuminate\Filesystem\FilesystemAdapter(
        new \Vfs\Adapter\StreamWrapperAdapter('vfs://'),
        'vfs',
        $config
    );
});

// Usage
Storage::disk('vfs')->put('file.txt', 'Hello');
$this->assertEquals('Hello', file_get_contents('vfs://file.txt'));

3. Dynamic Code Execution

Safely require files from VFS (avoids eval security risks):

$fs = FileSystem::factory('vfs://');
$fs->mount();

file_put_contents('vfs://dynamic.php', '<?php echo "Dynamic content";');
$result = include 'vfs://dynamic.php'; // Outputs: Dynamic content

4. Third-Party Library Compatibility

Works with Symfony’s Filesystem or Laravel’s Filesystem:

$symfonyFs = new \Symfony\Component\Filesystem\Filesystem();
$symfonyFs->mkdir('vfs://symfony_dir');

$laravelFs = new \Illuminate\Filesystem\Filesystem();
$this->assertTrue($laravelFs->exists('vfs://symfony_dir'));

Integration Tips

Testing File-Based Services

Mock Laravel’s Filesystem or Cache services:

public function test_cache_with_vfs()
{
    $fs = FileSystem::factory('vfs://');
    $fs->mount();

    Cache::store('file')->put('key', 'value');

    // Assert via VFS
    $this->assertEquals('value', file_get_contents('vfs://storage/framework/cache/data/file/key'));
}

Simulating Cloud Storage

Use VFS to mock S3 or other cloud adapters:

public function test_s3_upload()
{
    $fs = FileSystem::factory('vfs://');
    $fs->mount();

    Storage::fake('s3');
    Storage::disk('s3')->put('file.txt', 'Cloud content');

    // Assert via VFS (adjust path to match S3 adapter's local simulation)
    $this->assertEquals('Cloud content', file_get_contents('vfs://s3_file.txt'));
}

Cleanup Between Tests

Unmount the VFS after each test to avoid leaks:

public function tearDown(): void
{
    $fs = FileSystem::getInstance();
    if ($fs->isMounted()) {
        $fs->unmount();
    }
}

Gotchas and Tips

Pitfalls

1. Global State

  • Issue: Mounting the VFS globally affects all tests. Unmount after each test.
    // ❌ Bad: Mount once in setUp()
    public function setUp(): void { FileSystem::getInstance()->mount(); }
    
    // ✅ Good: Mount/unmount per test
    public function test_something()
    {
        $fs = FileSystem::factory('vfs://');
        $fs->mount();
        // ... test logic ...
        $fs->unmount();
    }
    

2. Stream Wrapper Conflicts

  • Issue: Other packages might use vfs://. Check for conflicts:
    if (!stream_wrapper_register('vfs', \Vfs\StreamWrapper::class)) {
        throw new \RuntimeException('VFS stream wrapper already registered');
    }
    

3. Laravel Storage Paths

  • Issue: Laravel’s storage_path() or public_path() won’t resolve to VFS. Use absolute vfs:// paths:
    // ❌ Fails: Uses Laravel's resolved path
    Storage::disk('local')->put('file.txt', 'Content');
    
    // ✅ Works: Uses VFS directly
    file_put_contents('vfs://file.txt', 'Content');
    

4. File Permissions

  • Issue: VFS doesn’t support permissions. Use chmod sparingly:
    // ❌ May fail silently
    chmod('vfs://file.txt', 0644);
    
    // ✅ Stick to VFS methods
    $file = new \Vfs\Node\File('Content');
    $file->setContent('Content'); // No permission handling
    

5. Symlinks and Locks

  • Issue: Not supported (see GitHub Issues). Workarounds:
    • For symlinks: Use link() with caution (may not work as expected).
    • For locks: Mock flock() in tests or use in-memory alternatives.

Debugging Tips

1. Verify Mounting

Check if the VFS is mounted:

$fs = FileSystem::getInstance();
if (!$fs->isMounted()) {
    $fs->mount();
}

2. Inspect VFS Contents

List all files/directories:

$root = FileSystem::getInstance()->get('/');
print_r($root->getChildren());

3. Handle PHP Warnings

VFS triggers warnings like real streams. Suppress or log them:

// Suppress warnings
$oldErrorHandler = set_error_handler(function () {});
file_put_contents('vfs://nonexistent', 'Content'); // No warning
restore_error_handler();

// Or log warnings
set_error_handler(function ($errno, $errstr) {
    error_log("VFS Warning: $errstr");
});

4. Test Isolation

Use unique paths per test to avoid collisions:

$fs = FileSystem::factory('vfs://unique_' . uniqid());
$fs->mount();

Extension Points

1. Custom Stream Wrapper

Extend \Vfs\StreamWrapper for custom behavior:

class CustomStreamWrapper extends \Vfs\StreamWrapper
{
    public function stream_open($path, $mode, $options, &$opened_path)
    {
        // Custom logic (e.g., logging)
        error_log("Opening $path");
        return parent::stream_open($path, $mode, $options, $opened_path);
    }
}

// Register
stream_wrapper_register('custom_vfs', CustomStreamWrapper::class);

2. Laravel Service Provider

Create a provider to auto-register VFS for testing:

// app/Providers/VfsServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Vfs\FileSystem;

class VfsServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton('vfs', function () {
            $fs = FileSystem::factory('vfs://');
            $fs->mount();
            return $fs;
        });
    }
}

3. PHPUnit Traits

Reusable VFS setup/teardown:

trait UsesVfs
{
    protected function createVfs()
    {
        $fs = FileSystem::factory('vfs://' . uniqid());
        $fs->mount();
        return $fs;
    }

    protected function tearDownVfs($fs)
    {
        $fs->unmount();
    }
}

// Usage in test
public function testSomething()
{
    $fs = $this->createVfs();
    // ... test logic ...
    $this->tear
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity