一、說明
一個優秀的PHP框架,能幫助我們的程式編寫更合理,更便於維護,框架題供的工具函式,也可以大量簡化我們的開發步驟,而在團隊開發中,框架更提供一個共同的規範讓團隊依循。
在此使用框架 CodeIngiter 3
二、建立Git repository
前往GitHub註冊帳號
建立repository: crud-training
點選右上角頭像旁的+號,再選「New repository」
填寫資料
取得 crud-training 的 Git Repo RUL
- 點選Clone or download
- 使用SSH URL並複製
Clone crud-training
1
2
3
4
5
6
7刪除原本的crud-training資料夾
cd /var/www/html
sudo rm -rf crud-training
Clone git repo 至 crud-training資料夾
git clone {Git Repo RUL} crud-training
回到crud-training
cd crud-training將**{Git Repo RUL}**替換成剛剛複製的Git Repo RUL
註:如果Linux與Github間的金鑰認証沒有做好,會clone失敗,請參考帳號安全設定-GitHub
三、安裝 CodeIngiter 3
3.1 下載CodeIngiter 3
前往 CodeIngiter 3 官網,下載檔案
3.2 解壓縮並上傳至遠端開發目錄
下載並安裝WinSCP
連線至遠端目錄
上傳檔案
沒用的檔案可以不傳
查看上傳結果-從VSCode
查看上傳結果-從瀏覽器
3.3 推送至Git
查看目前git log
1
git log
查看變動的檔案
1
git status
暫存”所有”變動檔案
1
git add .
再查看變動的檔案
1
git status
Commit 暫存檔案
1
2
3git commit
在第一行輸入: [Upload] Upload CodeIgniter 3
儲存離開- 用#開頭的行不會被git處理,是給使用者看的
推送至Git
1
git push
再查看目前git log
1
git log
去Github查看上傳結果
四、設定 CodeIngiter 3
4.1 建立Composer資料&目錄
在application目錄下建立檔案composer.json (按右鍵=>新增檔案)
填入composer.json檔案內容
1
2
3
4
5
6
7
8
9
10
11
12{
"name": "dev/codeigniter",
"description": "Composer package list and local code autoload support.",
"type": "project",
"license": "MIT",
"autoload": {
"psr-4": {
"app\\": "./"
}
},
"require": {}
}安裝composer相關資料
1
2cd application
composer install安裝完成後,application下會出現vendor目錄
4.2 修改composer設定值
- 開啟檔案 application/config/config.php
- 修改 $config[‘composer_autoload’] = TRUE; (FALSE => TRUE)
4.3 編輯.gitignore(忽略git處理清單)
1 | application/cache/* |
4.4 上傳Git
1 | 查看變動 |
五、目錄結構
1 | |-- application 項目目錄 |
system目錄下的資料不建議變動
六、第一支程式 Hello World!
6.1 建立Controller
建立檔案
application/controllers/Hello.php寫入內容
1
2
3
4
5
6
7
8
9
10
defined('BASEPATH') OR exit('No direct script access allowed');
class Hello extends CI_Controller {
public function index()
{
$this->load->view('hello');
}
}- Controller檔名第一個字母大寫,class名子和檔名一樣
- Load view時,只需填寫view的檔名
6.2 建立View
建立檔案
application/views/hello.php寫入內容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
defined('BASEPATH') or exit('No direct script access allowed');
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello World!</title>
</head>
<body>
<div>
<h1>Hello World!</h1>
<p>This is some text.</p>
</div>
</body>
</html>View檔名小寫即可
6.3 查看結果
打開網址https://crud-training.dev.idv/hello
上面的hello,是controller名稱Hello字首轉小寫而來 (只有字首會轉小寫)
6.4 推送至Git
1 | 查看變動 |
七、資料庫存取
本教學中選用MySQL資料庫
7.1 資料設計
使用者在網頁前端輸入的資料,傳送到後端處理完後,必需存到資料庫中,以待後續取用。但資料要如何存取才符合需求並有好的效率,資料庫設計至關重要。
7.1.1 建構原則
- 編碼使用 utf8_unicode_ci
如果資料欄位可能為中英夾雜,使用utf8_unicode_ci
如果可以確定欄位為純ASCII可用ascii_bin (進階) - 使用小寫英文命名,單字用底線分隔
不使用大寫及其他符號
- 資料表名稱不宜太長,以 4 個字以下為原則
字元過多可用縮寫代稱
- 欄位名稱不宜太長,以4個字以下為原則
字元過多可用縮寫代稱
- 資料表及欄位需有備註(COMMENT)
- 每個資料表需有主鍵、索引鍵
建議擁有auto_increment型態的主鍵,以便使用where in精確查詢
- 資料表建議有資料識別欄位
建立日、建立者、更新日、更新者、軟刪日、軟刪者、資料狀態
7.1.2 常用格式
數字型態
格式名稱 | 位元數 | 備註 |
---|---|---|
TINYINT[(M)] | 1 byte | Signed: -128 to 127 (-2^7 to 2^7-1) Unsigned: 0 to 255 (0 to 2^8-1) |
INT[(M)] | 4 byte | Signed: -2^31 to 2^31-1 Unsigned: 0 to 2^32-1 |
BIGINT[(M)] | 8 byte | Signed: -2^63 to 2^63-1 Unsigned: 0 to 2^64-1 |
DECIMAL[(M[,D])] | M+2 byte | M是數字的最大數(精度) D是小數點右側數字的數目(標度) decimal(5,2) 為 xxx.xx |
上表中的 M 代表「最大顯示寬度」
字串型態
格式名稱 | 位元數 | 備註 |
---|---|---|
VARCHAR(M) | L+1 bytes | 最大長度 M bytes |
TEXT | L+2 bytes | 最大長度 2^16-1 bytes |
MEDIUMTEXT | L+3 bytes | 最大長度 2^24-1 bytes |
LONGTEXT | L+4 bytes | 最大長度 2^32-1 bytes |
上表中的 L 代表「實際儲存的空間大小」
時間型態
格式名稱 | 位元數 | 備註 |
---|---|---|
DATE | 3 bytes | ‘0000-01-01’ to ‘9999-12-31’ |
TIME | 3 bytes | ‘-838:59:59’ to ‘838:59:59’ |
DATETIME | 8 bytes | 1000-01-01 00:00:00 to 9999-12-31 23:59:59 |
TIMESTAMP | 4 bytes | 自 1970 年起,至 2037 年的某時 |
列舉型態
格式名稱 | 位元數 | 備註 |
---|---|---|
ENUM | 1~2 bytes | 65535 個成員,單選 |
SET | 1~8 bytes | 64 個成員,可以多選 |
7.1.3 需求假設
有一部門管理介面,需要可填寫 部門代碼、部門名稱、部門層級、開始時間、結束時間、備註 ,其中部門代碼維一
欄位整理:
主鍵欄位 | 資料欄位 | 管理欄位 |
---|---|---|
系統序號 | 代碼 | 建立日 |
名稱 | 建立者 | |
層級 | 更新日 | |
開始日 | 更新者 | |
結束日 | 軟刪日 | |
備註 | 軟刪者 | |
資料狀態 |
管理欄位視狀況選用
7.1.4 需求設計
- 資料表 : dept_info 單位資料
- 欄位
欄位名稱 | 型態 | 長度 | 備註 | 說明 | A_I | 空值 |
---|---|---|---|---|---|---|
d_id | int | 10 | 系統序號 | SQL主鍵 | V | |
d_code | varchar | 15 | 代碼 | |||
d_name | varchar | 60 | 名稱 | |||
d_level | varchar | 15 | 層級 | |||
date_start | date | 開始日 | 預設 0000-00-00 | |||
date_end | date | 結束日 | 預設 9999-12-31 | |||
remark | text | 備註 | ||||
date_create | datetime | 建立日 | ||||
user_create | int | 10 | 建立者 | |||
date_update | datetime | 更新日 | ||||
user_update | int | 10 | 更新者 | |||
date_delete | datetime | 軟刪日 | ||||
user_delete | int | 10 | 軟刪者 | |||
rec_status | tinyint | 1 | 資料狀態 | 無效(0) 有效(1) |
- 索引
- 主鍵 : d_id
- 索引 : d_code
- 建構語法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18CREATE TABLE `dept_info` (
`d_id` int(10) UNSIGNED AUTO_INCREMENT NOT NULL COMMENT '系統序號',
`d_code` varchar(15) NOT NULL COMMENT '代碼',
`d_name` varchar(60) NOT NULL COMMENT '名稱',
`d_level` varchar(15) NOT NULL COMMENT '層級',
`date_start` date NOT NULL COMMENT '開始日',
`date_end` date NOT NULL DEFAULT '9999-12-31' COMMENT '結束日',
`remark` text NOT NULL COMMENT '備註',
`date_create` datetime NOT NULL COMMENT '建立日',
`user_create` int(10) NOT NULL COMMENT '建立者',
`date_update` datetime NOT NULL COMMENT '更新日',
`user_update` int(10) NOT NULL COMMENT '更新者',
`date_delete` datetime NOT NULL COMMENT '軟刪日',
`user_delete` int(10) NOT NULL COMMENT '軟刪者',
`rec_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '資料狀態 無效(0) 有效(1)',
PRIMARY KEY (`d_id`),
KEY `d_code` (`d_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='單位資料';
- 在本表中除主鍵d_id外,另增加一組索引d_code
- 索引建立原則為
- 主鍵/外鍵必須有索引
- 查詢常用條件
- 識別性夠高
- 資料表間聯合查詢常用
- 長度小的欄位,如TEXT就不適合
- 頻繁進行資料操作的表,不要建立太多的索引
7.2 資料庫建構
7.2.1 phpmyadmin管理
登入管理介面
- XAMPP版:http://localhost/phpmyadmin/
- LANP版:https://sql.dev.idv/
7.2.2 建立資料庫
- 建構語法
1
CREATE DATABASE training CHARACTER SET utf8 COLLATE utf8_unicode_ci;
7.2.3 建立資料表
方法一
- 點選 資料庫 training
- 點選「SQL」指令輸入
- 輸入資料表建構指令
- 點選「執行」
方法二
- 點選 資料庫 training
- 點選「結構」
- 輸入資料表名稱及欄位數
- 點選「執行」
- 填入欄位設定
7.2.4 建立存取帳號
- 點選 伺服器: localhost
- 點選「使用者帳號」、「新增使用者帳號」
- 輸入帳號密碼
- 選擇權限 僅資料
- 拉至最下方,點選「執行」
7.3 設定資料庫連線
- 打開設定檔 application/config/database.php
- 設定連線參數
- 資料庫網址:hostname
- 連線帳號:username
- 連線密碼:password
- 使用的資料庫:database
7.4 Model建構範例
- 建立model檔案 application/models/Dept_info_model.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/**
* 部門資料管理Model
*
* 提供通用函式 新增、讀取、更新、刪除、批次讀取、批次新增、批次更新、批次刪除 示範
*
* @author Mars.Hung 2020-02-29
*/
class Dept_info_model extends CI_Model
{
/**
* 資料表名稱
*/
protected $table = "dept_info";
/**
* 欄位資料
*/
protected $tableColumns = [
'd_id',
'd_code',
'd_name',
'd_level',
'date_start',
'date_end',
'remark',
'date_create',
'user_create',
'date_update',
'user_update',
'date_delete',
'user_delete',
'rec_status',
];
public function __construct()
{
parent::__construct();
// 載入資料連線
$this->load->database();
}
/**
* 取得資料 - 從主鍵
*
* 本函式只能取出 rec_status==1 的資料
*
* @param int $d_id 目標主鍵資料
* @param string $col 輸出欄位
* @return array
*/
public function get($d_id, $col = '*')
{
return $this->db->select($col)->from($this->table)->where('d_id', $d_id)->where('rec_status', '1')->get()->result_array();
}
/**
* 取得資料 - 從查詢條件
*
* 本函式只能取出 rec_status==1 的資料
*
* 格式:
* $conditions = [
* '欄位名' => '欄位值string/int/array',
* ];
*
* @param array $conditions 查詢條件
* @param string $col 輸出欄位
* @return array
*/
public function getBy($conditions = [], $col = '*')
{
// 查詢建構
$query = $this->db->select($col)->from($this->table)->where('rec_status', '1');
// 加入查詢條件
foreach ($conditions as $key => $where) {
if (is_array($where)) {
// 加入陣列查詢條件
$query->where_in($key, $where);
} else {
// 加入單一查詢條件
$query->where($key, $where);
}
}
// 執行查詢、取回資料並回傳
return $query->get()->result_array();
}
/**
* 新增資料
*
* @param array $data 部門資料
* @return int
*/
public function post($data)
{
// 過濾可用欄位資料
$data = array_intersect_key($data, array_flip($this->tableColumns));
// 移除主鍵欄位 - 新增時不帶入主鍵值,以便主鍵由sql自行增加
unset($data['d_id']);
// 寫入 date_create, user_create(未知,暫用0), rec_status
$data['date_create'] = date('Y-m-d H:i:s');
$data['user_create'] = 0;
$data['rec_status'] = '1';
// 移除 date_update, user_update, date_delete, user_delete
unset($data['date_update']);
unset($data['user_update']);
unset($data['date_delete']);
unset($data['user_delete']);
// 寫入資料表
$res = $this->db->insert($this->table, $data);
// 寫入成功時回傳寫入主鍵鍵值,失敗時回傳 0
return $res ? $this->db->insert_id() : 0;
}
/**
* 更新資料 - 從主鍵
*
* @param array $data 部門資料
* @return int
*/
public function put($data)
{
// 過濾可用欄位資料
$data = array_intersect_key($data, array_flip($this->tableColumns));
$res = 0;
// 檢查有無主鍵
if (isset($data['d_id'])) {
// 取出主鍵值並移除$data中主鍵欄位
$d_id = $data['d_id'];
unset($data['d_id']);
// 寫入 date_update, user_update(未知,暫用0)
$data['date_update'] = date('Y-m-d H:i:s');
$data['user_update'] = 0;
// 移除 date_create, user_create, date_delete, user_delete, rec_status
unset($data['date_create']);
unset($data['user_create']);
unset($data['date_delete']);
unset($data['user_delete']);
unset($data['rec_status']);
// 更新資料 - 成功時回傳主鍵鍵值,失敗時回傳 0
$res = $this->db->where('d_id', $d_id)->update($this->table, $data) ? $d_id : 0;
} else {
// 報錯-沒有主鍵欄位
throw new Exception('沒有主鍵欄位: d_id', 400);
}
return $res;
}
/**
* 刪除資料 - 從主鍵
*
* @param array|int $d_id 欲刪除的主鍵值
* @param bool $forceDelete 是否強制刪除 false時為軟刪除
* @return bool
*/
public function delete($d_id, $forceDelete = false)
{
$d_id = (array) $d_id;
// 刪除條件
$this->db->where_in('d_id', $d_id);
if ($forceDelete) {
// 直接刪除 - CI SQL Builder有限定需有where才可以執行delete
return $this->db->delete($this->table);
} else {
// 標記成刪除狀態 - 本練習中無法得知操作者id,暫不處理user_delete值
$data['date_delete'] = date('Y-m-d H:i:s');
$data['user_delete'] = 0;
$data['rec_status'] = 0;
return $this->db->update($this->table, $data);
}
}
/**
* 批次寫入資料 - 未完成,請補完
*
* 整批處理時,有一筆錯誤,整批都不可以處理
*
* @param [type] $datas
* @return void
*/
public function postBatch($datas)
{
foreach ($datas as $key => $data) {
// 過濾可用欄位資料
// 移除主鍵欄位 - 新增時不帶入主鍵值,以便主鍵由sql自行增加
// 寫入 date_create, user_create(未知,暫用0), rec_status
// 移除 date_update, user_update, date_delete, user_delete
}
// 批次寫入資料表 - 成功時回傳插入列數,失敗時回傳 FALSE
return $this->db->insert_batch($this->table, $datas);
}
/**
* 批次更新資料 - 未完成,請補完
*
* 整批處理時,有一筆錯誤,整批都不可以處理
*
* @param [type] $datas
* @return void
*/
public function putBatch($datas)
{
foreach ($datas as $key => $data) {
// 過濾可用欄位資料
// 檢查有無主鍵
// 寫入 date_update, user_update(未知,暫用0)
// 移除 date_create, user_create, date_delete, user_delete, rec_status
}
// 批次更新資料 - 成功時回傳更新列數,失敗時回傳 FALSE
$this->db->update_batch($this->table, $datas, 'd_id');
}
}
7.5 Model使用範例
- 建立Controller檔案 application/controllers/Dept_info.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
defined('BASEPATH') or exit('No direct script access allowed');
/**
* 部門資料庫存取範例
*
* 本Controller提供Model Dept_info_model 使用範例,請在觀察輸出時,也同步觀察資料庫中的資料
*
* @author Mars.Hung 2020-02-29
*/
class Dept_info extends CI_Controller
{
public function __construct()
{
parent::__construct();
// 開啟session功能
session_start();
}
public function index()
{
// 載入部門資料庫
$this->load->model('Dept_info_model');
echo "<pre>";
/**
* ========== 範例-新增 ==========
*/
// 新增一筆資料 - 使用session記錄計數
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
}
$count = ++$_SESSION['count'];
// 建構新增範例資料
$data = [
'd_code' => 'd' . str_pad($count, 4, '0', STR_PAD_LEFT),
'd_name' => '部門1',
'd_level' => '部',
'date_start' => '2020-01-01',
'remark' => '部門' . $count,
];
// 使用Dept_info_model中的post函式新增資料
$d_id = $this->Dept_info_model->post($data);
echo "新增:" . $d_id;
echo "\n";
echo "\n";
/**
* ========== 範例-讀取 ==========
*/
// 讀取剛才新增的資料
$data = $this->Dept_info_model->get($d_id);
echo "讀取:";
var_export($data);
echo "\n";
/**
* ========== 範例-修改 =========
*/
// 建構修改範例資料 - 修改剛才新增的資料
$data = [
'd_id' => $d_id,
'd_name' => '部門' . mt_rand(0000, 9999),
'd_level' => '組',
];
// 使用Dept_info_model中的put函式修改資料
$d_id = $this->Dept_info_model->put($data);
// 讀回修改的資料
$data = $this->Dept_info_model->get($d_id, 'd_id,d_name,d_level');
echo "修改後:";
var_export($data);
echo "\n";
/**
* ========== 範例-刪除 ==========
*/
// 使用Dept_info_model中的put函式修改資料 - 軟刪
$this->Dept_info_model->delete($d_id);
// 使用Dept_info_model中的put函式修改資料 - 強刪
// $this->Dept_info_model->delete($d_id, true);
// 讀回刪除的資料
$data = $this->Dept_info_model->get($d_id);
echo "刪除後:";
var_export($data);
echo "\n";
echo "請至資料庫中查看d_id=" . $d_id . "資料狀態";
echo "\n";
echo "\n";
/**
* ========== 範例-取得資料-從查詢條件 ==========
* 請先新增好一些資料再來查詢
*/
$where = [
'd_id' => ['31', '32'],
'd_level' => '部',
];
$data = $this->Dept_info_model->getBy($where);
var_export($data);
}
}
7.6 觀察資料庫存取狀況
7.7 推送至Git
1 | 查看變動 |
八、參考
九、作業
- 將「Model建構範例」中Dept_info_model的函式 postBatch($datas), putBatch($datas) 補完