เมื่อสร้างคลาส Task เสร็จแล้ว ขั้นตอนต่อมาคือการสร้างและแสดงผลแบบฟอร์ม HTML ใน Symfony การดำเนินการนี้ทำได้โดยการสร้างอ็อบเจ็กต์ของฟอร์มและแสดงผลในเทมเพลต ตอนนี้ทั้งหมดนี้สามารถทำได้จากภายใน controller
ตัวอย่างนี้ได้แสดงวิธีสร้างแบบฟอร์มโดยตรงจากภายใน controller ซึ่งในหัวข้อ "Creating Form Classes” คุณจะได้เรียนรู้วิธีสร้างฟอร์มในลักษณะ standalone class ซึ่งจะทำให้ฟอร์มที่คุณสร้างสามารถนำกลับมาใช้ได้ใหม่
การสร้างฟอร์มใช้โค้ดค่อนข้างน้อยเนื่องจากอ็อบเจ็กต์ของ Symfony สร้างขึ้นด้วย "form builder" ซึ่งวัตถุประสงค์ของ form builder คือช่วยให้งานในการสร้างฟอร์มน้อยลงและสามารถเขียนฟอร์มได้ง่ายขึ้น
แสดงผล field ของฟอร์มทั้งหมด ซึ่งรวมข้อความ การ validate และ error message
form_end(form)
เป็นคำสั่งที่บอกว่าการแสดงผลของฟอร์มสิ้นสุด
จะเห็นว่าเป็นเรื่องง่าย แต่ยังไม่ยืดหยุ่นพอ ซึ่งโดยปกติคุณจะต้องการควบคุมการแสดงผลของฟอร์มที่แยกเป็นส่วน ๆ ซึ่งคุณสามารถเรียนรู้ได้ในหัวข้อ “How to Control the Rendering of a Form”
ก่อนที่จะไปต่อ สังเกตการแสดงผลของ task input field ว่ามีค่าของ task property จาก $task object (เช่น “Write a blog post”) ซึ่งงานแรกของฟอร์มคือ การนำข้อมูลออกจาก object และแปลงมันให้อยู่รูปแบบที่เหมาะสมสำหรับนำไปแสดงผลในฟอร์ม HTML
ถ้าฟอร์มของคุณมีการระบุใช้ validate group ตัว field type guesser จะยังพิจารณา validate
constraints ทั้งหมดเวลาที่คาดเดาจาก field type (รวมไปถึง constraints ที่ไม่ได้กำหนดไว้ใน
validate group ก็จะถูกนำมาใช้ด้วย)
Field Type Options Guessing
นอกจากการคาดเดา type ของ field แล้ว ตัว Symfony ยังสามารถคาดเดาค่าที่ถูกต้องของ option ของ field ได้ด้วย
เมื่อมีการตั้งค่า option เหล่านี้ field จะแสดงผลด้วยแอตทริบิวต์ HTML พิเศษที่ทำให้ HTML5 มีการ
validate ฝั่ง client-side อย่างไรก็ตาม มันไม่ได้สร้าง constraints ด้าน server-side ที่เหมือนกัน
(เช่น Assert \ Length) และแม้ว่าคุณจะเพิ่มการ validate ด้าน server-side ด้วยตนเอง แต่ field
type option เหล่านี้จะสามารถคาดเดาได้จากข้อมูลดังกล่าว
โดย field option เหล่านี้จะถูกคาดเดาไว้เฉพาะในกรณีที่คุณใช้ Symfony เพื่อคาดเดา field type
(เช่นละเว้นการส่งค่าหรือส่งค่า null เป็นอาร์กิวเมนต์ที่สองของเมธอด add())
ถ้าคุณต้องการเปลี่ยนแปลงค่าของการคาดเดา คุณสามารถส่ง option ไปใน option field array
Creating Form Classes
จากที่ผ่านมา จะเห็นว่าฟอร์มสามารถสร้างได้โดยตรงใน controller อย่างไรก็ตามทางที่ดีกว่าคือการสร้างฟอร์มแยกไว้ต่างหาก ให้เป็น standalone PHP class ซึ่งจะช่วยให้สามารถนำกลับมาใช้ได้ใหม่ในทุก ๆ ที่ของแอพพลิเคชั่นของคุณ สร้าง new class สำหรับการสร้างฟอร์ม task
โดย class ใหม่นี้ข้างในจะมีสิ่งที่จำเป็นสำหรับการสร้างฟอร์ม Task โดยสามารถสร้าง form object ได้อย่างรวดเร็วใน controller
การสร้างฟอร์ม logic ไว้ใน class ของมันเอง นั้นจะทำให้เราสามารถนำมันไปใช้ใหม่ได้ง่ายในทุก ๆ ที่ของโปรเจ็ค ซึ่งเป็นวิธีที่ดีสำหรับการสร้างฟอร์ม
Setting the data_class
ทุกฟอร์มจำเป็นต้องทราบชื่อของ class ที่เก็บข้อมูลพื้นฐานไว้ (เช่น AppBundle\Entity\Task) โดยปกติแล้วนี่เป็นเพียงการคาดเดา object ที่ส่งผ่านไปยังอาร์กิวเมนต์ที่สองไปที่ createForm() (เช่น $task) โดยทั่วไปคุณควรระบุตัวเลือก data_class อย่างชัดเจนโดยเพิ่มข้อมูลต่อไปนี้ลงใน form type class
Form
การทำงานกับฟอร์ม HTML เป็นงานที่พบได้ทั่วไปและท้าทายสำหรับนักพัฒนาเว็บไซต์ โดย Symfony ได้รวมองค์ประกอบของแบบฟอร์มที่จะช่วยให้การจัดการกับฟอร์มเป็นเรื่องง่าย ในบทความนี้ คุณจะได้สร้างฟอร์มที่ซับซ้อนตั้งแต่เริ่มต้น ได้เรียนรู้คุณลักษณะที่สำคัญที่สุดของไลบรารี่ฟอร์ม
Creating a Simple Form
สมมติว่าคุณกำลังสร้างแอปพลิเคชันรายการสิ่งที่ต้องทำที่จะต้องแสดง "งาน" เนื่องจากผู้ใช้ของคุณจำเป็นต้องแก้ไขและสร้างงาน คุณจึงจำเป็นต้องสร้างแบบฟอร์ม แต่ก่อนที่คุณจะเริ่มต้น ให้มุ่งเน้นไปที่คลาส
Task
ซึ่งใช้ในการแสดงและเก็บข้อมูลสำหรับงานคลาสนี้เป็น “PHP-object แบบเก่า“ ไม่มีอะไรเกี่ยวข้องกับ Symfony หรือไลบรารี่ใด ๆ เป็นเพียงแค่ PHP object ธรรมดาที่สามารถแก้ไขปัญหาภายในแอพพลิเคชันของคุณได้โดยตรง ( เช่นต้องการแสดงงานในแอพพลิเคชันของคุณ) โดยในตอนท้ายของบทความนี้ คุณจะสามารถส่งข้อมูลไปยัง
Task
instance (ผ่านฟอร์ม HTML) ตรวจสอบความถูกต้องของข้อมูลและจัดเก็บในฐานข้อมูลBuilding the Form
เมื่อสร้างคลาส
Task
เสร็จแล้ว ขั้นตอนต่อมาคือการสร้างและแสดงผลแบบฟอร์ม HTML ใน Symfony การดำเนินการนี้ทำได้โดยการสร้างอ็อบเจ็กต์ของฟอร์มและแสดงผลในเทมเพลต ตอนนี้ทั้งหมดนี้สามารถทำได้จากภายใน controllerตัวอย่างนี้ได้แสดงวิธีสร้างแบบฟอร์มโดยตรงจากภายใน controller ซึ่งในหัวข้อ "Creating Form Classes” คุณจะได้เรียนรู้วิธีสร้างฟอร์มในลักษณะ standalone class ซึ่งจะทำให้ฟอร์มที่คุณสร้างสามารถนำกลับมาใช้ได้ใหม่
การสร้างฟอร์มใช้โค้ดค่อนข้างน้อยเนื่องจากอ็อบเจ็กต์ของ Symfony สร้างขึ้นด้วย "form builder" ซึ่งวัตถุประสงค์ของ form builder คือช่วยให้งานในการสร้างฟอร์มน้อยลงและสามารถเขียนฟอร์มได้ง่ายขึ้น
ในตัวอย่างนี้ คุณได้เพิ่ม 2 fields ไปในฟอร์มคือ
task
และdueDate
ซึ่งต้องตรงกับ propertiestask
และdueDate
ของคลาส Task คุณได้กำหนดประเภท “type” (เช่นTextType
และDataType
) ไว้ด้วยชื่อคลาส เหนือสิ่งอื่นใดจะกำหนดว่าจะให้แท็ก HTML form ใดแสดงผลสำหรับฟิลด์นั้นและสุดท้าย คุณได้เพิ่มปุ่ม submit เพื่อใช้ส่งข้อมูลไปยังเซิฟเวอร์
Symfony ยังมีฟอร์ม built-in type หลายชนิด ดูได้ในหัวข้อ Built-in Field Types
Rendering the Form
เมื่อฟอร์มได้สร้างขึ้นแล้ว ขั้นตอนไปคือการแสดงผลฟอร์ม ทำได้โดยการส่ง object view ไปยังเทมแพลต (สังเกตุที่
$form->createView()
จาก controller ข้างบน) และใช้ form helper functionต้องใช้คำสั่ง 3 บรรทัดนี้ในการทำให้ฟอร์มแสดงผลได้สมบูรณ์
form_start(form)
คำสั่งเริ่มต้นฟอร์ม โดยรวมถึงแอตทริบิวต์ enctype เมื่อใช้การอัพโหลดไฟล์
form_widget(form)
แสดงผล field ของฟอร์มทั้งหมด ซึ่งรวมข้อความ การ validate และ error message
form_end(form)
เป็นคำสั่งที่บอกว่าการแสดงผลของฟอร์มสิ้นสุด
จะเห็นว่าเป็นเรื่องง่าย แต่ยังไม่ยืดหยุ่นพอ ซึ่งโดยปกติคุณจะต้องการควบคุมการแสดงผลของฟอร์มที่แยกเป็นส่วน ๆ ซึ่งคุณสามารถเรียนรู้ได้ในหัวข้อ “How to Control the Rendering of a Form”
ก่อนที่จะไปต่อ สังเกตการแสดงผลของ
task
input field ว่ามีค่าของtask
property จาก$task
object (เช่น “Write a blog post”) ซึ่งงานแรกของฟอร์มคือ การนำข้อมูลออกจาก object และแปลงมันให้อยู่รูปแบบที่เหมาะสมสำหรับนำไปแสดงผลในฟอร์ม HTMLHandling Form Submissions
โดยค่าเริ่มต้น ฟอร์มจะส่งข้อมูลแบบ POST request ส่งกลับไปยัง controller เดิมเพื่อจะนำไปแสดงผล
โดยงานที่สองของฟอร์มคือ การแปลงข้อมูลที่ผู้ใช้ส่งกลับมายัง property ของ object เพื่อให้การทำงานเกิดขึ้น ข้อมูลที่ส่งมาจากผู้ใช้ต้องถูกเขียนลงใน Form object ดูตัวอย่างจาก controller ข้างล่าง
โดยทั่วไป controller จะมี 3 รูปแบบที่เป็นไปได้ในการจัดการกับฟอร์ม
handleRequest()
จะรู้ว่าฟอร์มยังไม่ถูก submit ทำให้เมธอดisSubmitted()
ส่งค่า false กลับมาถ้าฟอร์มยังไม่ถูก submithandleRequest()
จะรู้และจะส่งข้อมูลที่ submit มาไปยัง propertytask
และdueDate
ของ$task
object จากนั้น object จะถูก validate ถ้าข้อมูลไม่ถูกต้อง เมธอดisValid()
ส่งค่า false และฟอร์มจะแสดงผลอีกครั้งพร้อมด้วยข้อความ validate errorisValid()
จะส่งค่า true ทำให้เราสามารถที่จะทำงานกับ object นี้ได้ (เช่น จัดเก็บลงฐานข้อมูล) ก่อนที่จะ redirect หน้าเพจอื่น ๆถ้าคุณต้องการการควบคุมที่มากขึ้นสำหรับการ submit ฟอร์มหรือการส่งผ่านข้อมูล คุณสามารถใช้เมธอด
submit()
อ่านเพิ่มเติมได้หัวข้อ Calling Form::submit() manuallyForm Validation
ในหัวข้อก่อนหน้านี้ คุณได้เรียนรู้วิธีการ submit ฟอร์มกับข้อมูลที่ถูกต้องหรือไม่ถูกต้อง ใน Symfony การ validate จะถูกปรับใช้กับ object (เช่น
Task
) ในอีกความหมายนึงก็คือ คำถามไม่ใช่ว่าฟอร์มถูกต้องหรือไม่ แต่เป็นคำถามที่ว่าข้อมูลของ$task
object ถูกต้องหรือไม่หลังจากที่ฟอร์ม submit ส่งข้อมูลมา สามารถเรียกใช้$form->isValid()
เพื่อเช็คว่าข้อมูล$task
object ถูกต้องหรือไม่การ validation สามารถทำได้โดยการกำหนดกฎ (เรียกว่า constraints) เพิ่มไปใน class เพื่อให้เห็นการทำงาน ในตัวอย่างนี้จะเพิ่มการตรวจสอบ
task
field ห้ามเป็นค่าว่าง และdueDate
field ห้ามเป็นค่าว่างและข้อมูลต้องเป็น DateTime objectหลังจากนี้เมื่อคุณ submit ฟอร์มด้วยข้อมูลที่ไม่ถูกต้อง คุณจะเจอการแสดงของ error แสดงออกมาจากฟอร์ม
HTML5 Validation
บราวเซอร์จำนวนมากสามารถใช้การ validate ฝั่ง client side ได้ โดยการ validate ที่เป็นคำสั่งพื้นฐานที่สุดคือการเพิ่มแอตทริบิว required ใน field สำหรับบราวเซอร์ที่สนับสนุน HTML5 จากผลลัพธ์นี้ บราวเซอร์แจ้งเตือนแสดงข้อความออกมาหากผู้ใช้กด submit โดยที่ field ของฟอร์มไม่ได้ใส่ข้อมูลมา
อย่างไรก็ตามเราสามารถปิดการ validate โดยการเพิ่มแอตทริบิว
novalidate
ลงในform
tag หรือเพิ่มformnovalidate
ที่submit
tag ซึ่งจะทำในกรณีที่เราต้องการทดสอบการ validate ทางฝั่ง server-sideBuilt-in Field Types
ใน Symfony จะมาพร้อมกับ field type มาตรฐานที่ครอบคลุมรูปแบบ form พื้นฐานและ data type ต่าง ๆ
Text Fields¶
Choice Fields¶
Date and Time Fields¶
Other Fields¶
Field Groups¶
Hidden Fields¶
Buttons¶
Base Fields¶
Field Type Options
แต่ละ field type จะมีจำนวนของ option ให้ใช้สำหรับการ configure ตัวอย่างเช่น ณ ตอนนี้
duaDate
field แสดงผลโดยใช้ 3 select boxes อย่างไรก็ตามDateType
สามารถกำหนดค่าให้แสดงผลเป็น text box ช่องเดียวได้โดยแต่ละ field type จะมีตัวเลือก option ให้ใช้แตกต่างกัน โดยมี option หลายชนิดที่ต้องใช้เฉพาะเจาะจงกับ field type ชนิดนั้น ๆ
The required Option
option ที่พื้นฐานที่สุดคือ
requied
option ซึ่งสามารถใช้ได้กับทุก field type โดยค่าเริ่มต้นrequired
option จะถูกตั้งค่าไว้เป็นtrue
นั่นหมายความว่าทุกบราวเซอร์ที่รองรับ HTML5 จะทำการ validate ฝั่ง client ถ้า field ไม่ได้ใส่ข้อมูล ถ้าไม่ต้องการให้มันทำงาน ทำได้โดยปิด HTML5 validation หรือตั้งค่าrequired
option เป็นfalse
นอกจากนี้โปรดทราบว่าการตั้งค่า
required
option เป็นtrue
จะไม่ส่งผลให้มีการตรวจสอบความถูกต้องฝั่ง server side กล่าวอีกนัยหนึ่งถ้าผู้ใช้ส่งค่าว่างสำหรับฟิลด์ (เช่นกับเบราเซอร์รุ่นเก่าหรือ web service) มันจะถือว่าเป็นค่าที่ถูกต้องเว้นแต่คุณจะใช้ validate constraintNotBlank
หรือNotNull
ของ SymfonyField Type Guessing
เมื่อคุณได้เพิ่มการ validate ไปในคลาส
Task
ตัว Symfony จะรู้เกี่ยวกับ field ของคุณซึ่งมันสามารถคาดเดาได้ว่าประเภท field ของคุณเป็นอะไรและตั้งค่าให้ ในตัวอย่างนี้ Symfony คาดเดาจาก validate rules ของtask
field ว่าใช้เป็นTextType
และdueDate
field ควรเป็นDateType
การคาดเดาจะทำงานเมื่อคุณละเว้นการส่ง argument ตัวที่สองของเมธอด
add()
(หรือส่งเป็นค่าnull
ไปแทน) แต่ถ้ามี array option คุณสามารถทำได้โดยส่งมันไปใน argument ตัวที่สาม (ดังตัวอย่างdueDate
ข้างบน)Field Type Options Guessing
นอกจากการคาดเดา type ของ field แล้ว ตัว Symfony ยังสามารถคาดเดาค่าที่ถูกต้องของ option ของ field ได้ด้วย
Required
option สามารถคาดเดาได้ตาม validate rule (เช่น fieldNotBlank
หรือNotNull
หรือไม่) หรือใน Doctrine (เช่น fieldnullable
หรือไม่) นี่เป็นประโยชน์อย่างยิ่งเนื่องจากการ validate ฝั่ง client-side ของคุณจะตรงกับ validate rule ของคุณโดยอัตโนมัติMaxlenght
ถ้าฟิลด์บางฟิลด์เป็นการจัดเรียงข้อความmaxlength
option attribute สามารถคาดเดาได้จาก validate constraint (ถ้าใช้Length
หรือRange
) หรือจาก Doctrine (ผ่าน field length)ถ้าคุณต้องการเปลี่ยนแปลงค่าของการคาดเดา คุณสามารถส่ง option ไปใน option field array
Creating Form Classes
จากที่ผ่านมา จะเห็นว่าฟอร์มสามารถสร้างได้โดยตรงใน controller อย่างไรก็ตามทางที่ดีกว่าคือการสร้างฟอร์มแยกไว้ต่างหาก ให้เป็น standalone PHP class ซึ่งจะช่วยให้สามารถนำกลับมาใช้ได้ใหม่ในทุก ๆ ที่ของแอพพลิเคชั่นของคุณ สร้าง new class สำหรับการสร้างฟอร์ม task
โดย class ใหม่นี้ข้างในจะมีสิ่งที่จำเป็นสำหรับการสร้างฟอร์ม Task โดยสามารถสร้าง form object ได้อย่างรวดเร็วใน controller
การสร้างฟอร์ม logic ไว้ใน class ของมันเอง นั้นจะทำให้เราสามารถนำมันไปใช้ใหม่ได้ง่ายในทุก ๆ ที่ของโปรเจ็ค ซึ่งเป็นวิธีที่ดีสำหรับการสร้างฟอร์ม
Setting the data_class
ทุกฟอร์มจำเป็นต้องทราบชื่อของ class ที่เก็บข้อมูลพื้นฐานไว้ (เช่น
AppBundle\Entity\Task
) โดยปกติแล้วนี่เป็นเพียงการคาดเดา object ที่ส่งผ่านไปยังอาร์กิวเมนต์ที่สองไปที่createForm()
(เช่น$task
) โดยทั่วไปคุณควรระบุตัวเลือก data_class อย่างชัดเจนโดยเพิ่มข้อมูลต่อไปนี้ลงใน form type classเมื่อแม็ปฟอร์มกับอ็อบเจ็กต์ ฟิลด์ทั้งหมดจะถูกแมป ฟิลด์ใด ๆ ในแบบฟอร์มที่ไม่มีอยู่ในออบเจกต์ที่แมป จะทำให้เกิดข้อผิดพลาดแสดงออกมา
ในกรณีที่คุณต้องการเพิ่มฟิลด์ขึ้นมาในฟอร์ม (เช่น “คุณยอมรับเงื่อนไขหรือไม่” เป็น checkbox) ซึ่งไม่ได้แม็ปกับ object คุณจำเป็นที่จะต้องกำหนดค่า mapped option เป็น
false
นอกจากนี้ หากมี field ใด ๆ ในฟอร์มที่ไม่ได้รวมอยู่ในข้อมูลที่ submit มา ข้อมูลของ field เหล่านี้จะถูกกำหนดค่าเป็น
null
การเข้าถึงข้อมูลของ field ใน controller ทำได้โดย
นอกจากนี้การแก้ไขข้อมูลที่ไม่ได้แม็ปสามารถทำได้โดย
Final Thoughts
เมื่อกำลังสร้างฟอร์ม จำไว้ว่าเป้าหมายแรกของฟอร์มคือ การแปลงข้อมูลจาก object (Task) ไปแสดงยัง HTML ฟอร์มเพื่อให้ผู้ใช้สามารถแก้ไขข้อมูลได้ เป้าหมายต่อมาของฟอร์มคือ การนำข้อมูลที่ผู้ใช้ส่งกลับมาแปลงกลับไปสู่ object
source