Teren-app/app/Models/Document.php

97 lines
2.6 KiB
PHP

<?php
namespace App\Models;
use App\Traits\Uuid;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;
class Document extends Model
{
use HasFactory;
use SoftDeletes;
use Uuid;
protected $fillable = [
'uuid',
'name',
'description',
'user_id',
'disk',
'path',
'file_name',
'original_name',
'extension',
'mime_type',
'size',
'checksum',
'is_public',
'preview_path',
'preview_mime',
'preview_generated_at',
'template_id',
'template_version',
];
protected $casts = [
'is_public' => 'boolean',
'size' => 'integer',
'preview_generated_at' => 'datetime',
];
protected $appends = [];
public function documentable(): MorphTo
{
return $this->morphTo();
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
// No direct public URL exposure; serve via controller stream
protected static function booted(): void
{
static::deleting(function (Document $doc) {
// Only delete files on force delete to keep data when soft-deleted
if (method_exists($doc, 'isForceDeleting') && $doc->isForceDeleting()) {
try {
if ($doc->path) {
$disk = $doc->disk ?: 'public';
Storage::disk($disk)->delete($doc->path);
}
} catch (\Throwable $e) {
// swallow; avoid failing delete due to storage issue
}
try {
if ($doc->preview_path) {
$previewDisk = config('files.preview_disk', 'public');
Storage::disk($previewDisk)->delete($doc->preview_path);
}
} catch (\Throwable $e) {
// swallow
}
}
});
}
/**
* Include soft-deleted documents when resolving by route key (e.g. {document:uuid}).
*/
public function resolveRouteBinding($value, $field = null)
{
// Always include trashed so deep-linking to older documents works
return static::withTrashed()
->where($field ?? $this->getRouteKeyName(), $value)
->firstOrFail();
}
}