'boolean', 'file_size' => 'integer', 'deleted_at' => 'datetime', ]; /** * Get the tenant that owns the file */ public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } /** * Get the folder that contains this file */ public function folder(): BelongsTo { return $this->belongsTo(Folder::class); } /** * Get all share links for this file */ public function shareLinks(): HasMany { return $this->hasMany(FileShareLink::class); } /** * Get the uploader (User) */ public function uploader(): BelongsTo { return $this->belongsTo(User::class, 'uploaded_by'); } /** * Legacy: 연관된 모델 (Polymorphic) - for backward compatibility * * @deprecated Use document_id and document_type instead */ public function fileable() { return $this->morphTo(); } /** * Get the full storage path */ public function getStoragePath(): string { return Storage::disk('tenant')->path($this->file_path); } /** * Check if file exists in storage */ public function exists(): bool { return Storage::disk('tenant')->exists($this->file_path); } /** * Get download response */ public function download() { if (! $this->exists()) { abort(404, 'File not found in storage'); } return response()->download( $this->getStoragePath(), $this->display_name ?? $this->original_name ); } /** * Move file from temp to folder */ public function moveToFolder(Folder $folder): bool { if (! $this->is_temp) { return false; // Already moved } // New path: /tenants/{tenant_id}/{folder_key}/{year}/{month}/{stored_name} $date = now(); $newPath = sprintf( '%d/%s/%s/%s/%s', $this->tenant_id, $folder->folder_key, $date->format('Y'), $date->format('m'), $this->stored_name ?? $this->file_name ); // Move physical file if (Storage::disk('tenant')->exists($this->file_path)) { Storage::disk('tenant')->move($this->file_path, $newPath); } // Update DB $this->update([ 'file_path' => $newPath, 'folder_id' => $folder->id, 'is_temp' => false, ]); return true; } /** * Delete file (soft delete) */ public function softDeleteFile(int $userId): void { // Set deleted_by before soft delete $this->deleted_by = $userId; $this->save(); // Use SoftDeletes trait's delete() method $this->delete(); } /** * Permanently delete file */ public function permanentDelete(): void { // Delete physical file if ($this->exists()) { Storage::disk('tenant')->delete($this->file_path); } // Decrement tenant storage $tenant = Tenant::find($this->tenant_id); if ($tenant) { $tenant->decrement('storage_used', $this->file_size); } // Force delete from DB $this->forceDelete(); } /** * Scope: Temp files only */ public function scopeTemp($query) { return $query->where('is_temp', true); } /** * Scope: Non-temp files only */ public function scopeNonTemp($query) { return $query->where('is_temp', false); } /** * Scope: By folder */ public function scopeInFolder($query, $folderId) { return $query->where('folder_id', $folderId); } /** * Scope: By document */ public function scopeForDocument($query, int $documentId, string $documentType) { return $query->where('document_id', $documentId) ->where('document_type', $documentType); } }