$allowedColumns 허용 정렬 컬럼 화이트리스트 * @param string $defaultColumn 화이트리스트에 없거나 미전송일 때 사용할 컬럼 * @param string $defaultDirection 기본 정렬 방향 (asc|desc) * @param array $columnAliases 요청 값 → 실제 컬럼 매핑 (예: ['author' => 'author_name']) * @param string $columnKey 정렬 컬럼이 담긴 필터 키 * @param string $directionKey 정렬 방향이 담긴 필터 키 * @return array 정렬 스펙 배열 */ protected function resolveSortSpec( array $filters, array $allowedColumns, string $defaultColumn, string $defaultDirection = 'desc', array $columnAliases = [], string $columnKey = 'sort_by', string $directionKey = 'sort_order', ): array { $column = $this->normalizeSortValue($filters[$columnKey] ?? null); $direction = $this->normalizeSortValue($filters[$directionKey] ?? null); if ($column !== null && isset($columnAliases[$column])) { $column = $columnAliases[$column]; } if ($column === null || ! in_array($column, $allowedColumns, true)) { $column = $defaultColumn; } return [[ 'column' => $column, 'direction' => $this->normalizeSortDirection($direction, $defaultDirection), ]]; } /** * 정렬 방향 문자열을 asc/desc 로 정규화합니다. * * @param string|null $direction 요청 값 * @param string $default 허용 값이 아닐 때 사용할 기본 방향 * @return string asc 또는 desc */ protected function normalizeSortDirection(?string $direction, string $default = 'desc'): string { $normalized = strtolower((string) $direction); if (in_array($normalized, ['asc', 'desc'], true)) { return $normalized; } $fallback = strtolower($default); return in_array($fallback, ['asc', 'desc'], true) ? $fallback : 'desc'; } /** * 정렬 관련 요청 값을 문자열로 정규화합니다. (Enum/빈 문자열 흡수) * * @param mixed $value 요청 값 (문자열 또는 BackedEnum) * @return string|null 정규화된 문자열 (값이 없으면 null) */ private function normalizeSortValue(mixed $value): ?string { if ($value instanceof BackedEnum) { $value = $value->value; } if (! is_string($value) && ! is_int($value)) { return null; } $value = trim((string) $value); return $value === '' ? null : $value; } }