tutor4dev

คอร์สอบรม, บทความ และ คลิปวีดีโอ การพัฒนาเว็บแอพพลิเคชั่น

Form Builder ไม่ใช่สิ่งจำเป็นสำหรับ Laravel Framework


ผู้เขียนได้พบเห็นคำถามเกี่ยวกับปัญหาการใช้งาน Form Builder กับ Laravel Framework 5 ในกลุ่ม Facebook อยู่บ่อยครั้ง ทั้งๆ ที่ Form Builder ได้ถูกถอดออกจาก Core ของ Laravel ตั้งแต่เวอร์ชั่น 5 เป็นต้นมา

ผู้เขียนเข้าใจว่า นักพัฒนาที่ยังคงใช้งาน Form Builder อยู่นั้นอาจจะเคยใช้งาน Laravel Framework มาตั้งแต่เวอร์ชั่น 4 หรือ อาจะเป็นผู้เริ่มต้นใช้งานที่ยังไม่คุ้นเคยวิธีนำ HTML Form มาใช้งานกับ Laravel Framework

ซึ่งในบทความนี้จะขอเชิญชวนให้นักพัฒนาที่ใช้ Form Builder เปลี่ยนมาใช้ <form> แทน ซึ่งในเบื้องต้นเรามาดูตัวอย่างโค้ดของ Form Builder รวมถึงข้อดีข้อเสียกันพอสังเขป

ตัวอย่างโค้ดของ Laravel Form Builder

Blade

{!! Form::open([ 'url' => '/registers', 'method' => 'post' ]) !!}

    {!! Form::input('text', 'first_name', null, [ 'class' => 'input' ]) !!}
    {!! Form::input('text', 'last_name', null, [ 'class' => 'input' ]) !!}

    {!! Form::submit('Save', [ 'class' => 'button is-primary' ]) !!}
    {!! Form::reset('Cancel', [ 'class' => 'button is-danger' ]) !!}

{!! Form::close() !!}

ข้อดีของ Laravel Form Builder

  • คำสั่ง เขียน Form ในรูปแบบ Laravel Syntax
  • คำสั่ง Form::open() ใส่ csrf Token ให้โดยอัตโนมัติ
  • คำสั่ง Form::select() ไม่จำเป็นต้องการใช้ Loop
  • คำสั่ง Form Element ต่างๆ Restore ค่าเดิมให้กรณีที่ Validation ผิดพลาด
  • คำสั่ง Form::model() ช่วยอำนวยความสะดวกในการใช้ Form ร่วมกับEloquent`

ข้อเสียของ Laravel Form Builder

  • ถูกถอดออกจาก Core ของ Laravel Framework ตั้งแต่ Version 5 ทำให้ต้องติดตั้งเพิ่มเติม
  • Form Builder ถูก Maintain โดย 3rd Party ไม่ใช่ Community ของ Laravel
  • ต้องเรียนรู้ Syntax เพิ่มเติม
  • ไม่รองรับ Emmet และ เท่าที่ทราบไม่มี Editor ใดสนับสนุน Snippest ของ Form Builder
  • กรณี Web Application มี UI ของ HTML ที่ซับซ้อน ต้องใช้ Syntax ของ Form Builder ผสมกับ HTML Element ทำให้ดูไม่สวยงาม
  • ไม่สามารถขอความช่วยเหลือจากนักพัฒนาที่ไม่ได้ใช้ Form Builder

HTML Form

ก่อนที่จะเขียน <form> ร่วมกับ Laravel Framework เรามา Back To Basic ทดลองเขียน <form> แบบง่ายๆ กันดูก่อน

Path

|-register.html
|-submit.html
|-submit.php

กำหนด Attribute action เพื่อกำหนดว่า Form จะถูก Submit ไปที่ไฟล์ไหน ซึ่งสามารถกำหนดเป็นไฟล์ HTML ก็ยังได้

register.html

<form action="/submit.html">
    <input type="text" name="first_name">
    <input type="text" name="last_name">

    <input type="submit" value="Save">
</form>

Start PHP Built-in Web Server ที่ Root Path ของโปรเจค

Terminal

php -S localhost:8000

Browser

http://localhost:8000/register.html

Submit Form

register.html

<h3>Thanks</h3>

Submit Form ด้วย Default Method (GET) จะส่งผลให้เกิดเป็น Query String ตามรูปตัวอย่าง ในความเป็นจริงเราจะไม่เลือกใช้ GET Method สำหรับการ Submit Form เนื่องจากไม่มีความปลอดภัย

POST Method

register.html

<form action="/submit.html" method="POST">
    ...
</form>

Submit Form ด้วย POST Method ข้อมูลจะถูก Encode (เปลี่ยนแปลงรูปร่างหน้าตาเพื่อความสะดวกในการ Transportation) และ ถูกแนบไปกับ Request ซึ่งเราสามารถใช้ Chrome DevTools ในการตรวจสอบ Request และ Response

HTML Form & PHP Script

การ Submit Form ไปยังไฟล์ HTML นั้นสามารถทำได้ แต่ก็นำมาใช้ประโยชน์อะไรไม่ได้ ลองเปลี่ยนเป็นการ Submit Form ไปยังไฟล์ PHP ดีกว่า

register.html

<form action="/submit.php" method="POST">
    ...
</form>

submit.php

<?php

var_dump($_POST);

Result

array (size=2)
  'first_name' => string 'John' (length=4)
  'last_name' => string 'Doh' (length=3)

Laravel Project Setup

เรามาลอง Setup Laravel Project แบบง่ายๆ โดยมีไฟล์ที่จะนำมาใช้ตามบทความ ตามโครงสร้างด้านล่าง

Path

+-app
|   +-Http
|   |   +-Controllers
|   |   |   +-RegisterController
+-resources
|   +-views
|   |   +-registers
|   |   |   |-create.blade.php
|   |   |   |-edit.blade.php
|   +-routes
|   |   |-web.php

Route & Controller Setup

Terminal

สร้าง Controller และ Route ในแบบ ReSTful

php artisan make:controller RegisterController --resource

routes/web.php

Route::resource('registers', 'RegisterController');

app/Http/RegisterController.php

class RegisterController extends Controller
{
    public function index()
    {
        return 'Hello World';
    }
}

Terminal

php artisan serv

Browser

http://localhost:8000

ใช้งาน Form ใน Laravel Framework

จากโค้ดตัวอย่างในหัวข้อ HTML Form เราจะเห็นว่าสาระสำคัญในเรื่องการ Submit Form ก็คือ Attribute action ของ <form> ซึ่งเป็นตัวกำหนดว่า Form จะถูก Submit ไปที่ไฟล์ไหนเพื่อทำการประมวลผล ซึ่งสามารถระบุได้แม้กระทั่งไฟล์ HTML ดังนั้นเมื่อนำมาใช้กับ Laravel Framework เราก็เพียงแต่ระบุ URI ตามที่ต้องการ

resources/views/registers/create.blade.php

<form action="/registers" method="POST">
    <input type="text" name="first_name">
    <input type="text" name="last_name">

    <input type="submit" value="Save">
</form>

App/Http/Controllers/RegisterController.php

class RegisterController extends Controller
{
    public function create()
    {
        return view('registers.create');
    }

    public function store(Request $request)
    {
        return '<h3>Thanks</h3>';
    }
}

Oops !!! เกิดปัญหาหลังจากทดลอง Submit Form

CSRF Protection

Laravel Framework มีระบบป้องการการถูกโจมตีในรูปแบบ csrf เราจึงต้องทำการส่งค่า csrf Token แนบไปกับการ Submit Form ด้วย Request ถึงจะสามารถผ่านด่านอรหันต์นี้เข้าไปได้ แต่โชคดีที่ Laravel Framework มี Helper Function ไว้ให้เราเรียกใช้ โดยเราจะแก้ไขโค้ดตามตัวอย่างด้านล่าง

creates/views/registers/create.blade.php

<form action="/registers" method="POST">
    {{ csrf_field() }}
</form>

Refresh หน้าเว็ป และ ลองแสดง Page Source

Page Source

<form action="/registers" method="POST">
    <input type="hidden" name="_token" value="UeNq68NZdMAszrhDdS2QJ9zqXQ1G02nav4e3sW6P">
</form>

csrf_field() ได้สร้าง <input type="henden">

แก้ไขโค้ดเพิ่มเติมตามตัวอย่างด้านล่าง เพื่อ Retrieve ค่าจาก Form

App/Http/Controllers/RegisterController.php

class RegisterController extends Controller
{
    public function store(Request $request)
    {
        $inputs = request()->all();
        // $inputs = request()->except(_token);

        dd($inputs);
    }
}

Refresh เว็ป ป้อนข้อมูล และ ลอง Submit Form

Result

array:3 [▼
  "_token" => "UeNq68NZdMAszrhDdS2QJ9zqXQ1G02nav4e3sW6P"
  "first_name" => "John"
  "last_name" => "Doh"
]

action() Helper Function

หากเราไม่คุ้นเคยกับการเรียกใช้ URL Path ตรงๆ เราสามารถใช้ Helper Function action() เพื่อระบุการเข้าถึง Method ใน Controller ซึ่งง่ายกว่าในการทำความเข้าใจ

resources/views/registers/create.blade.php

<form action="{{ action('RegisterController@store') }}" method="POST">
    ...
</form>

ReSTful Method

การใช้ <form> เพื่อสร้าง ReSTful Request หลายๆ คนมักจะเข้าใจผิดว่าเราสามารถทำได้โดยการแก้ไข Attribute method เหมือนในตัวอย่างด้านล่าง

<form action="..." method="PUT">
    ...
</form>

แต่ในความเป็นจริงแล้ว PUT และ DELETE Verb ไม่มีตัวตนอยู่จริงใน HTML Form แต่มีตัวตนใน XMLHttpRequest (AJAX) ดังนั้นการจะประยุกต์ใช้งาน HTTP Verb เช่น PUT และ DELETE จึงเป็นได้แค่ส่วนขยายของ POST Method เท่านั้น

ซึ่งเป็นเรื่องของแต่ละ Framework ที่จะกำหนดวิธีการขึ้นมาเอง ซึ่งการกำหนด PUT และ DELETE Method ใน Laravel Framework จะใช้ Helper Function ชื่อ method_field() เป็นตัวกำหนด ตามตัวอย่างโค้ดด้านล่าง

PUT Method

creates/views/registers/edit.blade.php

<form action="{{ action('RegisterController@update', [ 'id' => 1001 ]) }}" method="POST">
    {{ csrf_field() }}

    {{ method_field('PUT') }}

    ...
</form>

ในการเข้าถึง RegisterController@update นั้นมีการ Require Parameter ซึ่งเป็น ID ของ Record ที่จะถูกแก้ไข ในครั้งนี้เราจึงจำเป็นจะต้องมี Argument เพิ่มเติมให้กับ action() ด้วย

Page Source

<form action="http://localhost:8000/registers/1001" method="POST">
    <input type="hidden" name="_token" value="UeNq68NZdMAszrhDdS2QJ9zqXQ1G02nav4e3sW6P">
    <input type="hidden" name="_method" value="PUT">

    ...
</form>

method_feld() ได้สร้าง <input type="henden">

DELETE Method

creates/views/registers/edit.blade.php

<form action="{{ action('RegisterController@destroy', [ 'id' => 1001 ]) }}" method="POST">
    {{ csrf_field() }}

    {{ method_field('DELETE') }}

    ...
</form>

Page Source

<form action="http://localhost:8000/registers/1001" method="POST">
    <input type="hidden" name="_token" value="UeNq68NZdMAszrhDdS2QJ9zqXQ1G02nav4e3sW6P">
    <input type="hidden" name="_method" value="DELETE">

    ...
</form>

บทสรุป

การใช้งาน <form> ถือเป็นพื้นฐานที่สำคัญในการพัฒนา Web Application ทั้งการพัฒนาแบบ Front-end และ Back-end ซึ่งการ Submit Form และ Retrieve ค่าจาก Form นั้นก็เป็นไปตามหลักการของ HTTP Protocol ทุกอย่างจึงสามารถการันตีได้ ไม่ว่าเราจะพัฒนา Web Application ด้วยภาษาใด หรือ Framework ใด ก็สามารถนำ <form> มาใช้งานได้อย่างไม่มีปัญหาใดๆ อย่างแน่นอน