[ตอนที่ 8] เวิร์คช้อป CMS อย่างง่าย เก็บข้อมูลเป็นไฟล์
ตอนนี้เป็นตอนสุดท้ายแล้วสำหรับเวิร์คช้อปนี้ ซึ่งในตอนก่อน เราได้สร้างฟอร์มไปแล้ว ซึ่งถ้าดูจากโค้ด action ของฟอร์มมันระบุว่าให้โพสต์ไปที่ index.php/index/model/pages/save หรือ Index\Pages\Model::save() ตามค่ากำหนดของ Router นั่นเอง
ซึ่งผมจะหยิบเฉพาะ method save มาอธิบายคร่าวๆ นะครับ
ที่ฟอร์ม Index\Pageswrite\View มีการกำหนดค่าให้มีการ submit แบบ Ajax ไว้ (ajax=true) ซึ่งก็จะทำให้มีการเรียกใช้ความสามารถด้าน Ajax ของ GForm มาใช้งาน ดังนั้นในการรับค่าจากฟอร์มเราก็ต้องออกแบบการรับค่าฟอร์มจาก Ajax และส่งค่ากลับไปยัง Ajax ด้วย JSON
บรรทัดแรกของการรับค่ามีการกระทำ 3 อย่าง คือ
ถัดมาคือการรับค่าข้อมูลต่างๆที่ถูกส่งมาจากฟอร์ม ที่ 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 ให้ชี้ไปยังไดเร็คทอรี่ที่ถูกต้อง
ซึ่งผมจะหยิบเฉพาะ 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 อย่าง คือ
- เปิดใช้งาน session $request->initSession()
- ตรวจสอบ token ซึ่งถ้ามาจากการ submit ผ่านฟอร์มปกติ token ต้องตรงกันกับที่เก็บไว้ตอนสร้างฟอร์ม ด้วย $request->isSafe()
- ตรวจสอบการ 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 ให้ชี้ไปยังไดเร็คทอรี่ที่ถูกต้อง