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

Gallery Bundle Laravel Package

fsi/gallery-bundle

FSi Gallery Bundle provides Doctrine-backed image galleries for Symfony applications, including photo uploads, thumbnail generation, and Twig helpers for rendering albums. Drop it into an existing admin to manage galleries and media with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: fsi/gallery-bundle is a Symfony2 bundle, not a Laravel package. It ships no ServiceProvider, no facade, no config publish tag, and its last release was 2015-03-10 (Symfony 2.x / PHP 5.x era). You cannot composer require it into a Laravel app and expect php artisan to find it. What you can do is use it as a reference implementation and port it, or run it behind a Doctrine-based bridge (see Gotchas). Plan accordingly before you sink a sprint into it.

If you are evaluating it in a Symfony context (or porting it), the minimum path is:

  1. Read README.md first — it's short and shows the intended flow: create a Gallery, attach Photos, attach the gallery to any entity implementing GalleryableInterface.
  2. Inspect DependencyInjection/Configuration.php to see the actual config tree (storage paths, image sizes/thumbs, entity class overrides). This tells you more than the docs do.
  3. Look at Entity/Gallery.php, Entity/Photo.php, and Entity/GalleryHasPhoto.php — that pivot entity is the heart of the model: it carries position for ordering photos inside a gallery.
  4. Check Resources/config/doctrine/*.orm.xml for the exact schema before writing any migration.
  5. Look at Resources/views/ for the Twig partials and Twig/ for the rendering extension.

First use case to target: "An Article has zero-or-many Galleries; each Gallery has ordered Photos; the front end renders a thumbnail grid with a lightbox." That's the one flow this bundle was built for. Get that working before touching anything else.

For a Laravel translation of that first use case, the equivalent skeleton is:

// migrations: galleries, photos, gallery_photo (pivot with position + galleryable morphs)
Schema::create('gallery_photo', function (Blueprint $t) {
    $t->id();
    $t->foreignId('gallery_id')->constrained()->cascadeOnDelete();
    $t->foreignId('photo_id')->constrained()->cascadeOnDelete();
    $t->unsignedInteger('position')->default(0);
    $t->timestamps();
});

Implementation Patterns

Doctrine-style entity graph → Eloquent relationships

The bundle's model is a three-table graph: Gallery ⟷ Photo through GalleryHasPhoto (a pivot with payload — position). In Laravel this maps almost 1:1:

class Gallery extends Model {
    public function photos(): BelongsToMany {
        return $this->belongsToMany(Photo::class)
            ->withPivot('position')
            ->orderBy('gallery_photo.position')
            ->withTimestamps();
    }
}

The orderBy on the pivot column is the pattern to preserve — it's the whole reason a non-trivial pivot entity exists.

"Galleryable" attachment pattern

The bundle's GalleryableInterface lets any domain object declare getGalleries() so galleries can be attached to articles, products, pages, etc. The Laravel analogue is a polymorphic many-to-many:

// on Gallery
public function galleryable() { return $this->morphTo(); }

// or, if galleries own the pivot:
public function attachTo(Model $model, int $position = 0) {
    $model->galleries()->attach($this->id, ['position' => $position]);
}

If you need galleries shared across multiple owners (the bundle supports this), model it as galleryables (morph pivot) rather than a galleryable_id column on galleries — otherwise you'll be rewriting migrations in month two.

Upload and storage flow

The bundle delegates file handling to fsi/resource-bundle and Symfony's filesystem, storing a relative path on Photo. That's a local-disk assumption baked in. In Laravel, replace it wholesale:

  • Use Storage::disk('public') (or S3) and store the disk-relative key, never an absolute path.
  • Generate thumbnails at upload time via a queued job (Intervention Image or spatie/laravel-image-optimizer), and persist dimensions + variants as JSON on the photos row. The bundle's config-driven "image sizes" section becomes a config/gallery.php array of variants — keep it a config file so front-end code never hardcodes sizes.
  • Store mime, width, height, alt, caption as columns; the bundle's Photo entity has title/description fields that are easy to forget and painful to backfill.

Rendering layer

Twig helpers (gallery_* functions) and partials are the presentation contract. For Laravel, port each Twig partial to a Blade component (<x-gallery.grid :gallery="$gallery" />, <x-gallery.lightbox />) so views stay swappable. Don't inline rendering logic into controllers — that's the one habit that makes a later migration away from this package expensive.

Admin / CRUD integration

The bundle was designed to drop into fsi/admin-bundle. There is no Laravel equivalent, so choose deliberately: Filament (closest ergonomics), Nova, or a hand-rolled Livewire form. Whatever you pick, keep the ordering UI explicit — a sortable list with a position integer is enough, and it mirrors GalleryHasPhoto exactly.

Configuration

Mirror the bundle's config tree into config/gallery.php (variants, disk, thumbnail driver, max upload size, allowed mime types). Bind entity class names via config only if you actually plan to override them; otherwise hardcode and move on.

Gotchas and Tips

  • It will not install on a modern stack. Symfony 2 only, PHP 5.x/7.x era constraints, no support for Symfony 5/6/7 or PHP 8 type declarations. composer require on a current Laravel app will either fail dependency resolution or drag in dead Symfony 2 packages. Treat this as a reference codebase, not a dependency.
  • No Laravel integration points exist. No service provider, no facade, no publishable config, no Artisan commands, no Blade views. Any "usage" in Laravel is a port by definition, so budget for that honestly rather than hoping for a shim.
  • Last release 2015, 5 stars, 0 dependents. There is no community to ask, no maintainer to file issues with, and no security patching. If you port code, keep the license header (MIT) and own the maintenance permanently.
  • The pivot carries state. GalleryHasPhoto.position is the most-missed detail. If you collapse it to a plain belongsToMany without withPivot('position'), ordering silently falls back to insertion order and breaks the moment someone reorders.
  • File paths are filesystem-relative and local-disk-only. There's no abstraction for cloud storage. Any port must introduce a disk abstraction before the first upload, not after — retrofitting stored absolute paths across an S3 migration is miserable.
  • Twig templates are the de facto view spec. When porting, treat Resources/views/* as the acceptance criteria for your Blade components; screenshot-diff against it.
  • Doctrine coexistence is technically possible but rarely worth it. You can run doctrine/orm under Laravel via laravel-doctrine/orm and boot this bundle's mappings, but you'll be maintaining two persistence layers for one feature. Only consider it if the rest of the app is already Doctrine-based.
  • Extension points, if you go the Symfony route: override templates via bundle inheritance, override entity classes through the config tree, and decorate the gallery/photo manager services rather than editing vendor code.
  • Debugging order when something renders blank: (1) verify Doctrine schema is in sync, (2) confirm the photo rows actually have a file path after upload, (3) check the Twig helper is registered, (4) check template block names — the bundle's partials rely on specific block overrides that fail silently.
  • Strong recommendation for a greenfield Laravel project: use spatie/laravel-medialibrary for the file/variant layer and a thin gallery_photo pivot for ordering. You'll get 90% of this bundle's feature surface with an actively maintained dependency, and you'll keep the one genuinely reusable idea — an ordered pivot plus a polymorphic "galleryable" attachment — without inheriting a 2015 Symfony bundle.
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.
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
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect