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

Laravel Media Laravel Package

jd-dotlogics/laravel-media

jd-dotlogics/laravel-media is a Laravel package for attaching, storing, and managing media files with clean model associations, upload handling, media collections, customizable storage disks, and simple APIs for serving images and files in common application workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

Verify before you commit. With 0 stars and 0 dependents, this is effectively an unreleased/internal package. Spend ten minutes reading the source before writing any application code — composer require jd-dotlogics/laravel-media, then open vendor/jd-dotlogics/laravel-media/src/, config/media.php (if present), and the migrations directory. The README is the only docs you'll get, and it may be thin or stale.

Minimal install sequence (confirm each step applies once you've read the service provider):

composer require jd-dotlogics/laravel-media
php artisan vendor:publish --provider="JdDotLogics\Media\MediaServiceProvider"
php artisan migrate
php artisan storage:link

Where to look first, in order:

  1. src/MediaServiceProvider.php — what's registered (config, migrations, routes, commands, Blade components).
  2. config/media.php — the storage disk, path prefix, allowed mimes, and any conversion queue settings. This is the file you'll touch most in production.
  3. The model trait (usually HasMedia) — that's the public API surface your models will use.
  4. The media migration — column names and whether there's a polymorphic mediable_type/mediable_id pair, a collection column, disk, size, mime, and ordering column.

First use case to get working end-to-end: attach a single uploaded image to a Post model, render its URL in a Blade view, and confirm the row lands in the media table with the right disk and path. Don't touch conversions or multiple collections until that round-trip works — it validates config, disk, storage link, trait wiring, and URL generation in one pass.

// app/Models/Post.php
use JdDotLogics\Media\Concerns\HasMedia; // confirm exact namespace

class Post extends Model
{
    use HasMedia;
}
$post = Post::create($validated);
$post->addMediaFromRequest('cover')->toMediaCollection('cover'); // confirm method names

If those method names don't match the trait, stop and adapt — the rest of this document assumes a Spatie-style API, which is the Laravel convention this package most likely mirrors.

Implementation Patterns

Controller-driven uploads with Form Requests. Keep validation in a FormRequest (image|mimes:jpg,png,webp|max:5120) and do the attach in the controller after the model is persisted. Attaching before save() means no mediable_id to hang the row off.

public function store(StorePostRequest $request)
{
    $post = Post::create($request->validated());

    if ($request->hasFile('cover')) {
        $post->addMediaFromRequest('cover')
             ->toMediaCollection('cover');
    }

    return redirect()->route('posts.show', $post);
}

Collections as a contract. Pick a fixed set of collection names (cover, gallery, documents) and treat them as constants — an enum or a Post::COLLECTION_GALLERY const. This keeps retrieval, deletion, and any conversion config sane as the app grows.

Multiple uploads. Loop over the request array rather than assuming a batch API exists:

foreach ($request->file('gallery', []) as $file) {
    $post->addMedia($file)->toMediaCollection('gallery');
}

Retrieval and URL generation. Wrap retrieval in accessors so views never touch the media relation directly — this is where you isolate the package if you later swap it out:

public function getCoverUrlAttribute(): ?string
{
    return $this->getFirstMediaUrl('cover') ?: null;
}

Use a placeholder (a static asset, not a generated image) when it returns null. Null-coalescing into a hardcoded CDN URL is how you get broken-image reports in production.

Queue heavy work. Any conversions, thumbnails, or remote-disk puts should be queued. The main risk with a zero-adoption package is that it hands you synchronous file processing in the request cycle. If config/media.php exposes a queue connection, set it; if not, consider triggering conversions from a queued job or listener on model creation and letting the request return fast.

Cleanup on delete. Register a deleting hook (or a model observer) to remove media rows and files. Confirm whether the package does this automatically; for a package with no dependents, assume it does the bare minimum and verify with a rollback test.

protected static function booted(): void
{
    static::deleting(fn (Post $post) => $post->clearMediaCollection('gallery'));
}

API responses. In API Resources, emit URLs plus width/height/mime metadata rather than raw paths:

'cover' => [
    'url'    => $this->cover_url,
    'thumb'  => $this->getFirstMediaUrl('cover', 'thumb'),
],

Testing. Use Storage::fake('public') in feature tests and assert the file lands via Storage::disk('public')->assertExists(...). Because the package is unmaintained, your test suite is the regression net — write one test per collection covering attach, retrieve, and delete.

Gotchas and Tips

  • Zero adoption means zero safety net. There is no Stack Overflow history, no GitHub issues to grep, and nobody has hit the edge case you're about to hit. Pin the exact version in composer.json ("jd-dotlogics/laravel-media": "1.x" or a commit hash), commit the lock file, and treat upgrades as deliberate migrations rather than composer update.
  • Read the trait before you trust the method names. addMediaFromRequest, toMediaCollection, getFirstMediaUrl, and the 'thumb' conversion argument are Spatie conventions. This package may use attach, upload, store, or ->to('cover'). Namespace and method mismatches between README and source are common in low-traffic packages — the source wins.
  • Disk config is the #1 production failure. Verify config/media.php points at your intended disk (public vs s3) and that the media.disk value matches filesystems.default if you're relying on the default. Uploading to public while serving from s3 (or vice versa) yields 404s that look like permission bugs.
  • storage:link is per-environment. Add it to your deploy script. Local works, staging 404s — classic.
  • Orphaned files. If the package doesn't cascade on model delete, you'll accumulate disk usage silently. Add the deleting hook defensively and run a periodic pruning command (php artisan media:clean if one is registered — check src/Console/).
  • Config caching bites in dev. After editing config/media.php, run php artisan config:clear. Forgetting this makes config changes appear to have no effect and sends you debugging the wrong layer.
  • Filename collisions. If the package preserves original names, two IMG_0001.jpg uploads into the same collection will collide or overwrite. Check whether it hashes/uniqid()s filenames; if not, wrap the attach in a custom useFileName() or your own path generator.
  • Validation belongs outside the package. Don't rely on its internal mime checks — image|max:5120 in a FormRequest gives you clear 422s and doesn't depend on unmaintained internals.
  • Extension points to look for if you need to customize: a PathGenerator or filename callback (for CDN-friendly layouts like posts/{id}/cover.webp), a custom Conversions class if the package supports per-model conversion definitions, and the ability to override the published config for allowed mimes and max size.
  • Have an escape hatch. Wrap the package's calls in a small MediaService or trait of your own (attachCover(Post $post, UploadedFile $file)). If the package proves unmaintained mid-project, you replace one class instead of hunting call sites across 40 controllers. Given the adoption numbers, this is not paranoia — it's the primary architectural decision here.
  • Budget for the swap. The realistic assessment: this package is a starting point, not a dependency. If it's internal to your org, fine — treat it as an in-house library. If it's a third-party you found, benchmark it against Spatie's laravel-medialibrary (mature, heavily used, same mental model) before building on it. The API surface described above is nearly identical, which makes a future migration cheap if you keep the wrapper layer thin.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core