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

Files Field Type Laravel Package

anomaly/files-field_type

Anomaly Files Field Type provides a Streams field type for uploading and managing one or more files in Laravel applications. It integrates file storage with Anomaly's Streams platform and offers a simple way to attach downloadable assets to entries.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Streams Platform field type addon (PyroCMS 3.x lineage), not a standalone Laravel package. It gives you a files field that stores a many-to-many relationship between a stream entry and rows in the Files module's files table. If you aren't already running anomaly/streams-platform, nothing here will work — there is no service provider you can register into a vanilla Laravel app.

Prerequisites, in order:

  1. A working Streams Platform install with the Files module (anomaly/files-module) installed and at least one storage disk/folder configured. The field type is a thin UI over that module; without it you get an empty uploader.
  2. Install the addon:
    composer require anomaly/files-field-type
    php artisan addon:install anomaly.field_type.files
    
  3. Confirm it is enabled (php artisan addon:list) before touching any stream definition — an uninstalled field type fails silently at migration time with a "field type does not exist" style error.

Where to look first, in this order:

  • src/FilesFieldType.php — the config array, $inputView, and the relationship definition. This file is the source of truth for every option you can pass in a migration.
  • resources/views/input.twig — the CP uploader markup; this is what you override when the UI doesn't match your admin theme.
  • src/FilesFieldTypePresenter.php — the methods available on the field value in Twig (url, path, thumbnail, etc.). Don't guess these; read the class.
  • src/FilesFieldTypeAccessor.php / Modifier.php — how IDs are read back out of the request and persisted.

Your first use case should be a single "attachments" or "gallery" field on one stream — a page with a files field, upload two images in the CP, and render them in Twig. That exercises the whole path (upload → Files module → pivot → presenter) in about fifteen minutes.

Implementation Patterns

Defining the field. Do it in the stream migration, not by hand in the CP, so it's reproducible:

$fields->addField('gallery', 'files', [
    'type' => 'anomaly.field_type.files',
    'config' => [
        'allowed_types' => ['jpg', 'jpeg', 'png', 'webp'],
    ],
]);

Check FilesFieldType::config() in your installed version for the exact keys — the config surface is small and has changed between releases. Assigning the field creates the pivot table automatically; if you rename the slug later you orphan that table.

Reading the value in Twig. The value is a collection of File presenters, so treat it like any Laravel collection:

{% for file in entry.files %}
    <img src="{{ file.url }}" alt="{{ file.name }}">
{% endfor %}

{# count, first, empty checks #}
{% if entry.files is not empty %}
    {{ entry.files|length }} file(s)
{% endif %}

Use file.path for filesystem paths and file.url for public links — mixing them up is the single most common bug. If you need the raw model, file.make() returns the underlying FileModel.

Writing the value programmatically. The field behaves like a standard Streams multiple field, so assignment works from PHP:

$entry->files = $fileIds;   // array of File module IDs
$entry->save();

If you're syncing manually outside the entry lifecycle, reach for the relationship directly ($entry->files()->sync($ids)) and be aware you skip the field type's accessor/modifier logic.

Uploading outside the CP. The field type's uploader is CP-oriented. For front-end uploads, use the Files module's uploader service and then attach the resulting IDs — don't try to POST to the field type's input endpoint directly, it expects CP auth and the form's session token.

Ordering. Files are stored with pivot ordering; if presentation order matters (a gallery, a carousel), set it explicitly after attach rather than relying on insertion order, which is not guaranteed across versions.

Extending rather than forking. Two clean options: (a) copy resources/views/input.twig into your own addon's view namespace and point the field's $inputView at it via a subclass; (b) subclass FilesFieldType in your own addon and register a new field type slug. Both survive composer update; editing files under vendor/ does not.

Gotchas and Tips

  • This package is effectively unmaintained. Last activity is the Streams 1.x / Laravel 5–6 era. On Laravel 8+ you will hit dependency resolution failures on anomaly/streams-platform long before you get to this addon. Budget for --ignore-platform-reqs at best, and a fork at worst. If you're greenfielding, use spatie/laravel-medialibrary or plain HasMany uploads instead.
  • Deleting an entry does not delete its files. The pivot rows go, the rows in files and the bytes on disk stay. Add an observer or a cleanup command, or your storage will grow monotonically.
  • allowed_types is a UI hint, not validation. It filters the file picker client-side. Any server-side enforcement is on you — validate mime and extension in your own request/observer.
  • Relationship name collision. The relation is files. If your stream already declares a files relation, one silently wins. Rename your field's slug or your other relation.
  • N+1 by default. {% for file in entry.files %} inside a loop over many entries fires a query per entry unless you eager-load the relation in whatever repository/query you use to fetch the entries.
  • Storage path rot. The stored value is a File ID, but the URL is resolved live from the Files module's disk/folder config. Move the disk or rename the folder and every historical link breaks at once. Pin the folder per field and leave it alone.
  • Debugging checklist when nothing renders: (1) addon:list shows the field type installed; (2) the pivot table exists and has rows (select * from <prefix>files_field_type_<slug> or the generic pivot, depending on version); (3) the Files module actually stored the file — check the CP Files listing, not the entry form; (4) php artisan view:clear after any view override, Twig caches aggressively.
  • Override views by publishing, not editing. Published views land in your app's resources and take precedence; editing vendor/anomaly/files-field-type/resources/... is lost on the next composer update and is invisible to code review.
  • Presenter methods are the safe API. Calling $file->url on the raw model throws; calling it on the presenter works. When in doubt, chain ->make() → presenter, or just use the field value directly in Twig where the presenter is already applied.
  • Version-pin the addon together with streams-platform and files-module. These three move in lockstep and a partial upgrade produces the confusing "field type exists but input renders blank" failure mode.
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