قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ. الخريطة: backend · payment_server · loction_server · ride_server · passenger_server · docker · dashboard · stress_test → الجذر siro_rider → apps/rider siro_driver → apps/driver siro_admin → dashboards/admin siro_service → dashboards/service android_bot → apps/android_bot socialBot → apps/socialBot نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب) لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً: كل ما يلي يصير فرقاً مقروءاً مقابل المصدر. لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز، سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh (ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و dashboards/transit-web). ⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة: 1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر): كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner. 2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist) يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً. 3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع → يجب ضمّ الحزم داخله أسوة بـ apps/rider. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
100 lines
3.5 KiB
PHP
100 lines
3.5 KiB
PHP
<?php
|
|
/**
|
|
* Get Places - Optimized with FULLTEXT and SPATIAL indexes.
|
|
* يستخدم الفهارس الذكية للبحث السريع جداً.
|
|
* * يتطلب:
|
|
* - connect.php: $con (PDO object) + filterRequest() + jsonSuccess() / jsonError()
|
|
* - جدول 'places11' مهيأ بالفهارس (FULLTEXT & SPATIAL)
|
|
*/
|
|
|
|
require_once __DIR__ . '/../../connect.php';
|
|
|
|
// اسم الجدول المستهدف
|
|
$tableName = 'palces11';
|
|
|
|
// تأكد من أن PDO يرمي استثناءات عند حدوث أخطاء
|
|
try {
|
|
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
} catch (PDOException $e) {
|
|
// تجاهل الخطأ إذا كان قد تم تعيينه بالفعل
|
|
}
|
|
|
|
// 1. استقبال المدخلات باستخدام دالة filterRequest الخاصة بك
|
|
$query = trim((string) filterRequest("query"));
|
|
$latMin = filterRequest("lat_min");
|
|
$latMax = filterRequest("lat_max");
|
|
$lngMin = filterRequest("lng_min");
|
|
$lngMax = filterRequest("lng_max");
|
|
|
|
// 2. التحقق من المدخلات
|
|
if ($query === "" || $latMin === null || $latMax === null || $lngMin === null || $lngMax === null) {
|
|
jsonError("Missing required parameters: query, lat_min, lat_max, lng_min, lng_max");
|
|
exit;
|
|
}
|
|
|
|
// تحويل الإحداثيات إلى أرقام عشرية
|
|
$latMin = (float) $latMin;
|
|
$latMax = (float) $latMax;
|
|
$lngMin = (float) $lngMin;
|
|
$lngMax = (float) $lngMax;
|
|
|
|
|
|
// 3. بناء الاستعلام الذكي (الجزء المحدّث)
|
|
|
|
// تحضير كلمة البحث لوضعها في MATCH() AGAINST()
|
|
// نضيف '*' لكل كلمة للبحث عن الكلمات التي تبدأ بهذا الجزء
|
|
$search_terms = preg_split('/\s+/', $query, -1, PREG_SPLIT_NO_EMPTY);
|
|
$search_boolean = '';
|
|
foreach ($search_terms as $term) {
|
|
$search_boolean .= '+' . $term . '* '; // '+' تعني أن الكلمة يجب أن تكون موجودة
|
|
}
|
|
$search_boolean = trim($search_boolean);
|
|
|
|
|
|
// بناء المضلع الجغرافي (Bounding Box Polygon) للفهرس المكاني
|
|
$bbox_wkt = sprintf(
|
|
'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
|
|
$lngMin, $latMin,
|
|
$lngMax, $latMin,
|
|
$lngMax, $latMax,
|
|
$lngMin, $latMax,
|
|
$lngMin, $latMin
|
|
);
|
|
|
|
|
|
// الاستعلام النهائي الذي يجمع بين البحث النصي والجغرافي
|
|
$sql = "
|
|
SELECT
|
|
id, latitude, longitude, name, name_ar, name_en, address, category, created_at
|
|
FROM
|
|
`{$tableName}`
|
|
WHERE
|
|
-- الشرط الأول: البحث بالنص الكامل (سريع جداً)
|
|
MATCH(name, name_ar, name_en, address, category) AGAINST(? IN BOOLEAN MODE)
|
|
|
|
-- الشرط الثاني: البحث الجغرافي (سريع جداً)
|
|
AND ST_CONTAINS(ST_GEOMFROMTEXT(?), location)
|
|
LIMIT 50; -- حد أعلى للنتائج الأولية
|
|
";
|
|
|
|
// 4. تنفيذ الاستعلام وإرجاع النتيجة
|
|
try {
|
|
$stmt = $con->prepare($sql);
|
|
|
|
// ربط المتغيرات بالاستعلام بالترتيب
|
|
$stmt->execute([$search_boolean, $bbox_wkt]);
|
|
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
jsonSuccess($rows);
|
|
|
|
} catch (PDOException $e) {
|
|
// يمكنك استخدام هذا السطر أثناء التطوير لعرض الخطأ الفعلي
|
|
// jsonError('DB Error: ' . $e->getMessage()); exit;
|
|
|
|
// تسجيل الخطأ في سجلات الخادم للرجوع إليه لاحقاً
|
|
error_log("search_places_optimized.php error: " . $e->getMessage());
|
|
jsonError("Database query error occurred");
|
|
}
|
|
?>
|