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

Form Builder ได้ถูกถอดออกจาก Core ของ Laravel Framework ตั้งแต่เวอร์ชั่น 5 เป็นต้นมา หากนักพัฒนาต้องการใช้การ Form Builder จะต้องติดตั้ง Package laravelcollective/html เพิ่มเติมเอง บทความนี้จึงขอเสนอทางเลือกในการโค้ด Laravel Framework แบบไม่ใช้งาน Form Builder โดยการเปลี่ยนมาใช้ <form> แทนครับ

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

ก่อนอื่นเรามาดูตัวอย่างโค้ดของการใช้งาน 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
  • กรณี Web Application มี UI ของ HTML ที่ซับซ้อน ต้องใช้ Syntax ของ Form Builder ผสมกับ HTML Element ทำให้ดูไม่สวยงาม
  • ไม่สามารถขอความช่วยเหลือจากนักพัฒนาที่ไม่ได้ใช้ Form Builder

HTML Form

ก่อนที่จะเขียน <form> ร่วมกับ Laravel Framework เรามาลองเขียน <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>ได้รับข้อมูลเรียบร้อยแล้ว</h3>

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

การ Submit Form ด้วย POST Method

register.html


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

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

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 ไปที่ไฟล์ไหนเพื่อประมวลผล ดังนั้นเมื่อนำมาใช้กับ 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="UeNq68NZdMAszrhDdS2QJ9zqX...">
</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" => "UeNq68NZdMAszrhDdS2QJ9zq..."
  "first_name" => "John"
  "last_name" => "Doh"
]

action() Helper Function

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

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 Method ไม่มีตัวตนอยู่จริงใน HTML Form แต่มีตัวตนใน XMLHttpRequest (AJAX) ดังนั้นการจะประยุกต์ใช้งาน HTTP Method เช่น 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 นั้นจะต้องแนบ Argument ซึ่งเป็น 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> มาใช้งานได้อย่างไม่มีปัญหาอย่างแน่นอน