Kotchasan Framework Documentation
การสร้างฟอร์มและ HTML
การสร้างฟอร์มและ HTML
Kotchasan Framework มีชุดคลาสที่ครอบคลุมสำหรับการสร้างฟอร์มและการจัดการ HTML ตั้งแต่การสร้างฟิลด์อินพุตพื้นฐาน การจัดการตาราง จนถึงการสร้างเลย์เอาต์ที่ซับซ้อน
สารบัญ
- Form Class - การสร้างฟิลด์ฟอร์ม
- Html Class - การจัดการ HTML Elements
- HtmlTable Class - การสร้างตาราง
- Grid Class - การจัดการเลย์เอาต์กริด
- การใช้งานในระบบจริง
- Best Practices
Form Class - การสร้างฟิลด์ฟอร์ม
Input Fields พื้นฐาน
use Kotchasan\Form;
// Text input
$textInput = Form::text([
'id' => 'username',
'name' => 'username',
'class' => 'g-input',
'placeholder' => 'กรุณากรอกชื่อผู้ใช้',
'maxlength' => 50,
'required' => true
]);
// Password input
$passwordInput = Form::password([
'id' => 'password',
'name' => 'password',
'class' => 'g-input',
'placeholder' => 'กรุณากรอกรหัสผ่าน',
'required' => true
]);
// Email input with validation
$emailInput = Form::email([
'id' => 'email',
'name' => 'email',
'class' => 'g-input',
'placeholder' => 'name@example.com',
'required' => true,
'title' => 'กรุณากรอกอีเมลที่ถูกต้อง'
]);
// Number input
$ageInput = Form::number([
'id' => 'age',
'name' => 'age',
'class' => 'g-input',
'min' => 1,
'max' => 120,
'placeholder' => 'อายุ'
]);Select และ Options
// Simple select
$countrySelect = Form::select([
'id' => 'country',
'name' => 'country',
'class' => 'g-select',
'options' => [
'TH' => 'ประเทศไทย',
'US' => 'สหรัฐอเมริกา',
'JP' => 'ญี่ปุ่น',
'UK' => 'สหราชอาณาจักร'
],
'value' => 'TH' // ค่าเริ่มต้น
]);
// Select with grouped options
$productSelect = Form::select([
'id' => 'product',
'name' => 'product',
'class' => 'g-select',
'options' => [
'Electronics' => [
'laptop' => 'โน๊ตบุ๊ก',
'smartphone' => 'สมาร์ทโฟน',
'tablet' => 'แท็บเล็ต'
],
'Clothing' => [
'shirt' => 'เสื้อเชิ้ต',
'pants' => 'กางเกง',
'shoes' => 'รองเท้า'
]
],
'required' => true
]);
// Multi-select
$skillsSelect = Form::select([
'id' => 'skills',
'name' => 'skills[]',
'class' => 'g-select',
'multiple' => true,
'size' => 5,
'options' => [
'php' => 'PHP',
'javascript' => 'JavaScript',
'python' => 'Python',
'java' => 'Java',
'css' => 'CSS/HTML'
]
]);Checkbox และ Radio
// Single checkbox
$agreeCheckbox = Form::checkbox([
'id' => 'agree',
'name' => 'agree',
'value' => '1',
'checked' => false
]);
// Radio group
$genderOptions = [
'M' => 'ชาย',
'F' => 'หญิง',
'O' => 'อื่นๆ'
];
foreach ($genderOptions as $value => $label) {
$genderRadio = Form::radio([
'id' => 'gender_' . $value,
'name' => 'gender',
'value' => $value,
'checked' => ($value === 'M') // เซ็ตค่าเริ่มต้น
]);
}
// Checkbox group
$hobbies = [
'reading' => 'อ่านหนังสือ',
'music' => 'ฟังเพลง',
'sports' => 'กีฬา',
'travel' => 'ท่องเที่ยว',
'cooking' => 'ทำอาหาร'
];
foreach ($hobbies as $value => $label) {
$hobbyCheckbox = Form::checkbox([
'id' => 'hobby_' . $value,
'name' => 'hobbies[]',
'value' => $value
]);
}ฟิลด์พิเศษ
// File upload
$avatarUpload = Form::file([
'id' => 'avatar',
'name' => 'avatar',
'accept' => 'image/*',
'class' => 'g-file'
]);
// Multiple file upload
$documentsUpload = Form::file([
'id' => 'documents',
'name' => 'documents[]',
'multiple' => true,
'accept' => '.pdf,.doc,.docx,.txt'
]);
// Date input
$birthdateInput = Form::date([
'id' => 'birthdate',
'name' => 'birthdate',
'class' => 'g-input',
'max' => date('Y-m-d'), // ไม่เกินวันปัจจุบัน
'required' => true
]);
// DateTime-local input
$appointmentInput = Form::datetime([
'id' => 'appointment',
'name' => 'appointment',
'class' => 'g-input',
'min' => date('Y-m-d\TH:i'), // ไม่น้อยกว่าปัจจุบัน
'step' => 1800 // ทุก 30 นาที
]);
// Color picker
$colorInput = Form::color([
'id' => 'theme_color',
'name' => 'theme_color',
'value' => '#3498db'
]);
// Range slider
$volumeRange = Form::range([
'id' => 'volume',
'name' => 'volume',
'min' => 0,
'max' => 100,
'value' => 50,
'step' => 1
]);
*/Currency และ Number Format
// Currency input (Thai Baht)
$priceInput = Form::currency([
'id' => 'price',
'name' => 'price',
'class' => 'g-input',
'placeholder' => '0.00',
'min' => 0,
'step' => 0.01,
'currency' => 'THB'
]);
// Integer input
$quantityInput = Form::integer([
'id' => 'quantity',
'name' => 'quantity',
'class' => 'g-input',
'min' => 1,
'max' => 999,
'value' => 1
]);Buttons
// Submit button
$submitButton = Form::submit([
'id' => 'submit_btn',
'class' => 'button save large',
'value' => 'บันทึกข้อมูล'
]);
// Reset button
$resetButton = Form::reset([
'id' => 'reset_btn',
'class' => 'button cancel',
'value' => 'ล้างข้อมูล'
]);
// Custom button
$customButton = Form::button([
'id' => 'custom_btn',
'class' => 'button action',
'value' => 'ดำเนินการ',
'onclick' => 'handleCustomAction()'
]);Html Class - การจัดการ HTML Elements
การสร้างฟอร์มที่สมบูรณ์
use Kotchasan\Html;
// สร้างฟอร์มหลัก
$form = Html::create('form', [
'id' => 'user_form',
'class' => 'setup_frm',
'method' => 'post',
'action' => 'index.php/demo/save',
'autocomplete' => 'off',
'ajax' => true,
'token' => true
]);
// เพิ่ม fieldset
$personalInfo = $form->add('fieldset', [
'title' => 'ข้อมูลส่วนตัว',
'titleClass' => 'icon-user'
]);
// เพิ่มกลุ่มฟิลด์
$nameGroup = $personalInfo->add('groups');
// ชื่อจริง
$nameGroup->add('label', [
'for' => 'first_name',
'innerHTML' => 'ชื่อจริง <span class="required"></span>'
]);
$nameGroup->add('input', [
'type' => 'text',
'id' => 'first_name',
'name' => 'first_name',
'class' => 'g-input',
'maxlength' => 50,
'required' => true
]);
// นามสกุล
$nameGroup->add('label', [
'for' => 'last_name',
'innerHTML' => 'นามสกุล <span class="required"></span>'
]);
$nameGroup->add('input', [
'type' => 'text',
'id' => 'last_name',
'name' => 'last_name',
'class' => 'g-input',
'maxlength' => 50,
'required' => true
]);Input Groups และ Row Groups
// Input groups สำหรับการจัดกลุ่มฟิลด์
$contactGroup = $personalInfo->add('inputgroups');
// อีเมล
$emailRow = $contactGroup->add('groups');
$emailRow->add('label', [
'for' => 'email',
'innerHTML' => 'อีเมล <span class="required">*</span>'
]);
$emailRow->add('input', [
'type' => 'email',
'id' => 'email',
'name' => 'email',
'class' => 'g-input',
'required' => true,
'pattern' => '[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$'
]);
// เบอร์โทรศัพท์
$phoneRow = $contactGroup->add('groups');
$phoneRow->add('label', [
'for' => 'phone',
'innerHTML' => 'เบอร์โทรศัพท์'
]);
$phoneRow->add('input', [
'type' => 'tel',
'id' => 'phone',
'name' => 'phone',
'class' => 'g-input',
'pattern' => '[0-9]{9,10}'
]);Radio Groups และ Checkbox Groups
// Radio groups
$genderGroup = $personalInfo->add('radiogroups', [
'label' => 'เพศ <span class="required">*</span>',
'labelClass' => 'g-input',
'name' => 'gender',
'options' => [
'M' => 'ชาย',
'F' => 'หญิง',
'O' => 'ไม่ระบุ'
],
'value' => 'M' // ค่าเริ่มต้น
]);
// Checkbox groups
$skillsGroup = $personalInfo->add('checkboxgroups', [
'label' => 'ทักษะ',
'labelClass' => 'g-input',
'name' => 'skills[]',
'options' => [
'php' => 'PHP',
'javascript' => 'JavaScript',
'mysql' => 'MySQL',
'css' => 'CSS/HTML',
'python' => 'Python'
],
'value' => ['php', 'mysql'] // ค่าเริ่มต้นที่เลือก
]);Menu Button และ Dropdown
// Menu button พร้อม dropdown
$actionMenu = $form->add('menubutton', [
'class' => 'button action',
'text' => 'เลือกการดำเนินการ',
'options' => [
[
'text' => 'บันทึกและส่ง',
'onclick' => 'submitForm("send")'
],
[
'text' => 'บันทึกร่าง',
'onclick' => 'submitForm("draft")'
],
'-', // separator
[
'text' => 'ส่งออก PDF',
'onclick' => 'exportPDF()'
],
[
'text' => 'ส่งออก Excel',
'onclick' => 'exportExcel()'
]
]
]);การใช้ CKEditor
// Rich text editor
$descriptionEditor = $form->add('ckeditor', [
'id' => 'description',
'name' => 'description',
'height' => 300,
'language' => 'th',
'toolbar' => [
['Bold', 'Italic', 'Underline'],
['NumberedList', 'BulletedList'],
['Link', 'Unlink'],
['Image', 'Table'],
['Source']
],
'value' => '<p>เนื้อหาเริ่มต้น</p>'
]);การจัดการ JavaScript
// เพิ่ม JavaScript ลงในฟอร์ม
$form->script('
// Validation เบื้องต้น
document.getElementById("user_form").addEventListener("submit", function(e) {
var firstName = document.getElementById("first_name").value;
var lastName = document.getElementById("last_name").value;
if (!firstName.trim() || !lastName.trim()) {
alert("กรุณากรอกชื่อและนามสกุล");
e.preventDefault();
return false;
}
// ตรวจสอบรูปแบบอีเมล
var email = document.getElementById("email").value;
var emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (email && !emailPattern.test(email)) {
alert("รูปแบบอีเมลไม่ถูกต้อง");
e.preventDefault();
return false;
}
return true;
});
');HtmlTable Class - การสร้างตาราง
การสร้างตารางพื้นฐาน
use Kotchasan\HtmlTable;
// สร้างตารางใหม่
$table = new HtmlTable([
'id' => 'users_table',
'class' => 'data fullwidth',
'border' => 0
]);
// เพิ่ม caption
$table->addCaption('รายชื่อผู้ใช้งานในระบบ');
// เพิ่ม header
$table->addHeader([
'รหัส',
'ชื่อ-นามสกุล',
'อีเมล',
'สถานะ',
'วันที่สมัคร',
'การจัดการ'
]);
// เพิ่มข้อมูลแถว
$users = [
[
'id' => 1,
'name' => 'สมชาย ใจดี',
'email' => 'somchai@example.com',
'status' => 'active',
'created' => '2024-01-15',
'actions' => ['edit', 'delete']
],
[
'id' => 2,
'name' => 'สมหญิง รักเรียน',
'email' => 'somying@example.com',
'status' => 'inactive',
'created' => '2024-01-20',
'actions' => ['edit', 'delete']
]
];
foreach ($users as $user) {
// สร้างปุ่มการจัดการ
$actions = [];
if (in_array('edit', $user['actions'])) {
$actions[] = '<a href="edit.php?id=' . $user['id'] . '" class="icon-edit" title="แก้ไข"></a>';
}
if (in_array('delete', $user['actions'])) {
$actions[] = '<a href="javascript:void(0)" onclick="confirmDelete(' . $user['id'] . ')" class="icon-delete" title="ลบ"></a>';
}
// สถานะแบดจ์
$statusBadge = $user['status'] === 'active'
? '<span class="badge green">ใช้งาน</span>'
: '<span class="badge red">ไม่ใช้งาน</span>';
$table->addRow([
$user['id'],
$user['name'],
$user['email'],
$statusBadge,
date('d/m/Y', strtotime($user['created'])),
implode(' ', $actions)
]);
}
// เพิ่ม footer (ถ้าต้องการ)
$footerRow = \Kotchasan\TableRow::create();
$footerRow->addCell('รวม ' . count($users) . ' รายการ', [
'colspan' => 6,
'class' => 'center'
]);
$table->addFooter($footerRow);การสร้างตารางข้อมูลแบบซับซ้อน
// ตารางรายงานยอดขาย
$salesTable = new HtmlTable([
'id' => 'sales_report',
'class' => 'data responsive fullwidth'
]);
$salesTable->addCaption('รายงานยอดขายรายเดือน');
// Header แบบ multi-level
$salesTable->addHeader([
['text' => 'เดือน', 'rowspan' => 2],
['text' => 'ยอดขาย', 'colspan' => 3],
['text' => 'เปรียบเทียบ', 'rowspan' => 2]
]);
$salesTable->addHeader([
'เป้าหมาย',
'ยอดจริง',
'ร้อยละ'
]);
// ข้อมูลยอดขาย
$salesData = [
['มกราคม', 100000, 95000, 95.0, '+5%'],
['กุมภาพันธ์', 120000, 135000, 112.5, '+12%'],
['มีนาคม', 110000, 108000, 98.2, '-2%']
];
foreach ($salesData as $data) {
$row = [];
$row[] = $data[0]; // เดือน
$row[] = number_format($data[1]); // เป้าหมาย
$row[] = number_format($data[2]); // ยอดจริง
// ร้อยละ พร้อมสีตามผลงาน
$percentage = $data[3];
$percentageClass = $percentage >= 100 ? 'text-success' : 'text-warning';
$row[] = '<span class="' . $percentageClass . '">' . $percentage . '%</span>';
// การเปรียบเทียบ
$comparison = $data[4];
$comparisonClass = str_starts_with($comparison, '+') ? 'text-success' : 'text-danger';
$row[] = '<span class="' . $comparisonClass . '">' . $comparison . '</span>';
$salesTable->addRow($row);
}
// เพิ่มแถวสรุป
$totalRow = \Kotchasan\TableRow::create(['class' => 'summary']);
$totalRow->addCell('รวม', ['class' => 'bold']);
$totalRow->addCell(number_format(330000), ['class' => 'bold']);
$totalRow->addCell(number_format(338000), ['class' => 'bold']);
$totalRow->addCell('<span class="text-success bold">102.4%</span>');
$totalRow->addCell('<span class="text-success bold">+2.4%</span>');
$salesTable->addFooter($totalRow);Grid Class - การจัดการเลย์เอาต์กริด
การใช้งาน Grid System
use Kotchasan\Grid;
// สร้าง grid container
$grid = new Grid();
$grid->setCols(12); // ระบบ 12 คอลัมน์
// เพิ่มเนื้อหาลงใน grid
$content = '
<div class="ggrid">
<div class="block4 tablet6 mobile12">
<div class="card">
<h3>สถิติผู้ใช้งาน</h3>
<div class="stat-number">1,234</div>
<div class="stat-text">ผู้ใช้งานทั้งหมด</div>
</div>
</div>
<div class="block4 tablet6 mobile12">
<div class="card">
<h3>ยอดขายวันนี้</h3>
<div class="stat-number">฿45,680</div>
<div class="stat-text">เพิ่มขึ้น 12%</div>
</div>
</div>
<div class="block4 tablet12 mobile12">
<div class="card">
<h3>คำสั่งซื้อใหม่</h3>
<div class="stat-number">28</div>
<div class="stat-text">รอการยืนยัน</div>
</div>
</div>
</div>';
// Responsive grid layout
$responsiveLayout = '
<div class="ggrid">
<!-- Main content -->
<div class="block8 tablet12 mobile12">
<div class="content-area">
<h2>เนื้อหาหลัก</h2>
<p>เนื้อหาของหน้าเว็บไซต์...</p>
</div>
</div>
<!-- Sidebar -->
<div class="block4 tablet12 mobile12">
<div class="sidebar">
<h3>เมนูด้านข้าง</h3>
<ul>
<li><a href="#section1">หัวข้อ 1</a></li>
<li><a href="#section2">หัวข้อ 2</a></li>
<li><a href="#section3">หัวข้อ 3</a></li>
</ul>
</div>
</div>
</div>';การใช้งานในระบบจริง
ฟอร์มสมัครสมาชิก
use Kotchasan\Html;
use Kotchasan\Form;
class RegistrationForm
{
public static function create()
{
// สร้างฟอร์มหลัก
$form = Html::create('form', [
'id' => 'registration_form',
'class' => 'setup_frm',
'method' => 'post',
'action' => 'index.php/register/save',
'autocomplete' => 'off',
'ajax' => true,
'token' => true
]);
// ข้อมูลส่วนตัว
$personalSection = $form->add('fieldset', [
'title' => 'ข้อมูลส่วนตัว',
'titleClass' => 'icon-user'
]);
// ชื่อ-นามสกุล
$nameGroup = $personalSection->add('groups');
$nameGroup->add('label', [
'for' => 'first_name',
'innerHTML' => 'ชื่อจริง <span class="required"></span>'
]);
$nameGroup->add('input', [
'type' => 'text',
'id' => 'first_name',
'name' => 'first_name',
'class' => 'g-input',
'maxlength' => 50,
'required' => true,
'autofocus' => true
]);
$nameGroup->add('label', [
'for' => 'last_name',
'innerHTML' => 'นามสกุล <span class="required"></span>'
]);
$nameGroup->add('input', [
'type' => 'text',
'id' => 'last_name',
'name' => 'last_name',
'class' => 'g-input',
'maxlength' => 50,
'required' => true
]);
// อีเมลและรหัสผ่าน
$credentialGroup = $personalSection->add('groups');
$credentialGroup->add('label', [
'for' => 'email',
'innerHTML' => 'อีเมล <span class="required"></span>'
]);
$credentialGroup->add('input', [
'type' => 'email',
'id' => 'email',
'name' => 'email',
'class' => 'g-input',
'required' => true
]);
$credentialGroup->add('label', [
'for' => 'password',
'innerHTML' => 'รหัสผ่าน <span class="required"></span>'
]);
$credentialGroup->add('input', [
'type' => 'password',
'id' => 'password',
'name' => 'password',
'class' => 'g-input',
'minlength' => 8,
'required' => true
]);
// เพศ
$genderGroup = $personalSection->add('radiogroups', [
'label' => 'เพศ <span class="required"></span>',
'labelClass' => 'g-input',
'name' => 'gender',
'options' => [
'M' => 'ชาย',
'F' => 'หญิง',
'O' => 'ไม่ระบุ'
]
]);
// วันเกิด
$birthdateGroup = $personalSection->add('groups');
$birthdateGroup->add('label', [
'for' => 'birthdate',
'innerHTML' => 'วันเกิด'
]);
$birthdateGroup->add('input', [
'type' => 'date',
'id' => 'birthdate',
'name' => 'birthdate',
'class' => 'g-input',
'max' => date('Y-m-d')
]);
// ข้อมูลติดต่อ
$contactSection = $form->add('fieldset', [
'title' => 'ข้อมูลติดต่อ',
'titleClass' => 'icon-phone'
]);
// โทรศัพท์
$phoneGroup = $contactSection->add('groups');
$phoneGroup->add('label', [
'for' => 'phone',
'innerHTML' => 'เบอร์โทรศัพท์'
]);
$phoneGroup->add('input', [
'type' => 'tel',
'id' => 'phone',
'name' => 'phone',
'class' => 'g-input',
'pattern' => '[0-9]{9,10}',
'placeholder' => '0812345678'
]);
// ที่อยู่
$addressGroup = $contactSection->add('groups');
$addressGroup->add('label', [
'for' => 'address',
'innerHTML' => 'ที่อยู่'
]);
$addressGroup->add('textarea', [
'id' => 'address',
'name' => 'address',
'class' => 'g-input',
'rows' => 3,
'placeholder' => 'ที่อยู่ปัจจุบัน'
]);
// จังหวัด
$provinceGroup = $contactSection->add('groups');
$provinceGroup->add('label', [
'for' => 'province',
'innerHTML' => 'จังหวัด'
]);
$provinceGroup->add('select', [
'id' => 'province',
'name' => 'province',
'class' => 'g-select',
'options' => self::getProvinceOptions()
]);
// เงื่อนไขการใช้งาน
$termsSection = $form->add('fieldset', [
'title' => 'เงื่อนไขการใช้งาน',
'titleClass' => 'icon-verfied'
]);
$termsGroup = $termsSection->add('groups');
$termsGroup->add('label', [
'for' => 'accept_terms',
'innerHTML' => 'ยอมรับ <a href="terms.php" target="_blank">เงื่อนไขการใช้งาน</a> <span class="required"></span>'
]);
$termsGroup->add('input', [
'type' => 'checkbox',
'id' => 'accept_terms',
'name' => 'accept_terms',
'value' => '1',
'required' => true
]);
$newsletterGroup = $termsSection->add('groups');
$newsletterGroup->add('label', [
'for' => 'newsletter',
'innerHTML' => 'รับข่าวสารทางอีเมล'
]);
$newsletterGroup->add('input', [
'type' => 'checkbox',
'id' => 'newsletter',
'name' => 'newsletter',
'value' => '1',
'checked' => true
]);
// ปุ่มส่งข้อมูล
$submitGroup = $form->add('groups', ['class' => 'submit']);
$submitGroup->add('input', [
'type' => 'submit',
'class' => 'button save large',
'value' => 'สมัครสมาชิก'
]);
$submitGroup->add('input', [
'type' => 'reset',
'class' => 'button cancel',
'value' => 'ล้างข้อมูล'
]);
// เพิ่ม JavaScript validation
$form->script('
// Real-time validation
document.getElementById("email").addEventListener("blur", function() {
checkEmailAvailability(this.value);
});
document.getElementById("password").addEventListener("input", function() {
checkPasswordStrength(this.value);
});
// ฟังก์ชันตรวจสอบอีเมลซ้ำ
function checkEmailAvailability(email) {
if (email.length > 0) {
// Ajax request to check email
fetch("index.php/register/checkEmail", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({email: email})
})
.then(response => response.json())
.then(data => {
const emailField = document.getElementById("email");
if (data.available) {
emailField.setCustomValidity("");
} else {
emailField.setCustomValidity("อีเมลนี้ถูกใช้งานแล้ว");
}
});
}
}
// ฟังก์ชันตรวจสอบความแข็งแกร่งของรหัสผ่าน
function checkPasswordStrength(password) {
const strengthMeter = document.getElementById("password_strength");
let strength = 0;
let message = "";
if (password.length >= 8) strength++;
if (/[a-z]/.test(password)) strength++;
if (/[A-Z]/.test(password)) strength++;
if (/[0-9]/.test(password)) strength++;
if (/[^A-Za-z0-9]/.test(password)) strength++;
switch(strength) {
case 0:
case 1:
message = "อ่อน";
break;
case 2:
case 3:
message = "ปานกลาง";
break;
case 4:
case 5:
message = "แข็งแกร่ง";
break;
}
if (strengthMeter) {
strengthMeter.innerHTML = message;
strengthMeter.className = "password-strength " + message.toLowerCase();
}
}
');
return $form->render();
}
private static function getProvinceOptions()
{
// ตัวอย่างรายชื่อจังหวัด
return [
'' => 'เลือกจังหวัด',
'กรุงเทพมหานคร' => 'กรุงเทพมหานคร',
'เชียงใหม่' => 'เชียงใหม่',
'เชียงราย' => 'เชียงราย',
'ขอนแก่น' => 'ขอนแก่น',
'นครราชสีมา' => 'นครราชสีมา',
'ภูเก็ต' => 'ภูเก็ต',
'สุราษฎร์ธานี' => 'สุราษฎร์ธานี'
];
}
}ตารางจัดการข้อมูลผู้ใช้
use Kotchasan\HtmlTable;
use Kotchasan\Html;
class UserManagementTable
{
$perPage = 2; // 0)
{
// Container
$container = Html::create('div', ['class' => 'content_bg']);
// Header พร้อมปุ่มเพิ่ม
$header = $container->add('div', ['class' => 'table-header']);
$header->add('h2', ['innerHTML' => 'จัดการผู้ใช้งาน']);
$actions = $header->add('div', ['class' => 'table-actions']);
$actions->add('a', [
'href' => 'index.php/users/add',
'class' => 'button add',
'innerHTML' => '<span class="icon-plus"></span> เพิ่มผู้ใช้ใหม่'
]);
// ฟอร์มค้นหา
$searchForm = $container->add('form', [
'id' => 'search_form',
'class' => 'table-search',
'method' => 'get'
]);
$searchGroup = $searchForm->add('div', ['class' => 'inputgroup']);
$searchGroup->add('input', [
'type' => 'text',
'name' => 'search',
'class' => 'g-input',
'placeholder' => 'ค้นหาชื่อ หรือ อีเมล...',
'value' => isset($_GET['search']) ? $_GET['search'] : ''
]);
$searchGroup->add('button', [
'type' => 'submit',
'class' => 'button search',
'innerHTML' => '<span class="icon-search"></span>'
]);
// สร้างตาราง
$table = new HtmlTable([
'id' => 'users_table',
'class' => 'data fullwidth sortable'
]);
// Header
$table->addHeader([
'<input type="checkbox" id="select_all">',
'รูปภาพ',
'ชื่อ-นามสกุล',
'อีเมล',
'สถานะ',
'วันที่สมัคร',
'ล็อกอินล่าสุด',
'การจัดการ'
]);
// เพิ่มข้อมูลแถว
if (empty($users)) {
$table->addRow([
['text' => 'ไม่พบข้อมูล', 'colspan' => 8, 'class' => 'center empty']
]);
} else {
foreach ($users as $user) {
$table->addRow([
'<input type="checkbox" name="id[]" value="' . $user['id'] . '">',
self::renderAvatar($user),
self::renderUserName($user),
$user['email'],
self::renderStatus($user['status']),
date('d/m/Y', strtotime($user['created_at'])),
$user['last_login'] ? date('d/m/Y H:i', strtotime($user['last_login'])) : '-',
self::renderActions($user)
]);
}
}
$container->add('div', ['innerHTML' => $table->render()]);
// Pagination
if ($total > $perPage) {
$container->add('div', [
'innerHTML' => self::renderPagination($total, $page, $perPage)
]);
}
// Bulk actions
$bulkActions = $container->add('div', ['class' => 'bulk-actions']);
$bulkActions->add('select', [
'id' => 'bulk_action',
'class' => 'g-select',
'options' => [
'' => 'เลือกการดำเนินการ',
'activate' => 'เปิดใช้งาน',
'deactivate' => 'ปิดใช้งาน',
'delete' => 'ลบ'
]
]);
$bulkActions->add('button', [
'type' => 'button',
'class' => 'button action',
'onclick' => 'performBulkAction()',
'innerHTML' => 'ดำเนินการ'
]);
// JavaScript
$container->script('
// Select all checkbox
document.getElementById("select_all").addEventListener("change", function() {
const checkboxes = document.querySelectorAll("input[name=\'id[]\']");
checkboxes.forEach(cb => cb.checked = this.checked);
});
// Bulk actions
function performBulkAction() {
const action = document.getElementById("bulk_action").value;
const selected = document.querySelectorAll("input[name=\'id[]\']:checked");
if (!action) {
alert("กรุณาเลือกการดำเนินการ");
return;
}
if (selected.length === 0) {
alert("กรุณาเลือกรายการที่ต้องการดำเนินการ");
return;
}
const ids = Array.from(selected).map(cb => cb.value);
const confirmMessage = `ต้องการ${getActionText(action)} ${ids.length} รายการ?`;
if (confirm(confirmMessage)) {
// Submit form or Ajax request
submitBulkAction(action, ids);
}
}
function getActionText(action) {
switch(action) {
case "activate": return "เปิดใช้งาน";
case "deactivate": return "ปิดใช้งาน";
case "delete": return "ลบ";
default: return "";
}
}
function submitBulkAction(action, ids) {
// Ajax request
fetch("index.php/users/bulk", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest"
},
body: JSON.stringify({
action: action,
ids: ids
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert(data.message || "เกิดข้อผิดพลาด");
}
})
.catch(error => {
console.error("Error:", error);
alert("เกิดข้อผิดพลาดในการดำเนินการ");
});
}
// Delete confirmation
function confirmDelete(id, name) {
if (confirm(`ต้องการลบผู้ใช้ "${name}" ?`)) {
window.location.href = `index.php/users/delete/${id}`;
}
}
');
return $container->render();
}
private static function renderAvatar($user)
{
$avatar = $user['avatar'] ? $user['avatar'] : 'skin/img/noicon.png';
return '<img src="' . $avatar . '" alt="Avatar" class="avatar-small">';
}
private static function renderUserName($user)
{
$name = $user['first_name'] . ' ' . $user['last_name'];
$link = '<a href="index.php/users/view/' . $user['id'] . '">' . $name . '</a>';
if (!empty($user['role'])) {
$link .= '<br><small class="text-muted">' . $user['role'] . '</small>';
}
return $link;
}
private static function renderStatus($status)
{
$badges = [
'active' => '<span class="badge green">ใช้งาน</span>',
'inactive' => '<span class="badge red">ไม่ใช้งาน</span>',
'pending' => '<span class="badge yellow">รอยืนยัน</span>',
'suspended' => '<span class="badge gray">ถูกระงับ</span>'
];
return $badges[$status] ?? '<span class="badge gray">ไม่ทราบ</span>';
}
private static function renderActions($user)
{
$actions = [];
// ดูรายละเอียด
$actions[] = '<a href="index.php/users/view/' . $user['id'] . '" class="icon-eye" title="ดูรายละเอียด"></a>';
// แก้ไข
$actions[] = '<a href="index.php/users/edit/' . $user['id'] . '" class="icon-edit" title="แก้ไข"></a>';
// เปิด/ปิดใช้งาน
if ($user['status'] === 'active') {
$actions[] = '<a href="index.php/users/deactivate/' . $user['id'] . '" class="icon-ban" title="ปิดใช้งาน"></a>';
} else {
$actions[] = '<a href="index.php/users/activate/' . $user['id'] . '" class="icon-check" title="เปิดใช้งาน"></a>';
}
// ลบ
$actions[] = '<a href="javascript:void(0)" onclick="confirmDelete(' . $user['id'] . ', \'' . addslashes($user['first_name'] . ' ' . $user['last_name']) . '\')" class="icon-delete" title="ลบ"></a>';
return '<div class="actions">' . implode(' ', $actions) . '</div>';
}
private static function renderPagination($total, $page, $perPage)
{
$totalPages = ceil($total / $perPage);
$pagination = '<div class="pagination">';
// Previous page
if ($page > 1) {
$pagination .= '<a href="?page=' . ($page - 1) . '" class="prev">« ก่อนหน้า</a>';
}
// Page numbers
$start = max(1, $page - 2);
$end = min($totalPages, $page + 2);
if ($start > 1) {
$pagination .= '<a href="?page=1">1</a>';
if ($start > 2) {
$pagination .= '<span class="ellipsis">...</span>';
}
}
for ($i = $start; $i <= $end; $i++) {
if ($i == $page) {
$pagination .= '<span class="current">' . $i . '</span>';
} else {
$pagination .= '<a href="?page=' . $i . '">' . $i . '</a>';
}
}
if ($end < $totalPages) {
if ($end < $totalPages - 1) {
$pagination .= '<span class="ellipsis">...</span>';
}
$pagination .= '<a href="?page=' . $totalPages . '">' . $totalPages . '</a>';
}
// Next page
if ($page < $totalPages) {
$pagination .= '<a href="?page=' . ($page + 1) . '" class="next">ถัดไป »</a>';
}
$pagination .= '</div>';
return $pagination;
}
}Best Practices
1. การตั้งชื่อและการจัดระเบียบ
// ✅ ใช้ชื่อที่มีความหมาย
$userRegistrationForm = Html::create('form', [
'id' => 'user_registration_form',
'class' => 'setup_frm user-form'
]);
// ❌ หลีกเลี่ยงชื่อที่ไม่มีความหมาย
$form1 = Html::create('form', ['id' => 'f1']);
// ✅ จัดกลุ่มฟิลด์ที่เกี่ยวข้องกัน
$personalInfo = $form->add('fieldset', ['title' => 'ข้อมูลส่วนตัว']);
$contactInfo = $form->add('fieldset', ['title' => 'ข้อมูลติดต่อ']);
$preferences = $form->add('fieldset', ['title' => 'การตั้งค่า']);2. Accessibility และ UX
// ✅ ใช้ label ที่เหมาะสม
$emailGroup->add('label', [
'for' => 'email',
'innerHTML' => 'อีเมล <span class="required" aria-label="จำเป็น">*</span>'
]);
// ✅ เพิ่ม ARIA attributes
$form->add('input', [
'type' => 'password',
'id' => 'password',
'name' => 'password',
'aria-describedby' => 'password_help',
'aria-required' => 'true'
]);
// ✅ Placeholder ที่มีประโยชน์
$form->add('input', [
'type' => 'tel',
'placeholder' => '0XX-XXX-XXXX',
'pattern' => '[0-9]{3}-[0-9]{3}-[0-9]{4}'
]);3. การจัดการข้อผิดพลาด
// ✅ Client-side validation
$form->script('
function validateForm() {
const email = document.getElementById("email");
const password = document.getElementById("password");
// Custom validation
if (!isValidEmail(email.value)) {
showError(email, "รูปแบบอีเมลไม่ถูกต้อง");
return false;
}
if (password.value.length < 8) {
showError(password, "รหัสผ่านต้องมีอย่างน้อย 8 ตัวอักษร");
return false;
}
return true;
}
function showError(field, message) {
field.setCustomValidity(message);
field.reportValidity();
}
');
// ✅ Server-side validation feedback
if (isset($errors['email'])) {
$emailInput->setAttribute('class', 'g-input error');
$emailInput->setAttribute('title', $errors['email']);
}4. Performance
// ✅ โหลด JavaScript เมื่อจำเป็น
$form->script('
// โหลด library เมื่อต้องการใช้งาน
if (typeof DatePicker === "undefined") {
loadScript("/js/datepicker.js", function() {
initDatePicker("#birthdate");
});
}
');
// ✅ ใช้ lazy loading สำหรับตาราง
$table->setAttribute('data-lazy', 'true');
$table->setAttribute('data-source', 'index.php/api/users');5. Security
// ✅ เพิ่ม CSRF token
$form = Html::create('form', [
'token' => true, // เพิ่ม CSRF token อัตโนมัติ
'method' => 'post'
]);
// ✅ Escape user input
$userInput = htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// ✅ Validate file uploads
$fileUpload = Form::file([
'accept' => 'image/jpeg,image/png,image/gif',
'max-size' => '2MB'
]);การใช้คลาส Form, Html, HtmlTable และ Grid ของ Kotchasan จะช่วยให้การสร้างฟอร์มและตารางเป็นไปอย่างมีประสิทธิภาพ รวดเร็ว และปลอดภัย พร้อมรองรับการใช้งานบนอุปกรณ์ต่างๆ ได้อย่างสมบูรณ์