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

Download Library Bundle Laravel Package

xrow/download-library-bundle

A PHP bundle for building and managing a download library. Organize downloadable files, expose them through your application, and integrate reusable library management into your existing framework.

View on GitHub
Deep Wiki
Context7

Getting Started

First, a reality check: despite the "bundle" naming and the Laravel framing of this assessment, xrow/download-library-bundle is a Symfony bundle built for the eZ Publish / eZ Platform / Ibexa ecosystem (xrow GmbH ships eZ/Ibexa extensions). It will not drop into a Laravel app. If you are on Laravel, treat this as reference material for how to build a "download all subtree images as ZIP" feature yourself; if you are on Ibexa/eZ, this is directly usable.

Minimal steps on Ibexa:

  1. composer require xrow/download-library-bundle
  2. Register the bundle:
    • Symfony Flex era: add Xrow\DownloadLibraryBundle\XrowDownloadLibraryBundle::class => ['all' => true] to config/bundles.php.
    • Legacy eZ Publish: enable in ezpublish/EzPublishKernel.php / settings/override/site.ini.append.php activation block.
  3. Clear caches: bin/console cache:clear (or php ezpublish/console cache:clear on legacy).
  4. Inspect what the bundle registered: bin/console debug:router | grep -i download and bin/console debug:container | grep -i xrow. The bundle's whole job is a controller action that walks a subtree location, collects image fields, streams a ZIP.

Where to look first, in order:

  • Resources/config/routing.yml (or routing.yaml) — the actual URL you hit.
  • The controller under Controller/ — this tells you exactly how the location ID is passed and how the ZIP is built.
  • DependencyInjection/ — parameters and service IDs you can override.
  • README.md — often thin on this package; the routing file is more truthful.

First use case: expose a "Download all images" button on a gallery/album content view. Pass the current locationId, hit the bundle's route, receive a application/zip response. Confirm it works by hitting the route directly with a known location ID in the browser before wiring up any template.

Implementation Patterns

Direct route wiring (fastest win). Fetch the route name via debug:router, then render a link from a Twig template:

<a href="{{ path('xrow_download_library_download', {'locationId': location.id}) }}">
    Download all images
</a>

Guard the link with {{ ez_is_granted('read', location) }} (or the equivalent Ibexa policy check) so users only see the button for subtrees they can read. The bundle likely does not enforce this for you.

Service-level integration (recommended for anything non-trivial). Rather than depending on the bundle's controller, inject its ZIP-building service (find the ID via debug:container) into your own controller. This buys you:

  • Ability to add a synchronous permission pre-check before any ZIP work starts.
  • Ability to customize the filename, add a manifest/README inside the ZIP, or include content metadata JSON alongside the images.
  • Ability to filter which images are included (e.g. only images above a size threshold, only images from a specific content type).

Async pattern for large subtrees. A subtree with hundreds of images will blow past PHP's max_execution_time and memory_limit if the bundle buffers the ZIP in memory. For large libraries, wrap the ZIP generation in a Symfony Messenger / eZ Platform queue job:

  1. User clicks "Prepare download".
  2. Controller dispatches a BuildDownloadZipMessage($locationId, $userId).
  3. Worker builds the ZIP to a temp/var path, records the path against the user or a token.
  4. User is notified (email, or poll via AJAX) and gets a one-time download URL.

This is the pattern that holds up in production; the synchronous route is fine for demos and small albums.

Content-view template hook. Register a content view override so the button appears automatically on your gallery content type without touching every template:

# config/packages/views.yaml
ibexa:
    system:
        default:
            content_view:
                full:
                    gallery:
                        template: '@@Acme/gallery/full.html.twig'
                        match:
                            Identifier\ContentType: gallery

Filename and content-disposition hygiene. If you wrap or reimplement the bundle, sanitize the user-facing filename (slug the location name, strip quotes and semicolons) and set Content-Disposition: attachment; filename="..." explicitly. Do not trust the location name.

Testing seam. If you need to assert behavior, target the controller via a functional test hitting the route with a fixture location, and assert the response is application/zip and that the archive opens and contains the expected number of entries. Unit-testing the ZIP internals is usually not worth it; the route is the contract.

Gotchas and Tips

The package is effectively unmaintained. Zero stars and zero dependents on a public repo is a real signal. Before adopting: read the last commit date, check it against your Symfony/Ibexa version, and be prepared to fork. Pin the exact version in composer.json and vendor the fork if you need to patch.

Version skew with eZ/Ibexa. Bundles from this era frequently reference deprecated APIs (ezpublish kernel hooks, eZ\Publish\Core\… classes that moved in Ibexa 4). If the bundle won't boot, the first thing to diff is the composer.json require constraints against your platform version — not the code.

Memory and streaming. Two distinct failure modes:

  • The bundle collects all images into an array before zipping — memory blow-up on big subtrees.
  • The bundle streams but PHP's output_buffering or an upstream proxy buffers the response, so users see a stall and then a timeout.

Mitigations: raise memory_limit and max_execution_time for the route only (via a listener), disable output buffering (ob_end_clean() before streaming), and ensure ZipArchive (php-zip) is installed — it's a common missing extension that fails silently-ish.

Image variation paths. eZ/Ibexa image fields can resolve to multiple variations (original, large, small, aliases). The bundle likely picks one alias; if you get full-size originals in the ZIP when you expected thumbnails (or vice versa), look for a configurable alias/imageVariation parameter in DependencyInjection/Configuration.php. This is the most likely config quirk you'll hit.

Permissions are your responsibility. The bundle's route is a plain Symfony route — it does not automatically inherit content read policies. If a user can guess a locationId, they can trigger a ZIP. Add a kernel.request listener or a controller wrapper that checks read on the location before dispatch, and rate-limit the endpoint (ZIP generation is CPU/IO heavy).

Routing prefix conflicts and cache. If the bundle's route path collides with an existing route, you'll see "route already exists" at cache warmup or a 404 at runtime. Override the route by redefining it under your app's routing with a prefix: /custom/download and the bundle's controller as _controller. Always cache:clear after changing bundle registration — stale route caches are the #1 "the bundle isn't working" false alarm.

Debugging a failing download. The ZIP response makes browser devtools unhelpful (you get a broken archive, not an error page). To debug:

  • Temporarily change the controller to return the list of image paths as JSON instead of streaming.
  • Check var/log/dev.log for ZipArchive::addFile warnings (permission-denied on source files is common if the var/storage path is misconfigured).
  • Test the route with curl -v -o out.zip <url> and inspect unzip -l out.zip — a valid empty ZIP is 22 bytes, which tells you the loop found zero images (usually a wrong location ID or wrong content type filter).

Extension points if you fork. The cleanest customization seams are:

  • Overriding the image-collection service in services.yaml (Xrow\DownloadLibraryBundle\… → your class) rather than editing vendor code.
  • A compiler pass if you need to swap a constructor argument.
  • A decorator around the download service to add logging, metrics, or filename policy without touching the original.

Consider building it yourself if you're on Laravel. The feature is genuinely small: query the subtree, resolve image field URIs via your storage abstraction, ZipArchive::addFile each, stream with response()->streamDownload(). That's ~60 lines and zero dependency risk. The only thing you'd import from this bundle is the shape of the route and the button UX — which you can replicate in an hour.

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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment