CodeIgniter MVC 簡易入門

原始網址: http://codeigniter.com/wiki/MVC

目的

本教學將依續說明 MVC 是什麼,為什麼要有 MVC,以及 CI 如何支持它。在前面的說明之後,我將建立一個非常簡單的應用程式(一個用來顯示一些連結的應用程式)-- 但最重要的是這將用來解釋 MVC 模型 (model)。

MVC

model-view-controller (MVC) 是一種程式開發模式,針對目前以資料庫為基礎的網頁,將其區分成三個主要的功能 :

1. 資料庫功能 (Database functions) (CRUD)

2. 應用程式邏輯 (Application Logic) (例如,密碼的長度必須是 8 個字元)

3. 外觀 (Presentation) (HTML)

以上的元素都分別以 MVC 模型來代表

1. Model - 資料庫

2. Controller - 應用程式邏輯

3. View - HTML 頁面

一些規則

當使用 MVC 開發程式時,必須要考慮一些規則。 Here are a few to help get started:

不要 這樣做 (Don’t do these):

Views:

1. 絕對不要存取資料庫

2. 絕對不要使用任何複雜度超過 loops 和 if 的指令

Controllers:

1. 絕對不要包括 HTML 編碼

2. 絕對不要存取資料庫

Models:

1. 永遠,永遠絕對不要吐出 HTML

這樣做 (DO these):

Views:

1. 是模組化的 - 程式片段

2. 包含迴圈 (loops) 以及簡單的 if 邏輯

Controllers:

1. 擦掉所有 view 和資料庫的資訊

2. 提供所有 view 需要的資料

3. 對資料套用商業規則 (business rules)

4. 呼叫資料庫 models 來存取資料 (store/retrieve data)

5. 處理所有的錯誤訊息

Models:

1. 套用有限的商業邏輯 (business logic) -- 假如有的話 -- 到資料庫函式

2. 擷取任何錯誤並且將其送到 controller

3. 執行最少的資料完整性檢查

建立應用程式

資料庫

現在讓我們來建立網站資料庫的 ‘links’ table。此 table 需要下列欄位:

id - autoincrement
link_title - varchar(50)
link_url - varchar(255)

你可以隨意的在資料庫中加入一些測試資料。為這個資料庫建立一個 user。儘量避免使用 ‘root’ (sa) 帳號,確保資料庫的安全性。

CodeIgniter 資料庫設定

使用預設的 CI 安裝,開啟檔案 system/application/config/database.php :

$db['default']['hostname'] = "localhost";
$db['default']['username'] = "username"; //don't use root
$db['default']['password'] = "password";
$db['default']['database'] = "database";
$db['default']['dbdriver'] = "mysql"; //there are other drivers available! 

我假設你能夠設定 CI 的其餘部分,所以我不再繼續討論這部分。我比較喜歡自動載入此資料庫,所以設定了autoload 的檔案。

要如何著手? Where do I go now?

Model 期待由 controller 得到輸入

View 需要用 controller 來做顯示

Controller 需要由 view 來輸入

Model 需要將它的資料放在某個地方

...呃

下面是我已經找到的最簡單的方式:

1. 建立想要的 HTML/CSS layout.

2. 將界面拆解成下列三類:

- layout -- 只有架構 (structure)

- 所有 (大部分) 頁面的共同資料:

- - 頁尾 (footer)

- - affiliate links/ad space

- 各別頁面中不同的資料 (stuff that changes on each page):

- - 導覽 (navigation)

- - 頁面標題 (page title)

- - meta tags (keywords, description)

3. 建立第一個 controller,將所有的組件重新放在一起

4. 持續修正 model, form, 和各種資料... (“Get dynamic” with the model, forms, and stuff…)

The view(s)

我已經做了一個超級簡單的 view。可能有點太簡單了些,還請包涵。

application/views/layout/main.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?= $title ?></title>
</head>
<body>
<h1><?= $current_page ?></h1>
<div><?= $navigation ?></div>
<div><?= $content ?></div>
</body>
</html> 

你可以看到其中有三個變數:

title - 頁面標題

current_page - 表示此頁面標題的 header tag

navigation - 用來放頁面導覽 (page navigation) 的區塊

content - 用來放程式碼的區塊

application/views/navigation/nav_main.php

<ul id="navigation">
  <li><?= anchor("","Home") ?></li>
  <li><?= anchor("links","Links") ?></li>
</ul> 

在這個 view 中使用 URL helper 來建立連結。

最後,是一些內容:

application/views/content/link_list.php

注意到 view 和資料庫之間的相似性嗎?

The controller

讓我們用 controller 將這些放在一起:

application/controllers/welcome.php

<?php foreach($links as $link): ?>
<p><?= anchor($link->link_url,$link->link_title) ?><?= anchor('edit/'.$link->id,"Edit") ?></p>
<?php endforeach; ?> 
//function Welcome() (php4, php5 below)
function __construct()
{
  parent::Controller();
  $this->load->helper('url');    
}
function index() 
{
  $data = array(
   'title' => 'Test Application',
   'current_page' => 'Welcome',
   'navigation' => $this->load->view('navigation/nav_main','',true),
   'content' => ''
  );
  $this->load->view('layout/main',$data);
} 

請注意,我將陣列 $data 的 key 設成和 view 頁面中使用的變數一樣的名稱。你也會注意到我對變數 navigation 做了一些特別的事 -- 將一個 view 載入其中。載入 view 時將第三個參數設成 “true” 將會傳回產生的字串,而非將 view 載入到這個頁面。這樣可以將多個 view 頁面放在一個共用的 layout! :)

你也會注意到我讓 ‘content’ 保持空白。 (我將在稍後來處理它) 假如你現在載入你的頁面,你將會看到一個基本的 layout,其中有 “Welcome” 的 h1 tag 和 “Test Application” 的網頁的頁面標題。也包括未排序的導覽連結的列表 (其中一個連結是無效的)。

The model

我們要建立一個 model 來從資料庫取得連結 link 的列表:

application/models/links.php (檔名是小寫的 ‘L’)

<?php
//capital L for class name
class Links extends Model {
  function Links() {
    parent::Model();
  }
  function get_links() {
   $query = $this->db->get('links'); //same as Select * from links
   return $query->result();
  }
}
?> 

這個 model 只有一個簡單的 function -- get_links -- 用來取得我們先前建立的 links 資料庫中的所有的 record。

現在,讓我更新一下 controller:

application/controllers/welcome.php

function index() 
{
  $this->load->model('links');
  $links['links'] = $this->links->get_links();
  $data = array(
   'title' => 'Test Application',
   'current_page' => 'Welcome',
   'navigation' => $this->load->view('navigation/nav_main','',true),
   'content' => $this->load->view('content/link_list',$links,true)
  );
  $this->load->view('layout/main',$data);
} 

現在已經從資料庫取得資料,並且將資料放在 $links[‘links’] 陣列中。同時,我也載入另一個 view 頁面到 $data[‘content’] 陣列 -- 但第二個參數使用 $links 陣列來取代空白字申。

假如你重新載入網頁,你將會看到你所輸入到資料庫中的所有連結的列表!

結論

希望,這有助於說明如何建立 Model、View、Controller 來顯示從數據庫取出的訊息。

附記

關於 sub-view 的 load,我比較喜歡《Professional CodeIgniter》的方式,由 controller 傳 sub-view 的名稱,然後在 main layout 的 view 中再載入,如此比較 self-documented,由程式碼可以明確知道是載入一個 sub-view,與一般的變數能夠有所分別。各位可以比較看看,選用自己喜歡的風格。

前面的範例修改之後,列示如後

Controller: application/controllers/welcome.php

    function index()
    {
      $this->load->model('links');
      $links['links'] = $this->links->get_links();
      $data = array(
       'title' => 'Test Application',
       'current_page' => 'Welcome',
       'navigation' => 'navigation/nav_main',
       'content' => 'content/link_list',
       'links' => $links
      );
      $this->load->view('layout/main',$data);
    }

View: application/views/layout/main.php

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title><?= $title ?></title>
    </head>
    <body>
    <h1><?= $current_page ?></h1>
    <div><? $this->load->view($navigation); ?></div>
    <div><? $this->load->view($content,$links); ?></div>
    </body>