แปลงวันที่ ค.ศ. เป็น พ.ศ. อัตโนมัติ โดยการ Custom ActiveRecord Model ใน Yii Framework 2

คู่มือการเรียนรู้ Yii Framework 2 (Yii2)

บทเรียนดีๆ สำหรับผู้ที่ต้องการแบ่งปัน บทเรียนของคุณอาจมีค่าสำหรับอีกหลายๆ คน

beta version

แปลงวันที่ ค.ศ. เป็น พ.ศ. อัตโนมัติ โดยการ Custom ActiveRecord Model ใน Yii Framework 2

มานพ กองอุ่น yii date format 4,210

ปัญหาของวันที่นั้นค่อนข้างสำคัญ ในประเทศไทย ส่วนใหญ่ใช้รูปแบบ พุทธศักราช เช่น 30/04/2559 แต่เมื่อบันทึกในฐานข้อมูลจะกลายเป็นคนละเรื่อง หากบันทึกลักษณะนี้ก็จะไม่สามารถนำมาคำนวณได้ต้องเขียนโปรแกรมวุ่นวายกันใหญ่ จะหาทางแก้อย่างไรให้พิมพ์ 30/04/2559 แล้วไปบันทึกในฐานข้อมูลเป็น 2016-04-30 ให้อัตโนมัติ หรือใส่เวลาด้วย เช่น พิมพ์ 30/04/2559 12:30:45 แล้วไปบันทึกเป็น 2016-04-30 12:30:45 แบบอัตโนมัติ

ทางออกคือการกำหนดในระดับ Model เป็นการเปลี่ยนข้อมูลโดยใช้ method พิเศษของ Model คือ beforeSave() และ afterFind() เข้ามาช่วย และเขียนโปรแกรมในการแปลงค่า

ในกรณีศึกษานี้หากใช้ Yii Framework 2 ร่วมกับฐานข้อมูล Microsoft SQL Server ซึ่งเป็นการเก็บข้อมูลแบบ datetime2 ให้เปลี่ยน dbType == 'datetime2' ถ้าใช้ MySQL ให้เปลี่ยนเป็น dbType == 'datetime'

สร้าง Model MyActiveRecord

สร้าง model ใหม่ใน common/models/MyActiveRecord.php

<?php
namespace common\models;

use yii\db\ActiveRecord;

class MyActiveRecord extends ActiveRecord
{
    public function beforeSave($insert)
    {

        foreach($this->getTableSchema()->columns as $column) //loop column ทั้งหมด
        {
            $attribute = $this->getAttribute($column->name);
            if(empty($attribute)){ //หากได้ค่าว่าง
                $column->allowNull == 1 ? $this->setAttribute($column->name, null) : null;//ได้ตั้งค่า allow null ไหม ถ้าใช่ให้ใส่ null
            }else if($column->dbType == 'datetime' && preg_match('/(\d{1,2}\s?\/\s?\d{1,2}\s?\/\s?\d{4}\s?\w*)/', $attribute)){ //ถ้ารูปแบบเป็น datetime
                if(stripos($attribute,':') !== false){//ค้นหาตำแหน่ง : case-insensitive //ถ้ามีเวลาด้วย
                    $date_time = explode(' ', $attribute); //แยกวันที่กับเวลาด้วย space
                    $time = ' ' . trim($date_time[1]);
                }else{//ถ้าไม่มีเวลา
                    $date_time[0] = $attribute;
                    $time = '';//เวลาว่าง
                }

                $dmy = preg_split('/(\s?\/\s?)/', $date_time[0]); //แยก วัน/เดือน/ปี
                $year = (int) $dmy[2];//กำหนดเป็น int เพื่อการคำนวณ
                $year = $year - 543;//ปี พ.ศ.-543
                $result = $year . '-' . $dmy[1] . '-' . $dmy[0] . $time;//ได้รูปแบบ 2016-05-20
                $this->setAttribute($column->name, $result);//กำหนดค่าใหม่
            }
        }
        return parent::beforeSave($insert);
    }

    public function afterFind()
    {
        foreach($this->attributes as $column_name => $value){
            if(preg_match('/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/', $value)){ //ถ้ามีค่าในรูปแบบ 2016-05-20 13:30:45

                if($value == '0000-00-00 00:00:00'){ //ถ้าไม่มีข้อมูล
                    $this->setAttribute($column_name, null); //กำหนดให้เป็นค่าว่าง
                }else{
                    $date_and_time = explode('.', $value);
                    $date_time = explode(' ', $date_and_time[0]); //แยกวันและเวลา
                    if($date_time[1] == '00:00:00'){ //ถ้าเวลาว่าง
                        $date_time[1] = ''; //ไม่มีเวลา
                    }else{// ถ้ามีเวลา
                        $date_time[1] = ' ' . $date_time[1];//กำหนดเวลา
                    }

                    $ymd = explode('-', $date_time[0]);//แยก ปี-เดือน-วัน
                    $year = (int) $ymd[0];//กำหนดให้เป็น int เพื่อการคำนวณ
                    $year = $year + 543;// นำปี +543
                    $result = $ymd[2] . '/' . $ymd[1] . '/' . $year . $date_time[1];//ได้รูปแบบ วัน/เดือน/ปี ชั่วโมง:นาที:วินาทีี
                    $this->setAttribute($column_name, $result);//กำหนดค่าใหม่
                }
            }

        }
        return parent::afterFind();
    }
}

ตัวอย่างการนำไปใช้งาน

ตั้งค่า Model ให้สืบทอด (extends) มาจาก common/models/MyActiveRecord

<?php

namespace common\models;

use Yii;
use common\models\MyActiveRecord;

class Datetimetest extends MyActiveRecord
{

    public static function tableName()
    {
        return 'datetimetest';
    }

    public function rules()
    {
        return [
            [['datetime1', 'datetime2'], 'required'],
            [['datetime1', 'datetime2'], 'safe'],
        ];
    }

    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'datetime1' => 'Datetime1',
            'datetime2' => 'Datetime2',
        ];
    }

    public function attributeHints()
    {
        return [
            'datetime1' => 'ตัวอยาง 13/05/2559 01:20:30',
            'datetime2' => 'ตัวอย่าง 13/05/2559 01:20:30',
        ];
    }
}

ตัวอย่างการสร้างฟอร์มร่วมกับ MaskedInput

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\widgets\MaskedInput;

?>

<div class="datetimetest-form">

    <?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'datetime1')->widget(MaskedInput::className(), [
        'mask' => '99/99/9999 99:99:99',
    ]) ?>

    <?= $form->field($model, 'datetime2')->widget(MaskedInput::className(), [
        'mask' => '99/99/9999 99:99:99',
    ]) ?>

    <div class="form-group">
        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

ตัวอย่างการแสดงผล

เมื่อเพิ่มข้อมูล

เมื่อแก้ไขข้อมูล

เมื่อเปิดดู

ค่าที่บันทึกในฐานข้อมูล


หากบทเรียนรู้มีความผิดพลาดประการใด หรือมีข้อเสนอแนะกรุณาแจ้ง contact@programmerthailand.com
มานพ กองอุ่น

มานพ กองอุ่น
admin

  • 2 เพื่อน
  • 13 ผู้ติดตาม
  • 763 โพสต์