feat: 문서 관리 시스템 모델 생성 (Phase 1.2)

- Document 모델 (상태 관리, 다형성 연결, 결재 처리)
- DocumentApproval 모델 (결재 단계, 상태 처리)
- DocumentData 모델 (EAV 패턴 데이터 저장)
- DocumentAttachment 모델 (파일 첨부 연결)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-28 19:57:22 +09:00
parent c7b2e97189
commit 2bce30056d
4 changed files with 675 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
<?php
namespace App\Models\Documents;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* 문서 데이터 모델 (EAV 패턴)
*
* @property int $id
* @property int $document_id
* @property int|null $section_id 섹션 ID
* @property int|null $column_id 컬럼 ID
* @property int $row_index 행 인덱스
* @property string $field_key 필드 키
* @property string|null $field_value 필드 값
* @property \Carbon\Carbon|null $created_at
* @property \Carbon\Carbon|null $updated_at
*/
class DocumentData extends Model
{
protected $table = 'document_data';
// =========================================================================
// Fillable & Casts
// =========================================================================
protected $fillable = [
'document_id',
'section_id',
'column_id',
'row_index',
'field_key',
'field_value',
];
protected $casts = [
'section_id' => 'integer',
'column_id' => 'integer',
'row_index' => 'integer',
];
protected $attributes = [
'row_index' => 0,
];
// =========================================================================
// Relationships
// =========================================================================
/**
* 문서
*/
public function document(): BelongsTo
{
return $this->belongsTo(Document::class);
}
// =========================================================================
// Scopes
// =========================================================================
/**
* 특정 섹션의 데이터
*/
public function scopeForSection($query, int $sectionId)
{
return $query->where('section_id', $sectionId);
}
/**
* 특정 필드 키의 데이터
*/
public function scopeForField($query, string $fieldKey)
{
return $query->where('field_key', $fieldKey);
}
/**
* 특정 행의 데이터
*/
public function scopeForRow($query, int $rowIndex)
{
return $query->where('row_index', $rowIndex);
}
// =========================================================================
// Helper Methods
// =========================================================================
/**
* 값을 특정 타입으로 캐스팅
*/
public function getTypedValue(string $type = 'string'): mixed
{
return match ($type) {
'integer', 'int' => (int) $this->field_value,
'float', 'double' => (float) $this->field_value,
'boolean', 'bool' => filter_var($this->field_value, FILTER_VALIDATE_BOOLEAN),
'array', 'json' => json_decode($this->field_value, true),
default => $this->field_value,
};
}
}