vernova/app/Models/Concerns/HasAttachments.php
2026-07-26 19:58:27 +03:30

136 lines
3.5 KiB
PHP

<?php
namespace App\Models\Concerns;
use App\Models\Attachment;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
trait HasAttachments
{
/**
* Get all attachments for this model.
*/
public function attachments()
{
return $this->morphMany(Attachment::class, 'attachable');
}
/**
* Get receipts only.
*/
public function receipts()
{
return $this->morphMany(Attachment::class, 'attachable')
->where('category', 'receipt');
}
/**
* Get documents only.
*/
public function documents()
{
return $this->morphMany(Attachment::class, 'attachable')
->where('category', 'document');
}
/**
* Upload and attach a file.
*/
public function attachFile(
UploadedFile $file,
string $category = 'receipt',
?string $description = null,
?string $folder = null
): Attachment {
$folder = $folder ?? $this->getAttachmentFolder();
$filePath = $file->store($folder, 'public');
return $this->attachments()->create([
'tenant_id' => session('tenant_id') ?? $this->tenant_id,
'user_id' => Auth::id(),
'file_name' => $file->getClientOriginalName(),
'file_path' => $filePath,
'mime_type' => $file->getMimeType(),
'file_size' => $file->getSize(),
'category' => $category,
'description' => $description,
]);
}
/**
* Upload multiple files at once.
*/
public function attachFiles(array $files, string $category = 'receipt', ?string $folder = null): array
{
$attachments = [];
foreach ($files as $file) {
if ($file instanceof UploadedFile && $file->isValid()) {
$attachments[] = $this->attachFile($file, $category, null, $folder);
}
}
return $attachments;
}
/**
* Detach (soft delete) an attachment by ID.
*/
public function detachFile(int $attachmentId): bool
{
$attachment = $this->attachments()->find($attachmentId);
if ($attachment) {
$attachment->delete();
return true;
}
return false;
}
/**
* Migrate legacy receipt_path to the attachment system.
*/
public function migrateLegacyReceipt(): ?Attachment
{
$receiptPath = $this->getOriginal('receipt_path') ?? $this->receipt_path ?? null;
if (!$receiptPath) {
return null;
}
// Check if already migrated
$exists = $this->attachments()
->where('file_path', $receiptPath)
->exists();
if ($exists) {
return null;
}
if (!Storage::disk('public')->exists($receiptPath)) {
return null;
}
return $this->attachments()->create([
'tenant_id' => $this->tenant_id,
'user_id' => null,
'file_name' => basename($receiptPath),
'file_path' => $receiptPath,
'mime_type' => Storage::disk('public')->mimeType($receiptPath),
'file_size' => Storage::disk('public')->size($receiptPath),
'category' => 'receipt',
'description' => null,
]);
}
/**
* Get the default storage folder for this model's attachments.
*/
protected function getAttachmentFolder(): string
{
$className = strtolower(class_basename($this));
return "attachments/{$className}";
}
}