laravel-files/docs/attaching-files.md

6.6 KiB

Attaching Files to Models

The HasFiles trait connects any Eloquent model to the file system. Add the trait, and your model gains a polymorphic many-to-many relationship with the File model.

Setup

use Blax\Files\Traits\HasFiles;

class Product extends Model
{
    use HasFiles;
}

No further configuration needed — the trait registers a files() relationship automatically.

The files() Relationship

$product->files;                  // Collection of all attached File models
$product->files()->count();       // number of files
$product->files()->get();         // query builder — add your own constraints

Every pivot row carries three extra columns: as (role), order, and meta (JSON).


Attaching Files

attachFile()

$product->attachFile($file, as: FileLinkType::Gallery, order: 0);
Parameter Type Default Description
$file File|string A File model or its UUID
$as string|FileLinkType|null null Role / category for this attachment
$order ?int null Sort position
$meta ?array null Arbitrary metadata stored as JSON on the pivot
$replace bool false If true, removes existing attachments with the same role first

Duplicate prevention is built-in — attaching the same file with the same role twice is a no-op.

Replace Mode

Use replace: true for singular fields like avatars:

$user->attachFile($newAvatar, as: FileLinkType::Avatar, replace: true);
// The old avatar is detached; the new one takes its place.

Storing Metadata

$product->attachFile($file, as: 'document', meta: [
    'description' => 'Product specification sheet',
    'version'     => '2.1',
]);

Method Chaining

All attach/detach methods return $this, so you can chain:

$product
    ->attachFile($logo, as: FileLinkType::Logo, replace: true)
    ->attachFile($hero, as: FileLinkType::Banner, replace: true)
    ->attachFile($spec, as: FileLinkType::Document);

Detaching Files

detachFile()

Remove a specific file (optionally scoped by role):

$product->detachFile($file);
$product->detachFile($file, as: 'gallery');

detachFilesAs()

Remove all files with a given role:

$product->detachFilesAs(FileLinkType::Gallery);
$product->detachFilesAs('document');

detachAllFiles()

Remove every file attachment from the model:

$product->detachAllFiles();

Note: Detaching does not delete the File record or its contents — it only removes the pivot link. To delete a file permanently, call $file->delete().


Querying Attached Files

By Role

// Get all gallery images
$images = $product->filesAs(FileLinkType::Gallery)->get();

// Get the first document
$doc = $product->fileAs('document');

Convenience Getters

These methods resolve common roles with built-in fallback logic:

$user->getAvatar();      // tries Avatar, then ProfileImage
$user->getThumbnail();
$user->getBanner();
$user->getCoverImage();
$user->getBackground();
$user->getLogo();
$user->getGallery();     // returns a Collection

Each returns a ?File (or a Collection for getGallery()).


Pivot Access

Reading Pivot Data

$pivot = $product->getFilePivot($file); // returns ?Filable

$pivot->as;    // 'gallery'
$pivot->order; // 2
$pivot->meta;  // ['description' => '...']

Updating Pivot Data

The Filable model provides convenient setters:

$pivot->setAs(FileLinkType::Banner);   // updates and saves
$pivot->setOrder(5);                   // updates and saves
$pivot->getLinkType();                 // returns ?FileLinkType enum

Reordering Files

Reorder a set of files by passing their IDs in the desired order:

$product->reorderFiles([
    $fileC->id,
    $fileA->id,
    $fileB->id,
]);

Scope to a specific role:

$product->reorderFiles($ids, as: FileLinkType::Gallery);

The pivot order column is set to the array index (0, 1, 2, …). Files are auto-sorted by order thanks to a global scope on the Filable model.


Upload Helpers

The trait includes three convenience methods that create a file and attach it in a single call:

uploadFile()

Upload from a Laravel UploadedFile (e.g. $request->file('photo')):

$file = $product->uploadFile(
    $request->file('photo'),
    as: FileLinkType::Gallery,
    order: 0,
    replace: false,
);

uploadFileFromContents()

Create a file from raw string content:

$file = $product->uploadFileFromContents(
    contents: $pdfBinary,
    name: 'invoice-2024',
    extension: 'pdf',
    as: FileLinkType::Invoice,
    replace: true,
);

uploadFileFromUrl()

Download from a remote URL and attach:

$file = $product->uploadFileFromUrl(
    url: 'https://example.com/photo.jpg',
    name: 'product-hero',
    as: FileLinkType::Banner,
    replace: true,
);

All three return the created File model.


FileLinkType Enum

The FileLinkType enum provides 19 predefined roles grouped into categories:

Group Cases
Visual Identity Avatar, ProfileImage, CoverImage, Banner, Background, Logo, Icon, Thumbnail
Documents Document, Invoice, Contract, Certificate, Report
Media Gallery, Video, Audio
Attachments Attachment, Download
Catch-All Other
use Blax\Files\Enums\FileLinkType;

FileLinkType::Avatar->value;     // 'avatar'
FileLinkType::Avatar->label();   // 'Avatar'
FileLinkType::Avatar->isImage(); // true
FileLinkType::Document->isImage(); // false

You can also pass plain strings as the $as parameter if the built-in enum doesn't fit your use case.


Next: File Operations