QuestionDifficultyResolver.php 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. <?php
  2. namespace App\Services;
  3. use Illuminate\Support\Facades\DB;
  4. use Illuminate\Support\Facades\Schema;
  5. class QuestionDifficultyResolver
  6. {
  7. private const TABLE = 'question_difficulty_calibrations';
  8. private ?bool $tableReady = null;
  9. /**
  10. * @param array<int, int|string> $questionIds
  11. * @return array<int, float> question_bank_id => calibrated_difficulty
  12. */
  13. public function mapCalibratedDifficulty(array $questionIds): array
  14. {
  15. if (! $this->isReady()) {
  16. return [];
  17. }
  18. $questionIds = collect($questionIds)
  19. ->map(fn ($id) => (int) $id)
  20. ->filter(fn ($id) => $id > 0)
  21. ->unique()
  22. ->values()
  23. ->all();
  24. if ($questionIds === []) {
  25. return [];
  26. }
  27. return DB::table(self::TABLE)
  28. ->whereIn('question_bank_id', $questionIds)
  29. ->pluck('calibrated_difficulty', 'question_bank_id')
  30. ->map(fn ($v) => (float) $v)
  31. ->all();
  32. }
  33. /**
  34. * 批量给题目数组覆盖 difficulty(校准值优先,原始值兜底)
  35. *
  36. * @param array<int, array<string, mixed>> $questions
  37. * @return array<int, array<string, mixed>>
  38. */
  39. public function applyCalibratedDifficulty(array $questions): array
  40. {
  41. if ($questions === []) {
  42. return $questions;
  43. }
  44. $ids = [];
  45. foreach ($questions as $q) {
  46. $id = (int) ($q['id'] ?? $q['question_id'] ?? $q['question_bank_id'] ?? 0);
  47. if ($id > 0) {
  48. $ids[] = $id;
  49. }
  50. }
  51. $map = $this->mapCalibratedDifficulty($ids);
  52. if ($map === []) {
  53. return $questions;
  54. }
  55. foreach ($questions as &$q) {
  56. $id = (int) ($q['id'] ?? $q['question_id'] ?? $q['question_bank_id'] ?? 0);
  57. if ($id > 0 && array_key_exists($id, $map)) {
  58. $q['difficulty'] = (float) $map[$id];
  59. $q['difficulty_source'] = 'calibrated';
  60. }
  61. }
  62. unset($q);
  63. return $questions;
  64. }
  65. private function isReady(): bool
  66. {
  67. if ($this->tableReady !== null) {
  68. return $this->tableReady;
  69. }
  70. $this->tableReady = Schema::hasTable(self::TABLE);
  71. return $this->tableReady;
  72. }
  73. }