0%

[技能檢定]網頁乙級檢定-前置作業-程式功能整合測試-基礎

在做完必要的檢查、整理和基本測試後,如果還有時間,可以針對程式運行做整合測試,基本上就是針對PHP+MySQL的運作做整合性的測試,避免發生資料庫連不上或是編碼設錯,時區沒設定等狀況

撰寫共用函式檔

共用函式的目的在於簡化CRUD的動作,同時減少撰寫SQL語法時的錯誤,最後則是為了讓除錯過程可以變得簡單一些。

這邊我們建議採用物件導向的方式來簡化自訂函式的撰寫,但是考量到檢定時間的限制,所以並不是全面的採用物件導向,只是把常用的自訂函式包裝成一個工具類別(Class)來使用而已,

宣告類別

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class DB{

/**
* $dsn 用來作為PDO的資料庫設定dbname為使用的資料庫名稱
* $table 使用的資料表名
* $pdo PDO的物件變數
* */
protected $dsn='mysql:host=localhost;charset=utf8;dbname={your db name}';
protected $table;
protected $pdo;

/**
* 建立建構式,在建構時帶入table名稱會建立資料庫的連線
* 建構式為物件被實例化(new DB)時會先執行的方法
*/
function __construct($table)
{
//將物件內部的$table值設為帶入的$table
$this->table=$table;

//將物件內部的$pdo值設為PDO建立的資料庫連線物件
$this->pdo=new PDO($this->dsn,'root','');
}
}

撰寫內部共用方法

由於CRUD的SQL語法中有許多是類似的,比如where 後的句型;而我們希望能透過一些設計方式讓我們在建立SQL語法時可以更簡便,因此我們將一些接近的用法獨立出來做成一個可以被呼叫引用的方法,藉此來降低程式碼的重覆,提高可讀性、維護及擴充。
a2s()-內部保護函式,用來簡化陣列參數的字串轉換

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/** 
* 此方法僅供類別內部使用,外部無法呼叫
* 帶入的參數必須為key-value型態的陣列
* 陣列透過foreach轉化為`key`='value'的字串存入陣列中
* 回傳此字串陣列供其他方法使用
* */
protected function a2s($array){
foreach($array as $key => $value){

//如果陣列的key名有id的,則跳過不處理
if($key!='id'){

//將$key和$value組成SQL語法的字串後加入到一個暫存的陣列中
$tmp[]="`$key`='$value'";
}
}
//回傳暫存的陣列
return $tmp;
}

sql_all()-用來組合有特定條件並且為多筆結果的sql語句

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
/** 
* 此方法僅供類別內部使用,外部無法呼叫
* $sql 一個sql的字串,主要是where 前的語法
* $array sql語句需要的欄位和值
* $other sql特殊語句
**/
private function sql_all($sql,$array,$other){

// 如果有設定資料表且不為空
if (isset($this->table) && !empty($this->table)) {

// 如果參數為陣列
if (is_array($array)) {

// 如果陣列不為空
if (!empty($array)) {
$tmp = $this->a2s($array);
$sql .= " where " . join(" && ", $tmp);
}
} else {
$sql .= " $array";
}

$sql .= $other;

//回傳sql字串
return $sql;
}
}

math()-內部函式,用來做為聚合函式的sql語法轉換
雖然也可以直接使用,但是直接使用的話需要輸入較多的參數,所以我們利用類別內可以互相呼的方式來簡化參數的使用,對外則是以max(‘欄位’,’條件’)來使用,而不是較多參數的math(‘max’,’欄位’,’條件’)。

1
2
3
4
5
6
7
protected function math($math,$col,$array='',$other=''){
$sql="select $math($col) from $this->table ";
$sql=$this->sql_all($sql,$array,$other);

//因為這類方法大多是只會回傳一個值,所以使用fetchColumn()的方式來回傳
return $this->pdo->query($sql)->fetchColumn();
}

撰寫外部公開方法(資料庫相關功能)

外部公開方法是在類別實例化成物件後,提供外部來呼叫用的,可以根據自己的專案需要來加上各式便利的功能

$table->all()-查詢符合條件的全部資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/** 
* 此方法主要用來取得符合條件的所有資料
*
**/
function all($where = '', $other = ''){
//建立一個基礎語法字串
$sql="select * from $this->table ";

//將語法字串及參數帶入到類別內部的sql_all()方法中,結果會得到一個完整的SQL句子
$sql=$this->sql_all($sql,$where,$other);

//將sql句子帶進pdo的query方法中,並以fetchAll的方式回傳所有的結果
return $this->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}

$table->find($id)-查詢符合條件的單筆資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function find($id){
//建立一個基礎語法字串
$sql="select * from $this->table ";

// 如果 $id 是陣列
if (is_array($id)) {
//執行內部方法a2s
$tmp = $this->a2s($id);

//拚接sql語句
$sql .= " where " . join(" && ", $tmp);
}
// 如果 $id 是數字
else if (is_numeric($id)) {

//拚接sql語句
$sql .= " where `id`='$id'";
}

//將sql句子帶進pdo的query方法中,並以fetch的方式回傳一筆資料結果
return $this->pdo->query($sql)->fetch(PDO::FETCH_ASSOC);
}

$table->del($id)-刪除資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function del($id){
//建立一個基礎語法字串
$sql="delete from $this->table ";

if (is_array($id)) {
$tmp = $this->a2s($id);
$sql .=" where ". join(" && ", $tmp);
} else if (is_numeric($id)) {
$sql .= " where `id`='$id'";
}

//將sql句子帶進pdo的exec方法中,回傳的結果是影響了幾筆資料
return $this->pdo->exec($sql);
}

$table->save($array)-新增/更新資料

利用新增和更新語法的特點整合兩個動作為一個,簡化函式的數量並提高函式的通用性;

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
/**
* $arg 必須是個陣列,但考量速度,所以程式中沒有特別檢查是否為陣列,
* 依據$arg是否帶有'id'這個key名,來決定是更新(有id)還是新增(沒id)
*/
function save($array){
// 如果 $array 中有 'id' 鍵
if(isset($array['id'])){
// 建立更新資料的 SQL 語句
$sql = "update `$this->table` set ";

// 如果 $array 不為空
if (!empty($array)) {
// 將陣列轉換為字串
$tmp = $this->a2s($array);
}

// 拚接 SQL 語句
$sql .= join(",", $tmp);
$sql .= " where `id`='{$array['id']}'";
}else{
// 建立新增資料的 SQL 語句
$sql = "insert into `$this->table` ";
$cols = "(`" . join("`,`", array_keys($array)) . "`)";
$vals = "('" . join("','", $array) . "')";

$sql = $sql . $cols . " values " . $vals;
}

// 執行 SQL 語句並回傳結果
return $this->pdo->exec($sql);
}

sum()/max()/min()…-使用聚合函式來計算某個欄位的結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 直接呼叫內部的方法math(),帶入需要的參數即可
* 這樣設計的目的是為了讓外部呼叫時方法名稱比較直覺,
* 同時也減少需要帶入的參數
*/
function sum($col, $where = '', $other = ''){
return $this->math('sum',$col,$where,$other);
}

function max($col, $where = '', $other = ''){
return $this->math('max',$col,$where,$other);
}

function min($col, $where = '', $other = ''){
return $this->math('min',$col,$where,$other);
}

count()…-使用聚合函式來計算查詢到的資料筆數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 執行 SQL 語句並回傳結果
*
* @param string $sql SQL 語句
* @param string $where WHERE 條件
* @param string $other 其他條件
* @return int 回傳結果
*/
function count($where = '', $other = ''){
// 建立查詢資料筆數的 SQL 語句
$sql = "select count(*) from `$this->table` ";

// 拼接 WHERE 條件和其他條件
$sql = $this->sql_all($sql, $where, $other);

// 執行 SQL 語句並回傳結果
return $this->pdo->query($sql)->fetchColumn();
}

撰寫輔助用的全域函式

有些功能不必然都要放到類別中,我們可以宣告在共用的引入檔中,做為全域隨時可以呼叫的工具函式

q($sql)-複雜SQL語法的簡化函式

1
2
3
4
5
6
//用來解決聯表查詢或是子查詢之類較為複雜的語法
public function q($sql){
$dsn="mysql:host=localhost;charset=utf8;dbname=db01";
$pdo=new PDO($dsn,'root','');
return $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}

也可以在DB class中建一個q()函式來使用
DB.php

1
2
3
4
5
6
7
class DB{
.....

function q($sql){
return $this->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
}

$to($url)-頁面導向輔助函式

此函式會獨立在 DB 這個類別外,但是會和共用檔放在一起,然後include到所有的頁面去使用,主要目的是簡化header指令的語法,避免拚字錯誤之類的事發生。

1
2
3
function to($url){
header("location:".$url);
}

dd()-PHP陣列查看

1
2
3
4
5
6
//方便在網頁查上以比較美觀的方式來查看陣列的內容
function dd($array){
echo "<pre>";
print_r($array);
echo "</pre>";
}

時區設定

有些題組會使用到時間,直接修改apache設定檔或php.ini都可以,但如果是一般坊間的server,可能沒有提供使用者去更改全域設定的功能,此時可以簡單的加上一個動態時區設定的語法,讓我們的程式在執行期間可以使用我們自行設定的時區:

1
date_default_timezone_set("Asia/Taipei");

啟用session

有很多功能需要透過session來暫存狀態,因此我們可以在共用檔中先啟月session,方便在各個頁面都可以操作session。

1
session_start();

預宣告資料表變數

由於共用函式檔會include到所有的頁面去使用,如果每次要使用時才去做 new DB('table') 會有點囉嗦,因此可以考慮把常用或會用到的資料表都先建立一個 DB 的實體出來,當成全域變數先宣告,之後在各個頁面就可以直接套用。

1
2
3
4
//建議使用首字母大寫來代表這是資料表的變數,方便和全小寫的變數做出區隔
$User=new DB('user');
$Menu=new DB('menu');
//etc......

測試CRUD正常運作

  • 建一個資料表
  • 寫一個簡單的SQl語法來測試CRUD都正常

測試前端JS及jQuery運作正常

  • 檢查jQuery的引入是否正常運作