CakePHP1.3.6:Media Plugin1.3RCに挫折して、ファイルアップロードを自作(その2)
前回の続き。
まず、以下のアップロード画面を作る。これがメイン。
プログラム名はDocとするので、/app/controllersにdoc_controller.phpを作成する。
ビュー
/app/views/docsにadd.ctpを作る。
ファイルを複数uploadするには、DocImage.0.fileと同じ部分をコピーして、DocImage.1.fileとする。
<?php echo $form->create(null,array('type'=>'file','action'=>'add')); ?> <table> <?php echo "<tr><th>商品名</th>"; echo "<td>{$form->text('Doc.title',array('size'=>'20'))}{$form->error('Doc.title')} </td>"; echo "</tr>"; echo "<tr><th>メモ</th>"; echo "<td>{$form->textarea('Doc.description')}</td>"; echo "</tr>"; echo "<tr><th>ファイル</th>"; echo "<td>{$form->file("DocImage.0.file")}{$form->error('DocImage.path')}</td>"; echo "</tr>"; echo $form->end('登録'); ?> </table>
アクション
doc_controller.phpにadd()アクションを追加する。面倒くさいのでコントローラー全部を以下に書く。
以下では、120x90に画像を圧縮するようにしている。hasManyを定義しているので、Doc->savaAllでDocImageも保存される。
<?php require_once '../vendors/MyImageConv.class.php'; require_once '../vendors/MyConverter.class.php'; class DocsController extends AppController{ public $name = 'Docs'; public $uses = array('Doc','DocImage'); public $layout = 'myznala'; public $autoLayout = true; public $autoRender = true; public static $tmp_dir = './tmp/'; // 画像データの一時保管先 public static $save_dir = './img/'; // 画像データの保管先 public static $width = 120; // 画像データの幅 public static $height = 90; // 画像データの高さ /* * Paginatorの定義 */ public $paginate = array( 'page'=>1, 'conditions'=>array(), 'fields'=>array(), 'order'=>array('Doc.timestamp'=>'desc'), 'limit'=>5, 'recursive'=>1 // has manyのときは1 ); /** * * 初期画面(一覧表示) */ function index(){ $this->set('title_for_layout', "画像の一覧"); $req=null; if(!empty($this->data)){ //サニタイズ $req = MyConverter::getRequestParams($this->data["Doc"]); //絞り込みの場合には、コンディションを書き換える。 $this->paginate['conditions'] = array('Doc.title like ?' => array("%{$req["title"]}%")); } $data = $this->paginate(); $this->set('data',$data); } /** * * 登録 * * (注意);ファイルの保存場所とDocImageのパスについて * このサンプルでは、ファイルをwebroot/imgに保存する。このとき、$save_dirは./imgとするが、DocImage * にはファイル名のみを保存する。これは、$html->image()が、./imgまでを自動で補完するため。 * もし、webroot/img/[some dir]/に配置する場合には、$save_dirを./img/[some dir], DocImage * には[somedir]/[filename]を保管すること。 * */ function add(){ $this->set('title_for_layout', "画像の登録"); if(!empty($this->data)){ // サニタイズ $this->data["Doc"] = MyConverter::getRequestParams($this->data["Doc"]); // 写真の処理 $filename = $this->data['DocImage'][0]['file']['name']; // ファイルのアップロードチェック if(strlen(trim($filename))==0){ $this->DocImage->invalidate('path','画像を選択してください'); //(注意) 事前にinvalidateを使ってエラーチェックをする場合には、if..elseで分岐していかないと、 // save時のバリデーションがきかなくなってしまう。 }else{ $filename = $this->data['DocImage'][0]['file']['name']; $from_path = self::$tmp_dir.$filename; $to_path = self::$save_dir.$filename; if(move_uploaded_file($this->data['DocImage'][0]['file']['tmp_name'],$from_path)){ // イメージの圧縮 $ret = MyImageConv::imageConv($from_path, $to_path, self::$width, self::$height); if(!$ret) { $this->DocImage->invalidate('path','画像の形式が違います'); //(注意) 事前にinvalidateを使ってエラーチェックをする場合には、if..elseで分岐していかないと、 // save時のバリデーションがきかなくなってしまう。 }else{ $this->data['DocImage'][0]['path'] = $filename; // 登録 $this->Doc->saveAll($this->data); if($this->Doc->validates()){ // 登録できたらリダイレクト $this->redirect('.'); } } } } } } /** * * データの照会 * $paramsにIdが入ってくる。 * */ function show($param){ $this->set('title_for_layout', "画像の詳細"); $result=null; if(!empty($param)){ // Idフィールドによる検索 $this->data=$this->Doc->findById($param); if(!$this->data){ // 存在しないIDを参照された場合。 $this->Session->setFlash('存在しません'); $this->redirect('.'); } } $this->set('data',$this->data); } /** * * データの更新 * */ function edit($param){ $this->set('title_for_layout', "画像情報の更新"); // データの更新 if(!empty($this->data)){ // サニタイズ $this->data["Doc"] = MyConverter::getRequestParams($this->data["Doc"]); // Idフィールドによる検索 $check=$this->Doc->findById($param); if(!$check){ // 存在しないIDを更新しようとした場合。 $this->Session->setFlash('存在しません'); $this->redirect('.'); }else{ // 更新 $this->Doc->save($this->data); if($this->Doc->validates()){ // 更新できたらリダイレクト $this->redirect('.'); }else{ // 入力エラーの時、再検索して入力画面に戻す。 // これをやらないと、画像が表示できなくなる。 $this->data=$this->Doc->findById($param); } } // 更新データのセット(初期値) }else{ if(!empty($param)){ // Idフィールドによる検索 $check=$this->Doc->findById($param); if(!$check){ // 存在しないIDを更新しようとした場合。 $this->Session->setFlash('存在しません'); $this->redirect('.'); }else{ // Idフィールドによる検索 $this->data=$this->Doc->findById($param); } } } /* * 入力エラーの場合も通るようにする */ $this->set('data',$this->data); } /** * * データの削除 * */ function delete($param){ if(!empty($param)){ $check=$this->Doc->findById($param); if(!$check){ // 存在しないIDを削除しようとした場合。 $this->Session->setFlash('存在しません'); }else{ // Idフィールドによる削除 $this->data=$this->Doc->findById($param); $ret=$this->Doc->delete($param); // ファイルの削除 $path = self::$save_dir.$this->data['DocImage'][0]['path']; unlink($path); } $this->redirect('.'); } } } ?>
インデックス画面
インデックス画面は以下。
ビュー
index.ctpは以下。
<h2>画像の一覧</h2> <br> タイトルで絞り込みをします。 <?php // 絞り込み用フォーム echo $form->create(null,array('type'=>'post','action'=>'.')); echo $form->text('Doc.title', array('size' => 10)); echo $form->end('送信'); ?> <?php // ページネーション echo $paginator->numbers( array( 'before'=>$paginator->hasPrev() ? $paginator->first('<<').' ' : '', 'after'=>$paginator->hasNext() ? ' '.$paginator->last('>>') : '', 'modulus'=>4, 'separator'=>' ' ) ); ?> <table> <tr> <th><?php echo $paginator->sort('ID','Doc.id') ?></th> <th><?php echo $paginator->sort('タイトル','Doc.title') ?></th> <th>メモ</th> <th>画像</th> <th><?php echo $paginator->sort('更新日','Doc.timestamp') ?></th> </tr> <?php foreach ($data as $arr){ echo '<tr>'; echo '<td>'.$html->link($arr['Doc']['id'], array('controller'=>'docs', 'action'=>'show',$arr['Doc']['id'])).'</td>'; echo "<td>{$arr['Doc']['title']}</td>"; echo "<td>".mb_strimwidth($arr['Doc']['description'],0,50,'...')."</td>"; echo "<td>"; foreach ($arr['DocImage'] as $img){ echo $html->image($img['path']); echo " "; } echo "</td>"; echo "<td>{$arr['Doc']['timestamp']}</td>"; echo '</tr>'; } ?> </table> <?php echo $html->link('登録', array('controller'=>'docs', 'action'=>'add')); ?>
参照画面
上の一覧表示画面のIDにあるリンクをクリックすると以下の照会画面に遷移する。
ビュー
show.ctpは以下。
<h2>画像の詳細</h2> <br> <table> <?php echo "<tr><th>名前</th>"; echo "<td>{$data['Doc']['title']}</td>"; echo "</tr>"; echo "<tr><th>メモ</th>"; echo "<td>{$data['Doc']['description']}</td>"; echo "</tr>"; echo "<tr><th>画像</th>"; echo "<td>"; foreach ($data['DocImage'] as $img){ echo $html->image($img['path']); echo " "; } echo "</td>"; echo "</tr>"; echo "<tr><th>最新更新日</th>"; echo "<td>{$data['Doc']['timestamp']}</td>"; echo "</tr>"; ?> </table> <a href="../">リストに戻る</a> <?php echo $html->link('更新', array('controller'=>'docs', 'action'=>'edit', $data["Doc"]["id"])); ?>
更新画面
更新画面は以下。画像の入れ替えは面倒なのでできない仕様とした。その場合には削除後に再登録することになる。
ビュー
edit.ctpは以下。
<h2>画像情報の更新</h2> <?php echo $form->create('Doc',array('type'=>'post','action'=>'edit')); echo $form->hidden('Doc.id'); ?> <table> <?php echo "<tr><th>タイトル</th>"; echo "<td>{$form->text('Doc.title',array('size'=>'20'))}{$form->error('Doc.title')} </td>"; echo "</tr>"; echo "<tr><th>メモ</th>"; echo "<td>{$form->textarea('Doc.description')}</td>"; echo "</tr>"; echo "<tr><th>画像</th>"; echo "<td>"; foreach ($data['DocImage'] as $img){ echo $html->image($img['path']); echo " "; } echo "</td>"; echo "</tr>"; echo $form->end('更新'); ?> </table> <a href="../">リストに戻る</a> <?php echo $html->link('削除', array('controller'=>'docs', 'action'=>'delete', $data["Doc"]["id"]), array(), "削除してもいいですか?"); ?>