PHPackages                             aniftyco/laravel-attachments - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. aniftyco/laravel-attachments

ActiveLibrary[Database &amp; ORM](/categories/database)

aniftyco/laravel-attachments
============================

Turn any field on your Eloquent models into attachments

1.0.3(3mo ago)14675↓20%MITPHPPHP ^8.3CI passing

Since Mar 7Pushed 3mo ago2 watchersCompare

[ Source](https://github.com/aniftyco/laravel-attachments)[ Packagist](https://packagist.org/packages/aniftyco/laravel-attachments)[ Docs](https://github.com/aniftyco/laravel-attachments)[ RSS](/packages/aniftyco-laravel-attachments/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (5)Dependencies (8)Versions (6)Used By (0)

Attachments for Laravel
=======================

[](#attachments-for-laravel)

> Turn any field on your Eloquent models into attachments with automatic file management and cleanup.

[![Latest Version on Packagist](https://camo.githubusercontent.com/c1fb6631fd31ae825203b8bdfe6efa4ee35398cc2930900862489b3f9e255f9e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616e69667479636f2f6c61726176656c2d6174746163686d656e74732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aniftyco/laravel-attachments)[![Total Downloads](https://camo.githubusercontent.com/d0bafa2fb6c70b4732a4d70aaf41bb257e1c492f792f1512e438bc5c057f09b0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f616e69667479636f2f6c61726176656c2d6174746163686d656e74732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aniftyco/laravel-attachments)

Features
--------

[](#features)

- 🎯 **Simple API** - Easy-to-use casts for single and multiple attachments
- 🔄 **Automatic Cleanup** - Automatically delete files when models are deleted
- 🔗 **URL Generation** - Generate public and temporary URLs for attachments
- 📦 **Multiple Storage Disks** - Support for any Laravel filesystem disk
- 🗂️ **Organized Storage** - Automatic folder organization with customizable paths
- 🔒 **Type Safe** - Full type hints and IDE autocomplete support

Requirements
------------

[](#requirements)

- PHP 8.3 or higher
- Laravel 12.0 or higher

Installation
------------

[](#installation)

You can install the package via Composer:

```
composer require aniftyco/laravel-attachments
```

Publish the configuration file (optional):

```
php artisan vendor:publish --tag=attachments-config
```

Usage
-----

[](#usage)

### Migrations

[](#migrations)

Add attachment columns to your migrations using the provided Blueprint macros:

```
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();

            // Single attachment
            $table->attachment('avatar');

            // Multiple attachments
            $table->attachments('photos');

            $table->timestamps();
        });
    }
};
```

The `attachment()` and `attachments()` macros automatically create nullable JSON columns for storing attachment data.

### Adding Attachments to Models

[](#adding-attachments-to-models)

To add attachments to your Eloquent models, use the provided cast classes.

#### Single Attachment

[](#single-attachment)

Use the `AsAttachment` cast to handle a single attachment:

```
use NiftyCo\Attachments\Casts\AsAttachment;

class User extends Model
{
    protected function casts(): array
    {
        return [
            'avatar' => AsAttachment::class,
        ];
    }
}
```

To set an image as an attachment on your model:

```
use NiftyCo\Attachments\Attachment;

class UserController
{
    public function store(UserStoreRequest $request, User $user)
    {
        $user->avatar = Attachment::fromFile($request->file('avatar'), folder: 'avatars');

        $user->save();

        // ...
    }
}
```

#### Multiple Attachments

[](#multiple-attachments)

Use the `AsAttachments` cast to handle multiple attachments:

```
use NiftyCo\Attachments\Casts\AsAttachments;

class Post extends Model
{
    protected function casts(): array
    {
        return [
            'images' => AsAttachments::class,
        ];
    }
}
```

To attach multiple attachments to your model:

```
use NiftyCo\Attachments\Attachments;

class PostController
{
    public function store(PostStoreRequest $request, Post $post)
    {
        // Create from multiple files at once
        $post->images = Attachments::fromFiles($request->file('images'), folder: 'posts');

        // Or add files one at a time
        foreach ($request->file('images') as $image) {
            $post->images->attach($image, folder: 'posts');
        }

        $post->save();
    }
}
```

### Working with Attachments

[](#working-with-attachments)

#### Accessing Attachment Properties

[](#accessing-attachment-properties)

```
$attachment = $user->avatar;

$attachment->name();      // File name
$attachment->disk();      // Storage disk name
$attachment->folder();    // Folder path
$attachment->path();      // Full path (folder/name) - alias for name()
$attachment->size();      // File size in bytes
$attachment->mimeType();  // MIME type
$attachment->extname();   // File extension (e.g., 'jpg')
$attachment->extension(); // Alias for extname()
$attachment->url();       // Public URL
```

#### Generating URLs

[](#generating-urls)

```
// Public URL (for public disks)
$url = $user->avatar->url();

// Temporary URL (for private disks)
$url = $user->avatar->temporaryUrl(now()->addHours(1));

// Or use minutes
$url = $user->avatar->temporaryUrl(60); // 60 minutes
```

#### File Operations

[](#file-operations)

```
// Check if file exists
if ($user->avatar->exists()) {
    // File exists
}

// Get file contents
$contents = $user->avatar->contents();

// Download file
return $user->avatar->download();
return $user->avatar->download('custom-filename.jpg');

// Get human-readable file size
$size = $user->avatar->readableSize(); // "1.5 MB"

// Delete attachment
$user->avatar->delete();
```

#### Working with Multiple Attachments

[](#working-with-multiple-attachments)

```
// Count attachments
$count = $post->images->count();

// Loop through attachments
foreach ($post->images as $image) {
    echo $image->url();
}

// Add a new attachment
$post->images->attach($file, folder: 'posts');

// Remove an attachment
$post->images = $post->images->filter(fn($img) => $img->name() !== 'old.jpg');
$post->save();
```

Automatic File Cleanup
----------------------

[](#automatic-file-cleanup)

The package provides automatic file cleanup when models are deleted or attachments are replaced.

### Model Deletion Cleanup

[](#model-deletion-cleanup)

To enable automatic cleanup when a model is deleted, add the `HasAttachmentCleanup` trait to your model:

```
use NiftyCo\Attachments\Concerns\HasAttachmentCleanup;

class User extends Model
{
    use HasAttachmentCleanup;

    protected function casts(): array
    {
        return [
            'avatar' => AsAttachment::class,
        ];
    }
}
```

Now when you delete a user, their avatar file will be automatically deleted:

```
$user->delete(); // Avatar file is automatically deleted from storage
```

### Replacement Cleanup

[](#replacement-cleanup)

By default, when you replace an attachment with a new one, the old file is automatically deleted:

```
// Old avatar file is automatically deleted when replaced
$user->avatar = Attachment::fromFile($newFile, folder: 'avatars');
$user->save();
```

### Disabling Automatic Cleanup

[](#disabling-automatic-cleanup)

You can disable automatic cleanup globally in the configuration file:

```
// config/attachments.php

return [
    // Disable cleanup when models are deleted
    'auto_cleanup' => false,

    // Disable cleanup when attachments are replaced
    'delete_on_replace' => false,
];
```

Configuration
-------------

[](#configuration)

The package comes with sensible defaults, but you can customize the behavior by publishing and editing the configuration file:

```
php artisan vendor:publish --tag=attachments-config
```

Available configuration options:

```
return [
    /*
    |--------------------------------------------------------------------------
    | Default Disk
    |--------------------------------------------------------------------------
    |
    | The default filesystem disk to use for storing attachments.
    | This should match one of the disks defined in config/filesystems.php
    |
    */
    'disk' => env('ATTACHMENTS_DISK', 'public'),

    /*
    |--------------------------------------------------------------------------
    | Default Folder
    |--------------------------------------------------------------------------
    |
    | The default folder path where attachments will be stored.
    | You can override this per-attachment when creating them.
    |
    */
    'folder' => env('ATTACHMENTS_FOLDER', 'attachments'),

    /*
    |--------------------------------------------------------------------------
    | Automatic Cleanup
    |--------------------------------------------------------------------------
    |
    | When enabled, attachment files will be automatically deleted from storage
    | when the parent model is deleted. Requires the HasAttachmentCleanup trait.
    |
    */
    'auto_cleanup' => env('ATTACHMENTS_AUTO_CLEANUP', true),

    /*
    |--------------------------------------------------------------------------
    | Delete on Replace
    |--------------------------------------------------------------------------
    |
    | When enabled, the old attachment file will be automatically deleted
    | when it's replaced with a new attachment.
    |
    */
    'delete_on_replace' => env('ATTACHMENTS_DELETE_ON_REPLACE', true),

    /*
    |--------------------------------------------------------------------------
    | Temporary URL Expiration
    |--------------------------------------------------------------------------
    |
    | The default expiration time (in minutes) for temporary URLs.
    | This is used when calling temporaryUrl() without an expiration parameter.
    |
    */
    'temporary_url_expiration' => env('ATTACHMENTS_TEMP_URL_EXPIRATION', 60),
];
```

Testing
-------

[](#testing)

Run the test suite:

```
composer test
```

Run code style checks:

```
composer lint
```

Fix code style issues:

```
./vendor/bin/pint
```

Contributing
------------

[](#contributing)

Thank you for considering contributing to the Attachments for Laravel package! You can read the contribution guide [here](CONTRIBUTING.md).

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

45

—

FairBetter than 92% of packages

Maintenance78

Regular maintenance activity

Popularity25

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~79 days

Total

5

Last Release

113d ago

Major Versions

0.1.0 → 1.0.02025-12-25

PHP version history (2 changes)0.1.0PHP ^8.1

1.0.0PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/dbf1f9fd8a86d353261f446f70eda4fadbfd389fb6463cec9c2596539d81c418?d=identicon)[joshmanders](/maintainers/joshmanders)

---

Top Contributors

[![joshmanders](https://avatars.githubusercontent.com/u/352113?v=4)](https://github.com/joshmanders "joshmanders (37 commits)")

---

Tags

laraveleloquentattachments

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/aniftyco-laravel-attachments/health.svg)

```
[![Health](https://phpackages.com/badges/aniftyco-laravel-attachments/health.svg)](https://phpackages.com/packages/aniftyco-laravel-attachments)
```

###  Alternatives

[reedware/laravel-relation-joins

Adds the ability to join on a relationship by name.

2121.2M13](/packages/reedware-laravel-relation-joins)[toponepercent/baum

Baum is an implementation of the Nested Set pattern for Eloquent models.

3154.7k](/packages/toponepercent-baum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
