lesson_01.md * - Lesson 2 -> lesson_02.md * - Intro & Project -> intro_and_project.md * - GeoGebra Lab -> geogebra_lab.md * - Unit Exam -> unit_exam.md */ function parseAndIngestTextbookMarkdown(string $rawMarkdown, array $metadata = []): array { $lines = explode("\n", $rawMarkdown); $gradeName = $metadata['grade_name'] ?? 'الصف العاشر'; $gradeKey = $metadata['grade_key'] ?? 'grade_10'; $subName = $metadata['subject_name'] ?? 'الرياضيات'; $subKey = $metadata['subject_key'] ?? 'math_10'; $semName = $metadata['semester_name'] ?? 'الفصل الدراسي الأول'; $semKey = $metadata['semester_key'] ?? 'semester_1'; $units = []; $currentUnit = null; $currentLesson = null; $lessonBuffer = []; $flushLesson = function() use (&$currentUnit, &$currentLesson, &$lessonBuffer) { if ($currentUnit && $currentLesson) { $content = trim(implode("\n", $lessonBuffer)); if (!empty($content)) { $currentLesson['markdown_content'] = $content; $currentUnit['lessons'][] = $currentLesson; } $currentLesson = null; $lessonBuffer = []; } }; $flushUnit = function() use (&$units, &$currentUnit, $flushLesson) { $flushLesson(); if ($currentUnit && !empty($currentUnit['lessons'])) { $units[] = $currentUnit; $currentUnit = null; } }; $unitCounter = 0; $arabicOrdinalMap = [ 'الأولى' => 1, 'الاولى' => 1, '1' => 1, 'الثانية' => 2, 'الثانيه' => 2, '2' => 2, 'الثالثة' => 3, 'الثالثه' => 3, '3' => 3, 'الرابعة' => 4, 'الرابعه' => 4, '4' => 4, 'الخامسة' => 5, 'الخامسه' => 5, '5' => 5, 'السادسة' => 6, 'السادسه' => 6, '6' => 6, ]; foreach ($lines as $line) { $trimmed = trim($line); // Detect Unit (# UNIT or # الوحدة) if (preg_match('/^#\s+(UNIT|الوحدة)\s*([0-9\-\:A-Za-z\s\p{Arabic}]+)(.*)$/ui', $trimmed, $m) || preg_match('/^#\s+([A-Za-z0-9\s]+(?:SPOT|SKILLS|REFERENCE|LIST))/ui', $trimmed, $m2)) { $flushUnit(); $unitTitle = trim(preg_replace('/^#\s+/u', '', $trimmed)); $detectedNum = null; foreach ($arabicOrdinalMap as $word => $num) { if (mb_stripos($unitTitle, $word) !== false) { $detectedNum = $num; break; } } if ($detectedNum !== null) { $unitCounter = $detectedNum; } else { $unitCounter++; } $unitKey = sprintf('unit_%02d', $unitCounter); $currentUnit = [ 'unit_key' => $unitKey, 'unit_name' => $unitTitle, 'lessons' => [] ]; continue; } // Detect Section (## ...) if (preg_match('/^##\s+(.+)$/u', $trimmed, $mAlt) && $currentUnit) { $flushLesson(); $lessonTitle = trim($mAlt[1]); // Semantic Identification of Lesson ID and File if (preg_match('/(?:الدرس|Lesson)\s*([0-9]+)/ui', $lessonTitle, $mLes)) { $lesNum = (int)$mLes[1]; $lesId = sprintf('lesson_%02d', $lesNum); } elseif (preg_match('/(?:مقدمة|مشروع)/ui', $lessonTitle)) { $lesId = 'intro_and_project'; } elseif (preg_match('/(?:معمل|جيوجبرا|نشاط)/ui', $lessonTitle)) { $lesId = 'geogebra_lab'; } elseif (preg_match('/(?:اختبار|تدريب|مراجعة)/ui', $lessonTitle)) { $lesId = 'unit_exam'; } elseif (preg_match('/(?:إثراء|الإثراء|توسع|التوسع)/ui', $lessonTitle)) { $lesId = 'enrichment_and_expansion'; } else { $lesId = 'section_' . count($currentUnit['lessons'] ?? []); } $currentLesson = [ 'lesson_id' => $lesId, 'title' => $lessonTitle, 'outcomes' => [$lessonTitle] ]; $lessonBuffer = [$trimmed]; continue; } if ($currentLesson) { $lessonBuffer[] = $line; } } $flushUnit(); // Clean old files in target directories to eliminate stubs $baseUnitDir = __DIR__ . "/../storage/curriculum/{$gradeKey}/{$subKey}/{$semKey}/"; foreach ($units as $u) { $uDir = $baseUnitDir . $u['unit_key']; if (is_dir($uDir)) { $existingFiles = glob($uDir . '/*.md'); foreach ($existingFiles as $f) { if (basename($f) === 'lesson_1.md' || basename($f) === 'lesson_2.md') { @unlink($f); } } } } $extracted = [ 'grade_name' => $gradeName, 'grade_key' => $gradeKey, 'subject_name' => $subName, 'subject_key' => $subKey, 'semester_name' => $semName, 'semester_key' => $semKey, 'units' => $units ]; return CurriculumService::mergeExtractedCurriculum($extracted); }