เนื้อหาในตอนต่อไปนี้ เราจะมาทำความรู้จักกับ
URL ใน CI4 เพิ่มเติม อาจจะมีการอ้างอิงเนื้อหาบางส่วน
จากตอนที่แล้ว มาประกอบการอธิบาย
ทบทวนตอนที่แล้วได้ที่
สร้างระบบ CRUD เพื่อศึกษาฟังก์ชั่นของ Model ใน CodeIgniter 4 http://niik.in/995
https://www.ninenik.com/content.php?arti_id=995 via @ninenik
เกี่ยวกับ CodeIgniter URLs
โดยปกติแล้ว URL ใน CI จะออกแบบให้รองรับกับโปรแกรมหรือเครื่องมือที่ใช้ในการค้นหา และ
คนเราสามารถอ่านเข้าใจได้ง่าย ตัวอย่างเช่น URL จากตอนที่แล้ว
https://www.mysslweb.com/news/say-it-isnt-so
เราสามารถกำหนดหัวข้อของข่าว มาเป็น ส่วนหนึ่งของ url ซึ่งสามารถเข้าใจได้ง่าย ว่าข่าวในหน้านั้นเกี่ยวกับอะไร
และเวลาค้นหาใน search engine ก็จะมีโอกาสที่จะค้นเจอได้คำที่ต้องการใน url ที่เรากำหนด ซึ่งเราอาจจะคุ้นเคยกับ
รูปแบบ query string เช่น https://www.mysslweb.com/news.php?news_id=1
CI ใช้รูปแบบการกำหนด segment ให้กับ URL
การใช้งาน URI Segments
ใน CI มีการกำหนด sengment ใน url โดยพื้นฐานมาจากการใช้งานในรูปแบบ MVC ซึ่งจะแสดงในลักษณะดังนี้
example.com/class/method/ID
1. segment แรกจะแสดงถึง controller class ที่ต้องการใช้งาน
2. segment ที่สองจะแสดงถึง method ของ controller class ที่ต้องการเรียกใช้
3. segment ที่สาม และลำดับอื่นๆ เพิ่มเติม จะแสดงถึง ID หรือตัวแปร variables ที่ส่งเข้ามาใช้ใน controller
การลบ index.php ออกจาก URL
อยากที่เราทราบในตอนต้นแล้วว่า โฟลเดอร์ public จะเป็น document root หลักของ web app
และมีไฟล์ index.php เป็นเหมือนไฟล์หลักของโปรแกรม ที่เรียกใช้งานส่วนอื่นๆ ดังนั้นการเรียกไปที่ url
https://www.mysslweb.com/news/say-it-isnt-so
จากตอนที่แล้ว ก็จะมีค่าเท่ากับ
https://www.mysslweb.com/index.php/news/say-it-isnt-so
ซึ่งค่าเริ่มต้นของ CI4 ส่วนของ segment จะเริ่มนับตั้งแต่ หลัง "index.php/" เป็นต้นไป
เราสามารถใช้ mod_rewrite เพื่อกำหนดให้สามารถเรียกใช้งานโดยไม่ต้องระบุไฟล์ index.php ได้ โดยใช้รูปแบบ
การกำหนดดังนี้ในไฟล์ .htaccess ในโฟลเดอร์ public
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1 [L]
ในโปรเจ็ตของเรา จะเห็นว่าสามารถเรียกไปยัง url ที่ไม่มี index.php ทั้งนี้เพราะในไฟล์ .htaccess มีการกำหนด
mod_rewrite ให้สามารถตัด index.php ออกไป ไว้ให้แล้ว เราจึงไม่จำเป็นต้องกำหนดเพิ่มเติม
การกำหนด URI Routing
โดยทั่วไปแล้วความสัมพันธ์ระหว่าง url กับ controller class/method จะเป็นลักษณะ 1 ต่อ 1 ตามรูปแบบ segment
ที่อธิบายไปตอนต้น
example.com/class/method/id/
แต่บางครั้งอาจจะต้องการกำหนดรูปแบบที่แตกต่างออกไป ตัวอย่างเช่น
example.com/product/1/ example.com/product/2/ example.com/product/3/ example.com/product/4/
จะเห็น จากปกติที่ segment ตัวที่สองจะเป็นส่วนสำหรับใช้กำหนดชื่อ method แต่รูปแบบที่เราอยากได้คือ ต้องการ
ให้เป็น product ID และ ใน CI4 เราก็สามารถจัดรูปแบบที่ต้องการนี้ได้โดยการกำหนด rule ในไฟล์
app/config/Routes.php
/** * -------------------------------------------------------------------- * Route Definitions * -------------------------------------------------------------------- */ // We get a performance increase by specifying the default // route since we don't have to scan directories. $routes->get('/', 'Home::index'); $routes->match(['get'], 'news/delete/(:num)', 'News::delete/$1'); $routes->match(['get', 'post'], 'news/edit/(:num)', 'News::edit/$1'); $routes->match(['get', 'post'], 'news/create', 'News::create'); $routes->get('news/(:segment)', 'News::view/$1'); $routes->get('news', 'News::index'); $routes->get('(:any)', 'Pages::view/$1');
สังเกต rule ที่เรากำหนดในเนื้อหาผ่านๆ มาข้างต้น
ตัวแปร $routes จะเป็น instance ของ RouteCollection class ที่ให้เราสามารถกำหนดสูตรหรือรูปแบบ สำหรับ
routing ที่ต้องการได้ โดยจะใช้วิธีกำหนดด้วย Placeholder หรือ Regular Expressions ก็ได้
ในการกำหนด route เราจะกำหนดรูปแบบ url ที่ต้องการในฝั่งซ้าย จับคู่กับฝั่งขวาที่เป็นการใช้งาน controller
และ method ตามด้วย parameter ที่จะส่งไปใช้งานใน controller (ถ้ามี) ตัวอย่างจากการกำหนดด้านบน
News::view/$1
กำหนด controller ตามด้วยเครื่อง :: (double-colon) และต่อด้วย method name หากมี parameter จะตามด้วย
"/" และ $x เมื่อ x คือลำดับของ paramemter ที่ต้องการจับคู่กับฝั่งซ้าย เรียงจาก 1 เป็นต้นไป
ตัวอย่างเพิ่มเติม เช่น
// เรียกใช้งานผ่านคำสั่ง $News->create() // News controller เรียกใช้ create() method News::create // เรียกใช้งานผ่านคำสั่ง $News->view(1, 23) // News controller เรียกใช้ vies() method โดยส่ง parameter 2 ค่าเข้าไปคือ 1 และ 23 News::view/1/23
Placeholders
เปรียบเสมือนตัวที่กำหนดรูปแบบของตำแหน่ง ที่กันที่ไว้ให้กับค่าที่ต้องการใช้ ตัวอย่างเช่น
$routes->add('product/(:num)', 'App\Catalog::productLookup');
ใน route ค่า "product" เป็น parameter แรก ของข้อความ ที่เราต้องการให้มีอยู่ใน url ในขณะที่ ตัว parameter
ตัวที่สอง เป็นรูปแบบ placeholder ที่เราต้องการสำหรับกำหนดใน url เป็น (:num) แสดงถึงเป็นเลขจำนวนเต็มบวกตั้งแต่
ค่า 1 เป็นต้นไป ถ้าใน url ที่เรียกใช้ ขึ้นต้นด้วยคำว่า "product" อยู่ใน segment แรก และมีตัวเลขจำนวนเต็มที่มากกว่า 0
อยู่ในตำแหน่ง segment ที่สอง จะหมายถึงการเรียกใช้งานไปยัง “App\Catalog class“ และ “productLookup” method
นั่นคือ
// เรียกใช้งานผ่านคำสั่ง App\Catalog::productLookup() ทั้งสองกรณีด้านล่าง example.com/product/1/ example.com/product/2/
placeholder ก็คือข้อความที่แสดงถึงรูปแบบ หรือ pattern ใน Regular Expression โดยในกระบวนการทำงานของ
routing ตัว placeholder จะถูกแทนที่ด้วยค่าของรูปแบบ Regular Expression ซึ่งจะทำให้อ่านเข้าใจง่ายเมื่อใช้รูปแบบ
เป็นข้อความ
ด้านล่างเป็นข้อความสำหรับกำหนด placeholder ให้กับรูปแบบที่ต้องการ ใน routes
(:any) จะหมายถึง ตัวอักษระ อักขระ ตัวเลข หรือค่าใดๆ ซึ่งรวมถึง / ที่เป็นตัวแบ่ง segmnet ด้วย
(:segment) จะหมายถึง ตัวอักษระ อักขระ ตัวเลข หรือค่าใดๆ แต่ต้องไม่มี /
(:num) จะหมายถึง ตัวเลขจำนวนเต็มบวกตั้งแต่ 1 เป็นต้นไป
(:alpha) จะหมายถึง ข้อความหรือพยัญชนะต่างๆ
(:alphanum) จะหมายถึง เป็นเลขจำนวนเต็มก็ได้ หรือเป็นข้อความพยัญชนะก็ได้ หรือเป็นทั้งสองค่ารวมกันก็ได้
(:hash) จะหมายถึง รูปแบบเดียวกันกับ (:segment)
ทำความเข้าใจเพิ่มเติมกับตัวอย่างด้านล่าง ดังนี้
$routes->add('journals', 'App\Blogs');
URL ที่มีคำว่า "journals" อยู่ใน segment แรก จะเป็นกำหนดให้ "App\Blogs" class เรียกใช้งาน index() method
จะเห็นว่า แม้จะไม่ได้กำหนด method ต่อเข้าไป แต่ก็สามารถอ้างอิงถึง default method หรือ method เริ่มต้นได้
$routes->add('blog/joe', 'Blogs::users/34');
URL ที่มี segment เป็น "blog/joe" จะจับคู่การทำงานกับ "Blogs" class และ users() method โดยมีการส่งค่า
ID เท่ากับ 34 เป็น parameter เข้าไปใช้งาน
$routes->add('product/(:any)', 'Catalog::productLookup');
URL ที่มีคำว่า "product" อยู่ใน segment แรก และมีค่าใดๆ ก็ตามอยู่ใน segment ที่สอง จะจับคู่การทำงานของ
"Catalog" class และ productLookup() method
$routes->add('product/(:num)', 'Catalog::productLookupByID/$1');
URL ที่มีคำว่า "product" อยู่ใน segment แรก และมีตัวเลขจำนวนเต็มอยู่ใน segment ที่สอง จับคู่การทำงานกับ
"Catalog" class และ productLookupByID() method โดยส่งค่าตัวแปรไปใช้งานผ่าน parameter ของ method
*ข้อสังเกต เราจะพบว่า ตัวอย่างหลายตัวข้างต้น มีการใช้งาน add() method ในการกำหนด routes ทำไมไม่ใช่รูปแบบ
ตามที่เรากำหนดในตัวอย่างตอนที่แล้ว ให้เราเข้าใจแบบนี้ว่าคำสั่ง add() จะครอบคลุมเงื่อนไขมากว่า นั่นคือไม่ว่าจะ
เรียกผ่าน HTTP request ใดๆ ก็ตาม ก็จะเข้าเงื่อนไขในคำสั่ง add() ถ้ารูปแบบตรงตามที่กำหนด ในขณะที่คำสั่ง get()
post() หรืออื่นๆ ก็จะเป็นการแยกแบบเฉพาะเจาะจง ว่าจะต้องเรียกไปยัง url นั้นๆ ผ่าน method ที่กำหนดจึงจะเข้าเงื่อนไข
ซึ่งถ้าเรามั่นใจ หรือต้องการให้เรียกผ่าน method เฉพาะโดยตรง เราก็ควรกำหนดโดยใช้รูปแบบคำสั่ง ตามค่า method นั้น
เพราะจะช่วยในเรื่องของการทำงานที่เร็วขึ้นมาบ้างเล็กน้อย และไม่จำเป็นต้องครอบคลุมการเรียกใช้งานทุก method
อย่างไรก็ตาม ในที่นี้ จะเป็นการอธิบายการใช้งานเป็นส่วนใหญ่ จึงใช้รูปแบบคำสั่ง add() เป็นหลัก เราสามารถไปปรับ
ใช้เองได้ตามความเหมาะสม
รูปแบบ PlaceHolder แบบกำหนดเอง
นอกจากเราจะสามารถเรียกใช้งานรูปแบบ placeholder ตามค่าที่มีมาให้แล้ว เรายังสามารถกำหนดชื่อรูปแบบเองได้
โดยวิธีง่ายๆ ตามที่เราอธิบายไป ว่า รูปแบบที่ใช้จะเป็น regular expression จับคู่กับชื่อที่เรากำหนด ดังนั้น สามารถทำ
ได้ดังนี้
$routes->addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); $routes->add('users/(:uuid)', 'Users::show/$1');
เราต้องกำหนดชื่อ placeholder ก่อนเรียกใช้งาน โดยใช้คำสั่ง addPlaceholder('ชื่อที่จะใช้', รูปแบบ Regex)
ตัวอย่างข้างต้น อาจจะดูยาก ลองปรับเป็นแบบนี้
$routes->addPlaceholder('uuid', '(\d){5}'); // เป็นต้วเลข 5 หลัก $routes->add('users/(:uuid)', 'Users::show/$1');
ดังนั้น url ที่จะเข้าเงื่อนไขก็เช่น
example.com/users/12345 example.com/users/99999
หรือกรณีที่เราไม่ต้องการกำหนดชื่อ placeholder แต่ใช้เป็น Regex เลยก็สามารถทำได้ดังนี้
$routes->add('users/((\d){5})', 'Users::show/$1');
การกำหนด Closures
เราสามารถใช้งาน anonymous ฟังก์ชั่น หรือที่เรียกว่า closures เพื่อกำหนดเป้าหมายหรือเส้นทางของ URL ได้
ฟังก์ชั่่นจะทำงานเมื่อผู้ใช้ไปยัง URL ที่เข้าเงื่อนไข เหมาะสำหรับใช้กำหนดหรือจัดการรูปแบบการทำงานเล็กๆ ที่เรา
ต้องการความรวดเร็วในการเรียกใช้ เช่น อาจจะสำหรับต้องการแสดงข้อมูลอย่างง่ายเบื้องต้น ดูตัวอย่างการกำหนด
จะเป็นตามรูปแบบด้านล่าง
$routes->add('feed', function() { $rss = new RSSFeeder(); // เรียกใช้งาน feed object return $rss->feed('general'); // แสดงข้อมูล feed });
การกำหนด Routes โดยวิธี Mapping
วิธีกำหนด route โดยการ mapping ด้วยคำสั่ง map() เป็นอีกวิธีในการกำหนด route ซึ่งแทนที่เราจะกำหนดแต่ละค่า
โดยใช้คำสั่ง add() ก็เปลี่ยนมาเป็น กำหนดรูปแบบการจับคู่กันของ URL กับ controller/method ในรูปแบบ array จากนั้น
ใช้คำสั่ง map() เพื่อกำหนดการทำงาน ซึ่งวิธีนี้ เราจะต้องทำตั้งแต่เริ่มต้น กับทุกๆ route ที่เรากำหนด นั่นคือ สมมติจาก
ค่าเดิมในบทความตอนที่แล้ว
$routes->get('/', 'Home::index'); $routes->match(['get'], 'news/delete/(:num)', 'News::delete/$1'); $routes->match(['get', 'post'], 'news/edit/(:num)', 'News::edit/$1'); $routes->match(['get', 'post'], 'news/create', 'News::create'); $routes->get('news/(:segment)', 'News::view/$1'); $routes->get('news', 'News::index'); $routes->get('(:any)', 'Pages::view/$1');
หากใช้ในรูปแบบ mapping ก็จะเป็นดังนี้
$routes_data['/'] = 'Home::index'; $routes_data['news/delete/(:num)'] = 'News::delete/$1'; $routes_data['news/edit/(:num)'] = 'News::edit/$1'; $routes_data['news/create'] = 'News::create'; $routes_data['news/(:segment)'] = 'News::view/$1'; $routes_data['news'] = 'News::index'; $routes_data['(:any)'] = 'Pages::view/$1'; $routes->map($routes_data);
การจัดกลุ่ม Routes
เราสามารถจัดกลุ่ม route ในกรณีที่การกำหนดชื่อ route นั้นๆ อยู่ในกลุ่มเดียวกัน เช่น กรณีของตัวอย่างเรา
ที่มีการกำหนด news เราก็สามารถเปลี่ยนส่วนที่ segment เพิ่มเติม มาไว้ในกลุ่มเดียวกันได้ ดังนี้
$routes->get('/', 'Home::index'); $routes->group('news', function($routes) { $routes->match(['get'], 'delete/(:num)', 'News::delete/$1'); $routes->match(['get', 'post'], 'edit/(:num)', 'News::edit/$1'); $routes->match(['get', 'post'], 'create', 'News::create'); $routes->get('(:segment)', 'News::view/$1'); $routes->get('/', 'News::index'); }); $routes->get('(:any)', 'Pages::view/$1');
จะเห็นว่า URL ที่ขึ้นตันด้วย "news" ถูกจัดอยู่ในกลุ่มด้วยคำสั่ง group() ทำให้เราสามารถแยกส่วนของ routes
ได้ชัดเจน และจัดการได้ง่ายขึ้น
เรายังสามารถกำหนด group ซ้อนกันเป็นโครงสร้างได้ สมมติอย่างเช่นใน URL ของระบบ admin ที่จะมีส่วนของ
user และ list ตามตัวอย่างดังนี้
$routes->group('admin', function($routes) { $routes->group('users', function($routes) { $routes->add('list', 'Admin\Users::list'); $routes->add('add', 'Admin\Users::add'); }); });
นั่นคือเราสามารถเรียกไปยัง URL ตามรูปแบบด้านล่างได้
example.com/admin/users/list example.com/admin/users/add
การใช้งาน HTTP verb ใน Routes
เราสามารถกำหนด rule ให้กับ routes โดยใช้ค่าจาก HTTP request method สังเกตจากเนื้อหาตอนที่แล้ว เราใช้
get() ซึ่งเป็นคำที่มาจาก HTTP request method ที่เป็น GET นั่นเอง การกำหนดในลักษณะนี้ จะเป็นประโยชน์อย่างมาก
สำหรับการสร้าง RESTFUL Api โดยเราสามารถใช้ค่าต่างๆ ของ HTTP verb เช่น GET POST PUT DELETE หรืออื่นๆ
ซึ่งแต่ละชื่อ ก็จะมี method ตรงตามชื่อนั้นๆ ตัวอย่างเช่น
$routes->get('products', 'Product::feature'); $routes->post('products', 'Product::feature'); $routes->put('products/(:num)', 'Product::feature'); $routes->delete('products/(:num)', 'Product::feature');
หรือเราจะใช้ๆ หลาย method ใน routes เดียวกันโดยใช้คำสั่ง match() แล้วกำหนด method ที่ต้องการให้สามารถ
เรียกใช้งานที่ URL นั้นๆ เป็น array ดังนี้
$routes->match(['get', 'put'], 'products', 'Product::feature');
การกำหนด Options
ในการกำหนด rule ให้กับ routes เราสามารถกำหนด Options เป็นตัวแปร array เพิ่มเติม ส่งไปในคำสั่งต่างๆ ที่ใช้
กำหนด routes ได้ โดยจะกำหนดเป็น parameter ค่าสุดท้าย เพื่อให้ทำงานบางอย่างเพิ่มเติม
$routes->add('from', 'to', $options); $routes->get('from', 'to', $options); $routes->post('from', 'to', $options); $routes->put('from', 'to', $options); $routes->head('from', 'to', $options); $routes->options('from', 'to', $options); $routes->delete('from', 'to', $options); $routes->patch('from', 'to', $options); $routes->match(['get', 'put'], 'from', 'to', $options); $routes->resource('photos', $options); $routes->map($array, $options); $routes->group('name', $options, function());
ตัวอย่างการกำหนด option เพื่อทำงานบางอย่างเพิ่มเติม เช่น
ใช้ Option กำหนดตัว Filter เพื่อทำงานเฉพาะ
ในการเรียกใช้งาน filter ร่วมกับ routing เราจะต้องกำหนดการทำงานของ filter ในไฟล์ app/Config/Filters.php
ก่อนเรียกใช้ สมมติเช่น เรากำหนดชื่อ filter เป็น 'admin-auth' เพื่อทำงานกำหนดสิทธิ์การเข้าใช้งานสำหรับส่วน admin
ที่ต้องผ่านล็อกอิน หรือได้รับสิทธิ์การใช้งานก่อนถึงจะเรียกใช้ส่วนนั้นๆ เมื่อเรียกใช้งานร่วมกับการกำหนด routes ก็เพิ่ม
ในส่วนของ option ที่เป็น array ดังนี้
$routes->add('admin',' AdminController::index', ['filter' => 'admin-auth']);
ส่วนของ filter 'admin-auth' จะทำงานก่อน แล้วจึงเรียกใช้งาน routes ที่กำหนดภายหลัง
เราสามารถกำหนด filter เพื่อทำงานหลังจากทำงานในส่วนของ routes เพิ่มเข้าไปได้ดังนี้
$routes->add('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']);
'admin-auth' จะเป็นส่วนของ filter ที่มีการส่งค่า array ['dual', 'noreturn'] ไปใช้ใน
before() และ after() method ของ filter
เกี่ยวกับ controller filter จะได้นำเสนออีกครั้งเพิ่มเติมในภายหลัง
ใช้ Option กำหนด Namespace
ปกติแล้วค่า default namespace จะถูงเพิ่มแทรกไว้ด้านหน้าของ controller แต่เราสามารถระบุ namespace อื่น
ที่ต้องการได้ เพื่อใช้งานการทำงานบางอย่าง โดยระบุ namespace option ดังนี้
// เรียกใช้งาน controller \Admin\Users::index() $routes->add('admin/users', 'Users::index', ['namespace' => 'Admin']);
การกำหนดลักษณะข้างต้น จะมีผลเฉพาะ routes ที่เรากำหนดเท่านั้น ถ้าต้องการให้ผลกับหลายๆ routes เราอาจจะกำหนด
ในส่วนของการเรียกใช้แบบ group() ได้
ใช้ Option จำกัดการเข้าถึงของ hostname
เราสามารถใช้วิธีการนี้ในการกำหนดใน group ของ routes ให้สามารถเรียกใช้งานได้เฉพาะ domain หรือ sub-domain
ที่กำหนดเท่านั้น โดยสามารถกำหนดในลักษรณะ ดังนี้
$routes->get('from', 'to', ['hostname' => 'accounts.example.com']);
ในตัวอย่าง การกำหนดข้างต้น จะทำให้สามารถเรียกใช้งานผ่าน URL ที่เป็น sub-domain “accounts.example.com” เท่านั้น
ไม่สามารถเรียกใช้งานจากเว็บไซต์หลักหรือ “example.com” ได้
ใช้ Option จำกัดการเข้าถึงของ Subdomain
ในกรณีเรากำหนดเป็น subdomain option ระบบจะเข้าถึงได้ routes ที่กำหนดได้เฉพาะ subdomain ที่กำหนดเท่านั้น
// เรียกใช้งานได้เฉพาะ media.example.com $routes->add('from', 'to', ['subdomain' => 'media']);
หรือกรณีให้สามารถเรียกใช้งานในทุกๆ subdomain ก็สามารถกำหนดเป็นค่า (*) ได้ ในลักษณะดังนี้
// เรียกใช้งานได้ทุกๆ sub-domain $routes->add('from', 'to', ['subdomain' => '*']);
อย่างไรก็ตาม การกำหนดค่าต่างๆ เหล่านี้ เราจำเป็นต้องทดสอบการทำงานก่อนใช้งานจริง ระบบอาจจะไม่ได้เป็นไปตาม
ที่ระบุก็ได้ เพราะอาจจะมีปัจจัยอื่นๆ ประกอบ เพื่อป้องกันความผิดพลาดควรทดสอบการใช้งานก่อน หากต้องการเรียกใช้
การตั้งค่าเริ่มต้นของ Routes
การตั้งค่าเริ่มต้น ซึ่งจะเป็นค่าที่มีผลกับการทำงานของ routes ทั้งหมด ให้เป็นไปตามที่เราต้องการ สามารถทำได้โดย
กำหนดในส่วนด้านบนของไฟล์ /app/Config/Routes.php ดังนี้
/** * -------------------------------------------------------------------- * Router Setup * -------------------------------------------------------------------- */ $routes->setDefaultNamespace('App\Controllers'); $routes->setDefaultController('Home'); $routes->setDefaultMethod('index'); $routes->setTranslateURIDashes(false); $routes->set404Override(); $routes->setAutoRoute(true);
การกำหนด Default Namespace
ค่าเริ่มต้นของ CI4 จะกำหนดการทำงานของ controller ไว้ที่โฟลเดอร์ app/controllers ตามค่า namespace ด้านบน
ดังนั้น เวลาเราจะสร้าง controller class เราก็จะสร้างไว้ในโฟลเดอร์นี้ เวลาเราเรียกใช้งาน
// Controller class คือ App\Controllers\Home $routes->get('/', 'Home::index'); // Controller class คือ App\Controllers\Pages $routes->get('(:any)', 'Pages::view/$1');
แต่ถ้าสมมติว่าเรากำหนดเป็นดังนี้
$routes->setDefaultNamespace('App');
นั่นคือโฟลเดอร์ที่เก็บ controller ก็จะอยู่ในโฟลเดอร์ app และค่าของ Controller ก็จะเปลี่ยนไปตามประมาณนี้
// Controller class คือ \App\Users $routes->add('users', 'Users::index'); // Controller class คือ \App\Admin\Users $routes->add('users', 'Admin\Users::index');
ถ้าเราต้องการเปลี่ยนตำแหน่งโฟลเดอร์ที่เก็บ controller class ก็สามารถเปลี่ยนค่า Default Namespace ตามต้องการ
การกำหนด Default Controller
เมื่อเราเข้าใช้งานเว็บไซต์ใดๆ เช่น mysslweb.com ค่า Default controller คือ class แรกที่จะถูกเรียกใช้งาน ไม้ว่าเรา
จะกำหนดใน url หรือไม่ก็ได้ ซึ่งใน CI4 มีค่าเริ่มต้นเป็น Home
Controller 'Home' ก็คือ 'Home' class ที่อยู่ในไฟล์ App\Controllers\Home.php จะเป็น class ที่ถูกเรียกใช้งาน
เมื่อเข้ามายังเว็บไซต์ mysslweb.com เป็นต้น เราสามารถกำหนด class อื่นตามต้องการได้ สมมติเช่น อยากให้ "Welcome"
เป็น Controller class หลัก ก็สามารถกำหนดเป็น
// เปิดไปหน้า mysslweb.com ก็จะเรียกใช้งาน app/Controllers/Welcome.php $routes->setDefaultController('Welcome');
เมื่อเรากำหนด default controller แล้ว จะมีผลกับทุกโฟลเดอร์ที่มีการกำหนดใช้งาน controller ตัวอย่างเช่น ถ้าเราต้องการ
เข้าใช้งานในส่วนของ admin ซึ่งอยู่ที่ mysslweb.com/admin โดยโฟลเดอร์ admin เป็นโฟลเดอร์ที่เก็บ controller สำหรับ
จัดการในส่วนของ admin ทั้งหมด URL เริ่มต้นที่ชี้ไปยัง "admin" ก็จะเรียก "Home" class มาใช้งาน นั่นคือ เป็นการเรียกไป
ที่ไฟล์ /app/Controllers/admin/Home.php
การกำหนด Default Method
เช่นเดียวกับรูบแบบการกำหนดการทำงานของ controller เมื่อเราเปิดไปหน้าเว็บไซต์ เรารู้แล้วว่า controller เริ่มต้นที่ถูก
เรียกใช้งานคือ "Home" ตามค่าที่กำหนด หลังจาก "Home" class ก็จะไปทำคำสั่ง หรือ method เริ่มต้น นั่นคือ เมื่อเราเข้า
ผ่านเว็บไซต์ CI เราก็จะเรียกไปยัง URL เท่ากับ mysslweb.com/home/index โดย "Home" คือ default controller และ
"index" คือ Default Method ซึ่งเราสามารถเรียกไปยัง URL ของเว็บไซต์ mysslweb.com ก็ได้ผลลัพธ์เหมือนกัน
$routes->setDefaultMethod('index');
การกำหนด Default Method มีผลในลักษณะคล้ายกันกับ controller นั่นคือ ถ้าเราเรียกใช้งาน controller class ใดๆ แล้ว
ไม่ได้กำหนด method ต่อท้าย ตัว CI4 ก็จะไปเรียก "index" method ใน class นั้นๆ มาใช้งาน
การแปลงเครื่อง (-) ขีดกลาง ใน URL
ในการใช้งาน URL เราสามารถกำหนด - ไว้ในชื่อของ controller class ได้ แต่เราไม่สามารถกำหนดชื่อของ controller class
ในไฟล์ให้มีเครื่อง - ได้ เช่น เราสามารถกำหนดใน URL เป็น mysslweb.com/admin-auth แต่เราจะไม่สามารถกำหนดชื่อ
Class เป็น Admin-auth ได้ แต่สามารถใช้เป็น _ (underscore) แทนได้
ดังนั้น CI4 จึงมีวิธีที่จะแปลง - ใน URL ให้เป็น _ เพื่อให้ตรงกับชื่อ class ที่เรียกใช้งาน โดยสามารถกำหนดค่าเป็น true
$routes->setTranslateURIDashes(true);
เมื่อกำหนดให้สามารถแปลงได้ เราสามารถเรียกใช้งาน mysslweb.com/admin-auth โดยจะเป็นการเรียไปที่ไฟล์
/app/Controllers/admin_auth.php
<?php namespace App\Controllers; use CodeIgniter\Controller; class Admin_auth extends Controller { }
การกำหนด AutoRoute
หากมีการกำหนดเป็นค่า true นั่นหมายถึงว่า หากไม่เจอ routes ที่ตรงกับ URL ที่เรียกใช้ ระบบก็จะพยายาม จับคู่ URL
ให้มีความสอดคล้องกับค่า controller class และ method นั่นคือ สมมติเราเรียกไปยัง URL เป็น
mysslweb.com/login
ระบบก็จะมองคำว่า login เป็น controller class ก็จะไปหาไฟล์ /app/Controllers/Login.php และหา method ที่ชื่อ
index เพื่อเรียกใช้งาน ให้โดยอัตโนมัติ ถึงเราไม่ได้กำหนด routes ก็ตาม
แต่ถ้าเรากำหนดค่าเป็น false เมือเรียกไปยัง URL ที่ไม่ได้กำหนด routes ไว้ ก็จะกลาย error 404 ไม่พบหน้าดังกล่าว
$routes->setAutoRoute(false);
การทำ Override หน้า Error 404
ใน CI4 เวลาเราเรียกไปยังหน้าเพจที่ไม่มีอยู่จริง ก็จะถูกเปลี่ยนไปหน้า Error 404 ซึ่งเป็นหน้าเพจที่ CI4 กำหนดมาให้
เราสามารถกำหนดหน้าตาของ หน้า Error 404 โดยทำการ Override ได้ในรูปแบบดังนี้
// หรือให้เรียก App\Errors class และใช้งาน methd show404 ที่เรากำหนดขึ้น $routes->set404Override('App\Errors::show404'); // หรือแบบนี้ก็ได้ // ให้แสดงหน้าที่เรากำหนดเองในไฟล์ app/Views/my_errors/not_found.html $routes->set404Override(function() { echo view('my_errors/not_found.html'); });
เนื้อหาตอนนี้ ถือว่าเป็นการทำความรู้จัก และเรียนรู้การใช้งาน การตั้งค่า การกำหนดค่าต่างของ URL และ URI Routing
เป็นแนวทางให้เราสามารถจัดการกับ controller ในเนื้อหาต่อไป ได้มากขึ้น