טבלאות רב-לשוניות

איך WIZZO CMS שומר תוכן מתורגם: זוג טבלאות CRM_x ו-CRM_x_content, ה-join האוטומטי של ה-builder, קריאה וכתיבה של שדות מתורגמים, ומלכודות של שפה חסרה ומטמון רשימת הטבלאות.

⏱ 4 דק' קריאה 647 מילים ערוך דף זה ב-GitHub

תוכן שמשתנה לפי שפה (כותרת, תיאור, טקסט) לא נשמר באותה טבלה עם הנתונים הקבועים. לכל טבלה כזאת יש "טבלת תוכן" תאומה, וה-builder של DB מחבר ביניהן לבד. הדף מסביר את המבנה, איך קוראים וכותבים שדות מתורגמים, ומתי ה-join האוטומטי מפתיע.

בעמוד הזה system/ הוא תיקיית הליבה הפרוסה (= api/core בריפו) ו-{admin} הוא CONFIG::$admin_url של האתר.

המבנה#

לטבלה CRM_<t> (ה"conf": שדות קבועים כמו id, ord, מצב) יש תאומה CRM_<t>_content עם השדות המתורגמים ושתי עמודות קישור:

עמודהמשמעות
parentIdה-id של השורה ב-CRM_<t>
langIdמזהה השפה: CRM_platforms.id

שורה אחת בטבלה הראשית ושורה אחת לכל שפה בטבלת התוכן. "שפה" כאן היא פלטפורמה (CRM_platforms): CONFIG::$lang הוא מזהה הפלטפורמה הנוכחית (CONFIG::$platform_data["id"]). הפלטפורמה נבחרת לפי $_SERVER['SERVER_NAME'], אחר כך לפי allowed_domains, ובלית ברירה השורה הראשונה. הרשימה נטענת ב-CONFIG::init() ונשמרת במטמון 30 יום (platforms). ראו פלטפורמות ורב-לשוניות.

קריאה#

ה-builder בודק אם הטבלה CRM_<t>_content קיימת (DB::is_table_exists), ואם כן מחבר אותה אוטומטית ומסנן לפי השפה:

$page = DB::query("pages", ["id" => 12])->get_row();
// $page["title"] מגיע מ-CRM_pages_content, $page["noDelete"] מ-CRM_pages

ה-SQL שנבנה הוא בקירוב:

SELECT * FROM CRM_pages_content tData, CRM_pages tConf
WHERE true AND tData.parentId = tConf.id AND tData.langId = <lang> AND tConf.id = '12'

בחירת שפה אחרת: הארגומנט הרביעי של DB::query.

$en = DB::query("pages", ["id" => 12], "", $englishPlatformId)->get_row();
שורה בלי תרגום נעלמת

ה-join הוא למעשה INNER JOIN. שורה ב-CRM_pages שאין לה שורת תוכן בשפה המבוקשת פשוט לא תחזור מהשאילתה, בלי שגיאה. אם רשימה "חסרה" ערכים רק באתר בשפה מסוימת, בדקו קודם שיש להם שורת _content בשפה הזאת.

כשכותבים SQL גולמי אין join אוטומטי: מחברים בעצמכם.

$rows = DB::get_all(
  "SELECT c.id, t.title FROM CRM_pages c
   JOIN CRM_pages_content t ON t.parentId = c.id AND t.langId = " . (int)CONFIG::$lang
);

כתיבה#

set_var עם הארגומנט השלישי "content" כותב לטבלת התוכן:

$ins = DB::update("pages");
$ins->set_var("noDelete", 0);                       // conf
$ins->set_var("title", "כותרת", "content");         // content
$ins->insert();                                     // יוצר גם את שורת התוכן בשפה הנוכחית
$id = $ins->new_id;

$up = DB::update("pages");
$up->set_var("title", "Title", "content");
$up->update($id);                                   // יוצר שורת תוכן אם חסרה

מה קורה בפועל:

  • insert() יוצרת את שורת התוכן עם langId = CONFIG::$lang, כלומר בשפה הנוכחית בלבד. תרגום לשפות נוספות נעשה בקריאה נפרדת בכל שפה (החלפת CONFIG::$lang או כתיבת שורה ידנית).
  • update($id) מעדכנת את שורת התוכן של (parentId, langId), ויוצרת אותה אם אינה קיימת.
  • מחיקה עם DB::delete מסירה גם את כל שורות התוכן של ה-id.
copyToAllLangs

מתודת copyToAllLangs ב-DB_UPDATE_CLASS מיועדת להעתיק תוכן לכל השפות, אבל היא שבורה: היא קוראת מהטבלה הישנה CRM_langs, ובשורות השפה new_id ריק כי הרקורסיה רצה לפני ה-INSERT הראשי. אל תסתמכו עליה.

טבלאות בשם לא סטנדרטי#

ברירת המחדל היא <table>_content עם עמודת קישור parentId. טבלה שבנויה אחרת מוגדרת עם ChangeContentTable:

$u = DB::update("my_table");
$u->ChangeContentTable("my_table_lang", "item_id");

ובאובייקט שאילתה אפשר לשנות את contentTable ואת queryKey.

מטמון רשימת הטבלאות#

זיהוי טבלת התוכן נשען על DB::is_table_exists, שמחזיקה את רשימת כל הטבלאות במטמון 7 ימים (המפתח table_list, גלובלי לכל הדומיינים). מי שיוצר טבלת _content חדשה בזמן ריצה צריך למחוק את המפתח, אחרת ה-builder לא "יראה" אותה:

cache_engine::remove("table_list");
אחרי יצירת טבלה

ניקוי מהפאנל (ראו ניקוי ותחזוקה) או קריאה ל-system/Tools/delete_cache מנקים גם table_list.

ראו גם#

מצאתם טעות או חוסר? תקנו את הדף או פתחו Issue בריפו. התיעוד נכתב מתוך הקוד של ליבה 5.0.115.