locaine/lcn-image-uploader-bundle
A Symfony bundle for streamlined image uploads: validate incoming files, store them via configurable adapters, and manage upload workflows with minimal setup. Add reliable, configurable image handling to your PHP application quickly and without boilerplate.
Before anything: this is a Symfony2 bundle, not a Laravel package. There is no service provider, no config/lcn-image-uploader.php, and no facade. Dropping it into a Laravel app will not work — you are either evaluating it for a legacy Symfony project, or reading it as a reference implementation to port. Decide which before you spend time on it, because the two paths look very different.
If you are on Symfony2 (the only supported path):
composer require locaine/lcn-image-uploader-bundle (expect a ~2.x Symfony constraint; check composer.json before assuming it installs alongside anything modern).app/AppKernel.php under new Lcn\ImageUploaderBundle\LcnImageUploaderBundle().app/config/routing.yml — this is the actual upload endpoint the JS talks to:
lcn_image_uploader:
resource: "@LcnImageUploaderBundle/Resources/config/routing.yml"
prefix: /upload
php app/console assets:install web --symlink.DependencyInjection/Configuration.php for the real root key and defaults — don't guess at lcn_image_uploader: vs lcn_image_upload:).Where to look first, in order: Controller/ (the upload action and its JSON response shape), DependencyInjection/Configuration.php (every knob you can turn), Resources/public/js (what the widget actually posts — field name, expected response keys), then Resources/config/services.yml for the storage/handler service you can override.
First use case to prove it out: a single "cover image" field on an entity. Render the uploader widget, let it POST to the bundle route, confirm you get back a JSON payload with a stored filename, then persist that filename in a hidden form field on submit. If that round trip works, the rest is variations.
Treat the bundle as an endpoint, not a form type. The valuable part is the upload action that accepts a multipart POST, validates and renames the file, and returns JSON. Wire your own form around it:
// Controller
public function saveAction(Request $request)
{
$form = $this->createForm(new ArticleType(), $article);
$form->handleRequest($request);
// filename arrives from the JS widget via a hidden input
$article->setCoverImage($form->get('cover_image')->getData());
// ... persist
}
The hidden field holds the stored filename; the bundle has already written the bytes to disk on upload. This decouples "upload" from "save the entity" and gives you instant previews — which is the whole point.
Persist a filename, not a blob. Store the returned name (or relative path) in a string column. Resolve the public URL at render time through whatever the bundle exposes as its web path config, so you can move the directory later without a data migration.
Pair it with a JS widget rather than relying on the bundled one. Symfony2-era bundle JS is typically jQuery + a plugin, and it is usually the most brittle piece. The endpoint contract is simple enough (POST a file, get JSON) that swapping in a maintained uploader or a small XMLHttpRequest wrapper is often less work than debugging the shipped script.
Multiple images / galleries: run one uploader per file, collect the returned filenames into a JSON-encoded hidden input, and let the widget manage ordering client-side. Don't try to make the endpoint accept arrays unless the controller already supports it.
Validation belongs on both sides. The bundle will likely whitelist mime types and enforce a max size from config, but re-validate the filename server-side before persisting — a client can post any string into your hidden field, including a path that escapes the upload directory.
Porting to Laravel is the realistic path if you're reading this from a Laravel codebase. The surface is small: a controller action, a storage service, a JS widget. Reimplement as a route + $request->validate(['file' => 'image|max:5120']) + Storage::disk('public')->putFile(...) returning { "name": ..., "url": ... }. Budget half a day, not a week — but don't copy the code, copy the contract.
app/console-flavored and won't map cleanly.web/uploads/ style destinations need www-data write access and an .htaccess denying script execution. A writable upload directory that also serves PHP is a well-known footgun — verify this on day one.assets:install was skipped or the symlink points at a stale path after a composer update.IMG_0001.jpg simultaneously is a real scenario. Confirm the bundle randomizes names; if not, override the storage service in your app config (that's the intended extension point — rebind the handler service id) or patch it.debug:container to confirm which service implementation is live. Most failures are in step one.How can I help you explore Laravel packages today?