כל גישה למסד הנתונים ב-WIZZO CMS עוברת דרך מחלקה סטטית אחת, DB, בקובץ api/core/collections/DB.php. בדף הזה תלמדו איך החיבור נוצר, איך מתייחסים לשמות טבלאות, מתי משתמשים ב-builder ומתי ב-SQL גולמי, ואילו מגבלות כדאי להכיר לפני שכותבים שאילתה ראשונה.
בעמוד הזה system/ הוא תיקיית הליבה הפרוסה (= api/core בריפו) ו-{admin} הוא CONFIG::$admin_url של האתר.
החיבור#
החיבור נפתח בעצלות (lazy): רק כשמריצים שאילתה ראשונה, DB::create_connection() יוצרת אובייקט PDO מפרטי החיבור שב-CONFIG. בפועל CONFIG::$db_type הוא "PDO" (MySQL / MariaDB). ענפי mysql הישן, pg ו-clickhouse קיימים בקוד אבל אינם בשימוש באתרים רגילים.
מיד אחרי החיבור הליבה מריצה:
set names utf8mb4
SET SESSION sql_mode = ''
כלומר הקידוד הוא utf8mb4, ו-strict mode כבוי: ערך שלא נכנס לעמודה נחתך בשקט במקום להחזיר שגיאה.
כשל בחיבור מפעיל MISC::service_unavailable(...) והאתר מחזיר 503. אל תתפסו את זה ב-try/catch בקוד שלכם: אין מה להמשיך בלי מסד נתונים.
בסוף הבקשה core.php קוראת ל-DB::close_connection(). אם צריך את אובייקט ה-PDO עצמו (טרנזקציה, lastInsertId), קבלו אותו עם DB::get_connection().
הקידומת CRM_#
כל טבלה של WIZZO CMS מתחילה ב-CRM_ (CONFIG::$db_prefix הוא "CRM" ו-CONFIG::$db_fullprefix הוא "CRM_"). אי אפשר לשנות את הקידומת: כ-80 מקומות בליבה כוללים את CRM_ ישירות בתוך מחרוזות SQL.
| סגנון | שם הטבלה | דוגמה |
|---|---|---|
ה-builder (DB::query, DB::update, DB::delete, DB::get_val) | בלי קידומת | DB::query("pages") |
SQL גולמי (DB::sql, DB::get_all, DB::get_row עם מחרוזת) | עם הקידומת המלאה | "SELECT * FROM CRM_pages" |
// builder: שם טבלה חשוף
$page = DB::query("pages", ["id" => 12])->get_row();
// SQL גולמי: CRM_ מלא
$rows = DB::get_all("SELECT id, sysName FROM CRM_params ORDER BY sysName");
שתי דרכים לעבוד#
ה-builder מתאים לרוב הפעולות היומיומיות: קריאת שורה לפי תנאי שוויון, הוספה, עדכון ומחיקה, כולל טיפול אוטומטי בטבלאות תרגום (ראו טבלאות רב-לשוניות). הוא מעלים את הצורך לדעת איך נראית טבלת ה-_content.
SQL גולמי מתאים לכל מה שה-builder לא יודע: JOIN מפורש, GROUP BY מורכב, תנאים שאינם שוויון, UNION, פקודות DDL.
| מה צריך | הכלי | דף |
|---|---|---|
| לקרוא שורות או שורה | DB::query() או DB::get_all() / DB::get_row() | שאילתות |
| ערך בודד | DB::get_val() | שאילתות |
| להוסיף / לעדכן | DB::update(table)->set_var(...)->insert() / ->update($id) | בוני שאילתות |
| למחוק | DB::delete() | בוני שאילתות |
| פקודה חופשית | DB::sql() | שאילתות |
אין מתודה DB::insert(...), וקריאה אליה היא fatal error. הוספת שורה נעשית כך: DB::update("table")->set_var("col", $val)->insert(). קבצי ליבה ישנים שקוראים ל-DB::insert הם קוד מת, אל תעתיקו מהם.
מה אין בשכבה הזאת#
- אין prepared statements.
DB::sql()מבצעתprepareו-executeללא פרמטרים מקושרים, ולכן כל ערך שמגיע מבחוץ חייב לעבורDB::escape()ולהיכנס בין גרשיים שאתם מוסיפים בעצמכם. ראו שאילתות. - אין API של טרנזקציות. משתמשים ב-
DB::sql("START TRANSACTION")ו-COMMIT/ROLLBACK, או ב-DB::get_connection()->beginTransaction(). - אין מנגנון migrations בקוד האתר. טבלאות נוצרות על ידי עדכון גרסה או
ensure_*עצלים. ראו SQL להקמה.
שגיאות#
ב-PHP 8.3 PDO זורק חריגה על שאילתה שגויה, ו-DB::sql() זורקת אותה הלאה כ-Exception בפורמט "<הודעת הדרייבר> | <ה-SQL>". הערות בקוד שמדברות על "silent mode" הן שריד של PHP 7. פרטים נוספים ב-דיבוג SQL.
פונקציות עזר נוספות#
| מתודה | מה היא עושה |
|---|---|
DB::escape($str) | מחזירה את המחרוזת בלי גרשיים חיצוניים (PDO::quote עם קילוף). מחרוזת ריקה או NULL חוזרות כמות שהן |
DB::is_table_exists($table) | האם הטבלה (בשם חשוף, בלי CRM_) קיימת. הרשימה נשמרת במטמון ל-7 ימים תחת table_list |
DB::is_column_exists($table, $column) | האם עמודה קיימת. נשמר ב-table_columns_<table> ל-7 ימים |
DB::num_rows($res) | rowCount() של ה-statement |
DB::had_error() | true כש-DB::$error_count גדול מאפס |
מי שיוצר טבלה ידנית צריך למחוק את מטמון table_list (וגם platforms ו-params אם נגע בהם), אחרת is_table_exists ימשיך להחזיר את התשובה הישנה עד 7 ימים. ראו ניקוי ותחזוקה.