edit(更新処理) で put メソッドを使う CakePHP
v 2.5.6 より
乗り越えるべき課題
CakePHP では
X. View で $this->Form->Create
を定義したとき、デフォルトで method="post" が定義される
Y. Model が更新値を save する時
primary key が request->data['Model'] になかった場合
更新処理(update)ではなく作成処理(insert)になる
X-1. Form::Create で method の種類を指定しなかった場合
1 <?php 2 echo $this->Form->Create('Post');
次の通りに HTML 出力される
<form id="PostEditForm" accept-charset="utf-8" method="post" action="/cake/posts/edit/1">
Y-1.
posts db の属性が -> [id(PK), title, body, created_at, updated_at] で
app/View/Posts/edit.cpt 一部が次の通りとする
1 <?php 2 echo $this->Form->Create('Post'); 3 echo $this->Form->input('title'); 4 echo $this->Form->input('body')); 5 echo $this->Form->end('Update'); 6 ?>
app/Controller/PostsController/edit.php 一部が次の通りとする
34 public function edit($id = null) { 35 if($this->request->is('put')) { 36 if($this->Post->save($this->request->data)) {
フォームに入力された値が正常な場合でも、save では新規登録処理(insert) が行われる
課題への対策
X. FormHelper に type オプションとアクションを明示する
Y. primary key の属性に対するフィールドを hidden で埋め込み、request->data から参照できるようにする
1 <?php 2 echo $this->Form->input('id', array('hiddenField' => true)); 3 echo $this->Form->Create('Post', array('type' => 'put', 'action' => 'edit')); 4 echo $this->Form->input('title'); 5 echo $this->Form->input('body')); 6 echo $this->Form->end('Update'); 7 ?>
X. に付随して routing を修正する
例として次の通り
32 Router::connect('/:controller/:id', array('controller' => 'posts', 'action' => 'edit', '[method]' => 'PUT'), array('id' => '[0-9]'));
以下、個人的な止め書き(知ったことを列挙しているだけ)
Session パッケージを使わず、path parameter のみで edit 処理をできるだけ安全に処理させる
(curl などでリクエストされた時は危ないだろう)
app/View/Posts/edit.cpt
1 <?php 2 echo $this->Form->Create('Post', array('type' => 'put', 'action' => 'edit')); 3 echo $this->Form->input('id', array('default' => $put['Post']['id'], 'hiddenField' => true)); 4 echo $this->Form->input('title', array('default' => $put['Post']['title'])); 5 echo $this->Form->input('body', array('default' => $put['Post']['body'], 'rows' => 3)); 6 echo $this->Form->end('Update'); 7 ?>
app/Controller/PostsController/edit.php
29 public function edit($id = null) { 30 if(is_null($id)) { /* put 処理が失敗したときは $id が null になる 31 L42 で Post が再び findById できるように hidden で得た id を $id へ割り当てる */ 32 $id = $this->request->data['Post']['id']; 33 } 34 if($this->request->is('put')) { 35 if($this->Post->save($this->request->data)) { 36 $this->Session->setFlash('Success!'); 37 return $this->redirect(array('action' => 'index')); 38 } else { 39 $this->Session->setFlash('Failed!'); 40 } 41 } 42 $this->set('put', $this->Post->findById($id)); 43 }
app/Config/routes.php
32 Router::connect('/:controller/:id', array('controller' => 'posts', 'action' => 'edit', '[method]' => 'PUT'), array('id' => '[0-9]'));