Displaying files
Displaying files
Displaying files
Once a file exists, you render it from a URL. Every File resolves its own URL based on the collection access mode (public CDN, signed URL, or streamed), so you do not build paths by hand. The same call works for every access mode (see the Access control section for what each mode does).
The simplest path is to grab the file and read its url():
@php($avatar = $user->file('avatar')) @if ($avatar) <img src="{{ $avatar->url() }}" alt="Avatar"> @endif
For Blade convenience the model exposes accessors so you can skip the method call:
| Accessor | Equivalent to |
|---|---|
$file->link |
$file->url() |
$file->preview_link |
$file->variant('preview.thumbnail')->url('image'), falling back to the image placeholder |
<img src="{{ $file->link }}"> <img src="{{ $file->preview_link }}"> {{-- thumbnail for video, PDF, audio, image --}}
preview_link never throws: if the disk is unreachable or the variant is missing, it returns the configured placeholder so one broken file cannot break the page.
Navigating variants
A file can have derived variants (a thumbnail, a small image, a video preview, and so on, created by the pipeline). Reach them with variant() using dot notation:
$file->variant('thumbnail')->url(); $file->variant('preview.small')->url('image');
variant() never returns null. If any link in the chain is missing it falls back to the closest existing ancestor, so $file->variant('preview.small') returns the preview (or the original) when small was not generated yet. When that silent fallback would be a bug, use variantOrFail() instead, which throws RuntimeException if any segment is missing:
$thumb = $file->variantOrFail('preview.thumbnail'); // throws if not generated
To avoid lazy-loading each variant on access, eager load the tree with the withVariants() scope on the File model:
$files = File::withVariants()->get(); // loads file -> preview -> thumbnail|small|...
url() and forced types
url() returns the real URL, or null when no valid backend resolves. Pass a type to force a fallback: if the file is not that type, or its URL cannot be built, you get the configured placeholder for that type instead of null.
$file->url(); // real URL or null $file->url('image'); // real URL if it is an image, otherwise the image placeholder
Rendering from the parent model
The trait gives you two helpers that go straight from a model + collection to a renderable result, with placeholder fallback built in. Prefer these when you do not have a File instance in hand.
fileLink() returns a URL string (the file, a variant, or a placeholder), so the <img> always has a src:
<img src="{{ $user->fileLink('avatar') }}"> <img src="{{ $user->fileLink('avatar', 'medium') }}"> {{-- a variant --}} <img src="{{ $user->fileLink('cover', 'preview.thumbnail') }}">
public function fileLink(string $collection, ?string $variant = null, ?string $forceType = null): ?string
$forceType selects which placeholder to fall back to. You only need it for multi-type collections (for example a gallery that accepts both images and video). When a collection declares a single type in config, the type is inferred for you.
fileRender() returns rendered HTML. With no component configured it emits a plain <img>; with a component configured for the collection it renders that component instead. Extra attributes are forwarded:
{{ $user->fileRender('avatar', 'medium', ['class' => 'w-12 h-12 rounded-full']) }}
public function fileRender(string $collection, ?string $variant = null, array $attrs = []): HtmlString
Per-collection components
For a consistent look per collection (a round avatar with initials fallback, a card for documents), point the collection at a Blade component via the component config key (or the $fileCollections override shown above). fileRender() then renders:
<x-{component} :model="$model" :url="$url" ...attrs />
The component receives $model (the owning model) and $url (the resolved URL, which may be null when there is no file and no placeholder). A minimal component for the avatar example above:
{{-- resources/views/components/user-avatar.blade.php --}} @props(['model', 'url']) @if ($url) <img src="{{ $url }}" alt="{{ $model->name }}" {{ $attributes->merge(['class' => 'rounded-full']) }}> @else <span {{ $attributes->merge(['class' => 'rounded-full bg-gray-200 grid place-items-center']) }}> {{ Str::of($model->name)->substr(0, 1)->upper() }} </span> @endif
With that component registered, {{ $user->fileRender('avatar') }} renders the avatar everywhere, and falls back to the initials badge when the user has no photo.