Kotchasan PHP Framework

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

ตอนนี้เป็นตอนสุดท้ายแล้วสำหรับเวิร์คช้อปนี้ ซึ่งในตอนก่อน เราได้สร้างฟอร์มไปแล้ว ซึ่งถ้าดูจากโค้ด action ของฟอร์มมันระบุว่าให้โพสต์ไปที่ index.php/index/model/pages/save หรือ Index\Pages\Model::save() ตามค่ากำหนดของ Router นั่นเอง

ซึ่งผมจะหยิบเฉพาะ method save มาอธิบายคร่าวๆ นะครับ
public function save(Request $request)
{
  // session, token, member
  if ($request->initSession() && $request->isSafe() && Login::isMember()) {
    // รับค่าจากการ POST
    $save = array(
      'id' => time(),
      'module' => $request->post('write_module')->username(),
      'topic' => $request->post('write_topic')->topic(),
      'detail' => $request->post('write_detail')->detail()
    );
    // รายการที่แก้ไข 0 รายการใหม่
    $id = $request->post('write_id')->toInt();
    // ตรวจสอบรายการที่แก้ไข
    if ($id > 0) {
      $index = self::get($id);
    }
    if ($id > 0 && empty($index)) {
      $ret['alert'] = 'ไม่พบข้อมูลที่แก้ไข กรุณารีเฟรช';
    } elseif ($save['module'] == '') {
      $ret['alert'] = 'กรุณากรอก โมดูล';
      $ret['input'] = 'write_module';
    } elseif ($save['topic'] == '') {
      $ret['alert'] = 'กรุณากรอก หัวข้อ';
      $ret['input'] = 'write_topic';
    } elseif (!File::makeDirectory(ROOT_PATH.DATA_FOLDER.'index/')) {
      $ret['alert'] = 'ไดเร็คทอรี่ '.DATA_FOLDER.' ไม่สามารถเขียนได้';
    } else {
      // ตรวจสอบโมดูลซ้ำ
      if (self::exists($save['module'], $id)) {
        $ret['alert'] = 'มีโมดูลนี้อยู่ก่อนแล้ว';
      } else {
        $f = @fopen(ROOT_PATH.DATA_FOLDER.'index/'.$save['module'].'.php', 'w');
        if ($f) {
          fwrite($f, "<?php\nreturn ".var_export($save, true).';');
          fclose($f);
          // เคลียร์ Token
          $request->removeToken();
          // คืนค่า
          $ret['alert'] = 'บันทึกเรียบร้อย';
          $ret['location'] = 'index.php?module=pages';
        } else {
          $ret['alert'] = 'ไดเร็คทอรี่ '.DATA_FOLDER.'index/ ไม่สามารถเขียนได้';
        }
      }
    }
    // คืนค่าเป็น JSON
    echo json_encode($ret);
  }
}

ที่ฟอร์ม Index\Pageswrite\View มีการกำหนดค่าให้มีการ  submit แบบ Ajax ไว้ (ajax=true) ซึ่งก็จะทำให้มีการเรียกใช้ความสามารถด้าน Ajax ของ GForm มาใช้งาน ดังนั้นในการรับค่าจากฟอร์มเราก็ต้องออกแบบการรับค่าฟอร์มจาก Ajax และส่งค่ากลับไปยัง Ajax ด้วย JSON
// session, token, member
if ($request->initSession() && $request->isSafe() && Login::isMember()) {

บรรทัดแรกของการรับค่ามีการกระทำ 3 อย่าง คือ
  1. เปิดใช้งาน session  $request->initSession()
  2. ตรวจสอบ token ซึ่งถ้ามาจากการ submit ผ่านฟอร์มปกติ token ต้องตรงกันกับที่เก็บไว้ตอนสร้างฟอร์ม ด้วย $request->isSafe()
  3. ตรวจสอบการ Login เป็นการตรวจสอบซ้ำเพื่อให้แน่ใจว่ายัง login อยู่ด้วย Login::isMember()
// รับค่าจากการ POST
$save = array(
  'id' => time(),
  'module' => $request->post('write_module')->username(),
  'topic' => $request->post('write_topic')->topic(),
  'detail' => $request->post('write_detail')->detail()
);

ถัดมาคือการรับค่าข้อมูลต่างๆที่ถูกส่งมาจากฟอร์ม ที่ Method $_POST ซึ่งจะรับค่าโดย $request->post() (ลองเดาดูนะครับว่า ถ้าเป็น $_GET หรือ $_REQUEST จะรับค่าด้วยฟังก์ชั่นอะไร) ซึ่งในการรับค่ามาจะผ่านตัวกรองต่างๆเพื่อกรองข้อมูลให้เหมาะสมด้วย method อีกหลายรูปแบบ เช่น username() จะรับเฉพาะข้อมูลที่เป็น email หรือเบอร์โทร(ที่อาจใช้ในการเข้าระบบได้) เท่านั้น หรือ topic() จะรับข้อมูลที่เป็นตัวอักษรอย่างเดียวไม่ยอมรับ tag และมีได้แค่บรรทัดเดียวเท่านั้นเป็นต้น (ข้อมูลเพิ่มเติมดูได้ที่ InputItem)

ถัดมาก็จะเป็นการตรวจสอบข้อมูลที่กำลังแก้ไข ว่ามีอยู่จริงหรือไม่ และตรวจสอบค่าต่างๆที่ส่งมาว่าถูกต้องหรือไม่ ซึ่งถ้าไม่ถูกต้องก็จะทำการส่งค่ากลับรูปแบบ JSON เป็นข้อความเตือน และชื่อ Input ที่เกี่ยวข้อง

สุดท้ายหากไม่พบข้อผิดพลาดใดๆก็จะทำการบันทึกข้อมูลลงไฟล์ตามที่กำหนดไว้ และต้องไม่ลืมที่จะ remove token ออกด้วยโดยใช้คำสั้ง $request->removeToken(); เพื่อป้องกันการนำ token ไปใช้ซ้ำ และทำการส่งผลลัพท์กลับว่าบันทึกเรียบร้อยแล้วพร้อมกับการส่งค่า URL ที่จะ redirect กลับไปด้วย รูปแบบ JSON

จะเห็นได้ว่าไม่ว่าจะมีข้อผิดพลาดหรือไม่ก็ตามข้อมูลต่างๆ จะถูกส่งกลับไปยัง Ajax รูปแบบ JSON เหมือนกันทุกครั้ง ซึ่งจะต่างกันที่ข้อมูลที่ส่งกลับเท่านั้น ซึ่งเมื่อ Ajax รับค่ากลับไปแล้วจะต้องไปทำการแยกข้อมูลที่ส่งกลับว่าต้องทำอะไรกับข้อมูลนั้นๆ เช่น แสดงการแจ้งเตือน หรือจะทำการ redirect ไปยังหน้าถัดไป ซึ่งข้อมูลที่ส่งกลับจะถูกส่งไปที่ฟังก์ชั่น Javascript doFormSubmit ซึ่งอยู่ในไฟล์ admin/js/admin.js เพื่อแปลงผลลัท์จาก PHP กลับเป็น JSON และดำเนินการตามค่าที่ส่งมาต่อไป

สำหรับในส่วนของการรับค่าจากฟอร์ม เขียน-แก้ไขข้อมูลเมนูก็มีลักษณะเดียวกันนะครับ

สำหรับโค้ดส่วนอื่นๆ ที่ผมไม่ได้มีการกล่าวถึง จะมีลักษณะคล้ายๆกันกับโปรเจ็คก่อนๆ เช่น โค้ด index.html จะต้องมีการ include เอาไฟล์ Javascript และ CSS เข้ามาไว้ด้วย โดยทำการแก้ไข path ให้ชี้ไปยังไดเร็คทอรี่ที่ถูกต้อง