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

Image Library Laravel Package

outerweb/image-library

A Laravel package for building and managing image libraries in your application. It provides a simple, consistent API for storing, organizing, and retrieving images, keeping image handling centralized and reusable across your project. Ideal for apps that need organized image management.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is small and unopinionated, so the fastest path to productivity is to let its published config and migration tell you what it actually does rather than reading the README twice.

  1. Install and publish everything:
composer require outerweb/image-library
php artisan vendor:publish --tag="image-library-config"
php artisan vendor:publish --tag="image-library-migrations"
php artisan migrate
  1. Read config/image-library.php first. In a package this size, the config file is the documentation — it will show you the storage disk, the base path/URL prefix, the registered conversion sizes, and any route/middleware settings. Everything else in the package keys off those values.

  2. Make sure the disk is actually reachable:

php artisan storage:link

and confirm FILESYSTEM_DISK / the package's configured disk points at something with a public URL, otherwise rendered images will 404 while uploads succeed.

  1. First use case: attach an image to an existing model and render it. The typical shape is a trait or relationship on your Eloquent model, then a Blade component for output:
use Outerweb\ImageLibrary\Traits\HasImages;

class Post extends Model
{
    use HasImages;
}
<x-image-library::image :image="$post->images->first()" conversion="card" />

Get that single happy path working end-to-end (upload → stored file → rendered <img>) before touching conversions, because almost every problem you'll hit later is a storage-path or URL problem, not a package-API problem.

Implementation Patterns

Treat it as a thin layer over the filesystem, not a CMS. The package's value is the glue: model attachment, path conventions, conversion definitions, and a render helper. Keep your own domain logic (who can upload, what gets attached to what) in your application code and use the package only for storage + rendering.

Centralize upload handling in a form request + action. Don't scatter addImage() calls through controllers:

class StorePostRequest extends FormRequest
{
    public function rules(): array
    {
        return ['images.*' => ['image', 'max:5120']];
    }
}

// in the controller
foreach ($request->file('images', []) as $file) {
    $post->addImage($file);
}

Validate image and a max size before the package touches anything — the package will happily store a 40MB PNG and your conversions will then time out.

Define conversions once, in config, named by intent. Resist per-call ad-hoc sizes. thumb, card, hero in config means templates stay readable and you can regenerate everything later from one place. If a conversion is only used in one view, it's probably a sign the design hasn't settled.

Use it in seeders and factories. For local dev and tests, generating a real file beats mocking:

$post->addImage(UploadedFile::fake()->image('hero.jpg', 1600, 900));

This is the single highest-leverage pattern for day-to-day work — it makes image-dependent views testable and makes migrate:fresh --seed produce a realistic site instead of a wall of broken thumbnails.

Render through the component, not raw paths. If you need srcset, loading="lazy", or width/height attributes for CLS, wrap the package's URL helper in your own Blade component rather than spreading <img> tags across templates. That gives you one place to fix alt text handling and one place to swap the package out later.

Output JSON through an accessor, not the model's raw attributes. For an API, add an image_url / image_urls accessor or API Resource so the storage path never leaks into your public contract. If you later change disks or move to a CDN, only the resource changes.

Deletion: hook it into the model lifecycle explicitly. Whatever the package does or doesn't do on deleting, verify it. The safe pattern is a booted() hook on the model or an observer that removes stored files, plus a scheduled image-library:prune-style command (or your own) for orphans left by failed uploads.

Gotchas and Tips

  • Conversions are the main source of surprise. Check when they're generated — on upload, on first request via a route, or on demand. If it's request-time, the first visitor after a deploy pays the cost, and a cache clear can mean a thundering herd. If it's upload-time, a synchronous upload of 20 images will hit PHP's max_execution_time. Move generation to a queued job either way.
  • Config caching bites. php artisan config:cache in production means edits to conversion sizes silently do nothing until you re-cache. Any "my new size isn't rendering" bug is this, nine times out of ten.
  • Path vs. URL confusion. Debug with Storage::disk(config('image-library.disk'))->exists($path) before blaming the component. A missing storage:link, a disk without 'url' => env('APP_URL').'/storage', or an APP_URL mismatch behind a proxy will produce 404s that look like package bugs.
  • Deleting originals breaks conversions. If conversions are generated lazily from the original, deleting the original (or moving it) leaves broken derived images. Keep originals unless you have a deliberate retention policy.
  • Use Storage::fake() in tests. Real-disk tests are slow and leave junk. Assert on Storage::disk(...)->assertExists(...) for the path, and separately assert the rendered HTML contains the expected URL — those are two different failure modes and blurring them makes debugging harder.
  • Alt text should not be the filename. The package can't infer it. Add an alt column alongside the image record (or on the pivot, if images are shared) and make it required in your form request. Retrofitting accessibility is much more expensive than including it now.
  • Don't store images in public/ directly. Let the package write to the configured disk with its own path convention; hand-rolled paths defeat the point and will collide with cleanup logic.
  • Extension points to look for before forking: the published Blade views (override in resources/views/vendor/image-library/), the config-driven conversion list, and any bound interfaces in the service provider. For a 12-star package, expect the maintainer's own needs to define the API — if you need substantially different behaviour, wrapping it in your own ImageService is cheaper than fighting it.
  • Pin the version. Low star count and zero dependents means the API is not battle-hardened by downstream usage; a ^1.0 constraint and a quick look at the changelog on update will save you a broken deploy.
  • Have an exit plan. Because the package is thin, migrating off it later is mostly a matter of moving files and rewriting your Blade component. Keeping direct package calls confined to one service class and one component makes that a day of work instead of a week.
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.
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
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo