168 lines
4.0 KiB
PHP
168 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class DocumentVersion extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'document_id',
|
|
'version_number',
|
|
'version_notes',
|
|
'is_current',
|
|
'file_path',
|
|
'original_filename',
|
|
'mime_type',
|
|
'file_size',
|
|
'file_hash',
|
|
'uploaded_by_user_id',
|
|
'uploaded_at',
|
|
];
|
|
|
|
protected $casts = [
|
|
'is_current' => 'boolean',
|
|
'uploaded_at' => 'datetime',
|
|
];
|
|
|
|
// Versions are immutable - disable updating
|
|
protected static function booted()
|
|
{
|
|
static::updating(function ($version) {
|
|
// Only allow updating is_current flag
|
|
$dirty = $version->getDirty();
|
|
if (count($dirty) > 1 || !isset($dirty['is_current'])) {
|
|
throw new \Exception('Document versions are immutable and cannot be modified');
|
|
}
|
|
});
|
|
}
|
|
|
|
// ==================== Relationships ====================
|
|
|
|
/**
|
|
* Get the document this version belongs to
|
|
*/
|
|
public function document()
|
|
{
|
|
return $this->belongsTo(Document::class);
|
|
}
|
|
|
|
/**
|
|
* Get the user who uploaded this version
|
|
*/
|
|
public function uploadedBy()
|
|
{
|
|
return $this->belongsTo(User::class, 'uploaded_by_user_id');
|
|
}
|
|
|
|
// ==================== File Methods ====================
|
|
|
|
/**
|
|
* Get the full file path
|
|
*/
|
|
public function getFullPath(): string
|
|
{
|
|
return storage_path('app/' . $this->file_path);
|
|
}
|
|
|
|
/**
|
|
* Check if file exists
|
|
*/
|
|
public function fileExists(): bool
|
|
{
|
|
return Storage::exists($this->file_path);
|
|
}
|
|
|
|
/**
|
|
* Get file download URL
|
|
*/
|
|
public function getDownloadUrl(): string
|
|
{
|
|
return route('admin.documents.download-version', [
|
|
'document' => $this->document_id,
|
|
'version' => $this->id,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Verify file integrity
|
|
*/
|
|
public function verifyIntegrity(): bool
|
|
{
|
|
if (!$this->fileExists()) {
|
|
return false;
|
|
}
|
|
|
|
$currentHash = hash_file('sha256', $this->getFullPath());
|
|
return $currentHash === $this->file_hash;
|
|
}
|
|
|
|
// ==================== Helper Methods ====================
|
|
|
|
/**
|
|
* Get human-readable file size
|
|
*/
|
|
public function getFileSizeHuman(): string
|
|
{
|
|
$bytes = $this->file_size;
|
|
$units = ['B', 'KB', 'MB', 'GB'];
|
|
|
|
for ($i = 0; $bytes > 1024; $i++) {
|
|
$bytes /= 1024;
|
|
}
|
|
|
|
return round($bytes, 2) . ' ' . $units[$i];
|
|
}
|
|
|
|
/**
|
|
* Get file extension
|
|
*/
|
|
public function getFileExtension(): string
|
|
{
|
|
return pathinfo($this->original_filename, PATHINFO_EXTENSION);
|
|
}
|
|
|
|
/**
|
|
* Get file icon based on mime type
|
|
*/
|
|
public function getFileIcon(): string
|
|
{
|
|
return match(true) {
|
|
str_contains($this->mime_type, 'pdf') => '📄',
|
|
str_contains($this->mime_type, 'word') || str_contains($this->mime_type, 'document') => '📝',
|
|
str_contains($this->mime_type, 'sheet') || str_contains($this->mime_type, 'excel') => '📊',
|
|
str_contains($this->mime_type, 'image') => '🖼️',
|
|
str_contains($this->mime_type, 'zip') || str_contains($this->mime_type, 'compressed') => '🗜️',
|
|
default => '📎',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Check if version is current
|
|
*/
|
|
public function isCurrent(): bool
|
|
{
|
|
return $this->is_current;
|
|
}
|
|
|
|
/**
|
|
* Get version badge class for UI
|
|
*/
|
|
public function getBadgeClass(): string
|
|
{
|
|
return $this->is_current ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800';
|
|
}
|
|
|
|
/**
|
|
* Get version badge text
|
|
*/
|
|
public function getBadgeText(): string
|
|
{
|
|
return $this->is_current ? '當前版本' : '歷史版本';
|
|
}
|
|
}
|