|null $description * @property string $status * @property string|null $deactivated_reason * @property \Illuminate\Support\Carbon|null $deactivated_at * @property string|null $incompatible_required_version * @property bool $is_protected * @property array $manifest * @property string|null $source_type * @property string|null $source_url * @property int|null $installed_by * @property \Illuminate\Support\Carbon|null $installed_at * @property \Illuminate\Support\Carbon|null $activated_at */ class LanguagePack extends Model { use HasFactory; /** * 테이블명. * * @var string */ protected $table = 'language_packs'; /** * 기본키. * * @var string */ protected $primaryKey = 'id'; /** * 타임스탬프 사용 여부. * * @var bool */ public $timestamps = true; /** * 대량 할당 허용 컬럼. * * @var array */ protected $fillable = [ 'identifier', 'vendor', 'scope', 'target_identifier', 'locale', 'locale_name', 'locale_native_name', 'text_direction', 'version', 'latest_version', 'target_version_constraint', 'target_version_mismatch', 'license', 'description', 'status', 'deactivated_reason', 'deactivated_at', 'incompatible_required_version', 'is_protected', 'manifest', 'source_type', 'source_url', 'installed_by', 'installed_at', 'activated_at', ]; /** * 캐스팅 정의. * * @return array */ protected function casts(): array { return [ 'description' => 'array', 'manifest' => 'array', 'is_protected' => 'boolean', 'target_version_mismatch' => 'boolean', 'installed_at' => 'datetime', 'activated_at' => 'datetime', 'deactivated_at' => 'datetime', ]; } /** * 설치자(User) 와의 관계를 정의합니다. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function installer(): BelongsTo { return $this->belongsTo(User::class, 'installed_by'); } /** * 활성 상태 여부를 확인합니다. * * @return bool 활성 여부 */ public function isActive(): bool { return $this->status === LanguagePackStatus::Active->value; } /** * 코어 스코프 여부를 확인합니다. * * @return bool 코어 여부 */ public function isCoreScope(): bool { return $this->scope === LanguagePackScope::Core->value; } /** * 번들 (수정 보호) 언어팩 여부를 확인합니다. * * @return bool 번들 여부 */ public function isProtected(): bool { return (bool) $this->is_protected; } /** * UI 출처(origin) 분류를 반환합니다. * * `source_type` 컬럼을 3그룹(built_in / bundled / user_installed) 으로 매핑한 값. * 가상 미설치 번들 행도 source_type=bundled 이므로 동일 매핑. * * @return string|null origin 값 (source_type 누락 시 null) */ public function getOriginAttribute(): ?string { return LanguagePackOrigin::fromSourceTypeValue($this->source_type)?->value; } /** * 슬롯 키를 반환합니다 ({scope}|{target_identifier}|{locale}). * * @return string 슬롯 키 */ public function slotKey(): string { return sprintf( '%s|%s|%s', $this->scope, $this->target_identifier ?? '', $this->locale ); } /** * 활성 언어팩만 조회하는 스코프. * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeActive(Builder $query): Builder { return $query->where('status', LanguagePackStatus::Active->value); } /** * 특정 스코프 언어팩만 조회하는 스코프. * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $scope 스코프 문자열 * @return \Illuminate\Database\Eloquent\Builder */ public function scopeOfScope(Builder $query, string $scope): Builder { return $query->where('scope', $scope); } /** * 특정 슬롯의 언어팩만 조회하는 스코프. * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $scope 스코프 문자열 * @param string|null $targetIdentifier 대상 확장 식별자 * @param string $locale 로케일 * @return \Illuminate\Database\Eloquent\Builder */ public function scopeForSlot( Builder $query, string $scope, ?string $targetIdentifier, string $locale ): Builder { return $query ->where('scope', $scope) ->where('target_identifier', $targetIdentifier) ->where('locale', $locale); } /** * 활성 디렉토리 절대 경로를 반환합니다. * * source_type=bundled_with_extension 인 가상 레코드는 확장 디렉토리 경로를 반환하고, * 그 외에는 lang-packs/{identifier}/ 경로를 반환합니다. * * @return string 디렉토리 절대 경로 */ public function resolveDirectory(): string { if ($this->source_type === 'bundled_with_extension' && $this->source_url) { return base_path($this->source_url); } // uninstalled 가상 행(미설치 번들)은 활성 디렉토리가 없으므로 _bundled 원본을 가리킴 if ($this->status === LanguagePackStatus::Uninstalled->value) { return base_path('lang-packs/_bundled/'.$this->identifier); } return base_path('lang-packs/'.$this->identifier); } }