ความเดิมตอนที่แล้ว

ใครยังไม่ได้ initail project ให้ไปดูบทความย้อนหลังได้ที่ https://www.bigdata.rmutt.ac.th/?p=1754

เข้าใจเรื่อง Controller และ Action

ความสัมพันธ์ของ Controller และ Action

จากรูปด้านบน ให้เราลองเปิดไฟล์ frontend\controllers\SiteController.php ขึ้นมา เพื่อดูหลักการทำงาน สังเกตได้ว่าจะมี function actionXxx() อยู่ เช่น actionIndex() เป็นต้น

ปกติแล้ว Yii2 ทำการ route โดยใช้ keyword ของ function actionXxx() เป็นหลัก (ต้องพิมพ์คำว่า action นำหน้าชื่อของ function) เช่น actionIndex() ใน SiteController จะถูกเข้าถึงโดย

/index.php?r=site/index

ถ้าเป็น index อยู่แล้ว ผู้ใช้สามารถเข้าถึงได้โดยไม่ต้องใส่ index เพิ่มเติมเข้าไป หรือพูดง่าย ๆ ว่า

/index.php?r=site/index เทียบเท่า /index.php?r=site

คำว่า site บน URL มาจากชื่อ SiteController นั่นเองครับ สังเกตว่าบน URL จะใช้ตัวพิมพ์เล็กทั้งหมด มาลองกันดีกว่า ให้เราเพิ่ม function actionB() เข้าไปใน SiteController ดังนี้

 public function actionB(){
        echo "Hello Yii2";
    }

ลองเข้า URL ไปที่ http://localhost/my_app/frontend/web/index.php?r=site/b เพื่อทดสอบดู จะสังเกตผลลัพธ์ได้ว่า ระบบจะพิมพ์คำว่า Hello Yii2 เป็นข้อความปกติ โดยไม่ได้ render theme ที่เกี่ยวข้องเลย จะสอดคล้องกับภาพด้านบนว่า เราสามารถพ่น text ที่เราต้องการออกมาบนหน้าเว็บของเราได้โดยตรง โดยใช้คำสั่ง echo หรือ print ได้เลย (แต่วิธีนี้ default ของระบบจะให้เรา print ข้อความออกมาไม่ยาวมากนัก ถ้าต้องการ print text ยาว ๆ ให้โยนไปให้ view แสดงผลแทน ซึ่งจะกล่าวต่อไป)

ลองเพิ่ม function actionA() เข้าไปใน SiteController ดังนี้

public function actionA(){
        return $this->render("a");
    }

ลองเข้า URL ที่ http://localhost/my_app/frontend/web/index.php?r=site/a ตอนนี้ทุกคนจะต้องได้ error message ตามนี้

View not Found – yii\base\ViewNotFoundException
The view file does not exist: C:\xampp\htdocs\my_app\frontend\views\site\a.php

จากรูปด้านบนถ้าเราต้องการ render(“a”) เราจำเป็นต้องมี page PHP รองรับไว้ใน View ด้วย ในที่นี้ก็คือ View ที่อยู่ใน site นั่นเองครับ (มันจะสอดคล้องกัน เพราะเรากำลังเล่นอยู่ครับ SiteController) ดังนั้นให้ไปเพิ่มไฟล์ frontend\views\site\a.php และใส่ข้อความอะไรลงไปก็ได้เช่น

This is "a" page

หลังจากนั้นลองรันใหม่ครับ เราจะต้องได้หน้าจอดังรูปด้านล่าง

ลองทดสอบสร้าง actionC() แต่ใช้วิธีการ render อีกแบบหนึ่งดังนี้ และอย่าลืมไปสร้างไฟล์ frontend\views\site\c.php และใส่ข้อความอะไรลงไปก็ได้ด้วยนะครับ

 public function actionC(){
        return $this->renderPartial("c");
    }

ถ้าลองทดสอบแล้ว จะปรากฏว่าจะได้หน้าจอดังรูปต่อไปนี้ สังเกตได้ว่า หน้าจอนี้จะไม่มี layout theme เข้ามาเกี่ยวข้องเลย เหมือนเราเขียนไฟล์ใหม่สด ๆ ตั้งแต่แรก เพียงแค่ใช้การ route เป็น index.php?r=site/c เท่านั้นครับ ปกติผมจะใช้ในกรณีที่เราไม่อยากไปยุ่งกับ template ใน theme ของเรา เช่น สร้าง JSON API เป็นต้น ก็สามารถทำได้

นอกจากนี้เรายังส่งข้อมูลมาที่ view ที่เราต้องการจาก controller ได้อีกด้วย เช่น return $this->render(‘say’, [‘message’ => $message]); เป็นการส่ง message ไปให้ view ที่ชื่อว่า say เพื่อนำตัวแปร message ไปใช้ต่อได้ ถ้าเราต้องการใช้ใน view (ปกติแล้วจะต้องมีการส่งข้อมูลระหว่าง controller กับ view อยู่แล้วครับ ในสถานการณ์จริง)

ลองปรับแต่ง Routing ให้สวยงาม โดยทำเป็น Pretty URL

ปกติแล้ว URL ที่ใช้แสดงผล เป็นช่องทางหนึ่งที่ผู้ใช้สามารถเห็นรายละเอียดได้ เช่น เขียนด้วยภาษาอะไร มีตัวแปรใดส่งไปบ้าง เป็นต้น จะเป็นการดีกว่าถ้าเราสามารถซ่อนข้อมูลพวกนี้ได้

Yii2 ได้มีมาตรฐานการทำ Pretty URL ไว้ ซึ่ง Pretty URL คือทำให้ URL นั้นสั้น กระชับ และซ่อนรายละเอียดบางอย่างได้ ปกติแล้ว Yii2 สามารถปรับแต่ง Routing ได้ตามที่เราต้องการ แต่ในที่นี้ผู้เขียนขอใช้มาตรฐานที่มาพร้อมกับ Yii2 เพื่อไม่ให้ dev ปรับแต่งอะไรยุ่งยากมาก สามารถดูข้อมูลเพิ่มเติมได้ที่ https://www.yiiframework.com/doc/guide/2.0/en/runtime-routing

พร้อมแล้ว ลุยกันเลย เริ่มต้นเปิดไฟล์ frontend\config\main.php และแก้ไขข้อมูลในส่วน URL Manager ให้เป็นดังนี้


        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => array(
                '<controller:\w+>/<id:\d+>' => '<controller>/view',
                '<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
                '<controller:\w+>/<action:\w+>' => '<controller>/<action>',
                'module/<module:\w+>/<controller:\w+>/<action:\w+>' => '<module>/<controller>/<action>',
            ),
        ],

ในกรณีที่เป็น Apache ให้ทำการเพิ่มไฟล์ frontend\web\.htaccess (ไฟล์ชื่อว่า .htaccess มี . นำหน้าด้วยนะครับ) และให้เพิ่ม code ต่อไปนี้ลงไป เพื่อปรับการ rewrite rule (โดย default XAMPP จะเปิด mod RewriteRule ให้อยู่แล้ว)

RewriteEngine on
# If a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward it to index.php
RewriteRule . index.php

เมื่อปรับแล้วให้ลองทดสอบการทำงานดู จะสังเกตว่า URL แบบเต็มเช่น index.php?r=site/a จะถูกเปลี่ยนเป็น /site/a แทน โดย URL เต็ม ๆ ในที่นี้คือ http://localhost/my_app/frontend/web/site/a ซึ่งทำให้สามารถซ่อนรายละเอียดต่าง ๆ ได้ และมีความกระชับพอสมควร ลองทดสอบไปที่ http://localhost/my_app/frontend/web/site/about และตำแหน่งอื่น ๆ ดูครับ

ในที่นี้สามารถปรับที่ฝั่ง backend ได้ด้วย ด้วยการทำในลักษณะเดียวกัน แค่เปลี่ยนไปทำใน backend\config\main.php และ backend\web\.htaccess แทน หลังจากนั้นลองทดสอบดู

หากใครใช้เป็น Nginx ให้ลองหาข้อมูลด้วย keyword ว่า “Yii2 Pretty URL with Nginx” จะมี community ที่ได้ทำตัวอย่างไว้

ท้ายที่สุดแล้ว ในบทความนี้เราได้รู้หลักการของ Controller Action และการปรับแต่ง Route เบื้องต้น เดี๋ยวเราค่อย ๆ ไต่ระดับขึ้นไปครับ