Files
sam-manage/app/Models/Boards/Post.php
kent da159cc46e feat(boards): 게시글 파일 시스템 개선 및 이미지 미리보기 추가
- Morph map에 Post, Department 모델 등록 (ClassMorphViolationException 해결)
- 파일 저장 방식을 API 스타일로 변경 (document_id + document_type)
- 파일 미리보기 라우트 및 메서드 추가 (previewFile)
- 게시글 상세 페이지에서 이미지 첨부파일을 본문 상단에 풀 너비로 표시
- 비이미지 첨부파일은 하단에 다운로드 목록으로 분리

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 17:08:53 +09:00

212 lines
4.9 KiB
PHP

<?php
namespace App\Models\Boards;
use App\Models\Tenants\Tenant;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* 게시글 모델
*
* @property int $id
* @property int|null $tenant_id
* @property int $board_id
* @property int $user_id
* @property string $title
* @property string|null $content
* @property string $editor_type
* @property string|null $ip_address
* @property bool $is_notice
* @property bool $is_secret
* @property int $views
* @property string $status
*/
class Post extends Model
{
use SoftDeletes;
protected $table = 'posts';
protected $fillable = [
'tenant_id',
'board_id',
'user_id',
'title',
'content',
'editor_type',
'ip_address',
'is_notice',
'is_secret',
'views',
'status',
'created_by',
'updated_by',
'deleted_by',
];
protected $casts = [
'is_notice' => 'boolean',
'is_secret' => 'boolean',
'views' => 'integer',
];
protected $attributes = [
'is_notice' => false,
'is_secret' => false,
'views' => 0,
'status' => 'published',
'editor_type' => 'wysiwyg',
];
// =========================================================================
// Scopes
// =========================================================================
/**
* 특정 게시판의 글
*/
public function scopeOfBoard(Builder $query, int $boardId): Builder
{
return $query->where('board_id', $boardId);
}
/**
* 공지사항만
*/
public function scopeNotices(Builder $query): Builder
{
return $query->where('is_notice', true);
}
/**
* 일반 글만 (공지 제외)
*/
public function scopeRegular(Builder $query): Builder
{
return $query->where('is_notice', false);
}
/**
* 게시된 글만
*/
public function scopePublished(Builder $query): Builder
{
return $query->where('status', 'published');
}
/**
* 비밀글이 아닌 것만
*/
public function scopePublic(Builder $query): Builder
{
return $query->where('is_secret', false);
}
// =========================================================================
// Relationships
// =========================================================================
public function board(): BelongsTo
{
return $this->belongsTo(Board::class, 'board_id');
}
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class, 'tenant_id');
}
public function author(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function customFieldValues(): HasMany
{
return $this->hasMany(PostCustomFieldValue::class, 'post_id');
}
/**
* 첨부파일 (document_id + document_type 기반)
*/
public function files(): HasMany
{
return $this->hasMany(File::class, 'document_id')
->where('document_type', 'post');
}
// =========================================================================
// Helper Methods
// =========================================================================
/**
* 조회수 증가
*/
public function incrementViews(): void
{
$this->increment('views');
}
/**
* 커스텀 필드 값 가져오기
*/
public function getCustomFieldValue(string $fieldKey): ?string
{
$fieldValue = $this->customFieldValues()
->whereHas('field', fn ($q) => $q->where('field_key', $fieldKey))
->first();
return $fieldValue?->value;
}
/**
* 커스텀 필드 값들을 배열로 가져오기
*/
public function getCustomFieldsArray(): array
{
return $this->customFieldValues()
->with('field')
->get()
->mapWithKeys(fn ($v) => [$v->field->field_key => $v->value])
->toArray();
}
/**
* 비밀글 접근 가능 여부
*/
public function canAccess(?User $user): bool
{
// 비밀글이 아니면 모두 접근 가능
if (! $this->is_secret) {
return true;
}
// 비로그인이면 접근 불가
if (! $user) {
return false;
}
// 작성자 본인이면 접근 가능
if ($this->user_id === $user->id) {
return true;
}
// 관리자면 접근 가능
if ($user->hasRole(['admin', 'super-admin'])) {
return true;
}
return false;
}
}