三十分鐘做一個留言板 Part 2

前言(廢話


又到了快樂的 Part 2 摟!(相隔時間可能只有幾小時而已)這樣馬拉松寫文章還真是刺激,不過各位不用跟我一樣馬拉松式的把他做完阿!!

建立模型(Model)


基本上,就是產生一個物件,讓自己方便做一些特殊(?)的操作就是了!不過在 ActiveMongo 其實也就是先去定義一下有哪些欄位,然後就結束了!(當然,還有很多很神奇的技巧,不過還是先別探討了!)

首先,在 app/models 資料夾新增一個 Commetn.PHP 檔案,然後建立一個 Model

Comment.PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?PHP
/**
* Comment Model
*
* @author Aotoki
* @version 1.0
*/

class Comment extends ActiveMongo
{
truepublic $nickname = 'Unknow';
truepublic $content;
truepublic $timestamp;
}

沒錯,不要懷疑,就只有這樣!

在 Active Mongo 建立一個Model只要繼承 ActiveMongo 這個物件,接著將欄位設定上去即可。

因為目前留言板只需要紀錄 暱稱(Nickname) 以及 留言內容(Content) 和 時間(Timestamp) 即可,而且還不需要其他多餘的功能,因此保持這個狀態就完成 Model 了!

讀取留言(簡易)


我們回到 index.PHP 檔案,在連接資料庫的語法下方(上一篇文章提到的 ActiveMongo::connect() 區段下方),加入讀取 Model 的程式。

index.PHP
1
2
//載入 Model
require_once(ABSPATH . 'models/Comment.PHP');

位置會在第一個 $app->get(); 之前,因為我們必須先把 Model 引入,不然是無法使用這個 Model 的。

接著,我們編輯上一篇文章 $app->get(); 的部份,大致上改成這樣。

index.PHP
1
2
3
4
5
6
7
8
9
10
11
12
$app->get('/', function() use ($app){
true$comments = new Comment(); //產生模型實例
true$totalComments = $comments->count(); //取得留言總數
true$comments->reset(); //清除指標,避免影響結果

true$app->render('home.PHP',
truetruearray(
truetruetrue'comments' => $comments,
truetruetrue'totalComments' => $totalComments,
truetrue)
true);
});

剛剛,我們新增了一個 Comment 物件,因為 Active Mongo 會自動幫我們處理好一開始的查詢,所以我們只要直接讀取 $comments 就可以得知所有的留言了!

為了要讓我們的佈景檔(home.PHP)得知 $comments 這筆資料,我們使用 Slim Framework 的 render 方法的第二個參數,將 $comments 以 comments 這個識別名稱傳給 home.PHP 讓他可以使用。

現在,編輯 views/home.PHP 加入迴圈(Loop)將留言顯示出來(當然,目前還沒有任何留言,不會顯示任何東西)

home.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
<!DOCTYPE html>
<html lang="zh-tw">
<head>
true<meta charset="utf-8" />

true<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

true<title>My 30min Guest Book</title>
true<meta name="description" content="" />
true<meta name="author" content="Aotoki" />

true<meta name="viewport" content="width=device-width; initial-scale=1.0" />
true<link rel="stylesheet" href="http://twitter.Github.com/bootstrap/1.4.0/bootstrap.min.CSS" />
true<style>
.container{
margin:15px auto;
}

.comment-count{
margin-bottom: 10px;
}

</style>
</head>

<body>
true<div class="container">
truetrue<header>
truetruetrue<h1>Guest Book</h1>
truetrue</header>
truetrue<nav>
truetruetrue<!--- 選單 -->
truetrue</nav>

truetrue<div>
truetruetrue<div class="comment-count">
truetruetruetrue<span class="label notice">Notice</span>
truetruetruetrueSystem has <?PHP echo intval($totalComments); ?> comments.
truetruetrue</div>
truetruetrue<?PHP foreach($comments as $c){ ?>
truetruetrue<blockquote>
truetruetruetrue<p><?PHP echo $c->content; ?></p> <!-- 顯示留言內容 -->
truetruetruetrue<small><?PHP echo $c->nickname; ?>, <?PHP echo date('Y-m-d H:i:s', $c->timestamp); ?></small> <!-- 顯示暱稱以及輸出留言時間 -->
truetruetrue</blockquote>
truetruetrue<?PHP } ?>
truetrue</div>

truetrue<footer>
truetrue <p>&copy; Copyright by Aotoki</p>
truetrue</footer>
true</div>
</body>
</html>

因為有了初步的畫面顯示,所以就直接將 Bootstrap 的 CSS 用 Link 的方式直接導入(官方網站上的快速引用)這樣一來,原本單調的畫面也稍微變得豐富一點,目前可以看到畫面上顯示著之前設定的 Guest Book 標題以及 [Notice] System has 0 comments. 的字樣。

新增留言


既然輸出留言完成了,但是無法留言還是沒有辦法讓留言板發揮作用,所以打開 index.PHP 檔案,繼續編輯。

我們將位置移動到 $app->get(‘/‘, function() use ($app){}); 區塊的下方,加入新的區塊。

index.PHP
1
2
3
4
5
6
7
8
9
10
11

$app->post('/new', function() use ($app){
true//Save Comment
true$comment = new Comment;
true$comment->nickname = $app->request()->post('nickname');
true$comment->content = $app->request()->post('content');
true$comment->timestamp = time();
true$comment->save();
true
true$app->redirect($app->urlFor('home'));
});

咦,怎麼跟之前讀取的有點像,但是這次?

沒錯,起始的動作還是一樣建立一個 Model 接著,我們設定 $comment->nickname 為 $app->requrest()->post(‘nickname’); 來讀取暱稱。

不過,大家一定有疑問,是怎麼讀取呢? $app->requrest(); 會負責處理有關 HTTP 請求得部份,而留言都會以 POST 方式傳輸資料,所以就要以 $app->requrest()->post(‘資料名稱’); 來接收。

那麼為什麼 timestamp 不用接收呢?那是因為時間總不能由使用者自己決定,所以由我們產生(time() 會給出一組秒數,是從 1970 年 1 月 1 日到今天的秒數。)

不過還是會有人對於 $app->post() 和 $app->get() 的差異有所疑惑吧!對,這個差異就在於 $app->post() 只接受 POST 傳輸資料,所以直接打開 http://網址/new 是會出現找不到頁面的喔!(這也是 Slim Framework的特性,在之後的文章會簡單介紹。)

好,現在已經完成儲存留言的機制了!但是打開網頁卻出現了錯誤?

其實是 $app->redirect() (轉跳網頁)裡面的數值 $app->urlFor() 有問題!
使用 urlFor 這個方法前,得先將目標命名才行,所以我們回到 $app->get(‘/‘, function() use ($app) {}) 區段 稍微修改結尾部份。

index.PHP
1
2
3
$app->get('/', function() use ($app){
true//略
})->name('home');

這樣一來,就可以正常使用摟!而使用 urlFor 的理由就是確保網址格式不會發生問題(像是把留言板放在 http://網址/gb/ 下,如果網址設定為 / 那就會跑去 http://網址/ 而非 http://網址/gb 摟!)

那麼,我們也該幫 $app->post(‘/new’, function() use ($app){}); 設定一下,以備不實之需。

index.PHP
1
2
3
$app->post('/new', function() use ($app){
true//略
})->name('new');

那麼,最後就是加入表單了!

打開之前的 home.PHP 加入表單部份

home.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
<!-- 前略 -->
truetruetrue<div class="row">
truetruetruetrue<div class="span16">
truetruetruetruetrue<form method="post" action="<?PHP echo $app->urlFor('new'); ?>">
truetruetruetruetruetrue<fieldset>
truetruetruetruetruetruetrue<legend>Leave a Comment</legend>
truetruetruetruetruetruetrue<div class="clearfix">
truetruetruetruetruetruetruetrue<label>Nickname</label>
truetruetruetruetruetruetruetrue<div class="input"><input name="nickname" type="text" class="xlarge" /></div>
truetruetruetruetruetruetrue</div>
truetruetruetruetruetruetrue<div class="clearfix<?PHP if($errorStatus){ echo ' error'; } ?>">
truetruetruetruetruetruetruetrue<label for="textarea">Content</label>
truetruetruetruetruetruetruetrue<div class="input">
truetruetruetruetruetruetruetruetrue<textarea name="content" class="xlarge<?PHP if($errorStatus){ echo ' error'; } ?>"></textarea>
truetruetruetruetruetruetruetruetrue<?PHP if($errorStatus){ ?><span class="help-block">You must enter some content.</span> <?PHP } ?>
truetruetruetruetruetruetruetrue</div>
truetruetruetruetruetruetrue</div>
truetruetruetruetruetruetrue<div class="actions">
truetruetruetruetruetruetruetrue<button class="btn primary" type="submit">Add Comment</button>
truetruetruetruetruetruetrue</div>
truetruetruetruetruetrue</fieldset>
truetruetruetruetrue</form>
truetruetruetrue</div>
truetruetrue</div>
<!-- 後略 -->

不過,打開網頁又發生錯誤了!到底是怎麼一回事?原來是表單的 action 指向了 $app 但是我們並沒有把 $app 傳給 home.PHP 使用!

回到 index.PHP 稍微修改一下

index.PHP
1
2
3
4
5
6
7
8
9
10
11
$app->get('/', function() use ($app){
true//略
true$app->render('home.PHP',
truetrue$app->render('home.PHP',
truetruearray(
truetruetrue'comments' => $comments,
truetruetrue'totalComments' => $totalComments,
truetruetrue'app' => $app,
truetrue)
true);
})->name('home');

呼!這次終於成功運行了!

小結


好,這次教學就到這邊告一段落!(其實是寫到累了,想偷懶

如果善用工具如 Aptana, Dreamweaver 會更快的完成喔!

如果對於範例的完整原始碼有興趣,可以到 Github 上面看看。

(V1.0版有加上分頁功能和簡易的檢查機制,而V1.0.1版則是修正了程式碼的Bug各位所看到的都是V1.0.1的程式碼)

分頁完成後大致上會長這樣:

2012\-01\-03 20\-04\-16

但是實際上會跟你想像的落差很大!

留言