Filament is one of the best admin panel packages of Laravel. It is a modern admin panel for Laravel, designed to help developers quickly build internal dashboards, admin panels, and complex form-based interfaces.
I have been building one of my applications with Filament and i saw following statement in the Filament Documentation about File Uploads:
Please note, it is the responsibility of the developer to delete these files from the disk if they are removed, as Filament is unaware if they are depended on elsewhere. One way to do this automatically is observing a model event.
https://filamentphp.com/docs/2.x/forms/fields#file-upload
Since i’m using the file upload and the attachment function of the Rich Editor, i need to remove the uploaded file when they are deleted from Rich Editor or on File Upload mask.
For this i have to create an Observer to listen any updates on the desired model. In my case i’m using the Rich Editor and File Upload of Filament. Here is how i’m deleting the file, when it’s deleted in Rich Editor:
Delete Files in Rich Editor
First of all create the observers with following command. And then register the Observer Class with following “ObservedBy” Attribute in the Model:
php artisan make:observer ImageObserver --model=Image
////
#[ObservedBy([ImageObserver::class])]
class Image extends Model
When “Blog” Model is updated, look if the content is changed. If so regex in the original state of the content all of the images. In my case the images are in “/attachment/dynamicfolder/file.type”
If the file exists in the original and not in new state, then remove it from storage.
<?php
namespace App\Observers;
use App\Models\Blog;
use Illuminate\Support\Facades\Storage;
class BlogObserver
{
public function updated(Blog $blog): void
{
if ($blog->isDirty('content')) {
$oldState = $blog->getOriginal('content');
$newState = $blog->getAttribute('content');
$files = $this->extractFiles($oldState);
$checked = [];
foreach ($files as $file) {
if (in_array($file, $checked)) {
continue;
}
if (str_contains($file, $newState)) {
continue;
}
$checked[] = $file;
Storage::disk('blog')->delete($file);
}
}
}
public function deleted(Blog $blog): void
{
$content = $blog->getAttribute('content');
$files = $this->extractFiles($content);
$checked = [];
foreach ($files as $file) {
if (in_array($file, $checked)) {
continue;
}
$checked[] = $file;
Storage::disk('blog')->delete($file);
}
}
private function extractFiles(string $content): array
{
preg_match_all('@(?<=\/attachments\/)(?<files>\w{1,}\/.\w{1,}.\w{3})@', $content, $files);
return $files['files'];
}
}
Delete Files in File Upload
I have a “Image” Model for all of the images in the application. There is a column “images”, this can be either array or string. So i created for the Image Model also a new “ImageObserver”:
<?php
namespace App\Observers;
use App\Models\Blog;
use App\Models\Envelope\Image;
use Illuminate\Support\Facades\Storage;
class ImageObserver
{
public function updated(Image $image): void
{
$original = $image->getOriginal('images');
$current = $image->getAttribute('images');
if ($image->isDirty('images')) {
$diff = array_diff($original, $current);
foreach ($diff as $file) {
Storage::disk('public')->delete($file);
}
}
}
public function deleted(Image $image): void
{
$images = $image->getAttribute('images');
if (is_array($images)) {
foreach ($image->getAttribute('images') as $file) {
Storage::disk('public')->delete($file);
}
return;
}
Storage::disk('public')->delete($images);
}
}