#MVC
有一種設計模式叫做MVC,我們現在已經接觸了可以被用戶直接觸發的C,也有了可以直接訪問數據表的M,還差一個叫做視圖的V(View)。
我們比喻的官方一些,MVC是這樣的:
從用戶發送數據開始,經歷1-2-3-4-5-6步,再將數據返回給用戶。如下圖所示:

當然了,在沒有使用V以前,我們傳遞數據的過程是1-2-3-6。
對于MVC的理解,下圖可能更加直觀:

推薦學習以下視頻:
http://www.imooc.com/video/5019
## 引用V層
沒錯,V層就是用來對數據進行包裝的。
那么C層呢,C層就是個大指揮官,它從這邊拿點數據,從那邊拿點數據,讓這個處理處理,讓那個處理處理。然后讓這個包裝一下,讓那個包裝一下,最后它感覺滿意了,再把包裝好的產品一并返回給用戶。
M層呢?就是用來被C層調用的,我們前面已經講過了怎么調用M層,本節主要講怎么調用V層。
### 引用think\Controller
引用后代碼如下:
~~~
<?php
namespace app\index\controller; // 該文件位于application\index\controller文件夾
use think\Controller; // 用于與V層進行數據傳遞
use app\common\model\Teacher; // 教師模型
/**
* 教師管理,繼承think\Controller后,就可以利用V層對數據進行打包了。
*/
class TeacherController extends Controller
{
public function index()
{
$Teacher = new Teacher;
$teachers = $Teacher->select();
// 向V層傳數據
// 取回打包后的數據
// 將數據返回給用戶
}
}
~~~
### 建立V層文件
和C層一樣,V層文件的位置也是固定的,每一個V層文件默認對應一個action。
我們看到,V層的文件,位于同模塊下的view文件夾下,與控制器的名字和方法的名字相對應。如下圖所示:

**注意Teahcer文件夾名與控制器名完全對應(大小寫),并省略Controller后綴。**
V層文件(application\index\view\Teacher\index.html)代碼如下:
~~~
Hello I am V of TeahcerController\index
~~~
V層代碼位置如下圖所示:

### 補齊C層代碼
~~~
public function index()
{
$Teacher = new Teacher;
$teachers = $Teacher->select();
// 向V層傳數據
$this->assign('teachers', $teachers);
// 取回打包后的數據
$htmls = $this->fetch();
// 將數據返回給用戶
return $htmls;
}
~~~
測試結果顯示如下:

在上述方法中,我們使用了$this->assign()調用了其父類(think\Controller)中的assign()函數。如果我們忘記在定義類時,做繼承操作,那么將會出現以下錯誤:
**Call to undefined method app\index\controller\TeacherController::assign()**
譯為:調用了一個在app\index\controller\TeacherController中沒有被定義的assign()方法。解決的方法當然也很簡單了,將`class TeacherController`改為`class TeacherController extends Controller`就可以了。
> 什么是$this? 簡單來說,$this = 我自己,$this->assign()調用我自己(自己沒有就找父類,父類沒有就找父父類)的assign()方法。前面已經講過了,我們這個類是沒有,但是它的父類有,正是我們繼承了think\Controller,所以我們也就可以在TeacherController里面使用think\Controller中的方法。
### 在V層中查看變量
我們在V層中的文件index.html中,輸入以下代碼:
~~~
<!--在V層中使用php的函數需要類似于這樣使用-->
{:var_dump($teachers)}
~~~
測試結果顯示如下:

沒有什么技巧,這東西是thinkphp規定好的,我們記住就可以了,至于為什么可以這樣用,我們在后續進階教程中會專門針對「標簽」這個東西,與大家進行詳細的交流。
#### assign()
我們再來看下Think\Controller中的assign()函數:
~~~
/**
* 模板變量賦值
* @access protected
* @param mixed $name 要顯示的模板變量
* @param mixed $value 變量的值
* @return void
*/
protected function assign($name, $value = '')
{
$this->view->assign($name, $value);
}
~~~
有人說,什么亂七八糟的代碼,我看不懂。沒關系,注釋能看懂就好了。
注釋說的很清楚了,本函數的作用是給模板變量賦值,然后接收兩個變量,一個是要顯示在模板中的變量名,另一個是要傳入的變量的值。
> 良好的注釋習慣是通往優秀程序員的必經之路!重要的事情好像要說三遍:注釋、注釋、注釋!
也就是說,我們也可以這樣寫:
~~~
public function index()
{
$Teacher = new Teacher;
$teachers = $Teacher->select();
// 向V層傳數據
$this->assign('hello', $teachers);
// 取回打包后的數據
$htmls = $this->fetch();
// 將數據返回給用戶
return $htmls;
}
~~~
然后我們在V層中這樣輸出:
~~~
{:var_dump($hello)}
~~~
當然了,大多數情況下,我們都會這樣用
~~~
// 向V層傳數據
$this->assign('teachers', $teachers);
~~~
原因很簡單,變量名統一,更加易于記憶。
### 引入html
html代碼如下:
~~~
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>教師管理</title>
</head>
<body>
<table>
<tr>
<th>序號</th>
<th>姓名</th>
<th>性別</th>
<th>郵箱</th>
<th>用戶名</th>
</tr>
<tr>
<td>1</td>
<td>張三</td>
<td>男</td>
<td>11@maol.com</td>
<td>zhangsan</td>
</tr>
</table>
</body>
</html>
~~~
測試效果:

測試發現整體沒有問題后,我們繼續,如果有界面不符合預期,需要先修改界面。
html的錯誤,直接通過firefox的查看源代碼來檢查,如果有錯誤,firefox會以紅色的字體標明。
~~~
git checkout -f step3.2.5.1
~~~
執行上述命令后,上述示例代碼信息如下:
C層:

V層:

### 加入動態數據
在這里,我們用到一個標簽,叫做`volist`,作用是循環輸出一個數組。關于標簽的知識,我們以后需要參考官方的thinkphp5快速入門教程來進行單獨的學習。
> 有人說,太多了,我記不住。是的,我們也記不住。現在我們能夠不查手冊使用的,也就那么幾個常用的標簽,記住的原因還僅僅是我們用的多了而已。記住標簽不是我們學習的目標,每個框架的標簽都不一樣,記住去哪找標簽才是我們學習的目標。去哪找呢?thinkphp5官方手冊!
加入volist標簽后的代碼如下:
~~~
<table>
<tr>
<th>序號</th>
<th>姓名</th>
<th>性別</th>
<th>郵箱</th>
<th>用戶名</th>
</tr>
{volist name="teachers" id="teacher"}
<tr>
<td>1</td>
<td>張三</td>
<td>男</td>
<td>11@maol.com</td>
<td>zhangsan</td>
</tr>
{/volist}
</table>
~~~
我們再測試一遍,測試的時候,我們只是刷新一次而已,并不麻煩,不要等寫了很多代碼后再統一刷新測試,并不是說那種方法不可以,而是說,我們現在的水平還沒有達到。測試結果如下所示:

我們看到成功的將張三的信息輸出了兩遍,說明volist成功的執行了。
現在我們再加入一行測試代碼,讓我們能夠更清晰的看到teachers變量的結構。如下所示:
~~~
<body>
<table>
<tr>
<th>序號</th>
<th>姓名</th>
<th>性別</th>
<th>郵箱</th>
<th>用戶名</th>
</tr>
{volist name="teachers" id="teacher"}
<tr>
<td>1</td>
<td>張三</td>
<td>男</td>
<td>11@maol.com</td>
<td>zhangsan</td>
</tr>
{/volist}
</table>
{:var_dump($teachers)}
</body>
~~~
測試結果如下所示:

> 永遠不要認為加入測試代碼是件麻煩的事情,因為你盲人摸象才是真麻煩。在使用一個數據時,必須非常清楚的知道這個數據的類型及結構。
好了,現在我們可以根據var_dump()出來的信息,進行數據的定制了。
測試信息如下:
~~~
<body>
<table>
<tr>
<th>序號</th>
<th>姓名</th>
<th>性別</th>
<th>郵箱</th>
<th>用戶名</th>
</tr>
{volist name="teachers" id="teacher" key="key"}
<tr>
<td>{$key}</td>
<td>{$teacher->getData('name')}</td>
<td>{$teacher->getData('sex')}</td>
<td>{$teacher->getData('email')}</td>
<td>{$teacher->getData('username')}</td>
</tr>
{/volist}
</table>
</body>
~~~
刷新頁面,測試結果如下:

### 解決性別為0的問題
性別為0,顯然不是我們想要的。這里,我們需要用到另外一個標簽 eq:即判斷如果是0,則顯示男,如果不是0,則顯示女。
將性別一欄改寫為:
~~~
<td>{eq name='teacher->getData("sex")' value='0'}男{else /}女{/eq}</td>
~~~
>{eq}{/eq}我們叫做非自閉合標簽,也就是肯定有自己的另一半的。
>{else /}我們叫做自閉全標簽,不需要找自己的另一半。
>是的,這和HTML一樣。
測試結果如下圖所示:

測試的時候,我們往往需要測試一個正確的,再測試一個錯誤的。拿到這里來講,就是我要測試一個男,還要測試一個女。
這里的方法有兩個:
1、修改數據表:這個我們還沒怎么學。
2、修改代碼:是的,我們用這個。
代碼修改為:
~~~
<td>{eq name='teacher->getData("sex")' value='1'}男{else /}女{/eq}</td>
~~~
測試結果如下圖所示:

最后,我們恢復正常的代碼,并且去除測試代碼:
~~~
<body>
<table>
<tr>
<th>序號</th>
<th>姓名</th>
<th>性別</th>
<th>郵箱</th>
<th>用戶名</th>
</tr>
{volist name="teachers" id="teacher" key="key"}
<tr>
<td>{$key}</td>
<td>{$teacher->getData('name')}</td>
<td>{eq name='teacher->getData("sex")' value='0'}男{else /}女{/eq}</td>
<td>{$teacher->getData('email')}</td>
<td>{$teacher->getData('username')}</td>
</tr>
{/volist}
</table>
</body>
~~~
最終,測試效果如下圖所示:

~~~
git checkout -f step3.2.5.2
~~~
執行上述命令后,上述示例代碼信息如下:

- 序言
- 第一章 準備知識
- 第一節:XAMPP
- 第二節:NAVICAT
- 第三節:GIT
- 第二章 HelloWorld
- 第一節:下載THINPHP5.0
- 第二節:啟動xampp
- 第三節:hello thinkphp
- 第四節:Hello world
- 第五節:MCA
- 第六節:單引號與雙引號
- 第三章 教師管理
- 第一節:新建數據庫
- 第二節:CURD之R 讀數據
- 3.2.1 時序圖
- 3.2.2 連接數據庫
- 3.2.3 直接讀取數據
- 3.2.4 間接讀取數據
- 3.2.5 使用V層顯示數據
- 3.2.6 引入bootstrap
- 3.2.7 加入bootstrap樣式
- 第三節:CURD之 C 增加數據
- 3.3.1 插入數據
- 3.3.2 表單傳值
- 3.3.3 存儲表單數據
- 3.3.4 自動時間戳
- 3.3.5 增加驗證
- 第四節:CURD之 D 刪除數據
- 3.4.1 什么是關鍵字
- 3.4.2 刪除數據
- 3.4.3 定制刪除鏈接
- 3.4.4 完善刪除
- 第五節:CURD之 U 更新數據
- 3.5.1 讀取數據
- 3.5.2 展示數據
- 3.5.3 修改數據
- 3.5.4 傳遞數據
- 3.5.5 接收數據
- 3.5.6 更新數據 方法一
- 3.5.7 更新數據 方法二
- 第六節:銜接各個action & 重構代碼
- 3.6.1 index action
- 3.6.2 add action
- 3.6.3 insert action
- 3.6.4 delete action
- 3.6.5 edit action
- 3.6.6 update action
- 第七節:分頁
- 3.7.1 調用內置分頁
- 3.7.2 select與paginate(選學)
- 3.7.3 分頁原理(選學)
- 3.7.4 調用page(選學)
- 第八節:模糊查詢
- 3.8.1 增加查詢
- 3.8.2 完善查詢
- 第四章 登錄與注銷
- 第一節:cookie 與 session
- 第二節:靜態方法
- 第三節:規劃URL跳轉
- 第四節:登錄
- 4.4.1 登錄流程
- 4.4.2 index action
- 4.4.3 login action
- 4.4.4 引入M層
- 4.4.5 異常Exception
- 第五節:注銷
- 第六節:驗證
- 4.6.1 action增加驗證
- 4.6.2 使用構造函數驗證
- 4.6.3 使用繼承驗證
- 第五章 E-R圖與數據字典
- 第一節:第一張E-R圖
- 第二節:實體間的關系
- 第三節:開發規范
- 第六章 班級管理
- 第一節:建立數據表
- 第二節:數據列表index
- 第三節:增加數據add
- 第四節:編輯數據edit
- 第五節:刪除數據delete
- 第七章 學生管理
- 第一節:建立數據表
- 第二節:數據列表
- 7.2.1 顯示性別
- 7.2.2 顯示創建時間
- 7.2.3 顯示班級名稱
- 7.2.4 顯示輔導員姓名
- 第三節:編輯數據
- 第四節:魔法函數
- 第五節:源碼分析
- 第八章 課程管理
- 第一節:建立數據表
- 第二節:新增課程
- 第三節:編輯課程
- 8.3.1 edit
- 8.3.2 update
- 第九章 代碼重構
- 第一節:add 與 edit
- 第二節:insert 與 update
- 第三節:模板繼承
- 9.3.1 index.html
- 9.3.2 edit.html
- 9.3.3 小結
- 第十章 UML圖
- 第一節:E-R圖回顧
- 第二節:UML圖
- 第十一章 菜單與路由
- 第一節:添加菜單
- 第二節:虛擬主機
- 第三節:定制路由
- 第十二章 開發調試
- 第一節:開啟trace
- 第二節:查看日志
- 第十三章:總結