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

ในเวิร์คช้อบนี้ defaultController หรือ Index\Index\Controller จะมีความแตกต่างจากเวิร์คช้อปก่อนหน้าเพียงนิดเดียวในส่วนของการเรียก Controller ถัดไป
namespace Index\Index;

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

class Controller extends \Kotchasan\Controller
{

  public function index(Request $request)
  {
    // รับค่าจาก $_GET['module'] ถ้าไม่มีการส่งค่ามาจะคืนค่า home โดยคืนค่าเป็น string ที่ตัวแปร module
    // method filter() กำหนดให้รับค่าเฉพาะตัวอักษรที่กำหนดเท่านั้น
    $module = $request->get('module', 'home')->filter('a-z');
    // กำหนดค่า template ที่ใช้งานอยู่
    Template::init(self::$cfg->skin);
    // ชื่อคลาสจากโมดูล
    $class = ucfirst($module).'\Index\Controller';
    if (!method_exists($class, 'init')) {
      // ไม่มีโมดูล เรียกหน้าเพจ
      $class = 'Index\Main\Controller';
    }
    // โหลดโมดูล
    $index = createClass($class)->init($request, $module);

    // เริ่มต้นใช้งาน View
    $view = new \Kotchasan\View;
    // ใส่เนื้อหาลงใน View ตามที่กำหนดใน Template
    $view->setContents(array(
      // ข้อความจาก View แสดงบน title bar
      '/{TITLE}/' => $index->title,
      // เนื้อหาหน้า View ที่เรียกใช้งาน
      '/{CONTENT}/' => $index->detail,
      // แสดงเมนู
      '/{TOPMENU}/' => \Kotchasan\Menu::render(\Index\Menu\Model::get(), $index->module),
      // จำนวน Query
      '/{QURIES}/' => \Kotchasan\Database\Driver::queryCount()
    ));
    // โหลด template หลัก (index.html)
    $template = Template::load('', '', 'index');
    // ส่งออก HTML
    echo $view->renderHTML($template);
  }
}

บรรทัดแรก เราจะกำหนดให้หน้าเพจที่เราต้องการเป็นชื่อคลาสเลย เช่น มีการเรียกหน้า home จะได้ชื่อคลาสเป็น Home\Index\Controller และให้ตรวจสอบว่ามีคลาสนี้ติดตั้งไว้หรือไม่ ถ้ามีจะไปโหลดคลาสที่พบ ซึ่งปกติแล้วคลาสที่พบจะเป็นโมดูลอื่นๆ เช่น Chat\Index\Controller ซึ่งก็คือ Controller หลักของโมดูล Chat (modules/chat/controllers/index.php) ส่วนในกรณีที่ไม่พบโมดูล ก็อาจจะเป็นหน้าเพจ ซึ่งจะถูกส่งต่อไปยัง Index\Main\Controller ที่บรรทัดถัดไปแทน

ส่วน Index\Main\Controller ก็แทบไม่มีอะไรแตกต่างเช่นกัน มันยังคงทำหน้าที่คล้ายๆเวิร์คช้อปก่อนหน้า
namespace Index\Main;

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

class Controller extends \Kotchasan\Controller
{

  public function init(Request $request, $module)
  {
    // ตรวจสอบหน้าที่เรียกจากฐานข้อมูล
    $page = \Index\Module\Model::get($module);
    if ($page === false) {
      $index = new \Index\Pagenotfound\View;
      $title = $index->title();
      $detail = $index->render();
    } else {
      $title = $page->topic;
      $detail = $page->detail;
    }

    // เริ่มต้นใช้งาน View ของโมดูล Main
    $view = new \Kotchasan\View;
    // ใส่เนื้อหาลงใน View ตามที่กำหนดใน Template
    $view->setContents(array(
      // หัวข้อ
      '/{TOPIC}/' => $title,
      // เนื้อหา
      '/{DETAIL}/' => $detail
    ));
    // โหลด template หน้า main (main.html)
    $template = Template::load('', '', 'main');
    // คืนค่าข้อมูลโมดูล
    return (object)array(
        'module' => $module,
        'title' => $title,
        'detail' => $view->renderHTML($template)
    );
  }
}

โดยการนำค่าโมดูลที่ส่งมา ไปตรวจสอบกับฐานข้อมูล ที่ Index\Module\Model ถ้าพบก็คืนค่าข้อมูลหน้าที่พบ ถ้าไม่พบก็จะคืนค่าข้อมูลจาก Index\Pagenotfound\View แทน

ในเวิร์คช้อปนี้จะใช้การอ่านข้อมูลจากฐานข้อมูลนะครับ ดังนั้น ที่ Index\Module\Model ก็จะทำหน้าที่เชื่อมต่อกับฐานข้อมูลเพื่ออ่านข้อมูล $module ที่เลือก ออกมา
namespace Index\Module;

class Model extends \Kotchasan\Model
{

  public static function get($module)
  {
    // เรียกใช้งาน Model
    $model = new static;
    // query ข้อมูลโมดูล (หน้าเพจ) ที่ต้องการ
    $query = $model->db()->createQuery()
      ->from('site')
      ->where(array(
        array('module', $module)
      ))
      ->cacheOn();
    // คำสั่งสำหรับดู query
    // SELECT * FROM `u`.`site` WHERE `module` = 'home' LIMIT 1
    //echo $query->select()->limit(1)->text();
    // คืนค่าข้อมูลที่พบ รายการเดียว
    return $query->first();
  }
}

อธิบายโค้ดเพิ่มเติมเป็นส่วนๆ นะครับ
// เรียกใช้งาน Model
$model = new static;

โค้ดด้านบนเป็นการเรียกใช้งาน Model ครับ คีย์เวิร์ด static เป็นคำสั่งของ PHP หมายถึงคลาสนี้ หรือก็คือ \kotchasan\Model นั่นเอง (เขียนได้อีกแบบว่า $model = new \Kotchasan\Model;)
// query ข้อมูลโมดูล (หน้าเพจ) ที่ต้องการ
$query = $model->db()->createQuery()
    ->from('site')
    ->where(array(
      array('module', $module)
    ))
    ->cacheOn();

โค้ดด้านบนเป็นคำสั่งของ Model ใช้สำหรับสร้าง SQL Query มีชื่อว่า QueryBuilder (ถ้ามีการใช้คำสั่ง createQuery() แสดงว่ามีการใช้ QueryBuilder) รูปแบบของคำสั่งจะมีลักษณะคล้ายๆกับคำสั่งของ SQL ปกติ เพื่อให้จดจำได้ง่าย ซึ่งการดูผลลัพท์ SQL ของ Query ที่สร้างสามารถดูได้จากคำสั่ง text();
// คำสั่งสำหรับดู query
// SELECT * FROM `u`.`site` WHERE `module` = 'home' LIMIT 1
//echo $query->select()->limit(1)->text();

คำสั่งด้านบนคือตัวอย่างการใช้งาน text() พร้อมผลลัพท์ SQL ที่ได้
คำสั่ง cacheOn(); เป็นคำสั่งเปิดการใช้งานแคชของ QueryBuilder ถ้าต้องการเปิดใช้งานแคชจะต้องมีการดำเนินการดังนี้
  1. ต้องมีไดเร็คทอรี่ datas/cache/ และสามารถเขียนได้ ไฟล์แคชจะถูกเก็บไว้ในไดเร็คทอรี่นี้
  2. ต้องมีการตั้งค่าอายุของแคช (Kotchasan\Config::$cache_expire) เนื่องจากค่าเริ่มต้นระบุค่าเป็น 0 ไว้ ซึ่งจะหมายถึงไม่มีการใช้งานแคช หากต้องการใช้งานแคชจะต้องกำหนดค่านี้มากกว่า 0 เช่น 10 จะหมายถึงมีการแคชฐานข้อมูลเก็บไว้ 10 วินาที ค่านี้สามารถกำหนดใส่ไฟล์ settings/config.php ได้ (ไม่แนะนำให้แก้ไขไฟล์ของคชสารตรงๆ)
เมื่อมีการเปิดใช้งานแคชแล้ว และมีการเขียนคำสั่งเรียกใช้งานแคชที่ฐานข้อมูล (cacheOn) ฐานข้อมูลจะทำการสร้างไฟล์แคชเก็บไว้ที่ datas/cache/ สำหรับเวิร์คช้อปนี้ ผมได้แสดงตัวอย่างว่ามีการใช้งานแคชหรือไม่ที่ footer ของไซต์ โดยแสดงจำนวน query ที่มีการใช้งาน ในกรณ๊ที่มีการรีเฟรชหน้าและมีการใช้งานแคช ตัวเลขนี้จะลดลง เนื่องจากข้อมูลที่แสดงเอามาจากแคชแทนนั่นเอง
// คืนค่าข้อมูลที่พบ รายการเดียว
return $query->first();

สุดท้ายคือคำสั่ง query เอาผลลัพท์ออกมา ซึ่งคำสั่งนี้จะคืนค่าผลลัพท์ออกมารายการแรกที่พบเท่านั้น

สำหรับส่วนของเมนูก็แทบไม่มีอะไรแตกต่างจากเดิมเช่นกัน ที่เปลี่ยนแปลงไปจะมีเพียงการอ่านข้อมูลเมนูจากฐานข้อมูลเท่านั้น
namespace Index\Menu;

class Model extends \Kotchasan\Model
{

  public static function get()
  {
    // เรียกใช้งาน Model
    $model = new static;
    // query ข้อมูลเมนูจากฐานข้อมูล
    $query = $model->db()->createQuery()
      ->select()
      ->from('menu')
      ->order('order ASC')
      ->cacheOn();
    // คำสั่งสำหรับดู query
    // SELECT * FROM `u`.`menu` ORDER BY `order` ASC
    //echo $query->text();
    $result = array();
    // query ข้อมูลและจัดรูปแบบเพื่อใส่ลงใน Array ตามข้อกำหนดของโมดูล
    foreach ($query->execute() as $item) {
      // จัดรูปแบบข้อมูลเมนูให้เหมาะสม สำหรับการสร้างเมนู
      $result[$item->module] = array(
        'text' => $item->text,
        'target' => $item->target
      );
      if (empty($item->url)) {
        $result[$item->module]['url'] = WEB_URL.'index.php?module='.$item->module;
      } else {
        $result[$item->module]['url'] = $item->url;
      }
    }
    // คืนค่ารายการเมนูที่จัดรูปแบบแล้ว
    return $result;
  }
}

ที่ Index\Menu\Model จะทำการอ่านข้อมูลเมนูทั้งหมดออกมาจากฐานข้อมูล โดยมีลักษณะคล้ายการอ่านหน้าเพจนั่นแหละครับ ต่างกันแค่มีการอ่านข้อมูลด้วย execute() แทน ซึ่งคำสั่งนี้จะให้ผลลัพท์ออกมาได้หลายรายการ และจะส่งต่อผลลัพท์ไปวนลูปเพื่อจัดรูปแบบให้เหมาะสม ก่อนส่งข้อมูลเมนูกลับไปแสดงผล
0SHAREFacebookLINE it!