coldfusion / דיון שרשרת עם coldfusion / בניית הלוח


בניית הלוח


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

בפועל, התהליך הזה מתחלק לחמישה חלקים:

הוסף משתמש (Add user):

החלק הזה מאפשר למשתמשים להירשם ולהשיג הרשאות ללוח ההודעות. הוא כולל UI להכנסת המידע וקוד לאחסנתו במאגר.

אבטחה (Security):

חלק האבטחה שומר שמשתמשים לא רשומים לא יכתבו בלוח. הוא כולל רכיב login, חלקיק הרשאה שבודק את הלוגין מול מאגר מידע, ועמוד שניתן לכלול בעמודים אחרים כדי להפוך אותם למאובטחים.

שלח (Post):

פעולת ה"שלח" היא זו שמאפשרת למשתמשים להציב הודעות בלוח. זה כולל שליחה, תגובה ורישום במאגר המידע.

הצג הודעה (Display Message):

החלק הזה מציג הודעה מסוימת וכולל את הכלים למעבר בין הודעה להודעה (הבא, הקודם וכו').

הצג הודעות (Browse Messages):

פעולה זו מציגה את ההודעות בלוח ומסדרת אותן לפי שרשרת או על פי תאריך.

הנה, ראו:





רכיבי לוח הודעות

מאחר וכל משתמש שרוצה לשלוח חייב לעבור דרך תהליך ההרשמה, ומאחר ובלי שליחות לא יהיה לנו לוח הודעות מוצלח במיוחד, נתחיל את בניית הלוח שלנו במבט מעמיק על תהליך ההרשמה.


הרשמה, בבקשה

אני שונאת למלא טפסים ארוכים ואני גם לא אוהב לגרום לאנשים אחרים למלא אותם. ללוח ההודעות הזה, דרושים ארבעה שדות בלבד: שם משתמש (username), כינוי(nickname), סיסמא (password) וכתובת אי-מייל (e-mail address). אני אזדקק לשתי טבלאות כדי לאגור את המידע הזה: USER ו-PASSWORD. טבלת ה-USER תכיל את השם וכתובת האי-מייל, וטבלת ה-PASSWORD תכיל את שם ה-login והסיסמא.

על מנת שנוכל לעבוד עם הטבלאות הללו, נזדקק ליישום הכנסת מידע פשוט כדי לנהל את ההרשמה. ליישום זה יש מעט תחומי אחריות: לקחת את המידע אודות המשתמש, לאמת אותו ולהכניס אותו למאגר מידע. נשמע פשוט? תכף נראה...


יישום ההרשמה

יישום ההרשמה שלנו כולל שני עמודים. העמוד הראשון, addUser.cfm, הוא הטופס שנותן למשתמש להכניס את פרטיו. הוא מכיל טופס HTML ומספר ערכי קונפיגורציה של coldfusion. כאשר המשתמש מגיש את הטופס, המידע מועבר הלאה לעמוד השני שלנו, addUserValidate.cfm. העמוד הזה מבצע אימות בסיסי של המידע. אם משהו לא תקין, המשתמש מוחזר לעמוד הראשון. אחרת, המידע מוכנס לתוך מאגר המידע והמשתמש מועבר לעמוד הצלחה. אני יודעת כמה ויזואליים אתם, אנשי webmonkey, אז הנה תרשים שמראה איך כל זה הולך לעבוד.



פונקציות בסיסיות של יישום רישום המשתמש

קולטים? אחרי שהבנתם את זרימת העניינים, פתחו את addUser.cfm ואת addUserValidate.cfm ב-CF studio. (וודאו שאתם מבינים כל מה שקורה שם, בגלל שעוד מעט תרצו לערוך בו שינויים).
אגב שינויים, הדבר הראשון שתרצו לעשות הוא להוסיף שדות נוספים לטופס ההרשמה שלכם. כדי לעשות זאת:

הוסיפו את העמודות הנוספות לטבלת ה-USER.
הוסיפו אותם למשתני ה-userFields ב- addUser.cfm.
הוסיפו אותם לשאילתות ההכנסה ב- addUserValidate.cfm.
הוסיפו תהליכי אימות עבורם ב- addUserValidate.cfm(אופציונלי). השדות החדשים יאומתו אוטומטית כדי לוודא שהם לא ריקים, אבל אם תרצו אימות נוסף תאלצו להוסיף אותו בעצמכם.


ה-log in (כניסה למערכת)

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

Gatekeeper: Gatekeeper היא תווית שמונעת כניסה לא מורשית לעמוד מסוים. היא פועלת כמו מנעול. אתם מוסיפים את התווית בראש העמוד אותו ברצונכם לאבטח, והמנעול מותקן. מעכשיו, כל פעם שמשתמש מנסה להיכנס לעמוד מסוים, ה-Gatekeeper מופעל ומוודא שיש לו את ה"מפתח" הנכון כדי לפתוח אותו עמוד. אם יש לו אותו, מותר לו להמשיך. אם לא, ה-Gatekeeper שולח אותו חזרה ל-Keymaster כדי שישיג כזה.
Keymaster: ה- Keymaster הוא יישום קטן ששואל משתמשים לשם ה-login שלהם ולסיסמא, ואז בודק מול מאגר המידע כדי לוודא שהם תקפים. אם הם כן, ה- Keymaster נותן למשתמש "מפתח" איתו הוא יכול לגשת לאזורים מוגבלים באתר. אם לאו, הוא מבקש מהמשתמש להכניס את המידע שוב.

הערה לביצוע: במובנים מעשיים, Keymaster ו-Gatekeeper פועלים ע"י קריאת משתני סשנים. בגלל ההבדלים בין CF 4.x לבין CF 4.5, אני לא מתכוון להפעיל את הנעילה כאשר אני יוצר או קורא את אותם משתנים. עם זאת ,לפני שאתם משחררים את הילד הרע הזה באתר שלכם, עליכם לקחת את הקוד שקורא או כותב משתני סשנים ולנעול אותו.


Gatekeeper.cfm

אם תפתחו את הקובץ הזה ב-CF studio, תוכלו לראות שמדובר בתווית פשוטה יחסית. היא בודקת אם המשתנה session.login מוגדר או לא. אם לא, היא שולחת משתמשים ל-keymaster.cfm כדי שיוכלו לעשות login. Gatekeeper.cfm אמור להיות כלול בכל עמוד שדורש חסימה של חלקים ממנו. הוסיפו אותו לעמוד בעזרת הפקודה הבאה:

<cfinclude template="gatekeeper.cfm">


חשוב שתכללו את העמוד, אבל אל תתפתו להשתמש בתחביר מסוג אחר, כמו
<CF_GATEKEEPER> לדוגמא. ע"י הכללתו, אתם מקבלים את כל המידע המאוחסן בבקשה הנוכחית. לדוגמא, אם הגשתם משתני טפסים , פקודת הוספה הופכת אותם לנגישים לעמוד המצורף. פקודות אחרות עלולות למקם את המידע בתחום אחר ולהפוך את הגישה אליו לקשה יותר. זה חשוב מכיוון שכש- keymaster.cfm מאותחל, הוא לא יעבוד עד אשר יהיה לו חלק מהמידע המבוקש. נדבר על זה שוב בעוד שניה.


keymaster.cfm

היישום keymaster.cfm הוא בעיקרו שילוב של טופס-ושאילתא. הטופס מבקש שם וסיסמא, השאילתא בודקת מול מאגר המידע ומוודאת שהשם והסיסמא קיימים. אם הם קיימים, המידע אודות המשתמש מאוחסן בתוך משתנה סשן ו-session.login מכוון על "אמת". אם לא, keymaster מכבה את עצמו כדי לאפשר למשתמש ניסיון נוסף.

Keymaster מופעל כאשר משתמשים מנסים לגשת לעמוד מוגבל. הוא מסיט אותם מהיעד המכוון שלהם ושולח אותם לעמוד login. מכאן שברגע שמשתמשים מכניסים את המידע הדרוש, הם אמורים להיות מוחזרים ליעדם. אבל היעד זה יכול להיות כל עמוד שיש בו Gatekeeper. איך נדע לאן לשלוח את המשתמש?

כדי לאתר את העמוד הנכון, keymaster עושה שימוש במשתנה בשם cgi.script_name. המשנה הזה נקבע כשהמשתמש מבקש עמוד בפעם הראשונה. במקרה של Keymaster ו-Gatekeeper, שני העמודים כלולים בתוך עמודים אחרים. מכן שהבקשה הראשונית תהיה תמיד של עמוד אחר, ולא של העמוד הדרוש עצמו. בגלל זה, cgi.script_name מכיל את שם העמוד אליו ניסה המשתמש לגשת במקור.



אם תפתחו את keymaster.cfm ב-studio, תראו שהאימות מנוהל ע"י תווית מותאמת אישית בשם <CF_AUTHENTICATE>. התווית הזאת עוטפת יחד את תהליך בדיקת-מאגר-המידע ותהליך קביעת המשתנים. ע"י הפרדת הלוגיקה מהממשק, אנו דואגים לכך שיהיה קל הרבה יותר לבצע שינויים בעתיד. לדוגמא, אם תחליטו שאתם רוצים לשמור מידע נוסף על המשתמשים, תוכלו לערוך שינויים ב-authenticate.cfm מבלי לפגוע ב- keymaster.cfmולהפך.


קבל את ההודעה

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

אילו מאפיינים כדאי שיהיה להודעה? ובכן, אם אתם רוצים ליצור קבוצת דיון משורשרת (וזה מה שאנחנו רוצים), אנחנו זקוקים לשיטת מעקב אחר השרשראות. אם אנחנו רוצים לאפשר לאנשים למיין הודעות (לפי תאריך למשל) עלינו לדעת מתי הוצבה כל הודעה. כדאי גם לדעת מי הציב את ההודעה, כדי שנוכל לעקוב אחרי המחבר. וכמובן שנצטרך לדעת מה יש בכותרת ובתוכן שלה.

פתחו את הטבלה message ב-MB.mdb והביטו בעמודות שהיא כוללת. למרות שיש רק שש עמודות בטבלה הזאת, הן מספיקות כדי לאפשר לנו את כל הפעולות שפירטנו לפני רגע, כולל צפייה ושרשור (ואם תרצו להוסיף אותן מאוחר יותר, אז גם פעולות חסימה וחיפוש). טבלה זו מציגה את כל אחת מהעמודות ומסבירה בקצרה איזה מידע היא מכילה.

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


שליחת הודעות

עכשיו שהבנו את מבנה ההודעה, אנחנו יכולים ליצור רכיבים שיאפשרו לנו להציב הודעה בלוח. נזדקק ליישום הכנסת-מידע נוסף כדי לעשות זאת. אבל היישום הזה לא צריך לעשות אימות, אז הוא הולך להיות הרבה יותר פשוט. נקרא לו newPost.cfm לעת עתה. אנחנו גם צריכים לעבד את ההודעה ולהכניס אותה למאגר המידע. כדי לעשות את זה, ניצור רכיב בשם addPost.cfm.


newPost.cfm

אם תפתחו את newPost.cfm, תראו שהוא טופס HTML פשוט. הוא מעודד את המשתמש להכניס מידע ואז מפעיל את addPost.cfm על מנת שיכניס את אותו מידע למאגר. אבל אם תביטו קרוב יותר, תוכלו לקראות כמה כותרות משנה בדרך שבה הוא בנוי. רואים איך אנחנו מאתחלים את שדות השרשרת, הנושא והתוכן?

<cfparam name="thread" default="-1">
<cfparam name="subject" default="">
<cfparam name="message" default="">


אם חושבים על זה, אין שום סיבה לעשות את הדברים האלה ב- newPost.cfm. דבר ראשון? למה אנחנו זקוקים לערך thread? ולמה לאתחל את השדות subject ו-value? בהודעות חדשות, לשדות הללו תמיד יהיו אותם ערכים. הנושא של כל הודעה חדשה תמיד יהיה ריק, וכך גם התוכן שלה. אתם לא רוצים שההודעות החדשות שלכם תכלולנה מידע מצורף מראש, נכון? אז אתחול הערכים האלה נראה מיותר. עם זאת, היתירות הזאת היא זאת שמבטיחה שלכל הודעה תמיד יהיה ערכי תוכן, משתנה ושרשרת. ובמידה ונחליט לעשות שימוש חוזר בקוד הזה, ההבטחה הזאת תהיה נוחה.

למטה יותר, שימו לב לדרך שבה עושים שימוש בערכים התחלתיים:

<input type="hidden" name="thread" value="#thread#">
<input type="text" name="subject" value="#subject#">
<textarea name="message" rows="4">#trim(message)# </textarea>


בלי תיחום. בשיעורי Fast Track ו-DHPCFA, Allaire מלמדת שתיחום הוא דבר טוב. תחום משתנים אומר ל-coldfusion לאיזה משתנה אתה מתכוון כשאתה מתייחס אליו. השארת התיחום כבוי מאלצת את coldfusion לעבור על כל התחומים ולחפש את המשתנים ידנית. עם זאת, אנחנו בוחרים לא להפעיל או לאכלס את שדות הטופס ע"י שימוש בשמות מתוחמים מלאים כגון form.thread או form.subject. במקום, פשוט נעשה שימוש ב-subject או ב-thread. לא יהיה מהיר יותר פשוט להגדיר תחומים? יתכן. אבל היינו מקבלים מהירות על חשבון גמישות, ומאוחר יותר, ננצל את הגמישות של המשתנים הלא מתוחמים כדי לגרום לקוד שלנו לעבוד במהירות כפולה.

לסיום, שימו לב ששמות כל שדות הטופס (מלבד השדה החבוי action) מתאימים בדיוק לעמודות בטבלה "message". זה לא במקרה. היינו יכולים לקרוא לשדות בכל שם. אבל ככה השמות תואמים את העמודות במאגר המידע אליהן יוכנסו.

למה אני מדגיש לכם את זה? כי כל הדברים האלה הם חלק מתוכנית גדולה יותר שתאפשר לנו לעשות שימוש חוזר בעמוד הזה מאוחר יותר. הרשו לי להסביר...


הפיכת הישן לחדש

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

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

הדברים הדומים:

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

הדברים השונים:

בהודעה חדשה, אין שום צורך בערך thread. אין גם צורך לשייך את השדות subject ו-field לאיזשהו ערך נתון. בהודעת תגובה, לעומת זאת, המשתמשים מצפים לראות את כותרת ותוכן ההודעה המקורית מופיעים גם בהודעה שלהם. תגובות גם דורשות שלמאגר המידע יוכנס ID תקף של thread כדי לעקוב אחרי השרשרת אליה הן שייכות.

הפריטים עליהם הסתכלנו ב-newPost.cfm מטפלים בסוגיות הללו. אם רק נפתח את newPost.cfm, הטופס יהיה חלק, שזה בדיוק מה שאנחנו רוצים כשאנחנו מציבים הודעה חדשה. לעומת זאת, אם נעדכן ערכים לשדות thread, subject או message, הערכים הללו יופיעו בטופס מראש. בגלל שהערכים הראשוניים שלנו לא מציינים לאיזה תחום הם שייכים, אנחנו יכולים להעביר אותם תוך שימוש ב-GET או POST. זה מאפשר לנו לענות להודעה תוך שימוש בקישור או בכפתור בטופס.

ומאחר וכל שדות הטופס תואמים לעמודות במאגר המידע, אנחנו יכולים להשתמש בתווית
<CFINSERT> שתבצע את ההכנסה בשבילנו. למעשה, עכשיו שאנחנו מבינים איך newPost.cfm בנוי, יש באפשרותנו לראות בדיוק איך ההכנסה מתבצעת ב-addPost.cfm.


addPost.cfm

פתחו את addPost.cfm ב-studio. תראו שהוא מאוד קטן, ושהוא תוכנן כך שניתן יהיה להוסיף אותו לעמודים אחרים תוך שימוש במנחה . במהותו, הוא בודק אם הוגש שדה טופס בשם action. אם כן, הוא בודק אם ערך השדה שווה ל-post. אם הוא כן, addPost.cfm מנסה להוסיף הודעה חדשה לטבלה message בעזרת התווית :

<cfinsert
datasource="#application.dsn#"
tablename="message"
dbtype="ODBC"
formfields="frn_user_id,subject,message,thread">
addPost.cfm אז מציב דגלון (משתנה בשם addPost) שמציין האם ההכנסה הייתה מוצלחת או לא. אתם יכולים לבחון את הדגלון הזה אם אתם רוצים לבצע פעולה שתלויה בהצלחת ההכנסה.

תוך שימוש בתבנית הזאת, אנחנו יכולים להוסיף הודעות למאגר המידע. תלוי במידע שאנחנו מזינים לתוכה, ההודעה יכולה להיות הודעה חדשה או תשובה להודעה קיימת. אבל, אתם לא באמת יכולים להגיב להודעה עד שלא תוכלו לראות אותה על המסך שלכם. אז, לפני שנסגור את פרק התגובות, עלינו לדון בצפייה בהן.


צפייה בהודעות

יש לנו שיטה להכניס הודעות למאגר המידע. עכשיו אנחנו צריכים דרך להוציא אותן משם. עלינו ליצור מספר מרכיבי צפייה לפני שכל הסיפור יהיה גמור, וחלק מהם יהיו קצת מסובכים. אבל מאחר וצריך ללמוד ללכת לפני שמתחילים לרוץ, נפתח בניסיון לחשוב על דרך להציג הודעה יחידה.

ההחלטה על מה בדיוק צריך להציג היא די פשוטה. מן הסתם, אנחנו רוצים להציג את הנושא, תוכן ההודעה ותאריך השליחה. נרצה גם להציג את שם המחבר שלה. שימו לב שמאחר ורוב המשתמשים יעדיפו לכתוב הודעות כשיש להם אלמוניות מסוימת באתר, לא נכתוב את שמו האמיתי של המחבר אלא את הכינוי שלו (שם ה-login).

אז איפה משיגים את כל המידע העסיסי הזה? ובכן, כדי לשלוף את הכינוי עלינו לגשת לטבלה password. וכדי לשלוף את שאר המידע, ניגש לטבלה message. ברגע שיש לנו את כל המידע הדרוש, יהיה פשוט יחסית להציג אותו על המסך. פתחו את messageDetail.cfm ב-studio, ונראה איך כל זה עובד.


messageDetail.cfm

זהו דף מיוחד במינו שמטרתו לקיחת messageID כ-input, שליפת המידע על ההודעה ממאגר והצגתו על המסך. הוא עושה קצת אימות ובדיקת תוצאות, אבל בחלקו הגדול הוא פשוט שאילתא. אם אתם רוצים לבדוק את העמוד כדי לוודא שהוא עובד, נסו להוסיף כמה הודעות למאגר המידע בעזרת newPost.cfm, אז פתחו את messageDetail.cfm והדפיסו IDים של הודעות לתוך מחרוזת השאילתא, כך:

messageDetail.cfm?messageID=1


אתם אמורים לראות את ההודעה שיצרתם מוצגת בבירור על המסך. נסו לשנות את הערך של messageID וראו מה קורה כשאתם מנסים לצפות בהודעות שונות/לא קיימות. ברגע שתדעו שהכל עובד כמו שצריך, תמשיכו איתי ונראה לעומק מה נדרש כדי לענות על הודעה.


תגובה על הודעה

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

מאחר ותכננו קדימה כשבנינו את newPost.cfm, הוספת אפשרות התגובה תהיה פשוטה. כל שנצטרך לעשות הוא לעבור בשלושה ערכים: thread, message ו-subject. newPost.cfm ייקח את שלושת הערכים האלה ויעדכן מראש את השדות המתאימים. מהנקודה הזאת, נמשיך כאילו מדובר בהודעה חדשה רגילה.

עכשיו, יש לנו כמה אפשרויות להעברת הערכים ל- newPost.cfm. אנחנו יכולים להעביר אותם עם GET, לעשות להם POST לעמוד או לשלוף את המידע הדרוש ממאגר. GET היא לא אפשרות טובה במיוחד בגלל שכמות המידע שניתן להעביר על מחרוזת שאילתא היא מוגבלת (4kb מקסימום, לדעתי). POST יעבוד, אבל די צולע לשמור הודעה שלמה לתוך שדה חבוי. לכן נלך על שיטת מאגר המידע.

(למה די צולע? שמירת המידע בשדה חבוי מכפילה בפועל את גודלו של כל עמוד: אתם צריכים שבכל עמוד תהיה לכם את ההודעה פעמיים - פעם אחת על המסך, פעם אחת בשדה החבוי).


ReplyPost.cfm

כדי לראות כיצד מנגנון התגובה יעבוד, פתחו את ReplyPost.cfm ב-CF studio. ReplyPost הוא רכיב נוסף שתוכנן להיות כלול בעמוד אחר באמצעות . הוא מחפש פרמטר בשם replyID. אם הוא מוצא אותו, הוא משתמש ב-ID כדי לשלוף מידע על הודעה ממאגר המידע. אם הוא מצליח לבצע את זה, הוא מאתחל את ערכי thread, message ו-subject, ואז מחזיר את השליטה לעמוד הקורא.

כדי להוסיף את אפשרות התגובה ל- newPost.cfm, כל מה שאתם צריכים לעשות הוא להוסיף את הקוד ל- ReplyPost.cfmבאיזשהו מקום לפני טופס ה-input:

<CFINCLUDE TEMPLATE="replyPost.cfm">


אחרי שהוספתי את השורה הזאת ל- newPost.cfm, שמרתי גרסא מעודכנת בשם comboPost.cfm. אתם יכולים לבחון את הקובץ הזה באותו אופן בו בחנתם את messageDetail.cfm: ע"י הכנסת מספרי ID למחרוזת השאילתא, בסגנון:

ComboPost.cfm?replyID=1


אם הכנסתם ID תקף, אתם אמורים לראות את טופס התשומה ממולא מראש במידע על ההודעה. אם ה-ID שסיפקתם אינו תקף, אתם אמורים לראות שגיאה מוצגת על העמוד. וודאו שאתם יכולים לשלוח ולענות על הודעות נפרדות לפני שאתם ממשיכים, בגלל שבפרק הבא נתחיל להתמודד עם הממזרות בקבוצות.


מיון הודעות לפי תאריך

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

מיון לפי תאריך:

הצגת ההודעות בסדר שבו נשלחו.

שרשור:

הצגת ההודעות ממוינות לפי תאריך, אבל מקובצות לפי שרשרת.


מיון לפי תאריך

הצגת ההודעות לפי תאריך פשוטה מאין כמוה. פשוט שלפו את ההודעות ממאגר המידע והציגו את הפלט על המסך. נרצה להציג רק שלוש פיסות מידע: נושא, מחבר ותאריך. כדי להשיג את המידע הזה, השאילתא שלנו תצטרך לפעול שוב מול שתי הטבלאות password ו-message:

<cfquery name="qMessageQuery" datasource="#application.dsn#">
select a.id, a.subject, a.date, b.login
from message a, password b
where a.frn_user_id = b.frn_user_id
order by a.date DESC
</cfquery>


ברגע שיש לנו את השאילתא, אנחנו יכולים להציג את התוצאות בסיבוב מחזורי פשוט, בסגנון:

<cfoutput query="qMessageQuery">
<b>#subject#</b> [ #login# #dateformat(date, "ddmmmyy")# ]<br>
</cfoutput>


יישום מיון-לפי-תאריך בתשע שורות בלבד! כמובן, זה אף פעם לא פשוט כל כך. ככל שהלוח שלכם יגדל, כך תגדלנה גם מספר ההודעות שיש בו. ובנקודה מסוימת, יהיה מאוד לא מעשי להציג את כל ההודעות שהלוח מכיל. מכאן שנצטרך דרך לומר ללוח להציג רק הודעות חדשות יותר מתאריך מסוים.


גיל הפרישה

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

<cfparam name="application.retirementAge" default="30">


כעת נצטרך רק לשנות את השאילתא שלנו כך שתבדוק את הפרמטר הזה:

<cfquery name="qMessageQuery" datasource="#application.dsn#">
select a.id, a.subject, a.date, b.login
from message a, password b
where a.date >
#CreateODBCDate(DateAdd("d", evaluate('-' & application.retirementAge),
now()))#
and a.frn_user_id = b.frn_user_id
order by a.date DESC
</cfquery>


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

ונעשה זאת בקרוב. בינתיים יש לנו רק עוד כמה חלקיקים שדורשים בניה. לפי רגע סיימנו לבנות את רכיב התצוגה הפשוט ביותר. עכשיו נבנה את המסובך ביותר.


מיון לפי שרשרת

הצגת הודעות בצורה משורשרת קשה הרבה יותר. יש אלף דרכים לעשות זאת, ולכולן יש נקודות טובות ורעות. עבור הלוח הנוכחי, נתמודד עם השרשור בעזרת תווית רקורסיבית מותאמת אישית. רקורסיה היא לא רק יפה אלא גם אלגנטית. כמובן שיש את שיקול הביצועיות הקטן. אבל בלוחות הודעות קטנים, מהסוג שיהיה בסופו של דבר לרובכם, אתם אמורים להסתדר.

התווית המותאמת אישית שלנו תקרא displayThreaded.cfm והקוד שלה יראה בערך כך:

<cfparam name="attributes.iteration" default="0">
<cfparam name="attributes.thread" default="-1">

<!--- Get the category list --->
<cfquery name="qGetCategories" datasource="#application.dsn#">
select
a.thread, a.id, a.subject, a.date, b.login
from message a, password b
where a.date >
#CreateODBCDate(DateAdd("d", evaluate('-' & application.retirementAge), now()))#
and a.thread = #attributes.thread#
and a.frn_user_id = b.frn_user_id
order by a.date DESC
</cfquery>

<cfif qGetCategories.recordcount gt 0>
<cfoutput query="qGetCategories">
#RepeatString("...", attributes.iteration)# #subject#

<cfset tmpIt = attributes.iteration + 1>
<cf_displayThreaded iteration="#tmpIt#" thread="#id#">
<cfset tmpIt = attributes.iteration - 1>
</cfoutput>
</cfif>


מדובר בהרבה מאוד קוד, אבל חשוב שתבינו איך הוא עובד, אז בואו נצלול לתוכו. התווית עובדת ע"י קריאה עצמית שחוזרת על עצמה. בפעם הראשונה שהיא רצה, היא מחפשת את כל ההודעות שערך ה-thread שלהן הוא 1. מאחר וזה ערך ברירת המחדל שלנו להודעות חדשות (בדקו ב-newPost.cfm אם אתם לא יודעים למה אני מתכוון), הבדיקה תחזיר רק הודעות מסוג זה.

התווית אז עוברת שוב ושוב בצורה מחזורית על רשימת ההודעות שהיא שלפה, תוך שימוש ב-ID של ההודעה הנוכחית שלה כערך ה-thread בשאילתא הבאה. זה מחזיר רשימה של כל התגובות להודעה. בפעם הבאה, זה יחזיר את התגובות לתגובות וכן הלאה.

התוצר הסופי הוא רשימה יפה שמציגה כל שרשרת במיון לפי תאריך.

שימו לב: בגלל שהתווית קובעת את ה-ID של ההודעה המקורית ל-1, היא מציגה את כל השרשראות הפעילות על לוח ההודעות כאשר היא רצה. עם זאת ,אתם יכולים לקבוע ל-thread ההתחלתי כל message ID שרק תרצו, מה שיגרום לתווית להחזיר רק תגובות להודעה הספציפית שבחרתם.


הבא והקודם

המשימה הבאה שלנו היא לפתח שיטה בה יוכלו המשתמשים לעבור בין הודעות תוך שהם קוראים אותן. נאפשר להם לעבור בין הודעות משורשרות לבין הודעות הממוינות לפי תאריך, מה שנותן להם ארבע שיטות סה"כ לדפדף בלוח.

כמובן שעם כל התזוזות האלה, נצטרך לוודא שאנחנו לא הולכים לאיבוד. אז בואו נראה מה כל תנועה אמורה לעשות. כאשר הלוח הוא במוד משורשר, תזוזה בין הבא/הקודם אמורה להציג את ההודעה הבאה/קודמת בשרשרת. כאשר הלוח הוא במוד ממוין-לפי-תאריך, הבא/הקודם אמור לנווט בין ההודעות החדשות/ישנות יותר שיש בלוח.


מעקב אחרי ה"מוד" (mode)

כדי לספק את הפעולה הזאת, עלינו לעקוב אחרי המוד בו מסודר הלוח. משמעות הדבר היא יצירת דגלון אליו נוכל להתייחס בקוד שלנו. נקרא לדגלון session.browseMode, ונגדיר לו שני ערכים אפשריים: threaded (בשרשרת) או ByDate (לפי תאריך). נאתחל את המשתנה הזה בקובץ application.cfm, ונוודא שברירת המחדל שלו תהיה המוד המשורשר. אז, בראשו של כל עמוד דפדפן, נוכל להוסיף את הקוד שיכוון את הדגלון למוד המתאים. לדוגמא, בראשו של displayByDate.cfm, תהיה לנו השורה:

<cfset session.browseMode = "ByDate">


ובראשו של displayThreaded.cfm, תהיה לנו:

<cfset session.browseMode = "Threaded">


זה יאמר לנו באיזה מוד הלוח נמצא בזמן כלשהו, ויאפשר לנו לשייך לכפתור הבא/הקודם את הפעולה המתאימה.


NextPrevMSG.cfm

אם תפתחו את הקובץ הזה ב-CF studio, תראו דרך אחת ליישם את הפעולות שפורטו לעיל. זהו עמוד נוסף שתוכנן לשמש כ-, והקובץ הזה מחולק לשני חלקים עיקריים. החלק הראשון הוא חלק ה"שרשור". הוא בודק את אופן הדפדוף ומוודא שהמשתמש עובד בשיטה "threaded". אז הוא מתשאל את מאגר המידע כדי למצוא את ה-IDים להודעה הבאה/הקודמת. הוא יוצר קישור המכוון לעמוד תצוגה ומעביר את ה-"message ID"ים הנכונים כדי ליצור פעולות "הבא/הקודם". החלק השני הוא חלק ה"לפי-תאריך". הוא עובד בדיוק כמו חלק ה"שרשור", אבל מכיוון שאין צורך לשמר יחסים כאשר אנחנו ממיינים לפי תאריך, השאילתות הן הרבה יותר פשוטות. שימו לב שהוא עדיין פועל ע"י איתור ההודעות החדשות/ישנות ביותר והעברתן למודול תצוגה לצפייה.


מחברים הכל יחד

עכשיו שפונקצית "הבא/הקודם" שלנו פועלת, אנחנו מוכנים לקחת את כל הרכיבים ולתפור אותם יחד ללוח מודעות אחד שלם. נתחיל ע"י יצירת סרגל כלים שיכלול את רוב הפעולות.

הפעולות אותן אנחנו חייבים לספק הן:

הצבת הודעה חדשה
תגובה להודעה קיימת
צפייה בהודעות במוד שרשרת
צפייה בהודעות הממוינות עפ"י תאריך
לך להודעה הבאה/קודמת
צפה בתגובות (במוד המשורשר בלבד)

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


Toolbar.cfm

פתחו את Toolbar.cfm ב-CF studio. כפי שאתם יכולים לראות, אנחנו עושים שימוש ב-comboPost.cfm עד הסוף, ומנצלים אותו לאספקת פעולות השליחה והתגובה. מאחר ואנחנו רוצים לאפשר תגובה רק כאשר משתמש צופה בהודעה מסוימת, יש קצת לוגיקת תנאים בראש העמוד שקובעת האם להציג כפתור "תגובה" או לא. שאר התכונות תמיד מוצגות.

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


הכנסת סרגל הכלים

עכשיו שכל הפעולות הבסיסיות של הלוח מרוכזות במקום אחד, אנחנו צריכים להוסיף את סרגל הכלים למספר קבצים שונים. דבר ראשון, עלינו להוסיף אותו לעמודי הדפדוף בין ההודעות displayThreaded.cfm ו-displayByDate.cfm. מאחר ואנו לא זקוקים לפעולות ניווט או רשימת תגובות, אנחנו יכולים לדלג על הוספת תווית הסיום ופשוט "להפיל" את התווית לתוך ראשית הקבצים. פתחו את הקבצים האלה ב-CF studio כדי לראות כיצד זה נעשה.

אנחנו גם רוצים להוסיף את הפעולות האלה לעמודי פרטי ההודעות. היינו יכולים לעשות זאת ע"י צירופם ל-messageDetail.cfm. עם זאת, פשוט יחסית לבנות עמוד קטן שפשוט כולל את messageDetail ומוסיף לו את הפעולות. זה נעשה בקובץ displayMessage.cfm. הקובץ הזה הוא מאוד קטן.

<cftry>
<cf_toolbar><cfinclude template="messageDetail.cfm"></cf_toolbar>
<cfcatch type="any"></cfcatch>
</cftry>


כל מה שנעשה כאן בעצם הוא עטיפת עמוד ה- messageDetail בבלוק try-catch כדי למנוע ממשתמשים לראות שגיאות לא רצויות. אתם יכולים לעשות את כל זה גם ב- messageDetail, אבל ההפרדה הזאת מקלה על הוספת מודולים בעתיד.

וזהו זה! סיימנו!

עכשיו שסרגל הכלים פועל ומוכנס לתוך העמודים הנכונים, יש לנו לוח הודעות מוכן ועובד. כדי להשתמש בו, פשוט התחברו ל-displayThreaded.cfm או ל-displayByDate.cfm. כל השאר אמור להיות אוטומטי.







דיון שרשרת עם
coldfusion
בחרו לוח, כל לוח
בניית הלוח >