l10n และ i18n อาจทำพิษ จนออก Hoffman Framework pre-alpha ช้าลง

ทำ HMF เอง แถมทำข่าวเองเลย ฮา ….

วันนี้นั่ง implement ตัว Form Component และ DateTime Component ของ HMF ซึ่งกำลังไปได้ดี แต่สิ่งที่ผมลืมไปคือเรื่อง l10n และ i18n ไปสนิท เลยไล่ปรับใหม่สำหรับ Form และ DateTime (ผม note ใส่ใน TODO ของ project ไว้แล้ว แต่ไม่ได้สังเกตเลย) ทำให้ไล่หลายส่วนใหญ่ ซึ่งต้องไล่ส่วน Runtime, Configuration-file และ Component ที่เกี่ยวกับ l10n และ i18n ทั้งหมด เพื่อให้มันรองรับได้ตั้งแต่ต้น เหตุผลง่าย ๆ ในการรองรับ l10n และ i18n ตั้งแต่ pre-version เพราะผมอยากให้มันทำงานได้หลายภาษาตั้งแต่ต้นเลย และการมาไล่ปรับทีหลังหลังจากปล่อย pre ไปแล้ว อาจทำให้ app ของนักพัฒนาที่เอา pre-version ไปก่อนอาจมีปัญหาความเข้ากันไม่ได้เมื่อออก version ใหม่ ๆ ออกมา ซึ่งจริง ๆ มันก็มีความเสี่ยงอยู่แล้ว ไม่ว่าจะมี version ใด ๆ ออกมา แต่อยากให้น้อยที่สุดใน pre-version เพราะถือว่าเป็นการออกตัวครั้งแรก อยากให้ประทับใจในหลาย ๆ ส่วน

แต่ก็ยังมีข่าวดีตรงที่ผมทำ content-page แบบ multiple ได้แล้วในตอนนี้ ด้วยเหตุผลที่ว่า ถ้าทำ sigle master/content-page นี่มันดูเฉย ๆ และน่าจะยุ่งยาก ผมเลยนั่งไล่ปรับตัว content-page ของ RenderView ให้รองรับ multiple ของ content-page ได้ตั้งแต่ต้นเลย โดยส่วนของ RenderView หลายส่วน นั้นได้แนวคิดจาก PHPTemplate ของ Drupal มาด้วย โดยเอามาผสมกับ MasterPage ของ ASP.NET ครับ

ส่วนตัว Form Component กะว่าจะทำให้มันคล้าย ๆ กับ Rails (Ruby) แต่ไป ๆ มา ๆ ไม่เอาดีกว่า ทำตามแนวทางเดิม แต่เพิ่มความสะดวกลงไป น่าจะ work กว่า และกะจะ build-in ลงใน Smarty เป็น function นึงที่มา call กับ Form Component แต่ ไป ๆ มา ๆ ไม่เอาดีนั้นแหละ ใช้วิธีสร้าง object ในตัว Controller  แล้วโยนใส่ View ไปเลยง่ายกว่าเยอะ (ไม่เสียเวลาด้วย)

ตอนนี้ไล่ปรับหลายส่วนพยายามให้เท่ากับ version 0.1 ให้ได้ (ตัวนี้ไม่ได้ปล่อยออกมา เพราะใช้ยาก แต่ก็เป็นตัวที่เอาไว้รับงานประทังชีวิตไว้หลายงานเหมือนกัน)

 

Get Ready Hoffman Framework pre-alpha

ตอนนี้ส่วน RenderView ที่พัฒนาตรงตามแบบที่ต้องการพอสมควรแล้ว โดยใช้ Smarty มาช่วยในส่วนนี้โดยใช้ Instant ของ Smarty ในการทำ 2 ตัวด้วยกันทำ master-page กับ content-page อย่างละตัว แต่ในอนาคตจะทำ multiple content-page ด้วยคาดว่าหลังจากปล่อย beta โน้นเลย

ส่วน FlowController เพิ่มความสามารถเข้ามาพอสมควร ในส่วนของการให้ Controller นั้นควบคุมการแสดงผลส่วน View ได้ผ่าน Controller ซะ (คือตั้งค่าผ่าน Controller เลยเช่น ใส่ javascript, stylesheet หรือพวก title ต่าง  ๆ) เดี่ยวขอทดสอบกับ app จริง ๆ แล้วมา demo สักตัวนึงครับ

ส่วนของ Model นั้น ตัว LogicModel หลังจาก defend ตัวเองมานาน สรุปโดยแยกออกเป็น DB กับ Static ครับ โดยผมมองว่าบาง Model มันไม่ได้เกี่ยวกับ DB เลย ก็ควรไม่ต้องมี function ของ DB ติดมาด้วย เลยแยกออกจากกันไปซะ อะไรประมาณนั้นครับ

เหลือทดสอบกับ App จริง ๆ สัก 1-2 ตัวน่าจะ ok ปล่อยออกมาให้โหลดกันได้ครับ (เริ่มแรกน่าจะเป็นพวกเล็ก ๆ อย่าง register form กับ booking system ครับ) เดี่ยวถ้าเสร็จกับตัวนี้แล้วเอา demo ขึ้น พร้อมกับ commit เข้า svn และ link download เลยครับ

[สถานนะของ  SVN บนเครื่องผมคือ Revision.74 แล้ว]

 

มาบวกเลขป้องกัน spam จาก comment (หรืออื่น ๆ ) กันดีกว่าดีกว่า (ใน PHP)

เริ่มแรกง่าย ๆ เลย สุ่มตัวเลขสัก 2 ตัวก่อน แล้วเก็บลง Session ไว้ซะ

session_start();
// เริ่มสร้างตัวเลขสุ่มไว้สองตัว
$_SESSION['rand_x'] = rand(1, 9);
$_SESSION['rand_y'] = rand(1, 9);
// จบการสร้างตัวเลขสุ่ม

แล้วก็เอาค่าที่ได้ไปแสดง แล้วก็ให้กรอกผลของการบวก

<!-- เริ่มส่วนของการบวกเลข -->
กรุณาบวกเลขต่อไปนี้
<?php echo $_SESSION['rand_x']; ?> + <?php echo $_SESSION['rand_y']; ?> = <input type="text" name="rand_ans" size="10">
<!-- จบส่วนของการบวกเลข -->

โค้ดด้านบนก็เอาไปใส่ใน form เพื่อให้เอาคำตอบให้มันส่งค่าไปยังปลายทาง

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

session_start();
// เริ่มตรวจสอบการบวกเลข
if(($_SESSION['rand_x'] + $_SESSION['rand_y']) != $_POST['rand_ans']) {
die("คุณบวกเลขผิด");
}
// จบการตรวจสอบการบวกเลข

แค่นี้ก็พอกัน comment ที่มา spam ได้ อาจจะปรับเปลี่ยนรูปแบบการแสดงผล หรือตำแหน่งในการวาง input form ต่าง ๆ ได้ตามความเหมาะสม หรือจะสุ่มตำแหน่งก็ได้ เพื่อป้องกัน bot ที่สามารถปรับตัวได้ตามลักษณะของการบวกเลขแบบนี้ครับ ซึ่งการ ทำระบบบวกเลขนี้ก็คล้าย ๆ กับการทำ captcha แหละครับ แต่อันนี้จะง่ายและไม่ซับซ้อนมากเท่าครับ

โดยตัวแนวคิดได้มาจากแนวคิดของ Match Captcha ของ Drupal แหละครับ

 

ความคืบหน้า PHP Hoffman Framework (6)

วันนี้คงสั้น ๆ หน่อย เพราะกำลัง implement ส่วนของ Access Control List และ Authentication อยู่ครับ และ phase ต่อไปก่อนจะสามารถออก pre-alpha version ได้คงต้องทำส่วนของ view layer ให้ดีกว่านี้ โดยการนำเอา Smarty เข้ามาใช้งานนั้น มันเป็นแบบ single template / single layer มันทำให้การออกแบบ theme/template ที่แปลเปลี่ยนตามลักษณะการใช้งานนั้น ยากพอสมควร พอดีว่าผมได้ concept ของ master page ของ ASP.NET มา ซึ่งจริง ๆ มันก็แบบเดียวกับในพวก joomla หรือ drupal ที่มี template กลาง และเอา view มาใส่ซ้อนลงไปอีกทีนึงนั้นเอง ตอนนี้ไล่ทำทั้งหมดอยู่ แบบว่ามัน late มาจากวันที่ต้อง public source มาหลายวันแล้ว เร่งหูตูบเลยงานนี้

 

ความคืบหน้า PHP Hoffman Framework (5)

จาก ความคืบหน้า PHP Hoffman Framework (4) ตัวความสัมพันธ์ระหว่าง model กับ controller นั้น เพิ่มเติมและปรับเปลี่ยนเพื่อความเหมาะสม โดยถ้าเราจะกำหนด controller ต้องมี namespace หรือ prefix-name (ต่อไปจะเรียกว่า namespace อย่างเดียวครับ) ด้านหน้าเสียก่อน คือ

class controller_<ชื่อ controller> extends Hmf_FlowController {
....
}

โดยให้ extends มาจาก FlowController ครับ

ส่วนของ model ก็เช่นกันครับ

class model_<ชื่อ model> extends Hmf_LogicModel {
    function __construct(){
        parent::__construct();
    }
    ....
}

(อันนี้คือ model แบบมาตรฐาน)

แต่เวลาเรียกเอา model มาใช้ใน FlowController ก็ใช้ method ‘getInstantModel’ ของ FlowController ครับ โดยใส่ชื่อ model ลงไป และเดี่ยวมันจะเติม namespace ให้เอง แบบนี้ครับ

class model_user extends Hmf_LogicModel {
    function __construct(){
        parent::__construct();
    }
    ....
}

class controller_user extends Hmf_FlowController {
    function list($page = 1){

        $user = $this->getInstantModel('user');

        $out['data'] = $user->pagination($page, 5);
        $out['pagenav'] = $user->paginationLink(HttpPage::url('user','list'));

        return $out;

    }
}

แต่ถ้า model_user ไม่มี หรือไม่ได้สร้าง class ไว้ ตัว getInstantModel มันจะไปสร้าง Instant ของ class ของ model นั้นแล้วให้ตัวมันมีคุณสมบัติแบบเดียวกับ class ของ model แบบมาตรฐานด้านบนนั้นแหละครับ พูดง่าย ๆ ก็คือถ้าหาไม่เจอ ก็สร้างให้เลย ส่วนใช้งานได้หรือไม่อีกเรื่องครับ โดย class ของ model แบบมาตรฐานมีคุณสมบติแบบเดียวกับ LogicModel เลยครับ

class controller_user extends Hmf_FlowController {
    function list($page = 1){

        $user = $this->getInstantModel('user');

        $out['data'] = $user->pagination($page, 5);
        $out['pagenav'] = $user->paginationLink(HttpPage::url('user','list'));

        return $out;

    }
}

โดยตัวอย่างด้านบน ถ้าไม่มี model_user ก็ใช้งานได้เหมือนกันครับ ซึ่งสะดวกมากในกรณีที่ใช้ class มาตรฐานทั่วไปครับผม