Kotchasan PHP Framework

[ตอนที่ 7] เวิร์คช้อป CMS อย่างง่าย เก็บข้อมูลลงฐานข้อมูล

โมดูลสุดท้ายที่จะพูดถึงคือโมดูลห้องสนทนาหรือแชตนั่นเอง จุดประสงค์ของการแสดงตัวอย่างการใช้งานโมดูลแชต ก็เพื่อให้เห็นวิธีการอย่างง่ายในการใช้งาน API ร่วมกับคชสาร โดยที่แชตในตัวอย่างนี้จะใช้วิธีการติดต่อขอข้อมูลจาก Server ด้วยวิธีการของ API ทั้งหมด เช่น
        
  • การขอชื่อผู้ใช้งาน ซึ่งจะต้องไม่ซ้ำกัน ก็ต้องไปขอชื่อจาก Server ผ่าน API ได้ข้อมูลกลับมาในรูปแบบ JSON
  •     
  • ข้อมูลการสนทนา ก็ใช้วิธีร้องขอข้อมูลเป็นระยะด้วย Ajax โดยเรียกไปยัง API เช่นกันซึ่งจะได้ข้อมูลกลับมาในรูปแบบ JSON
  •     
  • การส่งข้อมูลสนทนาไปยัง Server ก็ทำผ่าน API โดยใช้ Ajax อีกเช่นกัน แต่บริการนี้ไม่ต้องการผลตอบกลับ
จะเห็นได้ว่าเราจะใช้การติดต่อในแบบ API ล้วนๆในโมดูลนี้
หมายเหตุ นอกจากนี้เรายังสามารถแยกเอาส่วนของข้อมูลต่างๆ (Model) ออกจากส่วนของการแสดงผล (Controller และ View) ได้ด้วย แต่เนื่องจากหากต้องการนำไปใช้เต็มรูปแบบผ่านโดเมนที่ต่างกันอาจต้องมีการจัดการเพิ่มมากกว่านี้ เช่น ปัญหาการใช้งานข้ามโดเมน ดังนั้นหากต้องการทดสอบ จะต้องคำนึงถึงเรื่องเหล่านี้ด้วย
คอนโทรลเลอร์หลักของแชตทำหน้าที่เรียก View มาแสดงหน้าจอแชตเท่านั้น ผมจะไม่พูดถึงละกัน
namespace Chat\Index;

use \Kotchasan\Http\Request;
use \Kotchasan\Template;

class View extends \Kotchasan\View
{

  public static function render(Request $request)
  {
    if ($request->initSession()) {
      if (empty($_SESSION['chat_name'])) {
        // ร้องขอชื่อ User จาก chat API
        $user = json_decode(file_get_contents(WEB_URL.'index.php/chat/model/index/getUser'));
        // บันทึกชื่อลง session
        $_SESSION['chat_name'] = $user->name;
      }
      // View
      $view = new static;
      $view->setContents(array(
        '/{NAME}/' => $_SESSION['chat_name']
      ));
      // โหลด template หน้า main (main.html)
      $template = Template::load('chat', '', 'main');
      // คืนค่า
      return $view->renderHTML($template);
    }
  }
}

ที่ Chat\Index\View หลักๆจะทำหน้าที่ในการแสดงกรอบแชตโดยโหลดเทมเพลต skin/default/chat/main.html มาแสดง และจะมีการร้องขอชื่อสมาชิกผ่าน Service API
$user = json_decode(file_get_contents(WEB_URL.'index.php/chat/model/index/getUser'));
ซึ่ง URL ที่ใช้ในการร้องขอชื่อสมาชิกก็คือ index.php/chat/model/index/getUser นั่นเอง ซึ่งข้อมูลที่ได้มาจะอยู่ในรูปของ JSON ซึ่งหลังจากที่ได้ชื่อมาแล้ว เราจะทำการบันทึกลง session ไว้เผื่อหากมีการรีเฟรชหน้าเรายังจะสามารถใช้ชื่อเดิมได้ โดยไม่ต้องร้องขอชื่อใหม่ และนำชื่อที่ได้ไปใส่ลงในฟอร์มแชตเพื่อใช้ในการสนทนาต่อไป
โค้ดในฝั่งของ UI หลักๆก็มีเพียงเท่านี้ โค้ดส่วนที่เหลือจะถูกจัดการโดย Javascript เป็นหลัก เนื่องจากหลักการของแชตก็คือการร้องขอไปยัง Server เพื่อขอข้อมูลการสนทนากลับมาหากมีการสนทนาใหม่เกิดขึ้น หรือส่งค่าว่างเปล่ากลับมาหากไม่มีข้อมูลใหม่ งานหลักจริงๆของแชตจึงเป็นส่วนของ Javascript มากกว่า
/* ตรวจสอบข้อความสนทนา */
var chat_id = 0;
/* อัตรา Refresh ของแชต (วินาที) */
var interval = 1;
var _getChat = function () {
  return 'id=' + chat_id + '&name=' + encodeURIComponent($E('chat_name').value);
};
var _chat = new GAjax();
_chat.autoupdate('index.php/chat/model/index/get', interval, _getChat, function (xhr) {
  /* ข้อมูลการสนทนาถูกส่งกลับมากับ xhr และนำมาแสดงผลภายใต้ฟังก์ชั่นนี้ */
});

โค้ดด้านบนเป็นโค้ดส่วนของ Javascript
GAjax มีคำสั่งสำหรับการอัปเดทแบบ Realtime อยู่แล้วคือ autoupdate ฟังก์ชั่นนี้จะทำการร้องขอข้อมูลไปยัง Service API ที่ไฟล์ index.php/chat/model/index/get เพื่อตรวจสอบการสนทนาโดยส่งพารามิเตอร์แบบ POST ไปด้วย (ตามคำสั่ง _getChat) เป็นระยะๆ
ข้อมูลจะถูกส่งกลับมาในรูปแบบ JSON ที่ตัวแปร xhr.responseText ซึ่งจะต้องรับค่าแล้วทำการจัดรูปแบบการแสดงผลก่อนนำไปแสดงที่หน้าจอแชตต่อไป

อีกทางหนึ่งเมื่อต้องการโพสต์ข้อความ ก็จะมีการส่งค่าไปยัง Service API ด้วย Ajax โดยใช้ฟังก์ชั่น send() ซึ่งจะมีการเรียกไปยัง GAjax อีกทอดหนึ่ง
var chatSend = function () {
  var q = 'message=' + encodeURIComponent($E('chat_message').value) + '&name=' + encodeURIComponent($E('chat_name').value);
  send('index.php/chat/model/index/send', q);
  $E('chat_message').value = '';
  $E('chat_message').focus();
  return false;
};

หลังจากมีการกด Enter หรือกดปุ่มส่ง จะมีการอ่านชื่อและข้อความที่จะส่ง ส่งไปยัง index.php/chat/model/index/send ด้วย Ajax เสร็จแล้วจะทำการเคลียร์ข้อความออกเพื่อรอรับข้อความสนทนาถัดไปได้ทันที
จะเห็นได้ว่า กระบวนการส่งข้อความนี้ไม่ได้มีการรอรับค่ากลับ เนื่องจากเพื่อให้แอพพลิเคชั่นตัวอย่างนี้เรียบง่าย จึงผลักภาระการอ่านข้อมูลให้เป็นหน้าที่ของ Javascript ในชุดก่อนหน้าเพียงอันเดียว