*/ protected array $trackableFields = ['name', 'is_active']; /** * 다국어 JSON 컬럼 — sub-key dot-path 단위 user_overrides 보존. * * @var array */ protected array $translatableTrackableFields = ['name']; /** * 모델 이벤트 등록 — 모든 변경 시 알림 정의 캐시 자동 삭제. */ protected static function booted(): void { $invalidate = function () { try { app(NotificationDefinitionService::class)->invalidateAllCache(); } catch (\Throwable) { // 테스트/마이그레이션 환경에서 서비스 미등록 시 무시 } }; static::saved($invalidate); static::deleted($invalidate); } /** * 활동 로그 추적 필드. * * @var array> */ public static array $activityLogFields = [ 'name' => ['label_key' => 'activity_log.fields.name', 'type' => 'text'], 'channels' => ['label_key' => 'activity_log.fields.channels', 'type' => 'text'], 'hooks' => ['label_key' => 'activity_log.fields.hooks', 'type' => 'text'], 'is_active' => ['label_key' => 'activity_log.fields.is_active', 'type' => 'boolean'], ]; /** * @var string */ protected $table = 'notification_definitions'; /** * @var array */ protected $attributes = [ 'variables' => '[]', 'channels' => '["mail"]', 'hooks' => '[]', ]; /** * @var array */ protected $fillable = [ 'type', 'hook_prefix', 'extension_type', 'extension_identifier', 'name', 'description', 'variables', 'channels', 'hooks', 'is_active', 'is_default', 'user_overrides', ]; /** * 캐스팅 정의. * * @return array */ protected function casts(): array { return [ 'name' => 'array', 'description' => 'array', 'variables' => 'array', 'channels' => 'array', 'hooks' => 'array', 'is_active' => 'boolean', 'is_default' => 'boolean', 'user_overrides' => 'array', ]; } /** * 알림 템플릿 관계. * * @return HasMany */ public function templates(): HasMany { return $this->hasMany(NotificationTemplate::class, 'definition_id'); } /** * 활성 알림 정의만 조회. * * @param Builder $query * @return Builder */ public function scopeActive(Builder $query): Builder { return $query->where('is_active', true); } /** * 특정 타입의 알림 정의 조회. * * @param Builder $query * @param string $type * @return Builder */ public function scopeByType(Builder $query, string $type): Builder { return $query->where('type', $type); } /** * 특정 확장의 알림 정의 조회. * * @param Builder $query * @param string $extensionType * @param string $extensionIdentifier * @return Builder */ public function scopeByExtension(Builder $query, string $extensionType, string $extensionIdentifier): Builder { return $query->where('extension_type', $extensionType) ->where('extension_identifier', $extensionIdentifier); } /** * 현재 로케일의 이름 반환. * * @param string|null $locale * @return string */ public function getLocalizedName(?string $locale = null): string { $locale = $locale ?? app()->getLocale(); $name = $this->name ?? []; return $name[$locale] ?? $name[config('app.fallback_locale', 'ko')] ?? ''; } /** * 현재 로케일의 설명 반환. * * @param string|null $locale * @return string */ public function getLocalizedDescription(?string $locale = null): string { $locale = $locale ?? app()->getLocale(); $description = $this->description ?? []; return $description[$locale] ?? $description[config('app.fallback_locale', 'ko')] ?? ''; } }