marktaborosi / flysystem-filter
A lightweight filtering layer and an easy-to-use filter builder for League/Flysystem filesystem contents.
Requires
- php: >=8.2
- illuminate/support: ^11.41
- league/flysystem: ^3.29
- league/mime-type-detection: ^1.16
- nesbot/carbon: ^3.10
Requires (Dev)
- orchestra/testbench: ^9.13
- phpunit/phpunit: ^11.5
- symfony/var-dumper: ^7.2
README
Flysystem Filter is a lightweight and intuitive filtering layer for League/Flysystem. It provides an easy-to-use FilterBuilder
for logical and chainable filtering of filesystem contents (DirectoryListing
).
Features
- Simple Filtering: Filter filesystem contents without writing complex callback functions.
- Logical Expressions: Combine conditions using
and()
,or()
,group_start()
, andgroup_end()
. - Chainable API: Build complex filters with a readable, chainable syntax.
- Integration with Flysystem: Works seamlessly with League/Flysystem's
DirectoryListing
.
Installation
Install via Composer:
composer require marktaborosi/flysystem-filter
Usage
Simple Example
Here's a basic example that filters only files:
use League\Flysystem\Filesystem; use League\Flysystem\Local\LocalFilesystemAdapter; use Marktaborosi\FlysystemFilter\FilterBuilder; use Marktaborosi\FlysystemFilter\FlysystemFilter; require 'vendor/autoload.php'; $adapter = new LocalFilesystemAdapter(__DIR__ . '/tests/Storage/'); $flysystem = new Filesystem($adapter); $flysystemContents = $flysystem->listContents('', true); $filter = new FilterBuilder(); $filter->isFile(); $flysystemFilter = new FlysystemFilter(); $filteredResults = $flysystemFilter->filter($flysystemContents, $filter); foreach ($filteredResults as $result) { echo $result->path() . PHP_EOL; }
Advanced Example
Filter files with advanced conditions:
$filter = new FilterBuilder(); $filter ->extensionEquals(['txt', 'log']) ->and() ->isPublic() ->and() ->sizeLt('1G'); $flysytemFilter = new FlysystemFilter(); $filteredResults = $flysystemFilter->filter($flysystemContents, $filter);
Using Grouping and Logical Operators
You can group conditions to create complex expressions:
$filter = new FilterBuilder(); $filter ->group_start() ->extensionContains(['log', 'txt']) ->and() ->isFile() ->group_end() ->or() ->pathMatchesRegex('/debug/'); $flysytemFilter = new FlysystemFilter(); $filteredResults = $flysystemFilter->filter($flysystemContents, $filter);
Laravel Integration
From v3.0.0, Flysystem Filter ships with native Laravel support — including a Service Provider and a Facade — for seamless integration into your Laravel projects.
Installation
If installed via Composer in a Laravel application, the package will be automatically discovered thanks to Laravel's package auto-discovery.
composer.json (auto-discovery config — already included in this package):
{ "extra": { "laravel": { "providers": [ "Marktaborosi\\FlysystemFilter\\Laravel\\FlysystemFilterServiceProvider" ], "aliases": { "FlysystemFilter": "Marktaborosi\\FlysystemFilter\\Laravel\\FlysystemFilterFacade" } } } }
If you have disabled auto-discovery, register them manually in config/app.php
:
'providers' => [ Marktaborosi\FlysystemFilter\Laravel\FlysystemFilterServiceProvider::class, ], 'aliases' => [ 'FlysystemFilter' => Marktaborosi\FlysystemFilter\Laravel\FlysystemFilterFacade::class, ],
Example: Using FilterBuilder
via the Facade
use Illuminate\Support\Facades\Storage; use Marktaborosi\FlysystemFilter\FilterBuilder; use FlysystemFilter; // Facade alias Route::get('/filtered-files', function () { $listing = Storage::disk('local')->listContents('', true); $builder = (new FilterBuilder()) ->isFile() ->group_start() ->filenameContains('console') ->or() ->filenameContains('file') ->group_end(); $filtered = FlysystemFilter::filter($listing, $builder); return $filtered->map(fn($i) => $i->path())->toArray(); });
Example: Using a Callable Predicate
use Illuminate\Support\Facades\Storage; use League\Flysystem\StorageAttributes; use FlysystemFilter; Route::get('/log-files', function () { $listing = Storage::disk('local')->listContents('', true); // Callable allows custom filter logic without building a `FilterBuilder` $callable = static fn(StorageAttributes $item): bool => str_ends_with($item->path(), '.log'); $filtered = FlysystemFilter::filter($listing, $callable); return $filtered->map(fn($i) => $i->path())->toArray(); });
Notes
FlysystemFilter::filter()
is now an instance method (since v3.0.0) — the Facade makes it look static in Laravel, but under the hood it is resolved from the container.- All filtering logic and method signatures remain the same as in standalone usage.
- Non-
StorageAttributes
entries in the listing are automatically skipped.
API Overview
Filtering Options
General Conditions
isFile()
: Matches file entries.isDirectory()
: Matches directory entries.
Path-Based Conditions
pathEquals($paths)
: Matches exact paths. Acceptsstring
orarray
.pathContains($substrings)
: Matches paths containing specific substrings.pathNotContains($substrings)
: Excludes paths containing any given substrings.pathMatchesRegex($pattern)
: Matches paths using a regular expression.pathStartsWith($prefixes)
: Matches paths starting with specific prefix(es).pathEndsWith($suffixes)
: Matches paths ending with specific suffix(es).
Filename-Based Conditions (excluding extension)
filenameEquals($filenames)
: Matches exact filenames (excluding extensions). Acceptsstring
orarray
.filenameNotEquals($filenames)
: Excludes filenames that match exactly.filenameContains($substrings)
: Matches filenames containing any of the substrings.filenameNotContains($substrings)
: Excludes filenames containing any of the substrings.filenameStartsWith($prefixes)
: Matches filenames starting with any of the specified prefix(es).filenameEndsWith($suffixes)
: Matches filenames ending with any of the specified suffix(es).filenameMatchesRegex($pattern)
: Matches filenames via regular expression.
Basename-Based Conditions (filename including extension)
basenameEquals($basenames)
: Matches the full filename (including extension) exactly.basenameNotEquals($basenames)
: Excludes files with exact matching basenames.basenameContains($substrings)
: Matches basenames containing any of the substrings.basenameNotContains($substrings)
: Excludes basenames containing any of the substrings.basenameStartsWith($prefixes)
: Matches basenames that start with the given prefix(es).basenameEndsWith($suffixes)
: Matches basenames that end with the given suffix(es).
Extension-Based Conditions
extensionEquals($extensions)
: Matches files with one or more exact extensions.extensionNotEquals($extensions)
: Excludes files with the specified extensions.extensionContains($substrings)
: Matches files whose extension contains any given substring.extensionNotContains($substrings)
: Excludes files whose extension contains any given substring.
Size-Based Conditions
sizeEquals($size)
: Matches files with an exact size.sizeGt($size)
: Matches files larger than a specific size.sizeGte($size)
: Matches files larger than or equal to a specific size.sizeLt($size)
: Matches files smaller than a specific size.sizeLte($size)
: Matches files smaller than or equal to a specific size.sizeBetween($min, $max)
: Matches files within a size range.
📌 Note: Size units can be specified as B
, K
, M
, G
, T
(e.g., '512K'
, '1G'
).
Date-Based Conditions
lastModifiedBefore($timestamp)
: Matches files modified before a given timestamp orCarbon
instance.lastModifiedAfter($timestamp)
: Matches files modified after a given timestamp orCarbon
instance.lastModifiedBetween($start, $end)
: Matches files modified within a date range.
Mime-Type Conditions
mimeTypeEquals($mimeTypes)
: Matches files with exact MIME types.mimeTypeNotEquals($mimeTypes)
: Excludes files with specific MIME types.mimeTypeContains($substrings)
: Matches files where the MIME type contains any substring.mimeTypeNotContains($substrings)
: Excludes files whose MIME type contains specific substrings.
📌 Note: MIME types are detected from file extensions using league/mime-type-detection
. No file contents are read.
Visibility-Based Conditions
isPublic()
: Matches files with'public'
visibility.isPrivate()
: Matches files with'private'
visibility.visibilityEquals($visibilities)
: Matches files with exact visibility values.visibilityContains($substrings)
: Matches files whose visibility string contains given substring(s).
Depth-Based Conditions
depthEquals($depth)
: Matches items with an exact directory depth.depthGt($depth)
: Matches items with a depth greater than the specified value.depthLt($depth)
: Matches items with a depth less than the specified value.
Logical Operators
and()
: Combines conditions with logical AND.or()
: Combines conditions with logical OR.group_start() / group_end()
: Groups conditions for logical precedence (like parentheses).
Requirements
- PHP 8.2 or higher
- League/Flysystem 3.29 or higher
Development
Run the tests:
composer test
Contributing
Feel free to contribute to the project by submitting issues or pull requests on GitHub.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Made with ❤️ by Mark Taborosi