天天看點

CI MVC

如果您是一位 PHP 開發人員,在使用 PHP 程式設計語言時不難發現:大型項目可能會變得複雜。

這并非 PHP 的缺點。是的,這種語言提供了豐富的特性,而且具有足夠理想的彈性,可區分程式員之間的工作成果。在這種意義上,PHP 類似于 Perl,這是一些人喜歡它(而其他人鄙視它)的原因之一。任何曾經檢視過遺留 PHP 項目的有經驗的 PHP 開發人員都可以輕松判斷出不同開發人員在項目不同階段的工作 — 就像您是一位考古學家,正在凝視着深深的墓穴,見證着不同文化在各自時代的發展。

不管涉及了什麼樣式或使用了什麼方法,超過幾千行代碼的 PHP 項目很容易在倉促之中變得淩亂不堪。這主要是因為它們在結構上不一緻。一些程式員建立類來組織其工作,但似乎沒有任何兩個程式員對于如何編寫類具有相同的看法。其他程式員建構大量充滿函數的包含檔案。還有其他人使用巨大、獨立的庫,比如 PEAR。

       MVC 架構如何提供幫助

在幾年前,PHP 一直缺乏一個良好的、功能完善的模型-視圖-控制器(Model-View-Controller,MVC)架構。MVC 架構允許程式員将其代碼組織為三個不同的功能區:

模型 包含與您的資料庫和其他資料結構相關的所有代碼。如果您具有一個名為 pages 的表,則您具有一個模型,其中具有用于從表中選擇、建立、更新和删除記錄的函數。

視圖 包含所有顯示和 UI 元素 — JavaScript 代碼、Cascading Style Sheets (CSS)、HTML 甚至 PHP。

控制器 将一切聯系在一起。控制器中的每個函數表示一個目的地或路線。如果您具有一個名為 /about 的目的地,則控制器将具有一個名為 <code>about()</code> 的函數。

如果以前沒有使用過 MVC 架構,上述三點無法展現出這種組織模式的強大之處。一旦您開始用 MVC 思考,您對 PHP 開發的觀點和态度将發生顯著變化。

例如,不是在項目的每個可用角落中都塞入資料庫查詢代碼,而是将一切都組織到模型中。為了從資料庫表中選擇頁面,可以使用頁面模型中的函數。

同樣地,如果您需要更新特定頁面的外觀,可以使用視圖,而不用與控制器打交道。與此類似,控制器是為您的應用程式添加目标和其他控制代碼的位置;不必在模型中放入任何此類東西。

無論使用哪種 MVC 架構,在一天之内,您就會意識到您具有一個容易記住、可按需擴充的系統。如果客戶在下周需要更改,沒問題 — 您可以搞定。如果第二年有什麼請求,同樣如此。        

約定優于配置 MVC

在所有 MVC 架構中,最著名的莫過于 Ruby on Rails。多年以前,它席卷 Web 開發領域,滿足了所有人的想像。它并非純粹的 MVC 架構,而是一種約定優于配置的 MVC 架構。

約定優于配置 意味着使用 Rails 時,您需要設定一些關鍵配置項(例如資料庫的位置、特定使用者名和路徑),其他配置均由智能預設設定處理,您可在随後修改,也可不加修改。

結果不僅僅能得到組織良好的代碼,而且還有速度極快、易于使用的 Web 開發環境。這都是 PHP 世界的夢想。經過一兩年之後,許多類似于 Rails 的工具紛紛出現:CakePHP、Symfony 等等。

了解 CodeIgniter

最終,EllisLab 的從業人員釋出了 CodeIgniter。許多企業嘗試體驗過所有 PHP MVC 架構之後,CodeIgniter 都成為赢家,主要是由于它為組織提供了足夠的自由支援,允許開發人員更迅速地工作。

自由意味着使用 CodeIgniter 時,您不必以某種方式命名資料庫表,也不必根據表命名模型。這使 CodeIgniter 成為重構遺留 PHP 應用程式的理想選擇,在此類遺留應用程式中,可能存在需要移植的所有奇怪的結構。

CodeIgniter 不需要大量代碼(1.6.2 版本僅為 2.8 MB,其中的 1.3 MB 是可以删除的使用者文檔),也不會要求您插入類似于 PEAR 的龐大的庫。它在 PHP 4 和 PHP 5 中表現同樣良好,允許您建立可移植的應用程式。最後,您不必使用模闆引擎來建立視圖 — 隻需沿用舊式的 HTML 和 PHP 即可。

至此,我們已經提供了足夠的介紹,下面來建構一個簡單的項目,看看它的效果。

安裝和配置 CodeIgniter

在建構任何 CodeIgniter 新項目時,第一步都是下載下傳最新軟體包(在本文撰寫時,最新軟體包是 1.6.2,請參見 參考資料 小節)。下載下傳壓縮存檔檔案(.zip)并解壓縮之後,您就獲得了一個 codeigniter_&lt;version_number&gt; 檔案夾,其中包括開始建立所必須的一切内容。

在進行一組必需的輕微的配置更改之前,本節将為您簡單介紹 CodeIgniter,使您熟悉它的基礎知識。

檔案夾結構

打開 CodeIgniter 檔案夾時,您會看到一個名為 system 的檔案夾。所有 CodeIgniter 代碼都将存放在這裡。在此檔案夾内還有一些檔案夾,其中有一個名為 application:您要處理的 99.999% 的檔案都将位于此檔案夾内。該檔案夾的命名十分貼切,因為它包含您的應用程式及其所有組成部分 — system 檔案夾的其他部分包括 CodeIgniter 核心代碼和其他不應混淆的檔案。

application 檔案夾下又分為多個檔案夾(參見 圖 1)。大多數檔案夾易于了解。模型存放在 models 檔案夾中、視圖存放在 views 檔案夾中、控制器存放在 controllers 檔案夾中,依此類推。還有一些檔案夾用于存儲 CodeIgniter 幫助程式和庫的本地擴充,這些内容不在本文讨論範圍之内。

圖 1. CodeIgniter 的檔案夾結構

就目前而言,system/application 檔案夾中最重要的檔案夾就是 config。該檔案夾内有兩個需要關注的檔案:config.php 和 database.php。

config.php 檔案包含設定 CodeIgniter 所需的基本參數和自變量。database.php 檔案包含連接配接資料庫所需的基本參數和自變量。

就目前而言,對于 config.php 檔案,您隻需設定 <code>base_url</code> 參數,例如設定為 http://127.0.0.1/CodeIgniter/。根據您正在使用的伺服器位址更改此設定:

務必牢記添加最後的斜杠,即便是在子目錄中設定 CodeIgniter 應用程式時也是如此。

接下來,打開 database.php 檔案,為資料庫伺服器設定 connection 參數:

就是這樣。您還可以進行其他一些設定(如自動加載首選項和特殊路徑),但隻要 CodeIgniter 了解它位于何處且可連接配接其底層資料庫,您就可以放心開始編寫代碼了。

您的第一個 CodeIgniter 項目

現在,您已經安裝和配置了 CodeIgniter,接下來即可建構項目,這項工作至少要占用一個小時的時間。

這一次,我們不會建構 Hello World 應用程式,而是使用 CodeIgniter 建立一個簡單的 Web 站點。該站點将有一個首頁,顯示一些宣傳文本和一個表單,該表單将釋出到資料庫表中。無需為其外觀費心 — 隻需關注對應用程式有用的部分即可。換句話說,讓美工去關心外觀 — 您隻要確定一切可以正常工作、迅速完成即可。

按照 CodeIgniter 的術語,可将這些需求轉換為以下内容:

一個控制器,僅包含少數功能(可使用預設的 Welcome 控制器)

一個模型(以及一個資料庫表),用于存儲聯系人資訊

一個主視圖,包含一些支援

建立資料庫表和模型

從模型入手可幫助您了解底層資料庫表,之後再開始布設功能和 UI。如果對表将存儲哪些内容認識不深,設計與表互動的表單将十分困難。

對于這個示例應用程式而言,您希望存儲的是來自表單的聯系人資訊。那麼需要的是哪些類型的聯系人資訊?目前而言,僅存儲基本資訊,要求提供姓名、電子郵件位址、電話号碼和簡短備注。您還可能希望在背景存儲時間戳和 IP 位址。

MySQL 表應如下所示:

現在我們已經有了表,接下來将建立第一個模型。在 system/application/models 檔案夾内,建立一個 mcontacts.php 檔案。為什麼要将其命名為 mcontacts?這是一種速記形式 — 檔案名中在模型名前加一個 m 可幫助您記住檔案的組織方式,而不必使用更長的字首或字尾,如 model_ 等。

所有模型都采用相同的方式構造:

請注意,類名與檔案名比對,必須為類提供一個構造函數。換句話說,一個模型就是一個 PHP 類。這也就意味着模型中的所有函數實際上都是該類的一個方法。

了解這一點之後,很快就能領悟到,需要具備一個函數,将資料安全地插入聯系人資料庫表中。提供此功能的函數如下:

注意,您擷取了 <code>POST</code> 數組的輸出、整理并将其存儲在名為 contacts 的資料庫表中。在此過程中,您使用了多個幫助程式來簡化工作。

例如,<code>$this-&gt;input-&gt;xss_clean()</code> 整理表單字段的資料、<code>$this-&gt;input-&gt;post()</code> 簡化對這些表單字段的通路、<code>$this-&gt;input-&gt;ip_address()</code> 從使用者的浏覽器擷取 IP 位址、<code>$this-&gt;db-&gt;insert()</code> 向資料庫表添加一條新記錄。

在這種上下文中,<code>$this-&gt;input-&gt;xss_clean()</code> 的使用必不可少 — 您正在處理 Web 使用者輸入,那可以是任何内容。使用 <code>xss_clean()</code> 函數或許是最基本的應對方法,您可能還要考慮應用更加穩妥的措施。添加功能來将字段長度縮短到一定大小可能也是一種合理做法。但就目前而言,<code>xss_clean()</code> 例程即可為您提供足夠的保護。

您隻用了短短幾分鐘就建立了一個可重用的函數,允許在資料庫中存儲聯系人資訊。現在,我們将轉而讨論控制器。

初始化控制器

在 CodeIgniter 中,控制器用于組織項目。設想每個函數都是站點或應用程式的一個頁面或目标。如果使用首頁,就需要一個 <code>index()</code> 函數。如果有一個 About up 頁面,就需要 <code>about()</code> 或 <code>about_us()</code> 函數 — 具體取決于您希望怎樣構造 URL。

甚至可以将控制器組織到檔案夾中,建立層次結構。例如,在 system/application/controllers 檔案夾中,可能有一個 admin 檔案夾,其中包含針對管理工具各主要部分的控制器。您可按照如下方法通路這些控制器(和函數):        http://www.example.com/admin/controller-name/function-name/。

目前隻需使用預設控制器,即 Welcome 控制器。它存儲在 system/application/controllers/ 檔案夾中,名為 welcome.php。打開時,應看到以下内容:

如您所見,類名反映了檔案名。這裡也有一個構造函數,調用 CodeIgniter 核心中的父 <code>Controller</code> 類。了解這些就夠了。

接下來,注意名為 <code>index()</code> 的啟動函數,它将加載 welcome_message 視圖。在删除此函數并編寫您自己的函數之前,有必要注意,此原型 <code>index()</code> 函數很好地滿足了為應用程式的最終使用者顯示資訊的最低要求。

我們繼續建構一個新的 <code>index()</code> 函數。首先需要加載有用的 Form — 它能幫助您完成建立聯系人表單的繁瑣任務。

下面,設定可在視圖内部使用的多個變量 — 通過這種方法,即可更好地組織應用程式。例如,您可能希望在控制器中設定标題和标題欄。如果要這樣做,就必須将變量載入視圖。所載入的變量之一就是所包含視圖的名稱。通過這種方法,即可設定包含所有外觀的主視圖,以及包含内容的各包含項:

<code>$data</code> 數組被傳入到一個稱為模闆的視圖(接下來即将建構此視圖)。數組内的資訊可使用鍵名通路,如果希望輸出标題欄,通過 <code>$headline</code> 通路它即可。

接下來,您将建立模闆和首頁視圖(後者隻是一個包含項),并完成控制器。

建立視圖

您的第一個視圖極為簡單 — 這是一個名為 template 的視圖。我們将盡力保持其簡單,展示視圖可以有多麼靈活。template 視圖存儲為 system/application/views 中的 template.php,初始形式如下所示:

但應牢記,您正在傳入三個變量:<code>$title</code>、<code>$headline</code> 和 <code>$include</code>(一個包含項的名稱)。下面是添加了粗體所示内容後的 template 視圖:

在添加的前兩條語句中,您将分别顯示在 <code>$data['title']</code> 和 <code>$data['headline']</code> 中找到的資料。随後使用 <code>$data['include']</code> 的值載入第二個視圖。在本例中是一個名為 home 的視圖(另請注意,為了簡化後續的一些工作,我們還添加了少許 CSS 代碼)。

如果需要調用,那麼最好首先進行建構。下面就是一個簡單的視圖,其中包含一個文本塊和一個從站點通路者處收集資訊的表單:

圖 2 顯示了将所有這些内容載入浏覽器後的效果。

圖 2. 帶有表單的簡單視圖

同樣,您使用了有用的 CodeIgniter 快捷方式集。這一次,使用的是 Form 幫助程式,将其載入控制器。<code>form_open()</code> 函數允許打開表單 — 它具有必要的自變量,即表單釋出的目标位置。下面,您将傳回控制器并添加 <code>contact()</code> 函數來處理表單釋出資料。

在表單中,您使用了 <code>form_label()</code> 來建立可通路的标簽,使用 <code>form_input()</code> 和 <code>form_textarea()</code> 來建構表單字段和文本區,使用 <code>form_submit()</code> 來建構輸入按鈕。請注意,通過 <code>form_input()</code> 和 <code>form_textarea()</code>(以及其他表單函數),您就可以傳入一個資訊數組,幫助跟蹤字段名稱、id、大小和其他資訊。

最後,使用 <code>form_close()</code> 關閉表單。

或許您會感到疑惑,為什麼要花時間來使用 Form 幫助程式。您可能充滿懷疑:如果在 Web 站點方面經驗豐富,為什麼還需要使用表單幫助程式?歸根到底,一切都與迅速、高效地完成工作有關,Form 幫助程式(以及其他幫助程式)能消除在使用 HTML 時遇到的大量繁雜工作。

讓我們回過頭來完成控制器。

完成應用程式

現在已經有了兩個視圖,因而需要重新回到控制器,為其添加兩個函數。您已經了解了第一個函數:即處理首頁上的表單傳入的 POST 的 <code>contactus()</code> 函數。第二個是 <code>thankyou()</code> 函數,它将用作該表單的最終确認頁面。

<code>contactus()</code> 函數非常簡單。載入 MContacts 模型,運作該模型内的 <code>addContact()</code> 函數,然後将使用者轉向 thank-you 頁面。請注意,要使用 <code>redirect()</code> 函數,必須載入 URL 幫助程式。

代碼如下所示:

thankyou()        函數如下所示:

一切都非常簡單,thanks 視圖如下所示:

您可能感到迷惑,為什麼要為如此簡單的一個視圖浪費時間。為什麼不在控制器中設定一個變量再運作它?當然可以那樣做,但分離函數元件總是最佳做法。通過這樣的方式,就不存在遇到任何麻煩的風險。

添加安全性

現在,還有一項工作需要完成。在 Welcome 控制器的 <code>contactus()</code> 函數中,有着在資料庫中建立多條空記錄的風險 — 這會導緻某人連續将聯系人目标載入其浏覽器或使用某種類型的機器人。

要避免此類情況發生,最簡單的方法就是在控制器中添加簡單的測試。如果存在 <code>POST</code> 資料,則載入模型和函數。如果沒有,則将其傳回首頁。改寫後的函數如下所示:

結束語

在不到一個小時的時間裡,您安裝并配置了 CodeIgniter,建立了一個包含首頁、将資訊添加到資料庫的表單和 thank-you 頁面的 Web 站點。

當然,要學習的東西還有很多。例如,您可自動加載所需的模型和任何幫助程式或庫。可以為應用程式調整緩存和性能。可以為視圖添加更多 CSS 内容。可以添加在資料庫插入操作結束後發送電子郵件通知的功能。

目前,您隻是掌握了開始使用 CodeIgniter 所需的一些内容。