โปรเจ็คตัวอย่างเว็บไซต์ร้านค้าออนไลน์ที่ใช้ Javascript API ในการแสดงสินค้า ตอนที่ 2
ไฟล์แรก คือ api.php เป็นไฟล์หลักสำหรับการเรียก API ครับ สามารถใช้ชื่ออื่นก็ได้ (ตัวอย่างนี้มีการใช้ index.php เป็นหน้าเว็บหลักไปแล้ว) จุดที่สำคัญในไฟล์นี้คือมีการกำหนดค่า Router ไปที่ \Gcms\Router และ Controller ไปที่ \Index\Api\Controller
<?php
/**
* api.php
* หน้าเพจสำหรับให้ API เรียกมา
*
* @author Goragod Wiriya <admin@goragod.com>
* @link http://www.kotchasan.com/
* @copyright 2016 Goragod.com
* @license http://www.kotchasan.com/license/
*/
// load Kotchasan
include 'load.php';
// Initial Kotchasan Framework
$app = Kotchasan::createWebApplication('Gcms\Config');
$app->defaultRouter = 'Gcms\Router';
$app->defaultController = 'Index\Api\Controller';
$app->run();
ไฟล์ที่สอง Gcms/Router.php หรือคลาส \Gcms\Router
<?php
/**
* @filesource Gcms/Login.php
* @link http://www.kotchasan.com/
* @copyright 2016 Goragod.com
* @license http://www.kotchasan.com/license/
*/
namespace Gcms;
/**
* Router Class สำหรับ GCMS
*
* @author Goragod Wiriya <admin@goragod.com>
*
* @since 1.0
*/
class Router extends \Kotchasan\Router
{
/**
* กฏของ Router สำหรับการแยกหน้าเว็บไซต์
*
* @var array
*/
protected $rules = array(
// api.php/products/<category_id>/<page>
'/api\.php\/(products)\/([0-9]+)\/([0-9]+)/i' => array('action', 'category_id', 'page'),
// api.php/products/<page>
'/api\.php\/(products)\/([0-9]+)/i' => array('action', 'page'),
// api.php/search/<q>/<page>
'/api\.php\/(search)\/([^\/]+|$)(\/([0-9]+))?/i' => array('action', 'q', '', 'page'),
// api.php/<action>/<id>
'/api\.php\/([a-z]+)(\/([0-9]+))?/i' => array('action', '', 'id'),
);
}
ใจความสำคัญของคลาสนี้คือมีการกำหนด $rules สำหรับกฏของ Router ในการแยกหน้า ตัวอย่างเช่น
'/api\.php\/(products)\/([0-9]+)\/([0-9]+)/i' => array('action', 'category_id', 'page'),
- (products) จะถูก map ไปที่ action ได้ action=products
- ([0-9]+) จะถูก map ไปที่ category_id ได้ category_id=xxx
- ([0-9]+) จะถูก map ไปที่ page ได้ page=xxx
ไฟล์ที่สาม modules/index/controllers/api.php หรือ \Index\Api\Controller ซึ่งเป็น Controller หลักของ API
<?php
/**
* @filesource modules/index/controllers/api.php
* @link http://www.kotchasan.com/
* @copyright 2016 Goragod.com
* @license http://www.kotchasan.com/license/
*/
namespace Index\Api;
use \Kotchasan\Http\Request;
/**
* Controller สำหรับโหลดข้อมูลด้วย Ajax
*
* @author Goragod Wiriya <admin@goragod.com>
*
* @since 1.0
*/
class Controller extends \Kotchasan\Controller
{
/**
* มาจากการเรียกด้วย Ajax
*
* @param Request $request
*/
public function index(Request $request)
{
$action = $request->get('action')->filter('a-z');
if (method_exists('Index\Api\Model', $action)) {
$result = \Index\Api\Model::$action($request);
}
if (!isset($result)) {
$result = array(
'error' => array(
'code' => 400,
'message' => 'bad request'
)
);
}
// Response
$response = new \Kotchasan\Http\Response;
$response->withHeaders(array(
'Content-type' => 'application/json; charset=UTF-8'
))
->withContent(json_encode($result))
->send();
}
}
คลาสนี้มีหน้าที่ในการเลือก Model ที่ต้องการจาก Request ที่ส่งมาจาก Router (ตัวแปร $request) และทำการส่งกลับข้อมูลรูปแบบ JSON ผ่าน Response
$action = $request->get('action')->filter('a-z');
เมธอดที่ต้องการส่งมาจาก Router ที่พารามิเตอร์ get('action') หรือเทียบเท่า $_GET['action']
if (method_exists('Index\Api\Model', $action)) {
นำเมธอดไปตรวจสอบว่ามีหรือไม่ในคลาส Index\Api\Model
$result = \Index\Api\Model::$action($request);
ถ้ามีก็จะเรียกใช้เมธอด คืนค่าผลลัพท์ที่ตัวแปร $result
ในกรณีที่ไม่พบเมธอด ตัวแปร $result จะถูกกำนดค่า error ไปแทน
และสุดท้ายคืนค่าผลลัพท์เป็น JSON โดยใช้คลาส Response
// Response
$response = new \Kotchasan\Http\Response;
$response->withHeaders(array(
'Content-type' => 'application/json; charset=UTF-8'
))
->withContent(json_encode($result))
->send();
ไฟล์สุดท้าย modules/index/models/api.php หรือคลาส \Index\Api\Model ซึ่งเป็น Model ที่ Controller เรียกใช้ (ผมจะอธิบายทีละเมธอดเลยนะครับ)
/**
* คืนค่ารายการหมวดหมู่ทั้งหมด
*
* @param Request $request
* @return array
*/
public static function categories(Request $request)
{
$query = static::create()->db()->createQuery()
->select('category_id', 'topic')
->from('category')
->where(array('type', 0))
->order('category_id')
->toArray()
->cacheOn();
$result = array();
foreach ($query->execute() as $item) {
$result[] = array(
'category_id' => $item['category_id'],
'topic' => $item['topic'],
);
}
return $result;
}
เมธอดแรก คืนค่าหมวดหมู่ทั้งหมด หรือเทียบเท่า SQL Query เป็น
SELECT category_id, topic FROM category WHERE type=0 ORDER BY category_id
เมธอด products คืนค่ารายการสินค้าที่เกี่ยวข้องตามพารามิเตอร์ที่ส่งมา เมธอดนี้จะทำหน้าที่หลายอย่าง เช่น query ข้อมูลสินค้าที่ต้องการตามหมวดหมู่ รวมถึง query ข้อมูลที่มาจากการค้นหา และส่งกลับข้อมูลสำหรับการแบ่งหน้าการแสดงผลด้วย
/**
* คืนค่ารายการสินค้า ถ้ามีการระบุ id มา หมายถึงสินค้าในหมวดที่เลือก
*
* @param Request $request
* @return array
*/
public static function products(Request $request)
{
// ค่าที่ส่งมา
$q = $request->get('q')->topic();
$category_id = $request->get('category_id')->toInt();
$page = $request->get('page')->toInt();
$list_per_page = $request->get('limit', 30)->toInt();
// ตัวแปรสำหรับส่งค่ากลับ
$result = array();
// Model
$model = new static;
$query = $model->db()->createQuery()->from('product');
if ($category_id > 0) {
$query->where(array('category_id', $category_id));
$result['category_id'] = $category_id;
}
$where = array();
if ($q != '') {
foreach (explode(' ', $q) as $item) {
$where[] = array('product_no', 'LIKE', "%$item%");
$where[] = array('topic', 'LIKE', "%$item%");
$where[] = array('description', 'LIKE', "%$item%");
}
}
if (!empty($where)) {
$query->andWhere(\Kotchasan\Database\Sql::WHERE($where, 'OR'));
$result['q'] = $q;
}
// จำนวน
$result['total'] = $query->cacheOn()->count();
$result['totalpage'] = ceil($result['total'] / $list_per_page);
$result['page'] = max(1, ($page > $result['totalpage'] ? $result['totalpage'] : $page));
$result['start'] = $list_per_page * ($result['page'] - 1);
// query
$result['items'] = $query->order('id')
->select()
->order('topic', 'product_no')
->limit($list_per_page, $result['start'])
->cacheOn()
->toArray()
->execute();
// คืนค่า
return $result;
}
เมธอดถัดมา เมธอด serach จะไปเรียกใช้เมธอด products อีกที
/**
* ค้นหารายการสินค้า จาก product_no topic description
*
* @param Request $request
* @return array
*/
public static function search(Request $request)
{
return self::products($request);
}
เมธอดสุดท้าย อ่านค่าสินค้าที่เลือกจาก ID ของสินค้า
/**
* คืนค่ารายละเอียดของสินค้าที่ id
*
* @param Request $request
* @return array
*/
public static function product(Request $request)
{
return static::create()->db()->createQuery()
->from('product')
->where(array('id', $request->get('id')->toInt()))
->cacheOn()
->toArray()
->first();
}
จะได้ SQL ประมาณนี้
SELECT * FROM product WHERE id=? LIMIT 1
ผลลัพท์ของ Query ทั้งหมด จะส่งกลับเป็นแอเรย์ กลับไปที่ Controller เพื่อใช้ในการส่งค่ากลับต่อไป
{
"id": 1,
"product_no": "0111900300104",
"topic": "Welness Smart Chek เครื่องตรวจวัดน้ำตาลกลูโคสในเลือด",
"description": "ตรวจวัดระดับน้ำตาลได้รวดเร็วแม่นยำ ด้วยวิธีการง่ายๆแค่ 4 ขั้นตอน",
"price": "1990.00",
"url": "http://www.tvdirect.tv/welness-smart-check",
"image": "http://cdns.cdntvdirect.com/media/catalog/product/s/m/smart-chek_1_2.jpg",
"last_update": 0,
"vat": "0.00",
"unit": "",
"category_id": 29,
"count_stock": 0
}
ตัวอย่างด้านบนเป็นผลลัพท์ของ API ในรูปแบบ JSON ที่ส่งกลับ
เพิ่มเติม สำหรับการใช้งาน API ที่อาจมีปัญหาการร้องขอข้อมูลจากเว็บไซต์ต่าง URL กัน (API อยู่โดเมนหนึ่ง และ เว็บไซต์ที่เรียกใช้อยู่อีกโดเมนหนึ่ง) ให้กำหนดค่า Apache ให้ยอมรับการร้องขอข้อมูลโดยการกำหนดที่ไฟล์ .htaccess
RewriteEngine On
# Cross domain access
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
สำหรับโปรแกรมที่ผมใช้สำหรับทดสอบการทำงานของ API ผมใช้ตัวนี้เลยครับ https://install.advancedrestclient.com (ตัวที่เป็น extension ของ Chrome ก็มี)
อ่านต่อตอนสุดท้ายคลิกลิงค์ด้านล่างเลยครับ