diff --git a/data/seed.php b/data/seed.php new file mode 100644 index 00000000..17614fe0 --- /dev/null +++ b/data/seed.php @@ -0,0 +1,482 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$pdo->exec('SET NAMES utf8mb4'); +$pdo->exec('SET FOREIGN_KEY_CHECKS = 0'); + +$now = time(); + +// ── Helpers ─────────────────────────────────────────────────────────────────── +function uuid(): string { + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', + mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), + mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, + mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)); +} +function rand_item(array $arr) { return $arr[array_rand($arr)]; } +function rand_items(array $arr, int $min, int $max): array { + $count = rand($min, $max); + $keys = (array) array_rand($arr, min($count, count($arr))); + return array_map(fn($k) => $arr[$k], $keys); +} +function mobile(): string { + $prefix = rand_item(['0910','0911','0912','0913','0914','0915','0916','0917','0918','0919', + '0930','0933','0935','0936','0937','0938','0939','0901','0902','0903', + '0920','0921','0922','0991','0992','0993','0994']); + return $prefix . str_pad((string)rand(1000000, 9999999), 7, '0', STR_PAD_LEFT); +} +function nationalCode(): string { + return str_pad((string)rand(1000000000, 9999999999), 10, '0', STR_PAD_LEFT); +} +function medicalCode(): string { + return (string)rand(10000000, 99999999); +} +function passwordHash(): string { + return '$2y$13$' . substr(base64_encode(random_bytes(32)), 0, 53); +} + +// ── Static data ─────────────────────────────────────────────────────────────── +$maleNames = ['علی','محمد','حسین','احمد','رضا','مهدی','حسن','اکبر','ابراهیم','کریم', + 'جواد','امیر','سعید','مجید','فرید','کامران','سیاوش','داریوش','پرویز','شهرام', + 'بهرام','فرهاد','نادر','مسعود','وحید','یاسر','حامد','سجاد','ایمان','میثم', + 'آرش','آرمان','آرمین','پدرام','پویا','کیان','سیروس','بابک','فریبرز','هوشنگ']; +$femaleNames = ['فاطمه','زهرا','مریم','سارا','نرگس','لیلا','نازنین','مهناز','شیرین','پروین', + 'ملیحه','الناز','آتنا','باران','ترانه','دلارام','رویا','شادی','گلناز','ماهرخ', + 'ندا','نیلوفر','هانیه','یاسمن','زینب','حدیثه','سمیه','طاهره','عاطفه','منیژه']; +$lastNames = ['احمدی','محمدی','رضایی','حسینی','موسوی','جعفری','کریمی','نوری','صادقی','قاسمی', + 'عباسی','میرزایی','رحیمی','اکبری','یوسفی','حیدری','طاهری','نصیری','سلیمانی','زارعی', + 'مرادی','شریفی','منصوری','ذبیحی','تهرانی','اصفهانی','مشهدی','شیرازی','تبریزی','همدانی', + 'ملکی','درویشی','امیری','نجفی','شاهی','بهرامی','خسروی','گلمحمدی','فدایی','ولیپور', + 'نظری','فروزان','پورعلی','دهقانی','صالحی','ربیعی','مجیدی','سبحانی','زمانی','بهشتی']; +$degrees = ['متخصص','فوق تخصص','دکترای عمومی','فلوشیپ','استادیار','دانشیار','پروفسور']; +$genders = ['male','female']; +$bios = [ + 'دارای بیش از ۱۵ سال سابقه در حوزه تخصصی خود، عضو انجمن پزشکی ایران.', + 'فارغ‌التحصیل دانشگاه علوم پزشکی تهران، دارای تجربه کار در بیمارستان‌های معتبر.', + 'متخصص با سابقه درخشان در درمان بیماران، ارائه خدمات با بالاترین کیفیت.', + 'عضو هیئت علمی دانشگاه و مشاور پزشکی با بیش از ۱۰ سال تجربه بالینی.', + 'دارای گواهینامه‌های تخصصی از مراکز بین‌المللی، آشنا با جدیدترین روش‌های درمانی.', + 'پزشک باتجربه با رویکرد جامع در درمان، اعتقاد به طب پیشگیری و توانبخشی.', + 'متعهد به ارائه بهترین مراقبت‌های پزشکی با رعایت اصول اخلاق پزشکی.', + 'دارای مدرک تخصصی از اروپا، تجربه کار در مراکز درمانی پیشرفته.', +]; +$clinicNames = ['کلینیک تخصصی','مرکز درمانی','بیمارستان','کلینیک جامع','مرکز مشاوره پزشکی', + 'مطب دکتر','کلینیک ویژه','مرکز پزشکی','درمانگاه','کلینیک سلامت']; +$clinicSuffixes = ['امید','نوین','رازی','ابن سینا','سینا','شفا','سلامت','آریا','پارس','ایران','مهر','صبا']; +$appointmentStatuses = ['reserved','visited','completed','cancelled_by_user','cancelled_by_doctor','no_show']; +$appointmentStatusWeights = [30,25,25,10,5,5]; // percent chance +$paymentStatuses = ['paid','pending','failed']; +$commentTexts = [ + 'دکتر بسیار خوب و دلسوزی هستند. توضیحات کاملی دادند.', + 'معاینه دقیق بود و تشخیص درست. ممنونم.', + 'وقت انتظار کمی داشتم، دکتر سر وقت حاضر بود.', + 'بسیار متبحر و با حوصله. مشکلم کاملاً حل شد.', + 'توصیه می‌کنم. رفتار بسیار حرفه‌ای دارند.', + 'دکتر خوبی هستند ولی وقت ویزیت کمی کوتاه بود.', + 'راضی بودم از ویزیت. درمان موثر بود.', + 'یکی از بهترین دکترهایی که به آنها مراجعه کرده‌ام.', + 'کمی منتظر ماندم ولی ارزشش را داشت.', + 'متخصص واقعی در حوزه کارشان. توصیه می‌کنم.', +]; +$blogTitles = [ + 'راهنمای جامع برای پیشگیری از بیماری‌های قلبی', + 'تغذیه سالم برای کودکان در سنین رشد', + 'اهمیت چکاپ منظم سالانه', + 'راهکارهای مقابله با استرس و اضطراب', + 'علائم هشداردهنده دیابت نوع ۲', + 'ورزش و تأثیر آن بر سلامت قلب و عروق', + 'خواب کافی و نقش آن در سلامت جسم و روان', + 'راهنمای مراقبت از پوست در فصول مختلف', + 'پیشگیری از پوکی استخوان با تغذیه مناسب', + 'نکات مهم برای مراقبت از بینایی', + 'سرطان پستان؛ تشخیص زودهنگام نجات‌بخش است', + 'بهداشت دهان و دندان در کودکان', + 'فشار خون بالا و روش‌های کنترل آن', + 'نقش واکسیناسیون در پیشگیری از بیماری‌ها', + 'آرتروز زانو؛ علائم، پیشگیری و درمان', +]; +$blogBodies = [ + 'بیماری‌های قلبی از مهم‌ترین علل مرگ در ایران و جهان هستند. با رعایت سبک زندگی سالم، ترک دخانیات و فعالیت بدنی منظم می‌توان خطر آن را کاهش داد.', + 'تغذیه متعادل و سرشار از ویتامین‌ها برای رشد کودکان ضروری است. مصرف میوه، سبزیجات، پروتئین و لبنیات را در برنامه غذایی کودک خود بگنجانید.', + 'انجام آزمایش‌های منظم، بررسی فشار خون، قند خون و چکاپ کلی هر سال توصیه می‌شود. تشخیص زودهنگام بیماری‌ها درمان را آسان‌تر می‌کند.', + 'مدیریت استرس با تکنیک‌های تنفس عمیق، مدیتیشن و فعالیت بدنی امکان‌پذیر است. در صورت نیاز از مشاور یا روانپزشک کمک بگیرید.', + 'دیابت نوع ۲ با علائمی مانند تشنگی زیاد، ادرار مکرر و خستگی مزمن همراه است. کنترل وزن و رژیم غذایی مناسب در پیشگیری از آن نقش دارد.', +]; + +// ── Load existing data ──────────────────────────────────────────────────────── +$provinces = $pdo->query('SELECT id FROM provinces')->fetchAll(PDO::FETCH_COLUMN); +$cities = $pdo->query('SELECT id, province_id FROM cities WHERE id != 600')->fetchAll(PDO::FETCH_ASSOC); +$cityIds = array_column($cities, 'id'); +$specialtyParents = $pdo->query('SELECT id FROM specialties WHERE parent_id IS NULL')->fetchAll(PDO::FETCH_COLUMN); +$allSpecialties = $pdo->query('SELECT id FROM specialties')->fetchAll(PDO::FETCH_COLUMN); +$allServices = $pdo->query('SELECT id, specialty_id FROM doctor_services')->fetchAll(PDO::FETCH_ASSOC); +$serviceIds = array_column($allServices, 'id'); + +// Build specialty->services map +$specialtyServicesMap = []; +foreach ($allServices as $svc) { + if ($svc['specialty_id']) { + $specialtyServicesMap[$svc['specialty_id']][] = $svc['id']; + } +} + +$count = 0; + +// ── 1. Insurances ───────────────────────────────────────────────────────────── +echo "Inserting insurances...\n"; +$basicInsurances = [ + ['تأمین اجتماعی','basic'],['خدمات درمانی','basic'],['نیروهای مسلح','basic'], + ['کمیته امداد','basic'],['بهزیستی','basic'],['روستایی','basic'], +]; +$suppInsurances = [ + ['ایران','supplementary'],['آسیا','supplementary'],['البرز','supplementary'], + ['پارسیان','supplementary'],['سامان','supplementary'],['میهن','supplementary'], + ['دانا','supplementary'],['رازی','supplementary'],['کوثر','supplementary'],['معلم','supplementary'], +]; +$insStmt = $pdo->prepare('INSERT IGNORE INTO insurances (uuid,name,type,status) VALUES (?,?,?,1)'); +$insIds = []; +foreach (array_merge($basicInsurances, $suppInsurances) as $ins) { + $insStmt->execute([uuid(), $ins[0], $ins[1]]); + $insIds[] = $pdo->lastInsertId(); + $count++; +} +$insIds = array_filter($insIds); // remove zeros from IGNORE +if (empty($insIds)) { + $insIds = $pdo->query('SELECT id FROM insurances')->fetchAll(PDO::FETCH_COLUMN); +} +echo " Insurances: " . count($insIds) . "\n"; + +// ── 2. Users (patients) ─────────────────────────────────────────────────────── +echo "Inserting users (patients)...\n"; +$usedMobiles = []; +$patientIds = []; +$uStmt = $pdo->prepare( + 'INSERT INTO users (uuid,mobile_number,password_hash,email,real_name,roles,status,created_at,updated_at) + VALUES (?,?,?,?,?,?,1,?,?)' +); +for ($i = 0; $i < 200; $i++) { + $gender = rand_item($genders); + $firstName = $gender === 'male' ? rand_item($maleNames) : rand_item($femaleNames); + $lastName = rand_item($lastNames); + $name = $firstName . ' ' . $lastName; + do { $mobile = mobile(); } while (isset($usedMobiles[$mobile])); + $usedMobiles[$mobile] = true; + $email = strtolower(rand_item(['user','p','pt','patient'])) . $i . '@example.ir'; + $ts = $now - rand(86400, 86400 * 365); + $uStmt->execute([uuid(), $mobile, passwordHash(), $email, $name, '["ROLE_USER"]', $ts, $ts]); + $patientIds[] = (int)$pdo->lastInsertId(); + $count++; +} +echo " Patients: " . count($patientIds) . "\n"; + +// ── 3. Doctor users ─────────────────────────────────────────────────────────── +echo "Inserting doctors...\n"; +$doctorUserIds = []; +$doctorIds = []; +$duStmt = $pdo->prepare( + 'INSERT INTO users (uuid,mobile_number,password_hash,email,real_name,roles,status,created_at,updated_at) + VALUES (?,?,?,?,?,?,1,?,?)' +); +$dStmt = $pdo->prepare( + 'INSERT INTO doctors (uuid,name,gender,medical_system_code,mobile_number,activity_time,degree,info, + images,doctor_rate,doctor_rate_percentage,active_doctor_appointment,created_at,updated_at,user_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?,1,?,?,?)' +); +for ($i = 0; $i < 60; $i++) { + $gender = $i % 4 === 0 ? 'female' : 'male'; + $firstName = $gender === 'male' ? rand_item($maleNames) : rand_item($femaleNames); + $lastName = rand_item($lastNames); + $name = 'دکتر ' . $firstName . ' ' . $lastName; + do { $mobile = mobile(); } while (isset($usedMobiles[$mobile])); + $usedMobiles[$mobile] = true; + $email = 'dr' . $i . '@clinic-pro.ir'; + $ts = $now - rand(86400 * 30, 86400 * 730); + $duStmt->execute([uuid(), $mobile, passwordHash(), $email, $name, '["ROLE_USER","ROLE_DOCTOR"]', $ts, $ts]); + $userId = (int)$pdo->lastInsertId(); + $doctorUserIds[] = $userId; + $rate = round(rand(35, 50) / 10, 1); + $ratePct = rand(72, 98); + $dStmt->execute([ + uuid(), $name, $gender, medicalCode(), $mobile, + rand(5, 25), rand_item($degrees), rand_item($bios), + json_encode([]), $rate, $ratePct, $ts, $ts, $userId + ]); + $doctorIds[] = (int)$pdo->lastInsertId(); + $count += 2; +} +echo " Doctors: " . count($doctorIds) . "\n"; + +// ── 4. Doctor specialties & services ───────────────────────────────────────── +echo "Linking doctor specialties/services...\n"; +$dsStmt = $pdo->prepare('INSERT IGNORE INTO doctor_specialties (doctor_id,specialty_id) VALUES (?,?)'); +$deStmt = $pdo->prepare('INSERT IGNORE INTO doctor_expertise (doctor_id,service_id) VALUES (?,?)'); +$dpStmt = $pdo->prepare('INSERT IGNORE INTO doctor_provinces (doctor_id,province_id) VALUES (?,?)'); +$dcStmt = $pdo->prepare('INSERT IGNORE INTO doctor_cities (doctor_id,city_id) VALUES (?,?)'); +$daStmt = $pdo->prepare( + 'INSERT INTO doctor_addresses (uuid,name,address,telephone,latitude,longitude,created_at,updated_at,doctor_id,city_id,province_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?)' +); + +$cityProvinceMap = array_column($cities, 'province_id', 'id'); +$streetNames = ['خیابان ولیعصر','خیابان انقلاب','خیابان آزادی','بلوار کشاورز','خیابان شریعتی', + 'خیابان مطهری','خیابان فردوسی','خیابان پاسداران','خیابان جمهوری','خیابان امام خمینی']; +$buildingDescs = ['ساختمان پزشکان','برج طبی','مجتمع پزشکی','کلینیک ویژه','مطب','مرکز درمانی']; + +foreach ($doctorIds as $idx => $doctorId) { + // 1-2 specialties per doctor + $numSpec = rand(1, 2); + $chosenParents = (array)array_rand(array_flip($specialtyParents), min($numSpec, count($specialtyParents))); + foreach ($chosenParents as $specId) { + $dsStmt->execute([$doctorId, $specId]); + $count++; + // Add 2-5 child specialties under same parent if exist + $children = array_values(array_filter($allSpecialties, fn($s) => !in_array($s, $specialtyParents))); + foreach (array_slice($children, 0, rand(2, 5)) as $cs) { + $dsStmt->execute([$doctorId, $cs]); + $count++; + } + // Services for this specialty + $svcPool = $specialtyServicesMap[$specId] ?? array_slice($serviceIds, 0, 10); + foreach (rand_items($svcPool, 3, 8) as $svcId) { + $deStmt->execute([$doctorId, $svcId]); + $count++; + } + } + + // 1-3 cities per doctor + $chosenCities = rand_items($cityIds, 1, 3); + foreach ($chosenCities as $cityId) { + $provId = $cityProvinceMap[$cityId] ?? null; + $dcStmt->execute([$doctorId, $cityId]); + if ($provId) $dpStmt->execute([$doctorId, $provId]); + $count += $provId ? 2 : 1; + + // Doctor address for each city + $street = rand_item($streetNames); + $building = rand_item($buildingDescs); + $no = rand(1, 200); + $address = 'تهران، ' . $street . '، پلاک ' . $no . '، ' . $building; + $lat = 33.0 + (rand(0, 700) / 100); + $lon = 48.0 + (rand(0, 1500) / 100); + $tel = '0' . rand_item(['21','511','411','31','71','81','351','44']) . rand(10000000, 99999999); + $ts = $now - rand(86400, 86400 * 180); + $daStmt->execute([uuid(), 'مطب شماره ' . ($idx+1), $address, $tel, $lat, $lon, $ts, $ts, $doctorId, $cityId, $provId]); + $count++; + } +} + +// ── 5. Clinics ──────────────────────────────────────────────────────────────── +echo "Inserting clinics...\n"; +$clinicIds = []; +$clStmt = $pdo->prepare( + 'INSERT INTO clinics (uuid,name,info,address,telephone,is_24_7,working_days,latitude,longitude, + city_id,province_id,images_clinic,clinic_logo,created_at,updated_at,user_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)' +); +$clDStmt = $pdo->prepare('INSERT IGNORE INTO clinic_doctors (clinic_id,doctor_id) VALUES (?,?)'); +$clSpStmt = $pdo->prepare('INSERT IGNORE INTO clinic_specialties (clinic_id,specialty_id) VALUES (?,?)'); +$clSvStmt = $pdo->prepare('INSERT IGNORE INTO clinic_services (clinic_id,service_id) VALUES (?,?)'); +$clInStmt = $pdo->prepare('INSERT IGNORE INTO clinic_insurances (clinic_id,insurance_id) VALUES (?,?)'); + +$workingDays = ['شنبه تا چهارشنبه ۸ تا ۲۰','شنبه تا پنجشنبه ۸ تا ۱۸','یک‌شنبه تا پنجشنبه ۹ تا ۱۷', + 'شنبه تا سه‌شنبه ۷ تا ۱۹','همه روزه ۸ تا ۲۲','شنبه تا چهارشنبه ۹ تا ۲۰']; + +$shuffledDoctors = $doctorIds; +shuffle($shuffledDoctors); + +for ($i = 0; $i < 30; $i++) { + $cityRow = rand_item($cities); + $cityId = (int)$cityRow['id']; + $provId = (int)$cityRow['province_id']; + $lat = 33.0 + (rand(0, 700) / 100); + $lon = 48.0 + (rand(0, 1500) / 100); + $is247 = rand(0, 5) === 0 ? 1 : 0; + $name = rand_item($clinicNames) . ' ' . rand_item($clinicSuffixes); + $ts = $now - rand(86400 * 30, 86400 * 365); + $tel = '0' . rand_item(['21','511','411','31','71','81','351','44']) . rand(10000000, 99999999); + $address = rand_item($streetNames) . '، پلاک ' . rand(1,300); + $ownerId = $doctorUserIds[array_rand($doctorUserIds)]; + $clStmt->execute([ + uuid(), $name, 'ارائه خدمات تخصصی پزشکی با استفاده از جدیدترین تجهیزات.', + $address, $tel, $is247, rand_item($workingDays), $lat, $lon, + $cityId, $provId, json_encode([]), json_encode([]), $ts, $ts, $ownerId + ]); + $clinicId = (int)$pdo->lastInsertId(); + $clinicIds[] = $clinicId; + $count++; + + // 2-4 doctors per clinic + $cDocs = array_splice($shuffledDoctors, 0, rand(2, 4)); + if (empty($cDocs)) $cDocs = rand_items($doctorIds, 2, 3); + foreach ($cDocs as $dId) { + $clDStmt->execute([$clinicId, $dId]); $count++; + } + // 2-4 specialties + foreach (rand_items($specialtyParents, 2, 4) as $spId) { + $clSpStmt->execute([$clinicId, $spId]); $count++; + } + // 3-6 services + foreach (rand_items($serviceIds, 3, 6) as $svId) { + $clSvStmt->execute([$clinicId, $svId]); $count++; + } + // 3-6 insurances + foreach (rand_items($insIds, 3, 6) as $inId) { + $clInStmt->execute([$clinicId, $inId]); $count++; + } +} +echo " Clinics: " . count($clinicIds) . "\n"; + +// ── 6. Appointments ─────────────────────────────────────────────────────────── +echo "Inserting appointments...\n"; +$apptStmt = $pdo->prepare( + 'INSERT INTO appointments (uuid,slot_start,slot_end,status,note,created_at,updated_at,doctor_id,user_id) + VALUES (?,?,?,?,?,?,?,?,?)' +); +$apptIds = []; +$apptStatusFinal = []; + +// weighted random status +function weightedStatus(array $statuses, array $weights): string { + $total = array_sum($weights); + $r = rand(1, $total); + $cum = 0; + foreach ($statuses as $i => $status) { + $cum += $weights[$i]; + if ($r <= $cum) return $status; + } + return $statuses[0]; +} + +$appointmentStatuses = ['reserved','visited','completed','cancelled_by_user','cancelled_by_doctor','no_show']; +$apptWeights = [20, 25, 30, 10, 8, 7]; + +for ($i = 0; $i < 500; $i++) { + $doctorId = rand_item($doctorIds); + $userId = rand_item($patientIds); + $status = weightedStatus($appointmentStatuses, $apptWeights); + + // Past appointments: visited/completed/cancelled, Future: reserved + if (in_array($status, ['visited','completed','no_show','cancelled_by_user','cancelled_by_doctor'])) { + $slotStart = $now - rand(3600, 86400 * 180); + } else { + $slotStart = $now + rand(3600, 86400 * 30); + } + $slotEnd = $slotStart + 1800; // 30 min + $ts = $slotStart - rand(3600, 86400 * 7); + $notes = ['','مراجعه اول','پیگیری','نوبت اضطراری','مشاوره','کنترل دوره‌ای']; + $apptStmt->execute([uuid(), $slotStart, $slotEnd, $status, rand_item($notes), $ts, $ts, $doctorId, $userId]); + $apptId = (int)$pdo->lastInsertId(); + $apptIds[] = $apptId; + $apptStatusFinal[] = $status; + $count++; +} +echo " Appointments: " . count($apptIds) . "\n"; + +// ── 7. Payments ─────────────────────────────────────────────────────────────── +echo "Inserting payments...\n"; +$payStmt = $pdo->prepare( + 'INSERT INTO payments (uuid,order_id,amount_rials,status,gateway,type,reference_id,created_at,updated_at,user_id,appointment_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?)' +); +$gateways = ['mellat','sep','zarinpal','parsian']; +// Only completed/visited appointments get paid +$paidApptIds = []; +foreach ($apptIds as $k => $apptId) { + if (in_array($apptStatusFinal[$k], ['visited','completed','reserved'])) { + $paidApptIds[] = [$apptId, $k]; + } +} +shuffle($paidApptIds); +$paidApptIds = array_slice($paidApptIds, 0, 380); + +foreach ($paidApptIds as [$apptId, $k]) { + $status = in_array($apptStatusFinal[$k], ['visited','completed']) ? 'paid' : rand_item(['paid','pending']); + $amount = rand_item([1500000,2000000,2500000,3000000,3500000,4000000,4500000,5000000]); + $userId = rand_item($patientIds); + $ts = $now - rand(3600, 86400 * 180); + $refId = $status === 'paid' ? (string)rand(100000000, 999999999) : null; + $payStmt->execute([ + uuid(), 'ORD-' . strtoupper(substr(uuid(), 0, 8)), $amount, $status, + rand_item($gateways), 'appointment', $refId, $ts, $ts, $userId, $apptId + ]); + $count++; +} +echo " Payments: " . count($paidApptIds) . "\n"; + +// ── 8. Rates ────────────────────────────────────────────────────────────────── +echo "Inserting rates...\n"; +$rateStmt = $pdo->prepare('INSERT INTO rates (uuid,score,created_at,updated_at,user_id,doctor_id) VALUES (?,?,?,?,?,?)'); +$usedRatePairs = []; +$rateCount = 0; +$i = 0; +while ($rateCount < 200 && $i < 1000) { + $i++; + $doctorId = rand_item($doctorIds); + $userId = rand_item($patientIds); + $key = "$userId-$doctorId"; + if (isset($usedRatePairs[$key])) continue; + $usedRatePairs[$key] = true; + $score = rand_item([1,2,3,3,4,4,4,5,5,5]); + $ts = $now - rand(3600, 86400 * 300); + $rateStmt->execute([uuid(), $score, $ts, $ts, $userId, $doctorId]); + $rateCount++; + $count++; +} +echo " Rates: $rateCount\n"; + +// ── 9. Comments ─────────────────────────────────────────────────────────────── +echo "Inserting comments...\n"; +$comStmt = $pdo->prepare('INSERT INTO comments (uuid,body,status,created_at,updated_at,user_id,doctor_id) VALUES (?,?,?,?,?,?,?)'); +$comStatuses = ['approved','approved','approved','pending','rejected']; +for ($i = 0; $i < 150; $i++) { + $doctorId = rand_item($doctorIds); + $userId = rand_item($patientIds); + $ts = $now - rand(3600, 86400 * 300); + $comStmt->execute([uuid(), rand_item($commentTexts), rand_item($comStatuses), $ts, $ts, $userId, $doctorId]); + $count++; +} +echo " Comments: 150\n"; + +// ── 10. Blogs ───────────────────────────────────────────────────────────────── +echo "Inserting blogs...\n"; +$blogStmt = $pdo->prepare( + 'INSERT INTO blogs (uuid,title,slug,body,summary,tags,status,created_at,updated_at,author_id) + VALUES (?,?,?,?,?,?,?,?,?,?)' +); +$adminUserId = null; +$adminRow = $pdo->query("SELECT id FROM users WHERE roles LIKE '%ROLE_ADMIN%' LIMIT 1")->fetch(PDO::FETCH_ASSOC); +if ($adminRow) $adminUserId = $adminRow['id']; + +$blogTags = [['سلامت','قلب'],['کودکان','تغذیه'],['پیشگیری','چکاپ'],['روانشناسی','استرس'], + ['دیابت','تغذیه'],['ورزش','قلب'],['خواب','سلامت'],['پوست','مراقبت'], + ['استخوان','تغذیه'],['چشم','بینایی'],['سرطان','پیشگیری'],['دندان','بهداشت'], + ['فشار خون','قلب'],['واکسن','پیشگیری'],['مفصل','ارتوپدی']]; +$usedSlugs = []; +for ($i = 0; $i < min(count($blogTitles), 15); $i++) { + $title = $blogTitles[$i]; + $slug = 'blog-post-' . ($i + 1) . '-' . rand(1000, 9999); + $body = rand_item($blogBodies) . ' ' . rand_item($blogBodies); + $tags = json_encode($blogTags[$i] ?? ['سلامت'], JSON_UNESCAPED_UNICODE); + $status = $i < 12 ? 'published' : 'draft'; + $ts = $now - rand(86400, 86400 * 200); + $authorId = $adminUserId ?? rand_item($doctorUserIds); + $blogStmt->execute([uuid(), $title, $slug, $body, mb_substr($body, 0, 150), $tags, $status, $ts, $ts, $authorId]); + $count++; +} +echo " Blogs: 15\n"; + +$pdo->exec('SET FOREIGN_KEY_CHECKS = 1'); + +echo "\n=== Seed Complete ===\n"; +$tables = ['users','doctors','clinics','clinic_doctors','doctor_specialties','doctor_expertise', + 'doctor_provinces','doctor_cities','doctor_addresses','appointments','payments', + 'rates','comments','blogs','insurances']; +$total = 0; +foreach ($tables as $t) { + $c = (int)$pdo->query("SELECT COUNT(*) FROM `$t`")->fetchColumn(); + echo " $t: $c\n"; + $total += $c; +} +echo "\nTotal records across tables: $total\n"; diff --git a/data/seed_finish.php b/data/seed_finish.php new file mode 100644 index 00000000..37b6ac1d --- /dev/null +++ b/data/seed_finish.php @@ -0,0 +1,126 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$pdo->exec('SET NAMES utf8mb4'); + +$now = time(); +function uuid(): string { + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', + mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff), + mt_rand(0,0x0fff)|0x4000,mt_rand(0,0x3fff)|0x8000, + mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff)); +} +function ri(array $a) { return $a[array_rand($a)]; } +function wRand(array $items, array $weights): mixed { + $total = array_sum($weights); $r = rand(1, $total); $c = 0; + foreach ($items as $k => $v) { $c += $weights[$k]; if ($r <= $c) return $v; } + return $items[0]; +} + +// Load existing IDs +$doctorIds = $pdo->query('SELECT id FROM doctors')->fetchAll(PDO::FETCH_COLUMN); +$patientIds = $pdo->query("SELECT id FROM users WHERE roles NOT LIKE '%ROLE_DOCTOR%' AND roles NOT LIKE '%ROLE_ADMIN%'")->fetchAll(PDO::FETCH_COLUMN); +echo 'Doctors: ' . count($doctorIds) . ', Patients: ' . count($patientIds) . "\n"; + +// ── Ratings ─────────────────────────────────────────────────────────────────── +echo "Inserting ratings...\n"; +$rateStmt = $pdo->prepare('INSERT INTO rates (uuid,score,created_at,updated_at,user_id,doctor_id) VALUES (?,?,?,?,?,?)'); +$usedPairs = []; +$rateCount = 0; +$pdo->beginTransaction(); +$tries = 0; +while ($rateCount < 3000 && $tries < 30000) { + $tries++; + $doctorId = ri($doctorIds); + $userId = ri($patientIds); + $key = $userId . '-' . $doctorId; + if (isset($usedPairs[$key])) continue; + $usedPairs[$key] = true; + $score = wRand([1,2,3,4,5], [3,5,15,35,42]); + $ts = $now - rand(3600, 86400 * 400); + $rateStmt->execute([uuid(), $score, $ts, $ts, $userId, $doctorId]); + $rateCount++; + if ($rateCount % 1000 === 0) { $pdo->commit(); $pdo->beginTransaction(); echo " $rateCount\n"; } +} +$pdo->commit(); +echo "Ratings: $rateCount\n"; + +// ── Comments ────────────────────────────────────────────────────────────────── +echo "Inserting comments...\n"; +$comTexts = [ + 'دکتر بسیار دلسوز و با حوصله هستند. توضیحات کامل دادند.', + 'معاینه دقیق بود. تشخیص درست و درمان موثر. ممنونم.', + 'وقت انتظار کم بود و کیفیت ویزیت عالی.', + 'بسیار متبحر و باتجربه. مشکلم حل شد.', + 'رفتار حرفه‌ای و انسانی. مطب تمیز و منظم. توصیه می‌کنم.', + 'ویزیت خوبی داشتم. دارو‌ها موثر بود.', + 'یکی از بهترین پزشکانی که دیده‌ام. صبور و دقیق.', + 'کمی صبر کردم ولی ارزشش داشت. وقت کافی گذاشت.', + 'متخصص واقعی. همه سوالات را صادقانه جواب داد.', + 'رزرو آسان و ویزیت به موقع. کاملاً راضی هستم.', + 'برخورد محترمانه و تخصص بالا. حتماً دوباره مراجعه می‌کنم.', + 'اطلاعات دقیق و مشاوره عالی. بهترین انتخاب بود.', +]; +$comStmt = $pdo->prepare('INSERT INTO comments (uuid,body,status,created_at,updated_at,user_id,doctor_id) VALUES (?,?,?,?,?,?,?)'); +$comStatuses = ['approved','approved','approved','approved','pending','rejected']; +$pdo->beginTransaction(); +for ($i = 0; $i < 2000; $i++) { + $ts = $now - rand(3600, 86400 * 400); + $comStmt->execute([uuid(), ri($comTexts), ri($comStatuses), $ts, $ts, ri($patientIds), ri($doctorIds)]); + if (($i+1) % 500 === 0) { $pdo->commit(); $pdo->beginTransaction(); echo " Comments: " . ($i+1) . "\n"; } +} +$pdo->commit(); +echo "Comments: 2000\n"; + +// ── Blogs ───────────────────────────────────────────────────────────────────── +echo "Inserting blogs...\n"; +$blogStmt = $pdo->prepare('INSERT INTO blogs (uuid,title,slug,body,summary,tags,status,created_at,updated_at,author_id) VALUES (?,?,?,?,?,?,?,?,?,?)'); +$blogData = [ + ['راهنمای جامع پیشگیری از بیماری‌های قلبی','heart-disease-prevention','بیماری‌های قلبی از علل اصلی مرگ هستند. با تغذیه سالم، ورزش منظم، ترک سیگار و کنترل فشار خون می‌توان خطر ابتلا را کاهش داد.',['قلب','پیشگیری','سلامت'],'published'], + ['تغذیه سالم برای کودکان در سنین رشد','healthy-nutrition-children','مصرف متعادل پروتئین، لبنیات، میوه و سبزیجات برای رشد کودکان ضروری است.',['کودکان','تغذیه','رشد'],'published'], + ['اهمیت چکاپ منظم سالانه','annual-checkup','آزمایش خون، فشار خون و غربالگری سرطان باید سالانه انجام شوند. تشخیص زودهنگام درمان را ساده‌تر می‌کند.',['چکاپ','پیشگیری'],'published'], + ['مدیریت استرس در زندگی مدرن','stress-management','تنفس عمیق، مدیتیشن، ورزش و ارتباط اجتماعی سالم از راهکارهای موثر مدیریت استرس هستند.',['استرس','سلامت روان'],'published'], + ['دیابت نوع ۲: علائم و کنترل','diabetes-type2','تشنگی زیاد، ادرار مکرر و خستگی از علائم دیابت هستند. رژیم مناسب و ورزش در مدیریت آن حیاتی است.',['دیابت','قند خون'],'published'], + ['نقش ورزش در سلامت قلب','exercise-cardiovascular','۱۵۰ دقیقه فعالیت هوازی در هفته برای سلامت قلب ضروری است.',['ورزش','قلب'],'published'], + ['خواب کافی و سلامت روان','sleep-health','بزرگسالان به ۷-۹ ساعت خواب نیاز دارند. کمبود خواب با بیماری‌های مزمن ارتباط دارد.',['خواب','سلامت'],'published'], + ['مراقبت از پوست در برابر آفتاب','skin-care-sun','استفاده از کرم ضدآفتاب SPF 30+ و پوشش مناسب از پوست محافظت می‌کند.',['پوست','ضدآفتاب'],'published'], + ['پیشگیری از پوکی استخوان','osteoporosis','مصرف کلسیم، ویتامین D و ورزش منظم از پوکی استخوان جلوگیری می‌کنند.',['استخوان','کلسیم'],'published'], + ['مراقبت از بینایی','eye-care','معاینه سالانه چشم و رعایت قانون ۲۰-۲۰-۲۰ برای سلامت چشم ضروری است.',['چشم','بینایی'],'published'], + ['سرطان پستان؛ تشخیص زودهنگام','breast-cancer','معاینه خودآزمایی ماهانه و ماموگرافی سالانه از ابزارهای تشخیص زودهنگام هستند.',['سرطان','پستان'],'published'], + ['بهداشت دهان و دندان','dental-hygiene','مسواک زدن دو بار در روز و مراجعه به دندانپزشک هر ۶ ماه توصیه می‌شود.',['دندان','بهداشت'],'published'], + ['کنترل فشار خون بالا','blood-pressure','کاهش نمک، ورزش منظم و مصرف داروها در کنترل فشار خون موثر هستند.',['فشار خون','قلب'],'published'], + ['واکسیناسیون بزرگسالان','adult-vaccination','آنفلوانزا، هپاتیت B و واکسن HPV از واکسن‌های مهم بزرگسالی هستند.',['واکسن','پیشگیری'],'published'], + ['آرتروز زانو: درمان و بازتوانی','knee-arthritis','فیزیوتراپی، ورزش‌های تقویتی و کاهش وزن در درمان آرتروز زانو موثر هستند.',['آرتروز','ارتوپدی'],'published'], + ['تغذیه در بیماری‌های کلیوی','renal-diet','رژیم کم‌پتاسیم و کم‌فسفر برای بیماران کلیوی ضروری است.',['کلیه','تغذیه'],'draft'], + ['سلامت روان در محیط کار','workplace-mental-health','تعادل کار و زندگی و ارتباط موثر با همکاران از عوامل سلامت روان در کار هستند.',['سلامت روان','کار'],'published'], + ['آلرژی فصلی','seasonal-allergy','اجتناب از محرک‌ها و استفاده از آنتی‌هیستامین از روش‌های اصلی مقابله با آلرژی هستند.',['آلرژی','تنفس'],'published'], + ['ورزش در دوران بارداری','pregnancy-exercise','پیاده‌روی و یوگای بارداری با نظر پزشک برای مادر و جنین مفید است.',['بارداری','ورزش'],'published'], + ['پیشگیری از سرطان روده','colorectal-cancer','کولونوسکوپی از سن ۴۵ سالگی و رژیم پرفیبر خطر را کاهش می‌دهند.',['سرطان','روده'],'published'], +]; +$adminRow = $pdo->query("SELECT id FROM users WHERE roles LIKE '%ROLE_ADMIN%' LIMIT 1")->fetch(PDO::FETCH_ASSOC); +$adminId = $adminRow ? $adminRow['id'] : ri($doctorIds); +foreach ($blogData as $b) { + $ts = $now - rand(86400, 86400 * 300); + $blogStmt->execute([ + uuid(), $b[0], $b[1] . '-' . rand(100,999), $b[2], + mb_substr($b[2], 0, 200), json_encode($b[3], JSON_UNESCAPED_UNICODE), + $b[4], $ts, $ts, $adminId + ]); +} +echo 'Blogs: ' . count($blogData) . "\n"; + +// ── Summary ─────────────────────────────────────────────────────────────────── +echo "\n=== Final counts ===\n"; +$tables = ['users','doctors','clinics','clinic_doctors','clinic_specialties','clinic_services','clinic_insurances', + 'doctor_specialties','doctor_expertise','doctor_provinces','doctor_cities','doctor_addresses', + 'appointments','payments','rates','comments','blogs','insurances','profiles']; +$total = 0; +foreach ($tables as $t) { + $c = (int)$pdo->query("SELECT COUNT(*) FROM `$t`")->fetchColumn(); + printf(" %-30s %d\n", $t . ':', $c); + $total += $c; +} +echo "\nTotal records: $total\n"; diff --git a/data/seed_full.php b/data/seed_full.php new file mode 100644 index 00000000..ec1851ff --- /dev/null +++ b/data/seed_full.php @@ -0,0 +1,708 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$pdo->exec('SET NAMES utf8mb4'); +$pdo->exec('SET FOREIGN_KEY_CHECKS = 0'); +$pdo->exec("SET SESSION sql_mode = ''"); + +$now = time(); +$BASE_DIR = '/var/www/html/public'; +$BASE_URL = ''; + +// ── Helpers ─────────────────────────────────────────────────────────────────── +function uuid(): string { + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', + mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff), + mt_rand(0,0x0fff)|0x4000,mt_rand(0,0x3fff)|0x8000, + mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff)); +} +function ri(array $a) { return $a[array_rand($a)]; } +function ris(array $a, int $min, int $max): array { + $n = rand($min, min($max, count($a))); + shuffle($a); + return array_slice($a, 0, $n); +} +function mobile(array &$used): string { + $prefixes = ['0910','0911','0912','0913','0914','0915','0916','0917','0918','0919', + '0930','0933','0935','0936','0937','0938','0901','0902','0920','0921', + '0991','0992','0993','0994']; + do { + $m = ri($prefixes) . str_pad((string)rand(1000000,9999999),7,'0',STR_PAD_LEFT); + } while (isset($used[$m])); + $used[$m] = true; + return $m; +} +function pw(): string { return '$2y$13$fakehash' . substr(str_replace(['+','/','='],'',base64_encode(random_bytes(24))),0,44); } + +// ── Download images with parallel curl ─────────────────────────────────────── +function downloadParallel(array $urls, array $paths, int $batchSize = 20): void { + $total = count($urls); + for ($offset = 0; $offset < $total; $offset += $batchSize) { + $batch = array_slice($urls, $offset, $batchSize, true); + $batchPath = array_slice($paths, $offset, $batchSize, true); + $mh = curl_multi_init(); + $handles = []; + foreach ($batch as $i => $url) { + if (file_exists($batchPath[$i])) continue; + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_TIMEOUT => 15, + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_USERAGENT => 'Mozilla/5.0', + ]); + curl_multi_add_handle($mh, $ch); + $handles[$i] = $ch; + } + $running = null; + do { curl_multi_exec($mh, $running); curl_multi_select($mh); } while ($running > 0); + foreach ($handles as $i => $ch) { + $data = curl_multi_getcontent($ch); + if ($data && strlen($data) > 1000) { + @mkdir(dirname($batchPath[$i]), 0755, true); + file_put_contents($batchPath[$i], $data); + } + curl_multi_remove_handle($mh, $ch); + curl_close($ch); + } + curl_multi_close($mh); + echo '.'; + } + echo "\n"; +} + +function imgJson(string $url, string $filename, int $filesize = 0): string { + return json_encode([[ + 'fid' => rand(10000, 999999), + 'uuid' => uuid(), + 'url' => $url, + 'filename' => $filename, + 'filemime' => 'image/jpeg', + 'filesize' => $filesize > 0 ? $filesize : rand(25000, 90000), + ]], JSON_UNESCAPED_UNICODE); +} + +// ── STEP 1 — Download doctor photos ────────────────────────────────────────── +echo "=== Downloading doctor photos ===\n"; +$doctorPhotoDir = $BASE_DIR . '/uploads/doctors/2026-06'; +@mkdir($doctorPhotoDir, 0755, true); + +$photoUrls = []; +$photoPaths = []; +$doctorPhotos = ['male' => [], 'female' => []]; + +// 99 male portraits +for ($n = 1; $n <= 99; $n++) { + $url = "https://randomuser.me/api/portraits/men/$n.jpg"; + $path = "$doctorPhotoDir/m-$n.jpg"; + $photoUrls[] = $url; + $photoPaths[] = $path; + $doctorPhotos['male'][] = [ + 'url' => "/uploads/doctors/2026-06/m-$n.jpg", + 'file' => "m-$n.jpg", + 'path' => $path, + ]; +} +// 99 female portraits +for ($n = 1; $n <= 99; $n++) { + $url = "https://randomuser.me/api/portraits/women/$n.jpg"; + $path = "$doctorPhotoDir/f-$n.jpg"; + $photoUrls[] = $url; + $photoPaths[] = $path; + $doctorPhotos['female'][] = [ + 'url' => "/uploads/doctors/2026-06/f-$n.jpg", + 'file' => "f-$n.jpg", + 'path' => $path, + ]; +} +echo "Downloading 198 doctor portraits "; +downloadParallel($photoUrls, $photoPaths, 25); + +// ── STEP 2 — Download clinic gallery & logos ────────────────────────────────── +echo "=== Downloading clinic images ===\n"; +$galleryDir = $BASE_DIR . '/uploads/clinics/gallery/2026-06'; +$logoDir = $BASE_DIR . '/uploads/clinics/logo/2026-06'; +@mkdir($galleryDir, 0755, true); +@mkdir($logoDir, 0755, true); + +$clinicPhotoUrls = []; +$clinicPhotoPaths = []; +$clinicGalleryPhotos = []; +$clinicLogoPhotos = []; + +// 60 clinic gallery photos (medical/building themed via picsum seeds) +$clinicSeeds = [100,200,300,400,500,600,700,800,900,1000,1100,1200,1300,1400,1500, + 1600,1700,1800,1900,2000,2100,2200,2300,2400,2500,2600,2700,2800, + 2900,3000,3100,3200,3300,3400,3500,3600,3700,3800,3900,4000, + 4100,4200,4300,4400,4500,4600,4700,4800,4900,5000,5100,5200,5300,5400,5500,5600,5700,5800,5900,6000]; +foreach ($clinicSeeds as $seed) { + $url = "https://picsum.photos/seed/$seed/640/480"; + $path = "$galleryDir/c-$seed.jpg"; + $clinicPhotoUrls[] = $url; + $clinicPhotoPaths[] = $path; + $clinicGalleryPhotos[] = ['url' => "/uploads/clinics/gallery/2026-06/c-$seed.jpg", 'file' => "c-$seed.jpg"]; +} +// 40 clinic logos (smaller) +$logoSeeds = [10,20,30,40,50,60,70,80,90,110,120,130,140,150,160,170,180,190,210,220, + 230,240,250,260,270,280,290,310,320,330,340,350,360,370,380,390,410,420,430,440]; +foreach ($logoSeeds as $seed) { + $url = "https://picsum.photos/seed/logo$seed/200/200"; + $path = "$logoDir/logo-$seed.jpg"; + $clinicPhotoUrls[] = $url; + $clinicPhotoPaths[] = $path; + $clinicLogoPhotos[] = ['url' => "/uploads/clinics/logo/2026-06/logo-$seed.jpg", 'file' => "logo-$seed.jpg"]; +} +echo "Downloading 100 clinic images "; +downloadParallel($clinicPhotoUrls, $clinicPhotoPaths, 25); + +// ── STEP 3 — Download insurance logos ───────────────────────────────────────── +echo "=== Downloading insurance logos ===\n"; +$insLogoDir = $BASE_DIR . '/uploads/insurances/logo/2026-06'; +@mkdir($insLogoDir, 0755, true); +$insLogoUrls = []; +$insLogoPaths = []; +$insLogoFiles = []; +for ($n = 1; $n <= 20; $n++) { + $seed = $n * 50; + $url = "https://picsum.photos/seed/ins$seed/200/200"; + $path = "$insLogoDir/ins-$n.jpg"; + $insLogoUrls[] = $url; + $insLogoPaths[] = $path; + $insLogoFiles[] = "/uploads/insurances/logo/2026-06/ins-$n.jpg"; +} +echo "Downloading 20 insurance logos "; +downloadParallel($insLogoUrls, $insLogoPaths, 20); + +// ── Load DB data ────────────────────────────────────────────────────────────── +$provinces = $pdo->query('SELECT id FROM provinces')->fetchAll(PDO::FETCH_COLUMN); +$cities = $pdo->query('SELECT id, province_id FROM cities WHERE id != 600')->fetchAll(PDO::FETCH_ASSOC); +$cityIds = array_column($cities, 'id'); +$cityProvMap = array_column($cities, 'province_id', 'id'); +$specParents = $pdo->query('SELECT id FROM specialties WHERE parent_id IS NULL')->fetchAll(PDO::FETCH_COLUMN); +$specChildren = $pdo->query('SELECT id, parent_id FROM specialties WHERE parent_id IS NOT NULL')->fetchAll(PDO::FETCH_ASSOC); +$allServiceRows = $pdo->query('SELECT id, specialty_id FROM doctor_services')->fetchAll(PDO::FETCH_ASSOC); +$serviceIds = array_column($allServiceRows, 'id'); +$specSvcMap = []; +foreach ($allServiceRows as $r) { + if ($r['specialty_id']) $specSvcMap[$r['specialty_id']][] = $r['id']; +} +$specChildMap = []; +foreach ($specChildren as $r) { + $specChildMap[$r['parent_id']][] = $r['id']; +} + +// ── Static data ─────────────────────────────────────────────────────────────── +$maleNames = ['علی','محمد','حسین','احمد','رضا','مهدی','حسن','اکبر','ابراهیم','کریم','جواد','امیر', + 'سعید','مجید','فرید','کامران','سیاوش','داریوش','پرویز','شهرام','بهرام','فرهاد','نادر', + 'مسعود','وحید','یاسر','حامد','سجاد','ایمان','میثم','آرش','آرمان','پدرام','پویا','کیان', + 'سیروس','بابک','فریبرز','هوشنگ','نیما','شاهین','کاوه','آریا','پارسا','دانیال','سینا', + 'رامین','کورش','منوچهر','فرامرز','بهزاد','پیمان','امین','اشکان','شایان','آیدین','ارسلان']; +$femaleNames = ['فاطمه','زهرا','مریم','سارا','نرگس','لیلا','نازنین','مهناز','شیرین','پروین','ملیحه', + 'الناز','آتنا','باران','ترانه','دلارام','رویا','شادی','گلناز','ماهرخ','ندا','نیلوفر', + 'هانیه','یاسمن','زینب','حدیثه','سمیه','طاهره','عاطفه','منیژه','سوده','ریحانه','فرزانه', + 'نسرین','ناهید','مینا','گیتی','آذر','پرستو','ژیلا','شکوفه','آفرین','بهناز','مهسا','رها']; +$lastNames = ['احمدی','محمدی','رضایی','حسینی','موسوی','جعفری','کریمی','نوری','صادقی','قاسمی', + 'عباسی','میرزایی','رحیمی','اکبری','یوسفی','حیدری','طاهری','نصیری','سلیمانی','زارعی', + 'مرادی','شریفی','منصوری','ذبیحی','تهرانی','اصفهانی','مشهدی','شیرازی','تبریزی','همدانی', + 'ملکی','درویشی','امیری','نجفی','شاهی','بهرامی','خسروی','گلمحمدی','فدایی','ولیپور', + 'نظری','فروزان','پورعلی','دهقانی','صالحی','ربیعی','مجیدی','سبحانی','زمانی','بهشتی', + 'عزیزی','خلیلی','رستمی','پورحسین','نظام‌الدینی','میرمحمدی','سیدی','سلطانی','نادری','ابراهیمی']; +$degrees = ['متخصص','فوق تخصص','دکترای عمومی','فلوشیپ','استادیار','دانشیار','پروفسور','رزیدنت']; +$bios = [ + 'دارای بیش از ۱۵ سال سابقه در حوزه تخصصی، عضو انجمن پزشکی ایران و سازمان نظام پزشکی.', + 'فارغ‌التحصیل دانشگاه علوم پزشکی تهران با تجربه کار در بیمارستان‌های معتبر کشور.', + 'متخصص با سابقه درخشان، ارائه خدمات با بالاترین کیفیت با استفاده از جدیدترین تجهیزات.', + 'عضو هیئت علمی دانشگاه با بیش از ۱۰ سال تجربه بالینی و پژوهشی.', + 'دارای گواهینامه‌های تخصصی از مراکز بین‌المللی، آشنا با جدیدترین روش‌های درمانی.', + 'پزشک باتجربه با رویکرد جامع در درمان و اعتقاد راسخ به طب پیشگیری.', + 'متعهد به ارائه بهترین مراقبت‌های پزشکی با رعایت کامل اصول اخلاق پزشکی.', + 'دارای مدرک تخصصی از اروپا و تجربه کار در مراکز درمانی پیشرفته اروپا و آمریکا.', + 'فارغ‌التحصیل ممتاز دانشگاه علوم پزشکی مشهد، برنده جایزه پزشک نمونه سال.', + 'متخصص با سابقه بیش از ۲۰ سال در درمان بیماری‌های مزمن و پیچیده.', + 'عضو چندین انجمن علمی تخصصی، دارای مقالات متعدد در مجلات معتبر.', + 'پزشک متخصص با رویکرد بیمار‌محور و استفاده از روش‌های نوین تشخیص و درمان.', +]; +$clinicNames = ['کلینیک تخصصی','مرکز درمانی','بیمارستان','کلینیک جامع','مرکز مشاوره پزشکی', + 'مطب','کلینیک ویژه','مرکز پزشکی','درمانگاه','کلینیک سلامت','مجتمع پزشکی']; +$clinicSuffixes = ['امید','نوین','رازی','ابن سینا','سینا','شفا','سلامت','آریا','پارس','ایران', + 'مهر','صبا','فجر','بهار','شهید بهشتی','حضرت علی','امام رضا','گلستان','نور','طلوع']; +$streets = ['خیابان ولیعصر','خیابان انقلاب','خیابان آزادی','بلوار کشاورز','خیابان شریعتی', + 'خیابان مطهری','خیابان فردوسی','خیابان پاسداران','خیابان جمهوری','خیابان طالقانی', + 'بلوار سعادت‌آباد','خیابان وزرا','خیابان بهشتی','خیابان میرداماد','خیابان حقانی', + 'خیابان دکتر چمران','بزرگراه شهید همت','خیابان ملاصدرا','خیابان زرتشت','بلوار اشرفی']; +$buildings = ['ساختمان پزشکان','برج طبی','مجتمع پزشکی','پلاک','مطب طبقه','واحد']; +$workingDaysList = [ + 'شنبه تا چهارشنبه ۸ تا ۲۰', 'شنبه تا پنجشنبه ۸ تا ۱۸', + 'یک‌شنبه تا پنجشنبه ۹ تا ۱۷', 'شنبه تا سه‌شنبه ۷ تا ۱۹', + 'همه روزه ۸ تا ۲۲', 'شنبه تا چهارشنبه ۹ تا ۲۰', + 'دوشنبه تا جمعه ۱۰ تا ۱۸', 'شنبه تا پنجشنبه ۷ تا ۱۳ و ۱۶ تا ۲۰', +]; +$apptStatuses = ['reserved','visited','completed','cancelled_by_user','cancelled_by_doctor','no_show','waiting','checked_in']; +$apptWeights = [15, 25, 30, 10, 5, 5, 5, 5]; +$commentTexts = [ + 'دکتر بسیار دلسوز و با حوصله هستند. توضیحات کاملی دادند و از معاینه راضی بودم.', + 'معاینه بسیار دقیق بود. تشخیص درست و درمان موثر. ممنونم از دکتر عزیز.', + 'وقت انتظار کمی داشتم و دکتر سر وقت حاضر بودند. کیفیت ویزیت بالا بود.', + 'بسیار متبحر و با تجربه. مشکلم کاملاً حل شد و از نتیجه درمان راضی هستم.', + 'توصیه می‌کنم به همه. رفتار حرفه‌ای و انسانی. مطب تمیز و منظم.', + 'دکتر خوبی هستند ولی وقت ویزیت کمی کوتاه بود. در کل تجربه خوبی داشتم.', + 'از ویزیت کاملاً راضی بودم. درمان موثر و پیگیری خوب.', + 'یکی از بهترین پزشکانی که تاکنون به آنها مراجعه کرده‌ام. بسیار ماهر و دلسوز.', + 'کمی منتظر ماندم اما ارزشش را داشت. دکتر وقت کافی برای بیمار می‌گذارند.', + 'متخصص واقعی در حوزه کار خود. با صبر و حوصله همه سوالات را جواب دادند.', + 'رزرو آنلاین خیلی راحت بود. دکتر به موقع ویزیت کردند و مشکلم برطرف شد.', + 'برخورد محترمانه و صادقانه. داروها اثر کردند. حتماً دوباره مراجعه خواهم کرد.', +]; + +// ── STEP 4 — Insurances ─────────────────────────────────────────────────────── +echo "\n=== Inserting insurances ===\n"; +$insData = [ + ['تأمین اجتماعی','basic'],['خدمات درمانی','basic'],['نیروهای مسلح','basic'], + ['کمیته امداد امام خمینی','basic'],['سازمان بهزیستی','basic'],['بیمه روستایی','basic'], + ['ایران','supplementary'],['آسیا','supplementary'],['البرز','supplementary'], + ['پارسیان','supplementary'],['سامان','supplementary'],['میهن','supplementary'], + ['دانا','supplementary'],['رازی','supplementary'],['کوثر','supplementary'], + ['معلم','supplementary'],['ملت','supplementary'],['حافظ','supplementary'], + ['اتکا','supplementary'],['توسعه','supplementary'], +]; +$insStmt = $pdo->prepare('INSERT INTO insurances (uuid,name,type,logo_url,status) VALUES (?,?,?,?,1)'); +$insIds = []; +foreach ($insData as $i => $ins) { + $logo = isset($insLogoFiles[$i]) ? $insLogoFiles[$i] : null; + $insStmt->execute([uuid(), $ins[0], $ins[1], $logo]); + $insIds[] = (int)$pdo->lastInsertId(); +} +echo 'Insurances: ' . count($insIds) . "\n"; + +// ── STEP 5 — Patients ───────────────────────────────────────────────────────── +echo "=== Inserting patients (3000) ===\n"; +$usedMobiles = []; +// Reserve admin mobile +$usedMobiles['09120671713'] = true; +$patientIds = []; + +$uStmt = $pdo->prepare( + 'INSERT INTO users (uuid,mobile_number,password_hash,email,real_name,roles,status,created_at,updated_at) + VALUES (?,?,?,?,?,?,1,?,?)' +); +$pStmt = $pdo->prepare( + 'INSERT INTO profiles (uuid,label,family,gender,blood_type,marital_status,sharing_with_user, + basic_insurance_id,supplementary_insurance_id,created_at,updated_at,user_id) + VALUES (?,?,?,?,?,?,1,?,?,?,?,?)' +); +$bloodTypes = ['A+','A-','B+','B-','O+','O-','AB+','AB-']; +$marital = ['single','married','divorced','widowed']; + +$pdo->beginTransaction(); +$batchCount = 0; +for ($i = 0; $i < 3000; $i++) { + $gender = rand(0,2) === 0 ? 'female' : 'male'; + $firstName = $gender === 'female' ? ri($femaleNames) : ri($maleNames); + $lastName = ri($lastNames); + $name = $firstName . ' ' . $lastName; + $mob = mobile($usedMobiles); + $email = 'patient' . $i . '@mail.ir'; + $ts = $now - rand(86400, 86400 * 730); + + $uStmt->execute([uuid(), $mob, pw(), $email, $name, '["ROLE_USER"]', $ts, $ts]); + $userId = (int)$pdo->lastInsertId(); + $patientIds[] = $userId; + + // Profile for some patients + if ($i % 3 === 0) { + $basicIns = ri(array_slice($insIds, 0, 6)); + $suppIns = rand(0,1) ? ri(array_slice($insIds, 6)) : null; + $pStmt->execute([ + uuid(), $firstName, $lastName, $gender, ri($bloodTypes), ri($marital), + $basicIns, $suppIns, $ts, $ts, $userId + ]); + } + + $batchCount++; + if ($batchCount % 500 === 0) { + $pdo->commit(); + $pdo->beginTransaction(); + echo " Patients: $batchCount\n"; + } +} +$pdo->commit(); +echo 'Total patients: ' . count($patientIds) . "\n"; + +// ── STEP 6 — Doctors (1000) ─────────────────────────────────────────────────── +echo "=== Inserting doctors (1000) ===\n"; +$doctorIds = []; +$doctorUserIds = []; +$doctorGenderMap = []; + +$duStmt = $pdo->prepare( + 'INSERT INTO users (uuid,mobile_number,password_hash,email,real_name,roles,status,created_at,updated_at) + VALUES (?,?,?,?,?,?,1,?,?)' +); +$dStmt = $pdo->prepare( + 'INSERT INTO doctors (uuid,name,gender,medical_system_code,mobile_number,activity_time,degree,info, + images,doctor_rate,doctor_rate_percentage,active_doctor_appointment,created_at,updated_at,user_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?,1,?,?,?)' +); +$dsStmt = $pdo->prepare('INSERT IGNORE INTO doctor_specialties (doctor_id,specialty_id) VALUES (?,?)'); +$deStmt = $pdo->prepare('INSERT IGNORE INTO doctor_expertise (doctor_id,service_id) VALUES (?,?)'); +$dpStmt = $pdo->prepare('INSERT IGNORE INTO doctor_provinces (doctor_id,province_id) VALUES (?,?)'); +$dcStmt = $pdo->prepare('INSERT IGNORE INTO doctor_cities (doctor_id,city_id) VALUES (?,?)'); +$daStmt = $pdo->prepare( + 'INSERT INTO doctor_addresses (uuid,name,address,telephone,latitude,longitude,created_at,updated_at,doctor_id,city_id,province_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?)' +); + +$malePhotos = $doctorPhotos['male']; +$femalePhotos = $doctorPhotos['female']; + +$pdo->beginTransaction(); +for ($i = 0; $i < 1000; $i++) { + $gender = $i % 4 === 0 ? 'female' : 'male'; + $firstName = $gender === 'female' ? ri($femaleNames) : ri($maleNames); + $lastName = ri($lastNames); + $name = 'دکتر ' . $firstName . ' ' . $lastName; + $mob = mobile($usedMobiles); + $email = 'doctor' . $i . '@clinic-pro.ir'; + $ts = $now - rand(86400 * 60, 86400 * 1000); + + // User + $duStmt->execute([uuid(), $mob, pw(), $email, $name, '["ROLE_USER","ROLE_DOCTOR"]', $ts, $ts]); + $userId = (int)$pdo->lastInsertId(); + $doctorUserIds[] = $userId; + + // Pick photo + $photoPool = $gender === 'female' ? $femalePhotos : $malePhotos; + $photo = $photoPool[$i % count($photoPool)]; + $imgJson = json_encode([[ + 'fid' => rand(10000,999999), + 'uuid' => uuid(), + 'url' => $photo['url'], + 'filename' => $photo['file'], + 'filemime' => 'image/jpeg', + 'filesize' => rand(30000, 80000), + ]], JSON_UNESCAPED_UNICODE); + + $rate = round(rand(32, 50) / 10, 1); + $ratePct = rand(68, 98); + + $dStmt->execute([ + uuid(), $name, $gender, + (string)rand(10000000, 99999999), $mob, + rand(3, 30), ri($degrees), ri($bios), + $imgJson, $rate, $ratePct, $ts, $ts, $userId + ]); + $doctorId = (int)$pdo->lastInsertId(); + $doctorIds[] = $doctorId; + $doctorGenderMap[$doctorId] = $gender; + + // 1-3 parent specialties + $chosenParents = ris($specParents, 1, 2); + foreach ($chosenParents as $spId) { + $dsStmt->execute([$doctorId, $spId]); + // 1-3 child specialties under same parent + $kids = $specChildMap[$spId] ?? []; + foreach (ris($kids, 1, 3) as $kid) { + $dsStmt->execute([$doctorId, $kid]); + } + // 3-8 services + $svcPool = $specSvcMap[$spId] ?? array_slice($serviceIds, 0, 15); + foreach (ris($svcPool, 3, 8) as $svcId) { + $deStmt->execute([$doctorId, $svcId]); + } + } + + // 1-3 cities + $chosenCities = ris($cityIds, 1, 3); + foreach ($chosenCities as $cid) { + $provId = $cityProvMap[$cid] ?? null; + $dcStmt->execute([$doctorId, $cid]); + if ($provId) $dpStmt->execute([$doctorId, $provId]); + + // Address + $street = ri($streets); + $bld = ri($buildings); + $no = rand(1, 300); + $addr = $street . '، ' . $bld . ' ' . $no; + $lat = 33.0 + rand(0, 700) / 100; + $lon = 48.0 + rand(0, 1500) / 100; + $tel = '0' . ri(['21','511','411','31','71','81','351','441','131','3411']) . rand(10000000, 99999999); + $ts2 = $now - rand(86400, 86400 * 200); + $daStmt->execute([uuid(), 'مطب ' . $firstName . ' ' . $lastName, $addr, $tel, $lat, $lon, $ts2, $ts2, $doctorId, $cid, $provId]); + } + + if (($i + 1) % 100 === 0) { + $pdo->commit(); + $pdo->beginTransaction(); + echo " Doctors: " . ($i + 1) . "\n"; + } +} +$pdo->commit(); +echo 'Total doctors: ' . count($doctorIds) . "\n"; + +// ── STEP 7 — Clinics (200) ──────────────────────────────────────────────────── +echo "=== Inserting clinics (200) ===\n"; +$clinicIds = []; + +$clStmt = $pdo->prepare( + 'INSERT INTO clinics (uuid,name,info,address,telephone,is_24_7,working_days,latitude,longitude, + city_id,province_id,images_clinic,clinic_logo,created_at,updated_at,user_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)' +); +$clDStmt = $pdo->prepare('INSERT IGNORE INTO clinic_doctors (clinic_id,doctor_id) VALUES (?,?)'); +$clSpStmt = $pdo->prepare('INSERT IGNORE INTO clinic_specialties (clinic_id,specialty_id) VALUES (?,?)'); +$clSvStmt = $pdo->prepare('INSERT IGNORE INTO clinic_services (clinic_id,service_id) VALUES (?,?)'); +$clInStmt = $pdo->prepare('INSERT IGNORE INTO clinic_insurances (clinic_id,insurance_id) VALUES (?,?)'); + +// 60% of doctors go into clinics +$clinicDoctorPool = array_slice($doctorIds, 0, 600); +shuffle($clinicDoctorPool); +$poolIdx = 0; + +$pdo->beginTransaction(); +for ($i = 0; $i < 200; $i++) { + $cityRow = ri($cities); + $cityId = (int)$cityRow['id']; + $provId = (int)($cityRow['province_id'] ?? 0); + $name = ri($clinicNames) . ' ' . ri($clinicSuffixes); + $is247 = rand(0, 7) === 0 ? 1 : 0; + $ts = $now - rand(86400 * 60, 86400 * 730); + $street = ri($streets); + $no = rand(1, 300); + $addr = $street . '، پلاک ' . $no; + $tel = '0' . ri(['21','511','411','31','71','81','351','441']) . rand(10000000, 99999999); + $lat = 33.0 + rand(0, 700) / 100; + $lon = 48.0 + rand(0, 1500) / 100; + $ownerId = $doctorUserIds[array_rand($doctorUserIds)]; + + // Clinic photos (1-3 gallery + 1 logo) + $galleryCount = rand(1, 3); + $galleryArr = []; + for ($g = 0; $g < $galleryCount; $g++) { + $photo = $clinicGalleryPhotos[($i * 3 + $g) % count($clinicGalleryPhotos)]; + $galleryArr[] = ['fid'=>rand(10000,999999),'uuid'=>uuid(),'url'=>$photo['url'], + 'filename'=>$photo['file'],'filemime'=>'image/jpeg','filesize'=>rand(60000,200000)]; + } + $logoPhoto = $clinicLogoPhotos[$i % count($clinicLogoPhotos)]; + $logoArr = [['fid'=>rand(10000,999999),'uuid'=>uuid(),'url'=>$logoPhoto['url'], + 'filename'=>$logoPhoto['file'],'filemime'=>'image/jpeg','filesize'=>rand(20000,50000)]]; + + $clStmt->execute([ + uuid(), $name, + 'ارائه خدمات تخصصی پزشکی با استفاده از جدیدترین تجهیزات و کادر درمانی مجرب.', + $addr, $tel, $is247, ri($workingDaysList), $lat, $lon, + $cityId, $provId > 0 ? $provId : null, + json_encode($galleryArr, JSON_UNESCAPED_UNICODE), + json_encode($logoArr, JSON_UNESCAPED_UNICODE), + $ts, $ts, $ownerId + ]); + $clinicId = (int)$pdo->lastInsertId(); + $clinicIds[] = $clinicId; + + // 3-6 doctors per clinic + $numDocs = rand(3, 6); + $addedDocs = 0; + while ($addedDocs < $numDocs && $poolIdx < count($clinicDoctorPool)) { + $clDStmt->execute([$clinicId, $clinicDoctorPool[$poolIdx++]]); + $addedDocs++; + } + + // 2-4 specialties + foreach (ris($specParents, 2, 4) as $spId) { + $clSpStmt->execute([$clinicId, $spId]); + } + // 3-6 services + foreach (ris($serviceIds, 3, 6) as $svId) { + $clSvStmt->execute([$clinicId, $svId]); + } + // 3-6 insurances + foreach (ris($insIds, 3, 6) as $inId) { + $clInStmt->execute([$clinicId, $inId]); + } + + if (($i + 1) % 50 === 0) { + $pdo->commit(); + $pdo->beginTransaction(); + echo " Clinics: " . ($i + 1) . "\n"; + } +} +$pdo->commit(); +echo 'Total clinics: ' . count($clinicIds) . "\n"; + +// ── STEP 8 — Appointments (8000) ────────────────────────────────────────────── +echo "=== Inserting appointments (8000) ===\n"; +$apptStmt = $pdo->prepare( + 'INSERT INTO appointments (uuid,slot_start,slot_end,status,note,created_at,updated_at,doctor_id,user_id) + VALUES (?,?,?,?,?,?,?,?,?)' +); +$apptIds = []; +$apptStatusArr = []; +$notes = ['','مراجعه اول','پیگیری','نوبت اضطراری','مشاوره','کنترل دوره‌ای','آزمایش تکمیلی','چکاپ سالانه']; + +function wRand(array $items, array $weights): mixed { + $total = array_sum($weights); $r = rand(1, $total); $c = 0; + foreach ($items as $k => $item) { $c += $weights[$k]; if ($r <= $c) return $item; } + return $items[0]; +} + +$pdo->beginTransaction(); +for ($i = 0; $i < 8000; $i++) { + $doctorId = ri($doctorIds); + $userId = ri($patientIds); + $status = wRand($apptStatuses, $apptWeights); + + if (in_array($status, ['visited','completed','no_show','cancelled_by_user','cancelled_by_doctor','checked_in'])) { + $slotStart = $now - rand(3600, 86400 * 365); + } else { + $slotStart = $now + rand(3600, 86400 * 45); + } + $slotEnd = $slotStart + 1800; + $ts = $slotStart - rand(3600, 86400 * 14); + + $apptStmt->execute([uuid(), $slotStart, $slotEnd, $status, ri($notes), $ts, $ts, $doctorId, $userId]); + $apptId = (int)$pdo->lastInsertId(); + $apptIds[] = $apptId; + $apptStatusArr[] = $status; + + if (($i + 1) % 1000 === 0) { + $pdo->commit(); + $pdo->beginTransaction(); + echo " Appointments: " . ($i + 1) . "\n"; + } +} +$pdo->commit(); + +// ── STEP 9 — Payments ───────────────────────────────────────────────────────── +echo "=== Inserting payments ===\n"; +$payStmt = $pdo->prepare( + 'INSERT INTO payments (uuid,order_id,amount_rials,status,gateway,type,reference_id,created_at,updated_at,user_id,appointment_id) + VALUES (?,?,?,?,?,?,?,?,?,?,?)' +); +$gateways = ['mellat','sep','zarinpal','parsian','sadad']; +$amounts = [1500000,2000000,2500000,3000000,3500000,4000000,4500000,5000000,5500000,6000000,7000000,8000000]; + +$pdo->beginTransaction(); +$payCount = 0; +foreach ($apptIds as $k => $apptId) { + $st = $apptStatusArr[$k]; + if (!in_array($st, ['visited','completed','reserved','waiting','checked_in'])) continue; + $payStatus = in_array($st, ['visited','completed','checked_in']) ? 'paid' : ri(['paid','pending']); + $userId = ri($patientIds); + $ts = $now - rand(3600, 86400 * 365); + $refId = $payStatus === 'paid' ? (string)rand(100000000, 999999999) : null; + $payStmt->execute([ + uuid(), 'ORD-' . strtoupper(substr(uuid(), 0, 8)), ri($amounts), + $payStatus, ri($gateways), 'appointment', $refId, $ts, $ts, $userId, $apptId + ]); + $payCount++; + if ($payCount % 1000 === 0) { + $pdo->commit(); + $pdo->beginTransaction(); + echo " Payments: $payCount\n"; + } +} +$pdo->commit(); +echo "Total payments: $payCount\n"; + +// ── STEP 10 — Ratings ───────────────────────────────────────────────────────── +echo "=== Inserting ratings (3000) ===\n"; +$rateStmt = $pdo->prepare('INSERT INTO rates (uuid,score,created_at,updated_at,user_id,doctor_id) VALUES (?,?,?,?,?,?)'); +$usedPairs = []; +$rateCount = 0; +$pdo->beginTransaction(); +$tries = 0; +while ($rateCount < 3000 && $tries < 20000) { + $tries++; + $doctorId = ri($doctorIds); + $userId = ri($patientIds); + $key = $userId . '-' . $doctorId; + if (isset($usedPairs[$key])) continue; + $usedPairs[$key] = true; + $score = wRand([1,2,3,4,5], [3,5,15,35,42]); + $ts = $now - rand(3600, 86400 * 400); + $rateStmt->execute([uuid(), $score, $ts, $ts, $userId, $doctorId]); + $rateCount++; + if ($rateCount % 1000 === 0) { + $pdo->commit(); + $pdo->beginTransaction(); + echo " Ratings: $rateCount\n"; + } +} +$pdo->commit(); +echo "Total ratings: $rateCount\n"; + +// ── STEP 11 — Comments ──────────────────────────────────────────────────────── +echo "=== Inserting comments (2000) ===\n"; +$comStmt = $pdo->prepare('INSERT INTO comments (uuid,body,status,created_at,updated_at,user_id,doctor_id) VALUES (?,?,?,?,?,?,?)'); +$comStatuses = ['approved','approved','approved','approved','pending','rejected']; +$pdo->beginTransaction(); +for ($i = 0; $i < 2000; $i++) { + $ts = $now - rand(3600, 86400 * 400); + $comStmt->execute([uuid(), ri($commentTexts), ri($comStatuses), $ts, $ts, ri($patientIds), ri($doctorIds)]); + if (($i + 1) % 500 === 0) { + $pdo->commit(); + $pdo->beginTransaction(); + echo " Comments: " . ($i + 1) . "\n"; + } +} +$pdo->commit(); + +// ── STEP 12 — Blogs ─────────────────────────────────────────────────────────── +echo "=== Inserting blogs ===\n"; +$blogStmt = $pdo->prepare( + 'INSERT INTO blogs (uuid,title,slug,body,summary,tags,status,created_at,updated_at,author_id) + VALUES (?,?,?,?,?,?,?,?,?,?)' +); +$blogData = [ + ['راهنمای جامع پیشگیری از بیماری‌های قلبی','heart-disease-prevention','بیماری‌های قلبی از مهم‌ترین علل مرگ هستند. با تغذیه سالم، ورزش منظم، ترک سیگار و کنترل فشار خون می‌توان خطر ابتلا را به شدت کاهش داد. چکاپ سالیانه و مشاوره با متخصص قلب توصیه می‌شود.',['قلب','پیشگیری','سلامت']], + ['تغذیه سالم برای کودکان در سنین رشد','healthy-nutrition-children','مصرف متعادل پروتئین، لبنیات، میوه و سبزیجات برای رشد کودکان ضروری است. از مصرف قند و چربی اشباع بپرهیزید و آب کافی بنوشید.',['کودکان','تغذیه','رشد']], + ['اهمیت چکاپ منظم سالانه برای همه سنین','annual-checkup-importance','آزمایش خون، فشار خون، قند خون و تست‌های غربالگری سرطان باید سالانه انجام شوند. تشخیص زودهنگام درمان را ساده‌تر می‌کند.',['چکاپ','پیشگیری','غربالگری']], + ['مدیریت استرس و اضطراب در زندگی مدرن','stress-management','تکنیک‌های تنفس عمیق، مدیتیشن، ورزش منظم و ارتباط اجتماعی سالم از راهکارهای موثر مدیریت استرس هستند.',['استرس','سلامت روان','مدیتیشن']], + ['دیابت نوع ۲: علائم، پیشگیری و کنترل','diabetes-type2','تشنگی زیاد، ادرار مکرر، خستگی و تاری دید از علائم دیابت هستند. رژیم غذایی مناسب، ورزش و کنترل وزن در پیشگیری و مدیریت آن حیاتی است.',['دیابت','قند خون','پیشگیری']], + ['نقش ورزش در سلامت قلب و عروق','exercise-cardiovascular-health','۱۵۰ دقیقه فعالیت هوازی متوسط در هفته برای سلامت قلب توصیه می‌شود. پیاده‌روی، شنا و دوچرخه‌سواری گزینه‌های عالی هستند.',['ورزش','قلب','سلامت']], + ['خواب کافی و تاثیر آن بر سلامت جسم و روان','sleep-health','بزرگسالان به ۷-۹ ساعت خواب شبانه نیاز دارند. کمبود خواب با دیابت، چاقی، افسردگی و بیماری قلبی ارتباط دارد.',['خواب','سلامت','استراحت']], + ['مراقبت از پوست در برابر آفتاب و آلودگی','skin-care-sun-pollution','استفاده از کرم ضدآفتاب با SPF 30+، پوشش مناسب و آنتی‌اکسیدان‌ها به محافظت از پوست کمک می‌کنند.',['پوست','ضدآفتاب','آلودگی']], + ['پیشگیری از پوکی استخوان با تغذیه مناسب','osteoporosis-prevention','مصرف کافی کلسیم، ویتامین D، ورزش با وزن بدن و پرهیز از سیگار و الکل از مهم‌ترین راهکارهای پیشگیری از پوکی استخوان هستند.',['استخوان','کلسیم','پیشگیری']], + ['راهنمای کامل مراقبت از بینایی','eye-care-guide','معاینه سالانه چشم، استفاده از عینک آفتابی مناسب، رعایت قانون ۲۰-۲۰-۲۰ هنگام کار با صفحه نمایش و تغذیه سرشار از لوتئین برای سلامت چشم ضروری است.',['چشم','بینایی','سلامت']], + ['سرطان پستان: تشخیص زودهنگام نجات‌بخش است','breast-cancer-early-detection','معاینه خودآزمایی ماهانه، ماموگرافی سالانه برای زنان بالای ۴۰ سال و مراجعه به پزشک در صورت تغییرات مشکوک توصیه می‌شود.',['سرطان','پستان','غربالگری']], + ['بهداشت دهان و دندان در همه سنین','dental-hygiene','مسواک زدن دو بار در روز، استفاده از نخ دندان و مراجعه به دندانپزشک هر ۶ ماه یک‌بار از اساسی‌ترین اصول بهداشت دهان است.',['دندان','بهداشت','پیشگیری']], + ['کنترل فشار خون بالا با تغییر سبک زندگی','high-blood-pressure-control','کاهش مصرف نمک، کنترل وزن، ورزش منظم، پرهیز از استرس و مصرف منظم داروها در کنترل فشار خون ضروری هستند.',['فشار خون','قلب','سبک زندگی']], + ['واکسیناسیون بزرگسالان؛ آنچه باید بدانید','adult-vaccination-guide','آنفلوانزا، کزاز، هپاتیت B، آبله مرغان و واکسن HPV از واکسن‌های مهم بزرگسالی هستند. برنامه واکسیناسیون را با پزشک خود مشورت کنید.',['واکسن','پیشگیری','بیماری']], + ['آرتروز زانو: درمان و بازتوانی','knee-osteoarthritis-treatment','فیزیوتراپی، ورزش‌های تقویتی، کاهش وزن و در موارد پیشرفته جراحی از روش‌های درمان آرتروز زانو هستند.',['آرتروز','زانو','ارتوپدی']], + ['تغذیه درمانی در بیماری‌های کلیوی','renal-diet','رژیم کم‌پتاسیم، کم‌فسفر و کم‌سدیم برای بیماران کلیوی ضروری است. مقدار پروتئین مصرفی باید با پزشک هماهنگ شود.',['کلیه','تغذیه','رژیم']], + ['سلامت روان در محیط کار','workplace-mental-health','تعادل کار و زندگی، ارتباط موثر با همکاران، مدیریت زمان و استراحت کافی از عوامل مهم سلامت روان در محیط کار هستند.',['سلامت روان','کار','استرس']], + ['آلرژی فصلی و راهکارهای مقابله','seasonal-allergy-management','اجتناب از محرک‌ها، استفاده از داروهای آنتی‌هیستامین، شستن منظم دست و چشم و مشاوره با متخصص آلرژی از راهکارهای اصلی هستند.',['آلرژی','تنفس','بهار']], + ['اهمیت ورزش در دوران بارداری','pregnancy-exercise','پیاده‌روی، شنا و یوگای بارداری با نظر پزشک برای سلامت مادر و جنین مفید هستند. از ورزش‌های پرضربه پرهیز کنید.',['بارداری','ورزش','سلامت']], + ['پیشگیری از سرطان روده بزرگ','colorectal-cancer-prevention','غربالگری با کولونوسکوپی از سن ۴۵ سالگی، رژیم پرفیبر، کاهش مصرف گوشت قرمز و ورزش منظم خطر را کاهش می‌دهند.',['سرطان','روده','غربالگری']], +]; +$adminRow = $pdo->query("SELECT id FROM users WHERE roles LIKE '%ROLE_ADMIN%' LIMIT 1")->fetch(PDO::FETCH_ASSOC); +$adminId = $adminRow ? $adminRow['id'] : $doctorUserIds[0]; +$statuses = ['published','published','published','published','published','draft']; +foreach ($blogData as $idx => $b) { + $ts = $now - rand(86400, 86400 * 300); + $blogStmt->execute([ + uuid(), $b[0], $b[1] . '-' . rand(100,999), $b[2], + mb_substr($b[2], 0, 200), json_encode($b[3], JSON_UNESCAPED_UNICODE), + ri($statuses), $ts, $ts, $adminId + ]); +} +echo 'Blogs: ' . count($blogData) . "\n"; + +$pdo->exec('SET FOREIGN_KEY_CHECKS = 1'); + +// ── Summary ─────────────────────────────────────────────────────────────────── +echo "\n=== COMPLETE — Record counts ===\n"; +$tables = ['users','doctors','clinics','clinic_doctors','clinic_specialties','clinic_services','clinic_insurances', + 'doctor_specialties','doctor_expertise','doctor_provinces','doctor_cities','doctor_addresses', + 'appointments','payments','rates','comments','blogs','insurances','profiles']; +$total = 0; +foreach ($tables as $t) { + $c = (int)$pdo->query("SELECT COUNT(*) FROM `$t`")->fetchColumn(); + printf(" %-30s %d\n", $t . ':', $c); + $total += $c; +} +echo "\nTotal records: $total\n";