如今已經有了數據流、模型、程序邏輯和定義數據流向的控制器。咱們要創建與上面例子中的 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>