CakePHP 2.x CookBook 中文版 第三章 入門(二)

創建 Post 視圖

如今已經有了數據流、模型、程序邏輯和定義數據流向的控制器。咱們要創建與上面例子中的 index 動做對應的視圖。 php

Cake 視圖僅是呈現應用程序佈局的片斷。對於多數應用程序,視圖是混合了 PHP 的 HTML,可是它也能夠是 XML、CSV,甚至是二進制數據。 數據庫

佈局是包裝視圖的處理顯示的代碼,可以定義和切換,可是如今,咱們使用默認的佈局。 數組

還記得上一節是如何使用 set() 方法給視圖中的 ‘posts’ 變量賦值的嗎?所傳遞的數據相似於: 瀏覽器

 1 // print_r($posts) output:  2  3 Array  4 (  5 [0] => Array  6  (  7 [Post] => Array  8  (  9 [id] => 1 10 [title] => The title 11 [body] => This is the post body. 12 [created] => 2008-02-13 18:34:55 13 [modified] => 14  ) 15  ) 16 [1] => Array 17  ( 18 [Post] => Array 19  ( 20 [id] => 2 21 [title] => A title once again 22 [body] => And the post body follows. 23 [created] => 2008-02-13 18:34:56 24 [modified] => 25  ) 26  ) 27 [2] => Array 28  ( 29 [Post] => Array 30  ( 31 [id] => 3 32 [title] => Title strikes back 33 [body] => This is really exciting! Not. 34 [created] => 2008-02-13 18:34:57 35 [modified] => 36  ) 37  ) 38 )

Cake 的視圖文件存儲在 /app/View 目錄下與控制器名稱(去掉了 controller 後綴)同名的文件夾中(如今的狀況下,要建立 /app/View/Posts 文件夾)。使用漂亮的表格格式化數據,其視圖相似於: 服務器

 1 <!-- File: /app/View/Posts/index.ctp -->  2  3 <h1>Blog posts</h1>  4 <table>  5 <tr>  6 <th>Id</th>  7 <th>Title</th>  8 <th>Created</th>  9 </tr> 10 11 <!-- Here is where we loop through our $posts array, printing out post info --> 12 13 <?php foreach ($posts as $post): ?> 14 <tr> 15 <td><?php echo $post['Post']['id']; ?></td> 16 <td> 17 <?php echo $this->Html->link($post['Post']['title'], 18 array('controller' => 'posts', 'action' => 'view', $post['Post']['id'])); ?> 19 </td> 20 <td><?php echo $post['Post']['created']; ?></td> 21 </tr> 22 <?php endforeach; ?> 23 <?php unset($post); ?> 24 </table>

但願這看起來挺簡單。 session

你可能已經注意到例子中所用的那個調用 $this->HTML 的對象,這是 CakePHP 中 ‘HtmlHelper’ 的一個實例。CakePHP 帶有一個生成相似連接、表單輸出、JavaScript 和 Ajax 快照的視圖助手集合。在 助手 一節你能學到更多如何使用它們的方法,如今要重點注意的是 link() 方法,它能用給定的標題(第一個參數)和 URL (第二個參數)生成 HTML 連接。 app

推 薦使用數組格式在 CakePHP 中指定 URLs。在「路由」一節對此有更多的解釋。使用數組格式處理 URLs 能夠得到 CakePHP 服務器的路由兼容性。也能夠用 /controller/action/param1/param2 的格式將 URLs 關聯到應用程序。 函數

如今,讓你的瀏覽器指向 http://www.example.com/posts/index 。你會看到帶有標題和帖子列表的格式正確的視圖。 oop

如 果你點擊了咱們創建的這個視圖中的某個連接(它將一個帖子標題連接到 URL /posts/view/some_id), 你應該會發現 CakePHP 會報告那個 action 尚未定義。 若是你沒有收到這個報告,代表有些事情可能出錯了,或者你居然已經定義了它,這是很詭異的一種情形^_^。 如今,讓咱們在 PostsController 中創建它: 佈局

 1 class PostsController extends AppController {  2 public $helpers = array('Html', 'Form');  3  4 public function index() {  5 $this->set('posts', $this->Post->find('all'));  6  }  7  8 public function view($id = null) {  9 $this->Post->id = $id; 10 $this->set('post', $this->Post->read()); 11  } 12 }

set() 調用看上去有點眼熟。須要注意的是,咱們在此優先使用 read() 而不是 find('all'),這是由於咱們僅僅要獲得一條帖子信息。

還要注意,咱們的視圖 action 獲取了一個參數: 咱們但願看到的帖子的 ID。 這個參數是經過 URL 請求傳遞給 action 的。 若是用戶請求 /posts/view/3,那麼值 ‘3’ 就被傳遞給 $id

如今讓咱們創建一個新的 ‘view’ action 放在 /app/View/Posts/view.ctp 文件中。

1 <!-- File: /app/View/Posts/view.ctp --> 2 3 <h1><?php echo h($post['Post']['title']); ?></h1> 4 5 <p><small>Created: <?php echo $post['Post']['created']; ?></small></p> 6 7 <p><?php echo h($post['Post']['body']); ?></p>

嘗試輸入連接 /posts/index 或者手動訪問 /posts/view/1,看看工做是否正常。.

添加帖子

雖然從數據庫中讀出貼子並展現給咱們是個不錯的開始,可是咱們還須要能夠添加貼子。

首先,從在 PostsController 中創建 add() 方法開始:

 1 class PostsController extends AppController {  2 public $helpers = array('Html', 'Form', 'Session');  3 public $components = array('Session');  4  5 public function index() {  6 $this->set('posts', $this->Post->find('all'));  7  }  8  9 public function view($id) { 10 $this->Post->id = $id; 11 $this->set('post', $this->Post->read()); 12 13  } 14 15 public function add() { 16 if ($this->request->is('post')) { 17 $this->Post->create(); 18 if ($this->Post->save($this->request->data)) { 19 $this->Session->setFlash('Your post has been saved.'); 20 $this->redirect(array('action' => 'index')); 21 } else { 22 $this->Session->setFlash('Unable to add your post.'); 23  } 24  } 25  } 26 }

註解

在使用 Session 的任何一個 controller 中都須要包含 SessionComponent (和SessionHelper)。若是須要,能夠將它包含在 AppController 中。

add() 實現了這樣幾個功能:若是表單提交的數據非空,就試圖使用 Post 模型保存數據。若是由於某些緣由保存未成功,則渲染視圖,這給了咱們向用戶顯示數據校驗或其它警告的機會。

每一個 CakePHP 請求包含一個 CakeRequest 對象,它能夠經過 $this->request 訪問。 request 對象包含此次請求被獲取的信息,並可以用於應用程序流的控制。 在本例中,咱們使用 CakeRequest::is() 方法檢驗請求是不是以 HTTP POST 格式提交的。

當用戶使用表單嚮應用程序提交數據(POST),其信息可使用 $this->request->data 獲取。 可使用 pr() 或debug() 方法輸出這些數據。

咱們使用了 Session 組件的 SessionComponent::setFlash() 方法發送了一條信息給 session 變量,用於在中轉頁上顯示。 在中轉頁的佈局中咱們用 SessionHelper::flash 顯示和清除這個 session 變量。 該控制器的Controller::redirect 方法用於跳轉到其它 URL。 參數 array('action' => 'index') 指定了跳轉到 /posts URL,等於 posts 控制器的 index 方法。 你能夠參考 API 中的 Router::url() 功能,它使你能夠指定爲不一樣的 Cake 函數指定一個 URL 格式。

調用 save() 方法將檢查檢驗錯誤,並在出現錯誤時跳過保存。 咱們將在後續的章節中討論如何處理這些錯誤。

數據校驗

Cake 在獲取表單校驗的單調輸出方面作了大量的工做。每一個人都痛恨無止境的編寫表單及其驗證。CakePHP 使其變得更快更容易。

想要更好的利用校驗功能,就須要在視圖中使用 FormHelper 助手。FormHelper 助手默認在全部視圖中均可用,用法是 $this->Form

這是咱們添加的視圖:

1 <!-- File: /app/View/Posts/add.ctp --> 2 3 <h1>Add Post</h1> 4 <?php 5 echo $this->Form->create('Post'); 6 echo $this->Form->input('title'); 7 echo $this->Form->input('body', array('rows' => '3')); 8 echo $this->Form->end('Save Post'); 9 ?>

在這裏,咱們用 FormHelper 助手生成一個 HTML 表單的起始標籤。$this->Form->create() 生成的 HTML 是:

1 <form id="PostAddForm" method="post" action="/posts/add">

若是 create() 是不帶參數調用的,表示建立的表單將以 POST 形式提交給同一個控制器的 add() (或者當表單中含有 id 元素時提交給 edit())動做。

$this->Form->input() 方法用來生成同名的表單元素,這個方法的第一個參數告訴 CakePHP 先後臺通信的是哪一個域,第二個參數容許指定選項:本例中,是 textarea 域的行數。這裏有一點自動完成的:input() 方法將基於 model 指定的域生成不一樣的表單元素。

$this->Form->end() 調用生成一個 submit 元素並結束表單。若是提供給 end() 方法的第一個參數是字符串,FormHelper 生成一個相應名稱的 submit 域並關閉表單標籤。再說一次, 助手 一節有更多的助手信息。

如今咱們返回並更新 /app/View/Posts/index.ctp 視圖使其包含一個新的 「Add Post」 連接。在 <table> 以前添加以下行:

1 <?php echo $this->Html->link( 2 'Add Post', 3 array('controller' => 'posts', 'action' => 'add') 4 ); ?>

你可能會奇怪:我如何通知 Cake 個人校驗要求?校驗規則是定義在模型中的。讓咱們回顧 Post 模型並稍做調整:

 1 class Post extends AppModel {  2 public $validate = array(  3 'title' => array(  4 'rule' => 'notEmpty'  5 ),  6 'body' => array(  7 'rule' => 'notEmpty'  8  )  9  ); 10 }

$validate 數組告訴 CakePHP 在 save() 方法被調用時如何校驗咱們的數據。這裏,我指定 title 和 body 都不能爲空。CakePHP 的校驗功能很強勁,帶有一批預置的規則(如 信用卡號碼、Email 地址等),並且能夠靈活地添加本身的校驗規則。能夠瀏覽 數據校驗 獲取更多的相關信息。

如今已經有了校驗規則,試着輸入空的 title 和 body,看看它們是如何工做的。當咱們使用 FormHelper 的FormHelper::input() 方法建立表單,校驗的錯誤信息會自動顯示。

編輯帖子

咱們已經來到了帖子編輯這一步,如今你已是一個 CakePHP 的高手了,因此你應該操起一個模式。編寫動做,而後是視圖。PostsController 的 edit() 方法相似於:

 1 public function edit($id = null) {  2 $this->Post->id = $id;  3 if ($this->request->is('get')) {  4 $this->request->data = $this->Post->read();  5 } else {  6 if ($this->Post->save($this->request->data)) {  7 $this->Session->setFlash('Your post has been updated.');  8 $this->redirect(array('action' => 'index'));  9 } else { 10 $this->Session->setFlash('Unable to update your post.'); 11  } 12  } 13 }

這個動做首先檢查用戶提交的是否是 GET 請求。若是是,就找到 Post 並將其傳遞給視圖。若是不是,就可能包含 POST 數據。咱們將使用 POST 數據更新貼子記錄,或者將校驗的錯誤信息踢回並顯示給用戶。

edit 視圖相似於:

1 <!-- File: /app/View/Posts/edit.ctp --> 2 3 <h1>Edit Post</h1> 4 <?php 5 echo $this->Form->create('Post', array('action' => 'edit')); 6 echo $this->Form->input('title'); 7 echo $this->Form->input('body', array('rows' => '3')); 8 echo $this->Form->input('id', array('type' => 'hidden')); 9 echo $this->Form->end('Save Post');

這個視圖輸出編輯表單(帶有相應數據值),全部的錯誤校驗信息也一併提供。

有件事須要注意:若是提供的數據數組中包含 ‘id’ 域,CakePHP 認爲這是要修改一個模型的數據。若是沒有 ‘id’ 域,cake 會認爲當 save() 方法被調用時插入一條新的模型數據(參見 add 視圖)。

如今能夠更新 index 視圖,添加一個用於編輯的連接:

 1 <!-- File: /app/View/Posts/index.ctp  (edit links added) -->  2  3 <h1>Blog posts</h1>  4 <p><?php echo $this->Html->link("Add Post", array('action' => 'add')); ?></p>  5 <table>  6 <tr>  7 <th>Id</th>  8 <th>Title</th>  9 <th>Action</th> 10 <th>Created</th> 11 </tr> 12 13 <!-- Here's where we loop through our $posts array, printing out post info --> 14 15 <?php foreach ($posts as $post): ?> 16  <tr> 17 <td><?php echo $post['Post']['id']; ?></td> 18  <td> 19 <?php echo $this->Html->link($post['Post']['title'], array('action' => 'view', $post['Post']['id'])); ?> 20  </td> 21  <td> 22 <?php echo $this->Html->link('Edit', array('action' => 'edit', $post['Post']['id'])); ?> 23  </td> 24  <td> 25 <?php echo $post['Post']['created']; ?> 26  </td> 27  </tr> 28 <?php endforeach; ?> 29 30 </table>

刪除帖子

下面咱們來看刪除貼子的道道。在 PostsController 中添加 delete() 動做:

1 public function delete($id) { 2 if ($this->request->is('get')) { 3 throw new MethodNotAllowedException(); 4  } 5 if ($this->Post->delete($id)) { 6 $this->Session->setFlash('The post with id: ' . $id . ' has been deleted.'); 7 $this->redirect(array('action' => 'index')); 8  } 9 }

這個邏輯根據 $id 刪除指定的貼子,而且使用 $this->Session->setFlash() 在用戶重定向到 /posts 以後顯示一條確認信息。若是用戶試圖用 GET 請求執行刪除,咱們就拋出一個異常。咱們沒有捕獲的異常,將被 CakePHP 的異常句柄捕獲並顯示一個友好的錯誤頁。有許多內置的 異常 ,可以用於指示應用程序須要生成的不一樣的 HTTP 錯誤。

由於咱們僅僅執行了一些邏輯就重定向了,這個動做沒有視圖。可是仍然可能須要更新 index 視圖,添加容許用戶刪除貼子的連接:

 1 <!-- File: /app/View/Posts/index.ctp -->  2  3 <h1>Blog posts</h1>  4 <p><?php echo $this->Html->link('Add Post', array('action' => 'add')); ?></p>  5 <table>  6 <tr>  7 <th>Id</th>  8 <th>Title</th>  9 <th>Actions</th> 10 <th>Created</th> 11 </tr> 12 13 <!-- Here's where we loop through our $posts array, printing out post info --> 14 15 <?php foreach ($posts as $post): ?> 16  <tr> 17 <td><?php echo $post['Post']['id']; ?></td> 18  <td> 19 <?php echo $this->Html->link($post['Post']['title'], array('action' => 'view', $post['Post']['id'])); ?> 20  </td> 21  <td> 22 <?php echo $this->Form->postLink( 23 'Delete', 24 array('action' => 'delete', $post['Post']['id']), 25 array('confirm' => 'Are you sure?')); 26  ?> 27 <?php echo $this->Html->link('Edit', array('action' => 'edit', $post['Post']['id'])); ?> 28  </td> 29  <td> 30 <?php echo $post['Post']['created']; ?> 31  </td> 32  </tr> 33 <?php endforeach; ?> 34 35 </table>
相關文章
相關標籤/搜索