ตัวอย่างไฟล์ 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>
ความคิดเห็น