การ Upload และ อ่านไฟล์ Excel ด้วย PHPExcel ใน Yii Framework 2

การ Upload และ อ่านไฟล์ Excel ด้วย PHPExcel ใน Yii Framework 2

มานพ กองอุ่น yii2 php excel 3,649

ตัวอย่างไฟล์ Excel ที่เราจะทำการเขียนโปรแกรมเพื่ออ่าน

การ upload และอ่านไฟล์ MS Excel เพื่อนำไปใช้ในระบบ เช่นบันทึกลงฐานข้อมูล หรือนำไปแสดงผลใน GridView (ตามตัวอย่าง) สามารถทำได้โดยใช้ PHPExcel Package ซึ่งสามารถทำได้ดังนี้

สำหรับ PHPExcel สามารถดูรายละเอียดได้ที่ https://github.com/PHPOffice/PHPExcel และสามารถติดตั้งผ่าน Composer ได้โดยใช้คำสั่ง

composer require phpoffice/phpexcel

จากนั้นเขียนโปรแกรมเพื่อ Upload ในที่นี้จะแยกการ Upload และการอ่านไฟล์ออกจากกันเพื่อให้ทำความเข้าใจได้ง่ายขึ้น

ใน Model ก็แก้ไขเพิ่มเติมจาก Model ที่ได้จากการ Gii มาก็ได้ครับ ในที่นี้จะเพิ่ม Property $uploadPath ซึ่งเก็บที่อยู่ของการ Upload ไฟล์ ซึ่งจะอยู่ที่ frontend/web/uploads/hospital/file ถ้ายังไม่มีก็สร้างไว้ก่อนนะครับ

จากนั้นก็ระบุส่วนของ rules เพื่อตรวจสอบนามสกุล และ เพิ่ม method uploadFile 

public $uploadPath = 'uploads/hospital/file';

//...
public function rules()
    {
        return [
            
            [['file'], 'file', 'extensions' => 'xls,xlsx', 'skipOnEmpty' => true]
        ];
    }

//...
public function uploadFile($model, $attribute)
    {
        $file = UploadedFile::getInstance($model, $attribute);

        if($file){
            if($this->isNewRecord){
                $fileName = time().'_'.$file->baseName.'.'.$file->extension;
            }else{
                $fileName = $this->getOldAttribute($attribute);
            }
            $file->saveAs(Yii::getAlias('@webroot').'/'.$this->uploadPath.'/'.$fileName);

            return $fileName;
        }
        return $this->isNewRecord ? false : $this->getOldAttribute($attribute);
    }

จากนั้นก็เขียนโปรแกรมในส่วน Controller เพื่อทำการ Upload ไฟล์ ใน action Create และ Update

public function actionCreate()
    {
        $model = new HospitalFile();

        if ($model->load(Yii::$app->request->post())) {

            $model->file = $model->uploadFile($model, 'file');
            $model->save();

            Yii::$app->session->setFlash('success', 'เพิ่มข้อมูลเรียบร้อยแล้ว');
            return $this->redirect(['view', 'id' => $model->id]);

        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }

//...
public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post())) {

            $model->file = $model->uploadFile($model, 'file');
            $model->save();

            Yii::$app->session->setFlash('success', 'แก้ไขข้อมูลเรียบร้อยแล้ว');
            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }

//...
public function actionDelete($id)
    {
        $model = $this->findModel($id);
        @unlink(Yii::getAlias('@webroot').'/'.$model->uploadPath.'/'.$model->file);
        $model->delete();

        Yii::$app->session->setFlash('success', 'ลบข้อมูลเรียบร้อยแล้ว');
        return $this->redirect(['index']);
    }

จากนั้นเขียนโปรแกรมเพื่ออ่านไฟล์ Excel แล้วนำไปแสดงที่ GridView โดยเขียนโปรแกรมใน Controller โดยนำใส่ใน ArrayDataProvider ดังต่อไปนี้

public function actionView($id)
    {
        $model = $this->findModel($id);

        try{
            $file = Yii::getAlias('@webroot').'/'.$model->uploadPath.'/'.$model->file;
            $inputFile = \PHPExcel_IOFactory::identify($file);
            $objReader = \PHPExcel_IOFactory::createReader($inputFile);
            $objPHPExcel = $objReader->load($file);
        }catch (Exception $e){
            Yii::$app->session->addFlash('error', 'เกิดข้อผิดพลาด'. $e->getMessage());
        }

        $sheet = $objPHPExcel->getSheet(0);
        $highestRow = $sheet->getHighestRow();
        $highestColumn = $sheet->getHighestColumn();

        $objWorksheet = $objPHPExcel->getActiveSheet();

        foreach($objWorksheet->getRowIterator() as $rowIndex => $row){
            $arr[] = $objWorksheet->rangeToArray('A'.$rowIndex.':'.$highestColumn.$rowIndex);
        }


        $dataProvider = new ArrayDataProvider([
            'allModels' => $arr,
            'pagination' => false,
        ]);

        return $this->render('view', [
            'model' => $model,
            'dataProvider' => $dataProvider,
        ]);
    }

 

จากนั้นนำไปแสดงผลเป็น GridView ใน view.php ดังนี้

<?=GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        [
            'label' => 'คำนำหน้า',
            'value' => function($model){
                return $model[0][0];
            }
        ],
        [
            'label' => 'ชื่อ นามสกุล',
            'value' => function($model){
                return $model[0][1];
            }
        ],
        [
            'label' => 'หมายเลขบัตรประชาชน',
            'value' => function($model){
                return $model[0][2];
            }
        ],
        [
            'label' => 'เพศ',
            'value' => function($model){
                return $model[0][3];
            }
        ],
        [
            'label' => 'อายุ',
            'value' => function($model){
                return $model[0][4];
            }
        ],
        [
            'label' => 'หน่วยอายุ(ปีเดือนวัน)',
            'value' => function($model){
                return $model[0][5];
            }
        ],
        [
            'label' => 'HN',
            'value' => function($model){
                return $model[0][6];
            }
        ],
        [
            'label' => 'AN',
            'value' => function($model){
                return $model[0][7];
            }
        ],
        [
            'label' => 'Doctor',
            'value' => function($model){
                return $model[0][8];
            }
        ],
        [
            'label' => 'Clinical Diagnosis',
            'value' => function($model){
                return $model[0][9];
            }
        ],
    ]
])?>

และเมื่อแสดงผลก็สามารถแสดงในรูปแบบ GridView ได้ดังนี้

การนำข้อมูลเข้าตารางในฐานข้อมูล

ก่อนอื่นก็ต้องสร้างตารางตามที่ต้องการเก็บข้อมูลก่อน โดยส่วนใหญ่ก็จะสร้างตารางให้ครบกับจำนวน Column ใน Excel เมื่อได้ตารางเสร็จแล้วก็มาทำการ Gii Model ให้เรียบร้อย

ในที่นี้ตารางเก็บข้อมูลชื่อ hospital_import จะได้ Model HospitalImport

จากนั้นก็เขียนโปรแกรมใน Controller เพื่อทำการบันทึกข้อมูลลงในตาราง

//...
if(Yii::$app->request->post('register')){
            $transaction = Yii::$app->db->beginTransaction();
            try {
                $register = Yii::$app->request->post('register');
                //var_dump($register);
                //die();
                foreach ($objWorksheet->getRowIterator() as $rowIndex => $row) {

                    $tmpdata = $objWorksheet->rangeToArray('A' . $rowIndex . ':' . $highestColumn . $rowIndex);
                    $data[] = $tmpdata[0];

                }

                foreach ($register as $key => $val) {
                    //Check if specific
                    if (!empty($val)) {//ถ้าเลือกส่ง
                        //var_dump($data[$key]);
                        //มีการ Import หรือยัง
                        $import = HospitalImport::find()->where(['name' => $data[$key][1]])
                            ->andFilterWhere(['like', 'id_card', $data[$key][4]])
                            ->one();
                        if (!$import) {//ถ้ายังไม่มีการ Import
                            
                            $gender = $data[$key][2] == 'หญิง' ? 1 : 0;


                            $import = new HospitalImport();
                            $import->token_action = $model->token_action;
                            $import->hospital_id = Yii::$app->user->identity->hospital_id;
                            $import->prefix = $data[$key][0];
                            $import->name = $data[$key][1];
                            $import->gender = $gender;
                            $import->race = $data[$key][3];
                            $import->id_card = $data[$key][4];
                            $import->birthdate = $data[$key][5];
                            $import->age = $data[$key][6];
                            $import->age_unit = $data[$key][7];
                            $import->h_n = $data[$key][8];
                            $import->a_n = $data[$key][9];
                            $import->ward = $data[$key][10];
                            $import->doctor = $data[$key][11];
                            $import->clinical_diagnosis = $data[$key][12];
                            $import->collected_at = $data[$key][13];
                            $import->regist_type = $val;

                            if($import->save()){
                                Yii::$app->session->addFlash('success', $import->name.' '.$import->regist_type.' นำเข้าข้อมูลเรียบร้อยแล้ว');
                            }else{
                                Yii::$app->session->addFlash('error', 'เกิดข้อผิดพลาดในการนำเข้าข้อมูล');
                                //var_dump($import);
                                //die();
                            }

                        }else{//รายการนี้ส่งแล้ว
                            Yii::$app->session->addFlash('info', $data[$key][1].' รายการนี้ส่งเข้าระบบแล้ว');
                        }

                    }else{//ถ้าไม่ได้เลือกส่ง
                        Yii::$app->session->addFlash('warning', $data[$key][1].' ไม่ได้เลือกส่ง');
                    }
                }//end foreach

                $transaction->commit();
                Yii::$app->session->addFlash('success', 'ดำเนินการนำเข้าข้อมูลเรียบร้อยแล้ว กรุณาตรวจสอบความถูกต้องอีกครั้ง');
                return $this->redirect(['view', 'id' => $model->id]);

            }catch (Exception $e){
                $transaction->rollBack();
                Yii::$app->session->addFlash('error', 'เกิดข้อผิดพลาด');
            }
        }///end if post
//...

หลังจากปรับแก้ ActionView แล้วมาดู Code แบบเต็มๆ 

public function actionView($id)
    {
        $model = $this->findModel($id);

        try{
            $file = Yii::getAlias('@webroot').'/'.$model->uploadPath.'/'.$model->file;
            $inputFile = \PHPExcel_IOFactory::identify($file);
            $objReader = \PHPExcel_IOFactory::createReader($inputFile);
            $objPHPExcel = $objReader->load($file);
        }catch (Exception $e){
            Yii::$app->session->addFlash('error', 'เกิดข้อผิดพลาด'. $e->getMessage());
        }

        $sheet = $objPHPExcel->getSheet(0);
        $highestRow = $sheet->getHighestRow();
        $highestColumn = $sheet->getHighestColumn();

        $objWorksheet = $objPHPExcel->getActiveSheet();

        foreach($objWorksheet->getRowIterator() as $rowIndex => $row){
            $arr[] = $objWorksheet->rangeToArray('A'.$rowIndex.':'.$highestColumn.$rowIndex);
        }

        /*
         * Post Register from active form
         */
        if(Yii::$app->request->post('register')){
            $transaction = Yii::$app->db->beginTransaction();
            try {
                $register = Yii::$app->request->post('register');
                //var_dump($register);
                //die();
                foreach ($objWorksheet->getRowIterator() as $rowIndex => $row) {

                    $tmpdata = $objWorksheet->rangeToArray('A' . $rowIndex . ':' . $highestColumn . $rowIndex);
                    $data[] = $tmpdata[0];

                }

                foreach ($register as $key => $val) {
                    //Check if specific
                    if (!empty($val)) {//ถ้าเลือกส่ง
                        //var_dump($data[$key]);
                        //มีการ Import หรือยัง
                        $import = HospitalImport::find()->where(['name' => $data[$key][1]])
                            ->andFilterWhere(['like', 'id_card', $data[$key][4]])
                            ->one();
                        if (!$import) {//ถ้ายังไม่มีการ Import
                            

                            $gender = $data[$key][2] == 'หญิง' ? 1 : 0;


                            $import = new HospitalImport();
                            $import->token_action = $model->token_action;
                            $import->hospital_id = Yii::$app->user->identity->hospital_id;
                            $import->prefix = $data[$key][0];
                            $import->name = $data[$key][1];
                            $import->gender = $gender;
                            $import->race = $data[$key][3];
                            $import->id_card = $data[$key][4];
                            $import->birthdate = $data[$key][5];
                            $import->age = $data[$key][6];
                            $import->age_unit = $data[$key][7];
                            $import->h_n = $data[$key][8];
                            $import->a_n = $data[$key][9];
                            $import->ward = $data[$key][10];
                            $import->doctor = $data[$key][11];
                            $import->clinical_diagnosis = $data[$key][12];
                            $import->collected_at = $data[$key][13];
                            $import->regist_type = $val;

                            if($import->save()){
                                Yii::$app->session->addFlash('success', $import->name.' '.$import->regist_type.' นำเข้าข้อมูลเรียบร้อยแล้ว');
                            }else{
                                Yii::$app->session->addFlash('error', 'เกิดข้อผิดพลาดในการนำเข้าข้อมูล');
                                //var_dump($import);
                                //die();
                            }

                        }else{//รายการนี้ส่งแล้ว
                            Yii::$app->session->addFlash('info', $data[$key][1].' รายการนี้ส่งเข้าระบบแล้ว');
                        }

                    }else{//ถ้าไม่ได้เลือกส่ง
                        Yii::$app->session->addFlash('warning', $data[$key][1].' ไม่ได้เลือกส่ง');
                    }
                }//end foreach

                $transaction->commit();
                Yii::$app->session->addFlash('success', 'ดำเนินการนำเข้าข้อมูลเรียบร้อยแล้ว กรุณาตรวจสอบความถูกต้องอีกครั้ง');
                return $this->redirect(['view', 'id' => $model->id]);

            }catch (Exception $e){
                $transaction->rollBack();
                Yii::$app->session->addFlash('error', 'เกิดข้อผิดพลาด');
            }
        }///end if post


        $dataProvider = new ArrayDataProvider([
            'allModels' => $arr,
            'pagination' => false,
        ]);

        $dataProviderImport = new ActiveDataProvider([
            'query' => HospitalImport::find()
                ->where(['token_action' => $model->token_action])
                ->orderBy(['id' => SORT_DESC])
        ]);

        return $this->render('view', [
            'model' => $model,
            'dataProvider' => $dataProvider,
            'dataProviderImport' => $dataProviderImport,
        ]);
    }

ส่วนใน View ก็เพิ่ม DropDownList และปุ่มสำหรับการส่งข้อมูลเพื่อ Import และเพิ่ม GridView สำหรับแสดงรายการ Record ที่ Import แล้วดังนี้

<?php

use yii\grid\GridView;
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\widgets\DetailView;

/* @var $this yii\web\View */
/* @var $model frontend\modules\hospital\models\HospitalFile */

$this->title = $model->file;
$this->params['breadcrumbs'][] = ['label' => 'ไฟล์', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<h1><?= Html::encode($this->title) ?></h1>

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

<div class="table-responsive">
<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        [
            'label' => 'คำนำหน้า',
            'value' => function ($model) {
                return $model[0][0];
            }
        ],
        [
            'label' => 'ชื่อ นามสกุล',
            'value' => function ($model) {
                return $model[0][1];
            }
        ],
        [
            'label' => 'เพศ',
            'value' => function ($model) {
                return $model[0][2];
            }
        ],
        [
            'label' => 'สัญชาติ',
            'value' => function ($model) {
                return $model[0][3];
            }
        ],
        [
            'label' => 'หมายเลขบัตรประชาชน',
            'value' => function ($model) {
                return $model[0][4];
            }
        ],
        [
            'label' => 'วันเดือนปีเกิด',
            'value' => function ($model) {
                return $model[0][5];
            }
        ],
        [
            'label' => 'อายุ',
            'value' => function ($model) {
                return $model[0][6];
            }
        ],
        [
            'label' => 'หน่วยอายุ(ปีเดือนวัน)',
            'value' => function ($model) {
                return $model[0][7];
            }
        ],
        [
            'label' => 'HN',
            'value' => function ($model) {
                return $model[0][8];
            }
        ],
        [
            'label' => 'AN',
            'value' => function ($model) {
                return $model[0][9];
            }
        ],
        [
            'label' => 'Ward',
            'value' => function ($model) {
                return $model[0][10];
            }
        ],
        [
            'label' => 'Doctor',
            'value' => function ($model) {
                return $model[0][11];
            }
        ],
        [
            'label' => 'Clinical Diagnosis',
            'value' => function ($model) {
                return $model[0][12];
            }
        ],
        [
            'label' => 'Collected at',
            'value' => function ($model) {
                return $model[0][13];
            }
        ],
        [
            'label' => 'สถานะ',
            'format' => 'raw',
            'value' => function($model){
                //Implement later
                return '<span class="label label-success">ข้อมูลสมบูรณ์</span>';
            }
        ],
        [
            'label' => 'ต้องการส่ง',
            'format' => 'raw',
            'value' => function ($model){
                return Html::dropDownList('register[]', null,
                    [
                        'CS' => 'ส่งปรึกษา (Consult (CS))',
                        'SN' => 'ส่งตรวจชิ้นเนื้อ (Surgical (SN))',
                        'PN' => 'ส่งตรวจวิเคราะห์เซลล์ (PAP)',
                        'FN' => 'ส่งตรวจวิเคราะห์เซลล์ (Non-Gyn)',
                        'EX' => 'ส่งย้อมพิเศษ (EX)',
                        'FI' => 'ส่งตรวจ FISH',
                        'FL' => 'ส่งตรวจ FLOW',
                        'MP' => 'ส่งตรวจ Molecular',
                    ],
                    ['class' => 'form-control', 'prompt' => 'เลือกรายการส่งตรวจ']);
            }
        ],
    ]
]) ?>
</div>
<div class="row">
    <div class="col-sm-6">
        <?= Html::a('<i class="glyphicon glyphicon-arrow-left"></i> กลับ', ['/hospital/file/index'], ['class' => 'btn btn-danger'])?>
    </div>
    <div class="col-sm-6 text-right">
        <?= Html::submitButton('<i class="glyphicon glyphicon-arrow-up"></i> นำเข้าข้อมูล', ['class' => 'btn btn-warning btn-lg']) ?>
    </div>
</div>

<?php ActiveForm::end() ?>

<h2>รายการที่มีการนำเข้าแล้ว</h2>
<div class="table-responsive">
    <?=GridView::widget([
        'dataProvider' => $dataProviderImport,
        'columns' => [
            'prefix',
            'name',
            'gender',
            'race',
            'id_card',
            'birthdate',
            'age',
            'age_unit',
            'h_n',
            'a_n',
            'ward',
            'doctor',
            'clinical_diagnosis',
            'collected_at',
            'regist_type',
            'created_at:datetime',
        ]
    ])?>
</div>

<div class="alert alert-info">
    <i class="glyphicon glyphicon-info-sign"></i> ประเภทการส่งตรวจ
    <ul>
        <li>SN ส่งตรวจชิ้นเนื้อ (Surgical)</li>
        <li>PN ส่งวิเคราะห์เซลล์ (PAP Smear)</li>
        <li>FN ส่งวิเคราะห์เซลล์ (Non-Gyn)</li>
        <li>CS ส่งปรึกษา (Consult)</li>
        <li>FI ส่งวิเคราะห์ FISH</li>
        <li>FL ส่งวิเคราะห์ FLOW</li>
        <li>MP ส่งวิเคราะห์ Molecular</li>
        <li>FS ส่งวิเคราะห์ Frozen Section</li>
        <li>EM ส่งตรวจ Electro Microscopy</li>
    </ul>
</div>


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

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

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