เนื้อหานี้เราจะมาพูดถึงการใช้งาน View กันต่อ
เป็นส่วนที่เกี่ยวกับการใช้งาน View Layout และต่อด้วย
การใช้งาน HTTP Response เป็นเนิ้อหาต่อเนื่องจากตอนที่แล้ว
ทบทวนตอนที่แล้วได้ที่บทความ
รู้จักับ Views และการใช้งาน View Cells ใน CodeIgniter 4 http://niik.in/999
https://www.ninenik.com/content.php?arti_id=999 via @ninenik
การใช้งาน View Layouts
ใน CI4 จะรองรับการกำหนดรูปแบบ Layout ให้กับ Views การใช้งาน Layout จะทำให้เราสามารถกำหนด
รูปแบบการแสดงของหน้าเพจได้หลายรูปแบบขึ้น ตัวอย่างเช่น การสร้างเป็น Layout แบบ 1 หรือ 2 คอลัมน์
การสร้างหน้า Blog ข่าวสารหรือบทความ หรือรูปแบบอื่นๆ ตามแต่กำหนด โดยตัว Layout จะรองรับการแทรก
เนื้อหาจากการเรียกใช้งาน View หรือกล่าวคือตัว view จะถูก render แล้วแทรกเข้ามาใน Layout โดยที่ตัว Layout
ไม่ได้ render โดยตรง ลองมองภาพตามวิธีการสร้างด้านล่าง
การสร้าง Layout
ในเนื้อหาตอนที่แล้วเกี่ยวกับการใช้งาน Views ด้วยการเรียกใช้ฟังก์ชั่น view() เพื่อ render ไฟล์ view ที่ต้องการ
โดยเวลาเราต้องการแยกเป็นส่วนๆ ก็สามารถกำหนดในรูปแบบดังนี้
<?php namespace App\Controllers; use CodeIgniter\Controller; // เรียกใช้งาน Controller class class Helloworld extends Controller { public function index() { echo view('pages/templates/header'); echo view('pages/helloworld'); echo view('pages/templates/footer'); } }
นั่นคือ เป็นไปในลักษณะ สร้างแต่ละส่วนแล้วกำหนดเชื่อมต่อกันเป็นโครงสร้างหน้าเพจ HTML
แต่สำหรับการใช้งาน Layout เราจะ render เฉพาะไฟล์ view ที่ต้องการ ซึ่งส่วนใหญ่ก็จะเป็นไฟล์ในส่วน
เนื้อหาหลัก อย่างข้างต้นก็คือเฉพาะส่วนของไฟล์ helloworld.php โดยไฟล์นี้จะต้องถูกแทรกเข้าไปในไฟล์
Layout โดยรูปแบบของไฟล์ Layout ก็คล้ายๆ กับรูปแบบของไฟล์ view
ตอนนี้เราจะเปลี่ยนการเรียกใช้งาน Controller ให้เพลือเฉพาะ ไฟล์ view หลัก จะได้เป็น
app/Controller/Helloworld.php
<?php namespace App\Controllers; use CodeIgniter\Controller; // เรียกใช้งาน Controller class class Helloworld extends Controller { public function index() { $data = [ 'title' => 'Hello World', 'day' => ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'] ]; echo view('pages/helloworld' ,$data); } }
ในที่นี้เราจะให้มีการส่งตัวแปรเข้าไปด้วย
ต่อไปให้เราสร้างไฟล์สำหรับเป็นไฟล์ Layout จะกำหนดชื่ออะไรก็ได้ ในที่นี้กำหนดเป็นไฟล์ชื่อ
layout.php ไว้ในโฟลเดอร์ app/Views/pages
app/Views/pages/layout.php
<!doctype html> <html lang="th"> <head> <meta charset="utf-8"> <title>Document</title> </head> <body> <?= $this->renderSection('content') ?> </body> </html>
สิ่งที่ไฟล์ Layout แตกต่างไปจากไฟล์ view ทั่วไปคือ มีการกำหนดการเรียกใช้งาน renderSection() method
การกำหนดค่านี้ เปรียบเหมือนการจองที่ว่างให้สำหรับเนื้อหาที่จะเอามาแทรก โดยกำหนดชื่อที่ต้องการเป็น parameter
เดียวสำหรับการเรียกใช้งาน ใช้เป็นชื่ออะไรก็ได้ ข้างต้นกำหนดชื่อเป็น 'content' สื่อถึงส่วนของเนื้อหาที่จะแสดง
ทีนี้ สมมติเดิมไฟล์ View ชื่อ helloworld.php มีเนื้อหาเป็นดังนี้
<h1>This is test title</h1>
สิ่งที่จะเกิดขึ้น เมื่อเราปรับมาใช้งานแบบ Layout ก็คือ เนื้อหาของไฟล์ helloworld ที่ถูก render ด้วยฟังก์ชั่น view()
ใน Controller จะถูกแทรกเข้าไปในไฟล์ Layout ชื่อ layout.php ตามตำแหน่งชื่อกำหนด ดังนั้น เพื่อให้ไฟล์ helloworld.php
แสดงใน layout.php เราจะต้องกำหนดดังนี้
app/Views/pages/helloworld.php
<?= $this->extend('pages/layout') ?> <?= $this->section('content') ?> <h1>This is test title</h1> <?= $this->endSection() ?>
เริ่มต้นที่ด้านบนของไฟล์ view เราจะต้องเรียกใช้คำสั่ง $this->extend() ก่อนทุกครั้งเสมอ โดยระบุไฟล์ layout ที่เรา
ต้องการจะแทรกเข้าไป ในที่นี้ก็คือ 'pages/layout'
ต่อด้วย ต้องมีการกำหนดการใช้คำสั่ง $this->section() และ $this->endSection() ตามลำดับ โดยเป็นการบอกจุดเริ่มต้น
ของเนื้อหาที่จะนำไปแทรกในไฟล์ Layout โดยคำสั่ง $this->section() เราต้องกำหนดชื่อให้สอดคล้องกับชื่อที่กำหนด
ในตอนเรียกใช้งานคำสั่ง $this->renderSection('content') ในส่วนนี้จึงมีค่าเป็น $this->section('content') และปิดด้วยคำสั่ง
$this->endSection()
ส่วนที่อยู่ระหว่างคำสั่ง $this->section('content') และ $this->endSection() คือเนื้อหาที่จะถูกแทรกไปยังไฟล์ layout.php
ดูผลลัพธ์ เมื่อเราเรียกไปยัง URL https://www.mysslweb.com/helloworld
เข้าใจอย่างง่าย ก็เหมือนเราเอาไฟล์ layout มาครอบส่วนของ view นั่นเอง
การกำหนดโดยใช้งาน layout ค่าตัวแปรต่างๆ จะถูกส่งไปต่อเข้าไปใน layout ด้วย นั่นคือเราสามารถเรียกใช้งาน $title
ในไฟล์ layout.php ได้ ดังนี้
app/Views/pages/layout.php
<!doctype html> <html lang="th"> <head> <meta charset="utf-8"> <title><?= esc($title) ?></title> </head> <body> <?= $this->renderSection('content') ?> </body> </html>
เราสามารถเรียกใช้งาน หรือ include ไฟล์ view ที่ต้องการมาใช้งานใน layout.php หรือ helloworld.php ได้
ด้วยคำสั่ง $this->include()
เช่นเรามีไฟล์ test.php เป็นดังนี้
app/Views/pages/test.php
<span>This is test file</span> <br> <?= esc($title) ?> <br>
เราสามารถแทรกเข้าไปในไฟล์ helloworld.php ดังนี้ได้
app/Views/pages/helloworld.php
<?= $this->extend('pages/layout') ?> <?= $this->section('content') ?> <h2>This is test title</h2> <?= $this->include('pages/test') ?> <?= $this->endSection() ?>
หรือจะ include ไปในไฟล์ layout ก็ได้เหมือนกัน
app/Views/pages/layout.php
<!doctype html> <html lang="th"> <head> <meta charset="utf-8"> <title><?= esc($title) ?></title> </head> <body> <?= $this->renderSection('content') ?> <?= $this->include('pages/test') ?> </body> </html>
ตัวแปรต่างๆ ที่ถูกส่งเข้ามา จะสามารถเรียกใช้งานได้ภายใน views ที่ใช้รูปแบบ layout
จะเห็นว่า การใช้งาน Layout ก็เป็นอีกวิธีที่เราสามารถใช้ในการสร้าง templates ของหน้าเพจที่ต้องการได้
การใช้งาน HTTP Response
โดยทั่วไปแล้ว การใช้งาน CI4 เราอาจจะไม่ค่อยจำเป็นต้องกำหนดหรือใช้งานในส่วนของ Response class เพราะตัว
CI จะจัดการให้แทบทุกอย่างแล้ว ตัว HTTP Response จะเป็นการจัดการเกี่ยวกับข้อมูลที่ server ต้องการกำหนด
โดยรวมถึงส่วนของการกำหนดค่า header และ body ก่อนที่จะส่งกลับไปแสดงที่ฝั่งยัง client โดยเราสามารถเรียกใช้งานใน
Controller ผ่านตัวแปร $this->response จะใช้เมื่อต้องการทำคำสั่งหรือการทำงานเฉพาะ ตัวอย่างเช่น การกำหนด status code
การทำการ HTTP Caching เป็นต้น จะได้ดูรายละเอียดการใช้งานตามลำดับ
ใช้กำหนด Output ที่จะแสดง
ในกรณีที่เราต้องการแสดงข้อมูล โดยไม่ใช้รูปแบบที่ CI จะมาให้ สามารถทำได้โดยใช้คำสั่ง setBody() ร่วมกับคำสั่ง
setStatusCode() ตัวอย่างเช่น
<?php namespace App\Controllers; use CodeIgniter\Controller; // เรียกใช้งาน Controller class class Helloworld extends Controller { public function index() { $data = NULL; return $this->response->setStatusCode(404) ->setBody($data); } }
ข้างต้น เรากำหนด status code เป็น 404 และกำหนดค่าข้อมูลเป็น NULL ทดสอบรันจะได้ผลลัพธ์ ดังรูป
ในส่วนของคำสั่ง setStatusCode() เราสามารถกำหนดข้อความที่ต้องการแสดงเป็นค่าใดๆ ก็ได้เช่น
$this->response->setStatusCode(404, 'Nope. Not here.');
หากกำหนดข้างต้น ค่า 'Nope. Not here.' จะไปแทนที่ข้อความ 'Not found'
เราสามารถแปลงข้อมูลตัวแปร array ให้อยู่ในรูปแบบ JSON Data หรือรูปแบบ XML ได้ด้วยคำสั่ง setJSON() กับ setXML()
ดูตัวอย่างการใช้งาน
class Helloworld extends Controller { public function index() { $data = [ 'success' => true, 'id' => 123 ]; return $this->response->setJSON($data); } }
status code ปกติเมื่อมีการส่งข้อมูลกลับมาจะเป็น 200 Ok กรณีนี้เราไม่จำเป็นต้องกำหนดด้วยคำสั่ง setStatusCode() ก็ได้
ผลลัพธ์ที่ได้เมื่อแสดงผ่านบราวเซอร์ เราจะได้ข้อมูลที่เป็น JSON Data ดังรูป
เราลองเปลี่ยนเป็นรูปแบบ XML จะได้เป็น
class Helloworld extends Controller { public function index() { $data = [ 'success' => true, 'id' => 123 ]; return $this->response->setXML($data); } }
ผลลัพธ์ที่ได้ก็จะเป็นรูปแบบ XML ตามรูปด้านล่าง
ใช้กำหนด Header
เราสามารถใช้งาน Response class กำหนดในส่วนของ Response Headers โดยใช้คำสั่ง setHeader() โดยกำหนด
parameter แรกเป็นชื่อของ header และ parameter ที่สองเป็นค่าของ header ที่จะกำหนด โดยค่าของ header สามารถ
กำหนดได้ทั้งรูปแบบที่เป็น String และรูปแบบ Array ตัวอย่างการใช้งาน เช่น
public function index() { $this->response->setHeader('Location', 'https://mysslweb.com') ->setHeader('WWW-Authenticate', 'Negotiate'); $data = [ 'success' => true, 'id' => 123 ]; return $this->response->setJSON($data); }
ดูผลลัพธ์ในส่วนของ response header จะมีค่าของ 'Location' และ 'WWW-Authenticate' ตามที่เรากำหนด แสดงอยู่ด้วย
ในบาง header อาจจะมีค่าอยู่แล้ว และสามารถกำหนดได้มากกว่า 1 ค่า เราสามารถใช้การเพิ่มค่าเข้าไปก่อนหรือหลังค่าเดิม
ที่มีอยู่แล้วได้ด้วยคำสั่ง prependHeader() และ appendHeader() ตัวอย่าง header ค่า 'Cache-Control' ตามรูปด้านล่าง
เป็นค่าเดิม เรายังไม่ได้กำหนดเพิ่ม
เราลองเพิ่มค่าคำว่า 'public' ไว้ด้านหน้า และค่าคำว่า 'must-revalidate' ไว้ด้านหลังในส่วนของค่า 'Cache-Control'
public function index() { $this->response->setHeader('Location', 'https://mysslweb.com') ->setHeader('WWW-Authenticate', 'Negotiate'); $this->response->prependHeader('Cache-Control', 'public') ->appendHeader('Cache-Control', 'must-revalidate'); $data = [ 'success' => true, 'id' => 123 ]; return $this->response->setJSON($data); }
จะได้ผลลัพธ์ ค่าทั้งเพิ่มเข้าไปด้าหน้าและด้านหลังของค่าเดิม ตามที่เรากำหนด
เราสามารถลบค่า Header ที่ไม่ต้องการโดยใช้คำสั่ง removeHeader() โดยกำหนดชื่อ header ที่จะลบ เป็นตัวพิมพ์เล็ก
หรือใหญ่ก็ได้ ไม่มีผล ตัวอย่างเช่น เราต้องการค่า X-Powered-By: PHP/7.3.6 เราก็กำหนดเป็น
$this->response->removeHeader('X-Powered-By'); // * แต่จากที่ลองดูเหมือนจะใช้งานไม่ได้ แต่สามารถใช้คำสั่งด้านล่างแทนได้ // header_remove("X-Powered-By");
ใช้กำหนดให้ดาวน์โหลดไฟล์
เราสามารถใช้งาน Response class สำหรับการกำหนดให้บราวเซอร์ขึ้นแจ้งให้ทำการดาวน์โหลดไฟล์ หรือการให้บันทึก
ไฟล์ที่เรียกใช้งานลงบนเครื่อง โดยใช้คำสั่ง download()
รูปแบบการกำหนดการเรียกใช้งาน จะเป็นดังนี้
public function index() { $data = 'Here is some text!'; $name = 'mytext.txt'; return $this->response->download($name, $data); }
การทำงานของรูปแบบข้างต้น คือ เราต้องการให้ข้อมูลในตัวแปร $data ถูกดาวน์โหลดไปเป็นไฟล์ชื่อว่า mytext.txt
เมื่อเราเรียกมายัง URL ที่ใช้งาน Controller นี้ ก็จะเป็นการดาวน์โไฟล์ชื่อ mytext.txt และมีข้อมูลด้านในเป็น ข้อความตาม
ตัวแปร $data หรือก็คือค่า 'Here is some text!'
กรณีเราต้องการให้ดาวน์โหลดข้อมูลไฟล์ที่มีอยู่แล้ว สามารถกำหนดในรูปแบบดังนี้
public function index() { $name = WRITEPATH.'/uploads/test.txt'; return $this->response->download($name, NULL); }
และกรณีต้องการเปลี่ยนชื่อดาวน์โหลดไฟล์เป็นชื่ออื่น ไม่ใช้ชื่อเดิม ก็สามารถกำหนดเป็นดังนี้
public function index() { $name = WRITEPATH.'/uploads/test.txt'; return $this->response->download($name,NULL)->setFileName('newfile.txt'); }
สามารถกำหนดเป็นไฟล์ใดๆ ก็ได้ตามต้องการ ในตัวอย่างทดสอบให้เห็นเฉพาะ text ไฟล์
ใช้กำหนด HTTP Caching
เราสามารถใช้ Response class กำหนด Header ที่ใช้ควบคุมการแคชให้กับบราวเซอร์ หรือก็คือการแคชที่ฝั่ง client
ทำให้ client ไม่จำเป็นต้องดึงข้อมูลจากฝั่ง server ตลอดเวลา จริงๆ แล้วการกำหนดส่วนนี้ เราสามารถทำได้หลายวิธี
เช่นกำหนดการแคชในไฟล์ htaccess แต่ในที่นี้เราจะพูดถึงการกำหนดด้วยวิธีการใช้งาาน Response class
การใช้งานก็คือแนวทางเดียวกับการกำหนด header ในหัวข้อที่อธิบายด้านบน แต่จะเป็นการกำหนดในส่วนของ
ค่า 'Cache-Control' และ 'ETag' header โดยใช้คำสั่ง setCache()
ในรายละเอียดของ HTTP Caching แต่ละค่าทำงานอย่าง ให้เราไปศึกษาเพิ่มเติม ที่ Google Developers
ในที่นี้เราจะแนะนำวิธีการกำหนดค่าเท่านั้น โดยสามารถทำได้ดังนี้
public function index() { $options = [ 'public', 'max-age' => 86400, 'etag' => 'abcde' ]; $this->response->setCache($options); echo view('pages/helloworld'); }
ค่าของ option ที่เราสามารถกำหนดได้ ถ้าตัวใด ไม่ต้องมีค่า key ให้กำหนดเป็นค่า value ไปเลย เหมืนอ public
- etag
- last-modified
- max-age
- s-maxage
- private
- public
- must-revalidate
- proxy-revalidate
- no-transform
เกี่ยวกับ HTTP Caching สามารถอ่านเพิ่มเติมที่ HTTP caching
https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
สำหรับเนื้อหาเกี่ยวกับการใช้งาน View Layout และ HTTP Response เบื้องต้น ก็จะประมาณนี้ เราละเอียดเพิ่มเติม
อาจจะมีแทรกในเนื้อหาในบทความอื่นๆ