Skip to main content

Overview

The Gallery feature provides a powerful photo management system with album organization. Built on Spatie Media Library, it supports automatic image conversions, thumbnails, and responsive image handling.

Database Structure

The album table organizes photos into collections:
album
  - id: bigint (primary key)
  - album_name: string (nullable)
  - slug: string (unique, nullable)
  - description: text (nullable)
  - created_at: timestamp
  - updated_at: timestamp
Auto-generated Slug: Automatically created from album_name using Str::slug()Reference: database/migrations/2025_03_31_154244_create_album_table.php:14

Model Relationships

Album Model

The Album model implements Spatie’s HasMedia interface:
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Album extends Model implements HasMedia
{
    use InteractsWithMedia;

    protected $table = 'album';
    
    protected $fillable = [
        'album_name', 'slug', 'category', 'description'
    ];

    // Auto-generate slug when creating
    protected static function boot()
    {
        parent::boot();
        static::creating(function ($album) {
            if ($album->album_name) {
                $album->slug = Str::slug($album->album_name);
            }
        });
    }

    // Use slug instead of ID in URLs
    public function getRouteKeyName()
    {
        return 'slug';
    }

    // Many-to-many relationship with photos
    public function photos()
    {
        return $this->belongsToMany(Photo::class, 'album_photo');
    }

    // Media conversions for thumbnails
    public function registerMediaConversions(?Media $media = null): void
    {
        $this->addMediaConversion('preview')
            ->fit(Fit::Contain, 300, 300)
            ->nonQueued();
    }
}
Reference: app/Models/Album.php:12

Photo Model

The Photo model also integrates with Spatie Media Library:
class Photo extends Model implements HasMedia
{
    use InteractsWithMedia;

    protected $table = 'photos';
    
    protected $fillable = ['title', 'description'];

    // Define media collection for images
    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('images');
    }

    // Auto-generate preview thumbnails
    public function registerMediaConversions(?Media $media = null): void
    {
        $this->addMediaConversion('preview')
            ->fit(Fit::Contain, 300, 300)
            ->nonQueued();
    }

    // Relationship to albums
    public function albums()
    {
        return $this->belongsToMany(Album::class, 'album_photo', 'photo_id', 'album_id');
    }
}
Reference: app/Models/Photo.php:11

Spatie Media Library Integration

Media Storage

Images are stored using Spatie’s media table:
  • Original files stored in filesystem
  • Metadata tracked in database
  • Automatic conversions generated
  • Responsive image support

Image Conversions

Automatic preview generation:
  • Preview Size: 300x300 pixels
  • Fit Mode: Contain (maintains aspect ratio)
  • Processing: Non-queued (immediate)
  • Use Case: Gallery thumbnails

Admin Workflows

Album Management

  1. View Albums
    • Navigate to /admin/gallery/albums
    • See all albums with photo count
    • Albums loaded with photos relationship and media
  2. Create Album
    • Resource route: POST /admin/gallery/albums
    • Provide album name (slug auto-generated)
    • Add optional description
  3. Album Features
    • Slug-based URLs: SEO-friendly album routes like /gallery/album/{slug}
    • Photo Count: Track number of photos per album
    • Cover Photo: Set featured image for album preview
Controller: Admin\AlbumController@index
Reference: app/Http/Controllers/Admin/AlbumController.php:14

Photo Management

  1. View All Photos
    • Route: GET /admin/gallery/photos
    • Displays all photos with media relationships
    • Shows preview thumbnails
  2. Upload New Photo
    • Route: POST /admin/gallery/photos
    • Submit title and description
    • Upload image file (processed by Spatie)
  3. Edit Photo Details
    • Route: PATCH /admin/gallery/photos/{photo}
    • Update title and description
    • Change album associations
  4. Delete Photo
    • Route: DELETE /admin/gallery/photos/{photo}
    • Removes photo record and associated media files
    • Automatically cleans up album relationships
Controller: Admin\PhotoController
Reference: app/Http/Controllers/Admin/PhotoController.php:15

Photo-Album Assignment

Photos can belong to multiple albums through the pivot table:
// Add photo to album
$album->photos()->attach($photoId);

// Remove photo from album
$album->photos()->detach($photoId);

// Sync album photos (replaces all)
$album->photos()->sync([1, 2, 3]);
Unique Constraint: Each photo can only be added once per album.Reference: database/migrations/2025_05_30_070106_create_album-photo_table.php:20

Frontend Display

Media Conversions

Spatie Media Library automatically generates image versions:

Preview Conversion

$this->addMediaConversion('preview')
    ->fit(Fit::Contain, 300, 300)
    ->nonQueued();
Usage in Views:
{{-- Original image --}}
<img src="{{ $photo->getFirstMediaUrl('images') }}">

{{-- Preview thumbnail --}}
<img src="{{ $photo->getFirstMediaUrl('images', 'preview') }}">
Reference: app/Models/Photo.php:27

Key Routes

Admin Routes

MethodURIActionDescription
GET/admin/gallery/albumsAlbumController@indexList all albums
POST/admin/gallery/albumsAlbumController@storeCreate album
GET/admin/gallery/albums/{album}AlbumController@showShow album
PATCH/admin/gallery/albums/{album}AlbumController@updateUpdate album
DELETE/admin/gallery/albums/{album}AlbumController@destroyDelete album
GET/admin/gallery/photosPhotoController@indexList all photos
POST/admin/gallery/photosPhotoController@storeUpload photo
PATCH/admin/gallery/photos/{photo}PhotoController@updateUpdate photo
DELETE/admin/gallery/photos/{photo}PhotoController@destroyDelete photo

Frontend Routes

MethodURIActionDescription
GET/galleryGalleryController@indexGallery home
GET/gallery/album/{album:slug}GalleryController@albumAlbum photos
GET/gallery/album/{album:slug}/{image}GalleryController@imageSingle image
GET/image/{photo}PhotoController@showDirect photo view
Reference: routes/web.php:61-68

Performance Considerations

Eager Loading

The album index uses eager loading to prevent N+1 queries:
$albums = Album::with('cover_photo')
    ->withCount('photos')
    ->latest()
    ->get();
Reference: app/Http/Controllers/Admin/AlbumController.php:16

Media Collections

Photos use dedicated media collection:
  • Collection name: images
  • Prevents media type mixing
  • Enables collection-specific processing
Reference: app/Models/Photo.php:23

Build docs developers (and LLMs) love