Weave 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

Finder Laravel Package

symfony/finder

Symfony Finder offers an intuitive fluent interface for locating files and directories by name, size, modification time, and content. Chain filters, sort results, and iterate with ease using this battle-tested, standalone PHP component trusted across the Symfony ecosystem.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require symfony/finder
    

    No additional configuration is required—it’s a standalone component.

    If you are already on 8.1.x, pull in the latest patch release to pick up two fixes that affect day-to-day usage (ignoreVCSIgnored() with .git-as-a-file repos, and glob patterns with consecutive *):

    composer update symfony/finder   # resolves to >= 8.1.8
    

    Both fixes are non-breaking—no code changes required.

  2. First Use Case: Locate all PHP files in a directory and its subdirectories:

    use Symfony\Component\Finder\Finder;
    
    $finder = Finder::create()
        ->files()
        ->in(__DIR__ . '/src')
        ->name('*.php');
    
    foreach ($finder as $file) {
        echo $file->getRealPath() . "\n";
    }
    
  3. Where to Look First:


Implementation Patterns

Core Workflows

1. Basic File Discovery

// Find all files in a directory (non-recursive)
$finder = Finder::create()
    ->files()
    ->in('/path/to/dir');

// Recursive search with glob patterns
$finder = Finder::create()
    ->files()
    ->in('/path/to/dir')
    ->name('*.{php,js}');

2. Filtering by Metadata

// Files modified in the last 7 days
$finder = Finder::create()
    ->files()
    ->in('/logs')
    ->date('>1 week ago');

// Files larger than 1MB
$finder = Finder::create()
    ->files()
    ->in('/uploads')
    ->size('>1M');

3. Excluding Directories

// Exclude 'vendor' and 'node_modules'
$finder = Finder::create()
    ->files()
    ->in(__DIR__)
    ->exclude([
        'vendor',
        'node_modules',
        '*.min.js'
    ]);

4. Respecting .gitignore (VCS-aware traversal)

// Skip anything ignored by git — useful for "scan the project" commands
$finder = Finder::create()
    ->files()
    ->in(base_path())
    ->ignoreVCSIgnored(true)
    ->name('*.php');

// Keep git metadata itself out of results
$finder->ignoreVCS(true);

As of v8.1.8, repositories where .git is a file rather than a directory (git worktrees, submodule checkouts, git submodule absorbgitdirs) are correctly treated as repository roots, so ignoreVCSIgnored() returns the expected file set instead of either ignoring nothing or over-ignoring.

5. Sorting Results

// Sort by modification time (newest first)
$finder = Finder::create()
    ->files()
    ->in('/assets')
    ->sortByModifiedTime('DESC');

6. Combining with Laravel

// Use with Laravel's Storage facade (for local files)
use Illuminate\Support\Facades\Storage;

$finder = Finder::create()
    ->files()
    ->in(storage_path('app/public'))
    ->name('*.jpg');

foreach ($finder as $file) {
    $url = Storage::url($file->getRelativePathname());
    // Process URL...
}

7. Iterating Efficiently

// Process files in chunks (memory-efficient for large directories)
$finder = Finder::create()->files()->in('/large/dir');
foreach ($finder as $file) {
    // Process $file (e.g., resize images, parse logs)
}

// Get an array of paths (for batch operations)
$paths = iterator_to_array($finder, false);

Integration Tips

Artisan Commands

use Symfony\Component\Finder\Finder;
use Illuminate\Console\Command;

class OptimizeImagesCommand extends Command
{
    protected $signature = 'images:optimize';
    protected $description = 'Optimize all images in the uploads directory';

    public function handle()
    {
        $finder = Finder::create()
            ->files()
            ->in(public_path('uploads'))
            ->name('*.{jpg,png}');

        foreach ($finder as $file) {
            $this->info("Optimizing: {$file->getRelativePathname()}");
            // Use Intervention Image or similar library
        }
    }
}

Service Providers

// Register a custom Finder service
public function register()
{
    $this->app->singleton('finder', function () {
        return Finder::create()
            ->ignoreDotFiles(false) // Include hidden files
            ->ignoreUnreadableDirs(true); // Skip permission-denied dirs
    });
}

Event Listeners

// Trigger actions when files match criteria
$finder = Finder::create()
    ->files()
    ->in(storage_path('logs'))
    ->date('>1 month ago');

foreach ($finder as $file) {
    event(new LogFileFound($file));
}

Testing

// Mock Finder in unit tests
$finder = $this->createMock(Finder::class);
$finder->method('getIterator')->willReturn(new ArrayIterator([
    new SplFileInfo('/fake/path/file1.txt'),
    new SplFileInfo('/fake/path/file2.txt'),
]));

Pinning behaviour on a worktree / CI checkout

If your command relies on ignoreVCSIgnored() and CI uses shallow or worktree-style checkouts, pin symfony/finder to ^8.1.8 and assert the discovered file count in a test—that is exactly the scenario the .git-file fix targets.


Gotchas and Tips

Pitfalls

  1. Path Separators:

    • Finder normalises separators internally, but for the paths you pass in prefer base_path()/realpath() over manual concatenation:
      $finder->in(realpath(__DIR__ . '/src'));
      
  2. Hidden Files/Directories:

    • By default, Finder ignores hidden files (prefixed with .). Explicitly include them if needed:
      $finder->ignoreDotFiles(false);
      
  3. .git Can Be a File:

    • In worktrees and submodules .git is a plain file, not a directory. Before v8.1.8, ignoreVCSIgnored() could mis-identify the repository root in that layout. If your ignore-aware scans behave differently depending on checkout style, upgrade to >= 8.1.8 rather than special-casing it.
  4. Globs with Consecutive Stars:

    • Patterns like **/*.php or src/**/**/*.php could previously degrade into quadratic backtracking on pathological directory trees (v8.1.8 fixes this). Practical guidance still applies: prefer one ** per pattern and use ->path()/->notPath() for structural filters rather than stacking stars.
  5. Performance with Large Directories:

    • Avoid loading all results into memory at once. Process files iteratively:
      foreach ($finder as $file) { ... } // Better than $finder->getIterator()->toArray()
      
  6. Symlinks:

    • Finder does not follow symlinks unless you ask it to. Enable explicitly when you need to traverse linked directories:
      $finder->followLinks(); // opt-in
      
  7. Case Sensitivity:

    • On case-insensitive filesystems (e.g., Windows), glob patterns may behave unexpectedly. Use regex for precise matching:
      $finder->name('/\.php$/i'); // Case-insensitive regex
      
  8. Empty Results:

    • Finder::append() can fail silently if iterators are empty. Validate inputs:
      $finder = Finder::create()->files()->in('/nonexistent');
      if ($finder->count() === 0) {
          $this->error('No files found!');
      }
      

Debugging Tips

  1. Inspect the Iterator:

    • Convert to an array to debug:
      $files = iterator_to_array($finder, false);
      dd($files);
      
  2. Check Paths:

    • Use getRealPath() to verify absolute paths:
      $file->getRealPath(); // Resolves symlinks and relative paths
      
  3. Verify What ignoreVCSIgnored() Skipped:

    • Diff an ignore-aware finder against a plain one to see what the .gitignore rules removed—the fastest way to confirm a repository-root detection issue:
      $all = Finder::create()->files()->in($path);
      $kept = Finder::create()->files()->in($path)->ignoreVCSIgnored(true);
      // compare counts / relative pathnames
      
  4. Date Comparisons:

    • Use now() or DateTime for dynamic comparisons:
      $finder->date('>' . now()->subDays(7)->format('Y-m-d'));
      
  5. Size Units:

    • Use B, K, M, G for sizes (e.g., >1M for 1MB). Avoid raw bytes unless necessary.

Extension Points

  1. Custom Comparators:

    • Extend Symfony\Component\Finder\Comparator\ComparatorInterface for custom logic (e.g., MIME-type filtering).
  2. Event Dispatching:

    • Wrap Finder in a class to dispatch events (e.g., FileFound, SearchComplete):
      class EventfulFinder
      {
          public function find()
          {
              $finder = Finder::create()->files()->in($this->path);
              foreach ($finder as $file) {
                  event(new FileFound($file));
              }
          }
      }
      
  3. Laravel Facade:

    • Create a facade for consistency:
      // app/Facades/Finder.php
      namespace App\Facades;
      use Illuminate\Support\Facades\Facade;
      class Finder extends Facade { protected static function getFacadeAccessor() { return 'finder'; } }
      
      Register in AppServiceProvider:
      $this->app->bind('finder', function () {
          return Finder::create()->ignoreDotFiles(false);
      });
      
  4. Caching Results:

    • Cache Finder results for performance-critical paths:
      $files = Cache::remember('finder_results', now()->addHours(1), function () {
          return iterator_to_array(Finder::create()->files()->in('/data'));
      });
      

Config Quirks

  • No Configuration File: Finder is stateless and requires no config. All options are method chained.
  • Default Exclusions: Always check for unintended exclusions (e.g., vendor, .git) in recursive searches. ignoreVCS(true) is the default; ignoreVCSIgnored() is opt-in and now repo-root aware for .git-as-a-file checkouts.
  • Patch Releases Matter: 8.1.x patch bumps have changed search results (VCS-root detection) and search cost (glob backtracking). Treat the changelog as required reading when upgrading, and run your file-discovery tests after composer update.
  • Memory Limits: For directories with millions of files, use ->limit($n) to cap results:
    $finder->limit(1000); // Process only the first 1000 files
    
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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core