Add seed script for populating database with initial data
- Implemented a comprehensive PHP script to seed the database with test data for users, doctors, clinics, appointments, payments, ratings, comments, and blogs. - Included functions for generating random data such as UUIDs, mobile numbers, and images. - Downloaded and stored images for doctors and clinics using parallel curl requests. - Inserted static data for insurances, patients, and doctors with various attributes including specialties and services. - Ensured data integrity by disabling foreign key checks during the seeding process and re-enabling them afterward. - Provided a summary of the total records inserted into each table at the end of the script.
This commit is contained in:
+482
@@ -0,0 +1,482 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
$pdo = new PDO('mysql:host=db;dbname=db;charset=utf8mb4', 'db', 'db');
|
||||
$pdo->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";
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
set_time_limit(0);
|
||||
|
||||
$pdo = new PDO('mysql:host=db;dbname=db;charset=utf8mb4', 'db', 'db');
|
||||
$pdo->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";
|
||||
@@ -0,0 +1,708 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
set_time_limit(0);
|
||||
ini_set('memory_limit', '512M');
|
||||
|
||||
$pdo = new PDO('mysql:host=db;dbname=db;charset=utf8mb4', 'db', 'db');
|
||||
$pdo->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";
|
||||
Reference in New Issue
Block a user