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

File Bundle Laravel Package

plumtreesystems/file-bundle

PlumtreeSystems FileBundle is a Symfony/PHP package for adding file management to applications, with bundle integration for handling uploads, storage paths, and file-related workflows so teams can avoid building custom file handling from scratch.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm what this package actually is before writing integration code. The -bundle suffix and the PlumTreeSystems vendor mean this is a Symfony bundle, not a Laravel package. As of 3.0.0 the platform floor moved significantly: PHP ≥ 8.2 and Symfony ≥ 7.2. That second constraint is the one that decides whether you can use this at all.

  1. Inspect the manifest first — it changed materially in 3.0.0:

    composer show plumtreesystems/file-bundle --all
    

    You should now see symfony/framework-bundle and symfony/http-kernel in require, and — importantly — no doctrine/orm, no knplabs/gaufrette, no gaufrette/aws-s3-adapter. Those were dropped in 3.0.0. That tells you the bundle no longer persists entities for you and no longer ships its own storage adapters; both responsibilities are now yours.

  2. Check your platform against the new floor before anything else:

    php -v
    composer why-not plumtreesystems/file-bundle 3.0.0
    

    Laravel 11/12 pull in Symfony 7.x components, but that is not the same as symfony/framework-bundle 7.2, and it is not a green light. If your host app pins an older Symfony, Composer will refuse the install — that is the honest answer, not a workaround prompt.

  3. Install in a Symfony 7.2+ context (or a scratch app):

    composer require plumtreesystems/file-bundle:^3.0
    

    Register in config/bundles.php (verify the class name against src/ — likely PlumTreeSystems\FileBundle\PlumTreeSystemsFileBundle).

  4. Discover the real config alias rather than guessing YAML keys:

    bin/console config:dump-reference <alias>
    

    The alias lives in DependencyInjection/Configuration.php. With Gaufrette gone, expect the config tree to have shrunk — the old adapter/flysystem keys may simply not exist anymore.

  5. Read in order: README.md → DependencyInjection/Configuration.php → Resources/config/services.yaml → src/ → tests/ → the 2.3.0→3.0.0 diff. With 1 star and no dependents, the source is the documentation, and the diff is the only migration guide you will get.

First use case: prove the new division of labour. Upload a file, persist your own record, write bytes through whatever storage seam the bundle now exposes, delete the record, clean up the blob. In 3.x that cleanup almost certainly does not happen automatically, so make "who deletes the file?" the first question you answer in code. Get that one flow working in a scratch app before touching a real codebase.

Implementation Patterns

Use it inside Symfony (its natural home). Inject the bundle's manager/storage service by interface so you can swap it later:

public function __construct(private FileManagerInterface $files) {}

Do not assume a Doctrine listener anymore. This is the biggest behavioural change in 3.0.0. Prior versions could plausibly wire doctrine.event_listener tags to write blobs on prePersist and delete them on postRemove; with doctrine/orm dropped, that wiring cannot exist. Grep Resources/config/services.yaml for doctrine.event_listener to confirm, but plan for the opposite: the bundle stores bytes, your application owns the lifecycle. That means explicit calls in your entity/aggregate code or an application-level listener/observer of your own:

// in your own listener, not the bundle's
public function prePersist(object $entity): void
{
    if ($entity->getUpload()) {
        $entity->setPath($this->files->store($entity->getUpload())); // bundle service
    }
}

public function postRemove(object $entity): void
{
    $this->files->delete($entity->getPath()); // you are responsible for this now
}

Code against the storage seam, and expect to supply the adapter. Gaufrette and the S3 adapter were removed, so the bundle is now either pure-local-filesystem or expects an injected PSR/Flysystem-style adapter you provide. Either way, keep your own services depending on the interface, not the concrete class — that is what lets you put S3 behind it and what makes the bundle replaceable later.

Consuming it from Laravel. Still not a drop-in. The 3.0.0 dependency cleanup genuinely improves option 2 below, because there are fewer third-party tangles to drag along — but the Symfony\Component\HttpKernel\Bundle\Bundle base class and container-compilation assumptions remain, and the Symfony 7.2 floor will not be satisfied by a Laravel app's component versions.

  1. Separate service — run a small Symfony 7.2 app exposing an HTTP endpoint your Laravel app calls. Cleanest isolation, and now it's a much smaller app to stand up.
  2. Extract the leaf classes — more viable than before. After reading src/, look for a file/storage class with no Symfony\Component\* imports and no Gaufrette imports (the latter are now gone by definition). If one exists, depend on it and bind it in a provider:
    $this->app->singleton(FileStorage::class, fn ($app) => new FileStorage(
        config('filesystems.disks.uploads.root')
    ));
    
    Verify framework-agnosticism by reading the imports, not by trying it and seeing what breaks.
  3. Reference implementation — read how it handles paths, naming and deletion, then reimplement ~50–100 lines natively with Laravel's Storage facade and a model observer. For a 1-star package this remains the highest-value option, and dropping the Gaufrette abstraction layer makes the reimplementation smaller than it was under 2.x.

Testing pattern. Point the storage at a temp directory or in-memory adapter, upload a fixture in setUp, assert the blob exists after persist, remove the record, assert the blob is gone. Since 3.x no longer guarantees the second half, this test is now testing your listener as much as the bundle — which is exactly what you want.

Gotchas and Tips

  • 3.0.0 is a hard breaking release, not a cosmetic bump. PHP 8.2, Symfony 7.2, and two dependency families removed. Treat an upgrade from 2.x as a migration project: inventory every place you relied on automatic Doctrine persistence or on a Gaufrette adapter, because those call sites now have no implementation behind them.
  • Post-upgrade orphaned blobs are near-certain. If 2.x deleted files via a Doctrine listener and 3.x does not, every delete path you owned implicitly is now a leak. Before deploying, write a reconciliation command that walks the storage directory and the DB and reports mismatches — run it read-only first.
  • Framework mismatch is still trap #1. Confirm symfony/framework-bundle in require before spending a day on missing-Bundle-class errors. Use composer why-not to get a clear answer instead of guessing at conflicts.
  • Treat the code as unaudited. 1 star, 0 dependents, a major release with removals. Read src/ for path handling, MIME validation, and any unlink/file_get_contents calls before putting user uploads through it. Sanitize filenames and validate MIME types in your layer regardless — the bundle no longer has an ORM layer to lean on for validation either.
  • Pin the exact version and commit the lock file: composer require plumtreesystems/file-bundle:3.0.0. With no downstream users and a history of major-version churn, this is not optional.
  • Config keys drift, and 3.0.0 almost certainly shrank the tree. Never copy YAML from the README — run config:dump-reference <alias> and diff it against whatever the 2.x docs showed. bin/console cache:clear after any edit; a stale container cache is the usual cause of "my new option does nothing."
  • Dangling rows vs dangling blobs. With the Doctrine integration gone you now own the failure modes too. Wrap your DB flush and storage write so a failure in one does not silently leave the other; decide explicitly whether you favour orphaned rows (safe, recoverable) or orphaned files (cheap, but permanent).
  • Upload paths and deploys. If the default path sits under var/, it is wiped by cache:clear and by most deploy scripts. Configure an absolute path outside the release directory and confirm the web-server user can write to it.
  • You now provide the dependencies. Anything that used to arrive transitively via Doctrine or Gaufrette — an S3 client, an adapter interface, an ORM — must be required and configured in your own composer.json. Expect class-not-found errors on first run if you assumed they came along for the ride.
  • Service not autoconfigured? Check Resources/config/services.yaml _defaults and whether the bundle assumes autoconfigure: true. You can add a missing tag in your own services.yaml as a workaround.
  • Extension points: decorate services (decorates:) rather than editing vendor code, override templates via templates/bundles/<BundleName>/, and grep src/ for dispatch( to find events worth subscribing to. Since the bundle now does less, there is less to extend — and correspondingly more reason to wrap it in your own thin service.
  • MIT license still applies, so forking and vendoring the relevant classes into your own namespace remains a legitimate escape hatch — and 3.0.0's slimmed dependency footprint makes a fork easier to maintain than it was under 2.x.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
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