מוסכמות ושמות

כל מוסכמות השמות והכתיבה ב-WIZZO CMS, בהפרדה בין מה שהקוד אוכף ומה שהוא מוסכמה של הצוות: טבלאות, עמודות, קבצים, מחלקות, SCSS, RTL, Vue, מילים ומטמון.

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

העמוד הזה מרכז את השמות והכללים שחוזרים בכל הליבה ובכל אתר. הוא מחלק אותם לשני סוגים, כי זה ההבדל בין "נשבר" ל"לא נעים":

  • נאכף על ידי הקוד: אם לא תעקבו אחריו, משהו נכשל בפועל (שאילתה, ניתוב, טעינת קובץ).
  • מוסכמה: הצוות עובד כך כדי שהקוד יהיה אחיד וקל לתחזוקה. שום דבר לא ישבר אם תחרגו, אבל עדיף לא.

נתיבי הקבצים הם יחסית ל-api/core בריפו, שהיא system/core/ באתר פרוס. {admin} הוא CONFIG::$admin_url. תקן הכתיבה המלא (עיצוב קוד, הערות, בדיקות) נמצא ב-תקן הקוד, והמחלקות שמוזכרות כאן ב-ה-Collections.

מסד הנתונים#

שמות טבלאות#

כללפירוטסוג
כל טבלה מתחילה ב-CRM_CONFIG_USER::$db_prefix מגדיר CRM, ו-CONFIG::$db_fullprefix הוא CRM_. בפועל חייבים להשאיר CRM: עשרות שאילתות בליבה כותבות CRM_ קשיח, למשל SELECT * FROM CRM_platforms ב-CONFIG::initנאכף
ה-API של DB מקבל שם בלי קידומתDB::query("pages"), ‏DB::update("params"), ‏DB::get_val("adminPanel_admins", 3)נאכף
שאילתה גולמית דורשת קידומת מלאהDB::sql("SELECT * FROM CRM_pages WHERE id = " . (int)$id), ‏DB::get_all(...), ‏DB::get_row(...)נאכף
קלט משתמש בשאילתה גולמית עובר ב-DB::escapeאו ב-(int) למספרים. בונה השאילתות מנקה ערכים של מערך התנאים, אבל לא מפתחותנאכף כדי לא לייצר SQLi
שמות באנגלית, snake_casecron_tasks, minify_groups. יש חריגים היסטוריים בסגנון adminPanel_admins ו-seoUrlמוסכמה
// בונה: בלי קידומת
$row = DB::query("pages", ["id" => (int)$id])->get_row();

// גולמי: עם CRM_ ועם escape
$res = DB::sql("SELECT * FROM CRM_pages WHERE slug = '" . DB::escape($slug) . "'");

DB::insert לא קיימת. הוספה נעשית דרך DB::update("table")->set_var("col", $v)->insert() (ו-set() הוא כינוי ל-set_var()), ועדכון דרך ->update($id).

טבלאות _content ועמודות קבועות#

מוסכמהפירוטסוג
id INT AUTO_INCREMENT PRIMARY KEYהבונים מניחים שבכל טבלה יש id (DB::get_val, DB::delete, ‏->update($id))נאכף
טבלת תוכן רב-לשונית: <table>_contentאם קיימת טבלה בשם <t>_content, ה-JOIN נבנה אוטומטית על parentId (מצביע ל-<t>.id) ו-langId (מזהה פלטפורמה). DB::delete מוחק גם ממנהנאכף
ord לסדר ידניpanel_table עם order_manager מוסיף עמודת ord INT בעצמו אם חסרה (ALTER TABLE בזמן ריצה)מוסכמה
is_active מול activeרוב הטבלאות משתמשות ב-is_active (יותר ממאה שימושים בליבה, מול כ-20 של active). modules.active ו-users.active הן חריגות שהקוד קורא בשמן. לא להחליף ביניהןנאכף לפי הטבלה

שורה בטבלה עם _content נעלמת מתוצאות DB::query אם אין לה שורת תוכן בשפה המבוקשת, כי ה-JOIN הוא פנימי. הפירוט ב-טבלאות רב-לשוניות וב-סכמת הטבלאות.

אל תוסיפו עמודת
langId לטבלה שלא נקראת _content רק טבלה ששמה מסתיים ב-_content מקבלת סינון langId. טבלת צד אחרת מקבלת JOIN בלי סינון שפה, ותקבלו שורה לכל שפה.

הפורמט |1||2|#

רשימות שמורות בעמודה אחת (דומיינים מורשים, תגיות, בחירה מרובה) בפורמט שבו כל ערך עטוף בקווים אנכיים ומופרד ב-||:

MISC::bgl_implode(["a", "b"]);   // "|a||b|"
MISC::bgl_explode("|a||b|");     // ["a", "b"]

הפורמט מאפשר LIKE '%|a|%' מדויק, בלי להתבלבל בין 1 ל-11. כללים לזכור:

  • bgl_implode מסננת ערכים ריקים עם array_filter, ולכן גם את הערך 0 וגם את "0". מזהה אפס לא יישמר.
  • bgl_explode מחזירה את תוצאת array_filter, כלומר המפתחות לא מסודרים מחדש. אם צריך אינדקסים רצופים, השתמשו ב-array_values.
  • קבוצה ריקה נשמרת כמחרוזת ריקה, לא כ-"||".

קבצים ומחלקות#

מהאיפהשם הקובץ והמחלקהסוג
קונטרולר של אתרapplication/controllers/<name>.phpמחלקה בשם <name> שיורשת מ-bgl_controller. MODULE::get עושה new $moduleנאכף
קונטרולר מערכתsystem/core/controllers/<name>.php (כתובת /system/<name>)אותו כללנאכף
פאנל ניהולapplication/admin/<panel>.php (או admin/<panel>.php בליבה)מחלקה ADMINMODULE_<panel> שיורשת מ-bgl_controller. שם הקובץ הוא panel_name בטבלה adminPanel_panelsנאכף
מודלCONFIG::$models_folder/<path>.phpהמחלקה נקראת כשם הקובץ (basename($path)) והמופע מוצב על הקונטרולר: $this->load->model("m_news") ואז $this->m_newsנאכף
ספריית ליבהsystem/core/libraries/<path>.php$this->load->library("name") טוען מהליבה בלבד ולא יוצר מופענאכף
ערכת נושאthemes/<name>/index.php + index.tplמחלקה TEMPLATE_<name> שיורשת מ-bgl_themeנאכף
תבנית של קונטרולרapplication/views/<tpl>.tplנטענת עם $this->view("<tpl>", $vars). תבנית של הליבה: system_viewנאכף
קובץ אתחול של האתרapplication/includes/*.phpנטענים בכל בקשה, בסדר אלפביתי, פעם אחת (FILES::include_dir)נאכף

הערות שחוזרות בכמה מהשורות:

  • שמות המחלקות של קונטרולר הם שם הקובץ בדיוק, כולל רישיות. בשרת Linux News.php ו-news.php שונים.
  • קונטרולר של אתר פועל רק אם יש לו שורה פעילה בטבלה modules (modules.active שווה "1"). קובץ בלי שורה נותן 404, וזו הסיבה לרישום ב-CRM_modules. ראו קונטרולרים של אתר.
  • מתודה בקונטרולר שמחזירה את המחרוזת "ERRORPAGE" מפעילה 404 דרך MODULE::errorpage(). ב-AdminModule אותה מחרוזת היא סימון למודול לא קיים. ראו 404, 503 ושגיאות.
  • ‏bgl_controller, ‏bgl_model ו-bgl_loader הם השמות שקוד אתר יורש מהם, ו-wz_* הם המחלקות שמאחוריהם.
פאנל חדש ללא רישום לא יופיע

קובץ application/admin/<panel>.php לבדו לא מספיק. הפאנל מופיע בתפריט רק כששורה ב-adminPanel_panels מצביעה עליו. ראו בניית פאנל.

כתובות ופרמטרי $_GET שקובע ה-ROUTER#

ROUTER::parse_friendly_url הוא המקום היחיד שכותב את הפרמטרים שהקונטרולר קורא. אל תחפשו אותם ב-.htaccess, כי הוא רק מעביר הכול ל-index.php.

פרמטרמתי מוגדרמשמעות
$_GET["module"]כתובת אתר <module>/<page>/<id>, וגם בפאנל {admin}/<module>/...שם הקונטרולר (באתר) או הפאנל (בניהול)
$_GET["pname"]הסגמנט השנישם המתודה (ברירת מחדל index)
$_GET["id"]הסגמנט השלישימזהה או שאר הנתיב
$_GET["sys_controller"]כתובת system/<name>/...שם קונטרולר המערכת
CONFIG::$system_type"admin" כשהכתובת מתחילה ב-{admin}, אחרת "client"צד הבקשה

כתובות ידידותיות ממפות לאותם פרמטרים דרך הטבלה seoUrl. ראו ניתוב (ROUTER) ו-כתובות ידידותיות. דף הבית (url ריק) משתמש ב-CONFIG::$default_module.

שמות סטטיים ומפתחות מטמון#

כללדוגמהסוג
תכונות סטטיות ב-snake_caseCONFIG::$platform_data, ‏PAGE::$cache_this_page, ‏DB::$error_countמוסכמה
מתודות סטטיות ב-snake_casePAGE::add_asset, ‏cache_engine::get_stats, ‏ROUTER::parse_friendly_urlמוסכמה
שמות מחלקות סטטיות באותיות גדולותDB, ‏PAGE, ‏MISC. חריגות: cache_engine, ‏bgl_*, ‏wz_*מוסכמה
מפתח מטמון גלובלי הוא מחרוזת קבועהplatforms, ‏params, ‏table_list, ‏redirections, ‏minify_files, ‏minify_groupsמוסכמה
מפתח שתלוי שפה מקבל את ה-id של הפלטפורמה כסיומתwords_lang<id>, ‏modules_lang<id>מוסכמה
מפתח שתלוי טבלה מקבל את שמהtable_columns_<table>מוסכמה

בקריאה ל-cache_engine::get($key, $func, $hours, $in_platform) הפרמטר $in_platform קובע אם הערך נשמר בתיקייה של הדומיין הנוכחי או בשורש המטמון. מפתחות שתלויים בשפה צריכים להישאר ברירת מחדל (true) כדי שדומיין אחד לא ידרוס את השני. הפירוט ב-איך המטמון עובד, ב-cache_engine API וב-פלטפורמות ורב-לשוניות.

צד הלקוח: SCSS, RTL, FontAwesome ו-Vue#

SCSS#

עורכים קבצי .scss בלבד. הליבה מקמפלת אותם בשרת (FILES::scss), והכתובת foo.scss.css מוגשת מהמטמון או מתקמפלת בבקשה הראשונה (ראו צינור הנכסים). קובץ .css שנוצר מהקומפילציה ייכתב מחדש, ושינוי ידני בו אובד. זה כלל נאכף בפועל, כי אין מקור אחר לאמת.

RTL#

כללפירוטסוג
מאפיינים לוגיים בלבדmargin-inline-start/end, ‏padding-inline-start/end, ‏inset-inline-start/end, ‏text-align: start/end. לא left ו-right פיזייםמוסכמה
end אינו rightב-RTL הצד inline-end הוא left. בחרו לפי המשמעות ולא לפי הצד שאתם רואים במסךמוסכמה
כיוון העמוד מגיע מהפלטפורמה<html dir="..."> ו-class rtl או ltr על <body>, שניהם מ-CRM_platforms.directionנאכף
בפאנל הניהול כותבים את שני הסלקטוריםהכיוון מסומן גם כ-dir על <html> וגם כ-class על <body>, וקובצי ה-SCSS של הפאנל כותבים [dir="rtl"] &, .rtl &מוסכמה

מאפיין לוגי נגזר מהכיוון של האלמנט עצמו: padding-inline-end על תא עם direction: ltr ינחת בצד הפיזי הנגדי למה שציפיתם. בדקו בדפדפן כשמערבבים כיוונים. ראו גם את הערה על <html lang> ב-פלטפורמות ורב-לשוניות.

FontAwesome#

פאנל הניהול טוען FontAwesome Free 5.15.4 כקובץ assets/fontawesome/js/all.min.js (בגרסת JS שמחליפה תגיות <i> ב-<svg>). שני כללים נגזרים:

  • שמות של אייקונים מגרסה 6 לא יוצגו. השתמשו בשמות של גרסה 5 (fas fa-..., ‏far, ‏fab).
  • לעולם לא לשים v-if, ‏v-else או v-for על התג <i> של האייקון. ה-JS מחליף אותו ב-<svg>, ו-Vue מאבד את הצומת שהוא מנסה לעדכן, ורכיב שלם מפסיק להתרנדר. עוטפים:
<span v-if="saved" class="wz_if"><i class="fas fa-check"></i></span>

אל תבנו ספינר מאייקון של FontAwesome. השתמשו באלמנט CSS רגיל, למשל <span v-if="loading" class="wz_spin"></span>.

הערה
wz_if ו-wz_spin הם שמות מוסכמים של הצוות אין להם הגדרה בקוד של api/core. wz_if הוא class מזהה על העטיפה, ו-wz_spin הוא class של ספינר שאתם מגדירים בעצמכם ב-SCSS. מה שחשוב הוא העטיפה והימנעות מ-v-if על <i>, לא השמות.

Vue#

רכיבי Vue של הפאנל כתובים ב-Vue 3 בסגנון Options API (export default { data() {...}, methods: {...} }, או אובייקט אפשרויות שמועבר ל-createApp), והספרייה נטענת כקובץ vue.global.min.js מהערכה admin_panel. הליבה מכילה רכיב .vue אחד, ו-FILES::vue($url, $m_settings) טוענת חבילה בנויה: קובץ HTML שה-<head> שלו מצביע על קובצי ה-JS וה-CSS.

פאנל שנטען בניווט AJAX של הניהול מוחלף בלי רענון עמוד, ולכן הוא צריך להרכיב את עצמו בכל כניסה ולפרק את עצמו ביציאה. מנהל הקבצים (assets/file_manager/app.js) עושה את זה עם mountApp() ו-unmountApp(), ועם MutationObserver על #mainframe שמזהה מתי הפאנל נכנס או יצא. זה הדפוס לחקות. ראו פאנלים מבוססי Vue.

מילים, פרמטרים ו-JSON#

מילים (LANGS)#

כללפירוטסוג
מפתח מילה הוא sysNameLANGS::get_word('EDIT'). מילה חסרה מחזירה מחרוזת ריקה ולא שגיאהנאכף
אותיות גדולות עם קווים תחתוניםEDIT, ‏ARE_YOU_SURE, ‏PANEL_MAIN. מילים של הליבה מתחילות לעיתים ב-_ ומסתיימות בו: _MESSAGE_ADDED_, ‏_SEND_מוסכמה
הערך נשמר בטבלת התוכןlangs_words_content.value (עמודות parentId, langId, value)נאכף
מילה לכל שפהשורה ב-langs_words ושורה ב-langs_words_content לכל langIdנאכף

הליבה אינה אחידה במלואה: יש מילים שנכתבות באותיות קטנות (add_correct_phone, ‏_secCodeError_). אל תתבססו על רישיות כשאתם מחפשים מילה, והשתמשו בחיפוש בטבלה. ראו פרמטרים ומילים.

פרמטרים (PARAMS)#

מפתחות PARAMS נשמרים ב-params.sysName, כמעט תמיד ב-snake_case באותיות קטנות: attaches_version, ‏log_sql, ‏cron_runner_token. פרמטר חסר מחזיר מחרוזת ריקה. ראו פרמטרים ומילים.

תגובות JSON#

אין צורת תגובה אחת לכל המערכת. הדפוסים בקוד הליבה, לפי תדירות:

דפוסדוגמה
error (נפוץ מאוד)["error" => "invalid_url"] או ["success" => false, "error" => $msg]
ok (נפוץ מאוד)["ok" => true, ...]
success["success" => true, ...]
result ו-msg["result" => false, "msg" => LANGS::get_word(...)], בבדיקות של שדות טופס

בקוד הליבה מתודות מחזירות JSON בשתי דרכים: return json_encode(...) או echo json_encode(...) ואז סיום. כדי שעברית לא תהפוך ל-\uXXXX הוסיפו JSON_UNESCAPED_UNICODE, כפי שעושה הקוד בכמה מקומות. ב-API חדש בחרו דפוס אחד (ok ו-error) ושמרו עליו. ראו JSON API של טפסים וטבלאות.

סיכום: מה נאכף ומה לא#

נאכף (אחרת זה נשבר)מוסכמה (אחרת זה פחות מסודר)
קידומת CRM_ בכל טבלהsnake_case בשמות טבלאות ועמודות
id בכל טבלה שעוברת בבוניםעמודת ord וכתיבת is_active
שם קובץ שווה לשם מחלקהמאפיינים לוגיים ב-SCSS
ADMINMODULE_<panel> ושורה ב-adminPanel_panelsשמות מילים באותיות גדולות
שורת modules פעילה לכל קונטרולר אתרדפוס תגובת JSON אחיד
DB::escape על קלט בשאילתה גולמיתשמות wz_if ו-wz_spin
אין v-if על <i> של FontAwesomeסגנון Options API בכל רכיב
מצאתם טעות או חוסר? תקנו את הדף או פתחו Issue בריפו. התיעוד נכתב מתוך הקוד של ליבה 5.0.115.