5.ビューを作る#3画面をちょっとカスタマイズ

ビューにデータがきれいに表示されたのはいいけど、このままじゃちょっと使えない…

なぜならどこからどうみてもCakePHPだから。

ちょっと自分仕様に変更してみたいと思いますが、ビューで表示させたのはあくまでデータの部分。他の部分を変更するにはどうするか調べました

参照URL:CakePHPマニュアル:ビュー»レイアウト

ここによるとレイアウトっていうのを作成してコントローラで指定するらしい…

app/views/layouts/レイアウト名.ctp

レイアウト名をboards.ctpにすることにして
内容は

■app/views/layouts/boards.ctp■

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><?php echo $title_for_layout?></title>
</head>
<body>
<center>
<hr color="green"><br>
☆s掲示板なんだぉ☆<br>
*:・(*-ω人)・:*<br>
<hr color="green">
</center>
<!-- ここに、ビューで表示するものを配置 -->
<?php echo $content_for_layout ?>
</body>
</html>

みたいな感じでレイアウトを作ってから、コントローラにどのレイアウトを使うか指定してあげる

■app/controllers/boards_controller.php■編集

class BoardsController extends AppController{
   var $name = "Boards";
   var $uses = array("Board");
   var $layout = 'boards';         //←これを追加

   function …続く…

これで、CakePHPのヘッダとか全部無くなった単純なページで表示されました
あとはこのレイアウトを自分仕様に変えてあげればいいみたいw01.gif

ただ…レイアウト内にはSQL文を表示する場所は無いのに表示されちゃう…
これをのけるには

■app/config/core.php■

内の設定を以下のように変更すると消える
Configure::write('debug', 0);

でもとりあえず最初のうちはあった方が便利なのでつけとくことにします




5.ビューを作る#4フォームを作ってみる

5.ビューを作る#4フォームを作ってみる

なんとなくビューが見えてきたところでデータを渡すためのフォーム作成に取りかかります

作る場所はapp/views/boards、functionがwriteにしたんでwrite.ctpを作ります
中身はというと…
■app/views/boards/write.ctp■

<?php
   echo $form->create('Board',array('action' => 'write'));
   echo $form->input('Board.title');
   echo $form->input('Board.contributor');
   echo $form->input('Board.comment', array('rows' => '3'));
   echo $form->end('Submit');
?>

でた。。。またこんだけ?こんだけbikkuri01.gif

で、とりあえず
http://cake.chorochoro.com/boards/write
で表示させたらエラーでるじゃん!どうも、SQLのインサート文が実行されて、Null値だからダメだよ~と言っている…
確かに、コントローラのwriteは書き込みを実行することしか書いてない…
ちょっと調べてみました

参照URL:http://cakephp.jp/doc/helpers.html

フォームに値が渡されたかどうか調べる???そんなんしてません。ということでコントローラを見直しました

コントローラの
function write(){
//書き込み処理
}

の頭に
if (!empty($this->data['Board'])){
を追加

そしたらうまくフォームが表示されて保存もきっちりいきましたが、今度はいつまでもwrite.ctpが表示されちゃう…naku02.gif書き込んだら一覧表示のindex.ctpにリダイレクトしたいんだけど…というわけで

コントローラの
function write(){
//書き込み処理
}

の末尾に
$this->redirect("/boards");
を追加。これで「/board/write」を開くと書き込みフォームが開いて、保存ボタンを押すと新たに行が追加された「/board」が開くようになりました

長々とやっちゃいましたがコントローラは以下のように修正

■app/controllers/boards_controller.php ■編集

<?php
class BoardsController extends AppController
{
   var $name = "Boards";
   var $uses = array("Board");
   var $layout = 'boards';

   function index(){
      $this->set("boards",$this->Board->find('all'));
   }
   function write(){
      if (!empty($this->data['Board'])){
         $data = array();
         $data["title"] = $this->data["Board"]["title"];
         $data["contributor"] = $this->data["Board"]["contributor"];
         $data["comment"] = $this->data["Board"]["comment"];
         $this->Board->save($data);
         $this->redirect("/boards");
      }
   }
}
?>

一応動きはできたので次はフォームの作り方について一個一個見ていきます




5.ビューを作る#5フォームの作り方

5.ビューを作る#5フォームの作り方

さっきは意味もわからずフォームを作ったのでちょっと詳しく見ていきます
今回使ったのはHTMLヘルパーFormヘルパーってやつらしいですhatena03.gif(1.1まではHTMLヘルパー)

参照URL:CakePHP:フォームの作成

まず一行目
echo $form->create("Board",array("action"=>"write"));
creat()メソッドでフォームの作成を開始します

create(モデル名, array $options = array())
$optionには action type url default が指定できます
・action =>実行するコントローラ内のアクションを指定
・type =>postやgetを指定
他のオプションについては今はよく分からないので保留しておきます

そしてフォームの部品ですが

参照URL:CakePHP:フォーム要素の自動生成
参照URL:CakePHP Note:フォームの部品

input(string $fieldName, array $options = array())
($fieldNameには「Model.fieldname」が入る)

を使います。なんだかすごいのは…「options」でいろいろ属性を指定もできるんですが、 $fieldName にテーブルで作ったフィールド名を入れてやれば自動的にそのフィールド属性にあったinput typeを出力してくれることです。いや便利。

便利は便利なんだけどもラベルが勝手に「fieldname」でついちゃったりサイズが意図した通りにならなかったりするので属性を指定します

■ラベルをはずす■

input("Board.title",array('label'=>false))
(モデル:Board フィールド名:title)

■サイズを意図したとおりにする■

input("Board.title",array(’size' => 50))
(モデル:Board フィールド名:title)
input("Board.comment",array('rows' => 10,'cols'=>30))
(モデル:Board フィールド名:comment)

他にもセレクトボックスを作成するときなどに必須の属性もありますが、今回はtextbox と、textareaしかないのでまた後で確認するです

上記を踏まえて作った書き込みフォームがこちら
■app/views/boards/write.ctp■

<?php
   echo $form->create('Board',array('action' => 'write'));
   echo "タイトル ";
   echo $form->input('Board.title',array('label'=>false,'size' => 20))."<br>";
   echo "投稿者名 ";
   echo $form->input('Board.contributor',array('label'=>false,'size' => 20))."<br>";
   echo "コメント ";
   echo $form->input('Board.comment', array('label'=>false,'rows' => 10,'cols'=>30))."<br><br>";
   echo $form->end('送信');
?>

そして「ん?hatena01.gif」となったのが
■error■

input("Board.title",array('error'=>'検証時にエラーのときのメッセージ'))
(モデル:Board フィールド名:title)

検証時?エラー?確かに…普通にphpやperlなどで掲示板のフォームを作るときに一番時間を割くのが「データの整合性の確認」なんですが(私はだけど)これらのフォームの部品にはそれを指定するとこが無いです…

空白だったらダメよとか、○文字以上だよとか。
それにこれだとフォームに入った値をそのまま保存しちゃう?XSSの対応なんかはどしたらいいのか…

それを調べていたらどうやら

Validation-バリデーション-

というのを使うようなのでこちらについて少し勉強してみることにするです




6.バリデーション#1バリデーションの基礎

フォームの作り方から関連して、データのバリデーション(検証)についてちょっと見てみることにしました

参考URL:CakePHP:データのバリデーション

バリデーションって言葉自体始めて聞いたんだけどもデータを保存するときにデータがきちんとしてるかどうかを調べる機能みたいです。私はCakePHP1.2を使ってますがこの機能は1.2でかなり強化されたとのことで1.1系バージョンとは違いがあるようです

で。バリデーション

作る場所はモデルの中なので、またまたモデルに戻ることになります( p_q)

どんな風に指定するかってと

var $validate = array('fieldName' => 'ruleName');

こんな感じ

よくわかんないから具体的に…とりあえず私の作る掲示板では
・全項目必須入力
・投稿者名は3文字以上10文字以下
・題名は3文字以上20文字以下
・コメントは5文字以上100文字以下
にしたいのです

全項目必須入力っていうのは、×文字以上に条件としては含まれるのでここでは省いてしまって、指定する条件は

・投稿者名は3文字以上10文字以下
・題名は3文字以上20文字以下
・コメントは5文字以上100文字以下

とします

バリデーションを見たら、フィールド名ってのが入ってるって事はとりあえず、フィールド毎指定してあげる必要があるのでしょう(間違ってるかもだけどとりあえず今はこれで)

モデルはこんな感じに追加

■app/models/board.php■
<?php
class Board extends AppModel {
   var $name = 'Board';

   var $validate = array(
   //ここに検証ルールを書いてくよ
   )

}
?>

各フィールドを検証するには

var $validate = array(
       'title' =>array(ここに検証内容),
       'contributor' =>array(ここに検証内容),
       'comment' =>array(ここに検証内容)

   )

こんな感じで検証内容は…

var $validate = array(
       'title' =>array(
       'required' =>true,
       'message' => 'タイトルの入力は必須です'
       ),

・・・・

1個のバリデーションならこんな感じになります。この検証内容が複数になってくるとさらに配列が入れ子になるので分かりにくいけどこんな感じ

var $validate = array(
       'title' =>array(
       array(
       'required' =>true,
       'message' => '題名の入力は必須です'
       'last' => true,
       ),

       array(
       'rule'=>array('minLength', '3'),
       'message' => '題名は3文字以上でお願いします',
       'last' => true,
       ),

       array(
       'rule'=>array('maxLength', '20'),
       'message' => '題名は20文字以下でお願いします',
       'last' => true,
       )

       )
・・・・

みたいな感じ。

でもここで注意点

ruleの中で使えるminLengthとmaxLengthはあくまで半角英数字の時しかうまく動かない(mb_strlenじゃなくてstrlen使ってるみたい)らしいのでこれを日本語でもちゃんと使えるようにしてあげなくちゃいけません。が!CakePHPにはその機能は実装されていない…どうするかというと、ここでバリデーションを作ってあげる必要があるようです…めんどいけど

ちょっと長くなったので続きます




6.バリデーション#2自分でバリデーションを設定する

6.バリデーション#2自分でバリデーションを設定する

自分でバリデーションを設定するときはモデルにメソッドを作成します

■app/models/board.php■
<?php
class Board extends AppModel {
   var $name = 'Board';
   var $validate = array(
   //ここに検証ルールを書いてくよ
   )

   function hogehoge(){
   //ここに自作の検証ルールを作るよ
   }

}
?>

て感じになります

で、日本語の文字数をチェックするメソッドですが、これはぐぐったらあったのでそのままいただいてしまいます

参考URL:CakePHP Note:独自の検証ルールを使用する

function maxLength($data, $max) {
  $check = array_shift($data);//配列から取り出す
  $length = mb_strlen($check);
  return ($length <= $max);
}
function minLength($data, $min) {
  $check = array_shift($data);//配列から取り出す
  $length = mb_strlen($check);
  return ($length >= $min);
} 

これを追加しましたので結果モデルはこうなりました

■app/models/board.php■編集最後[完成]

<?php
class Board extends AppModel {

   var $name = 'Board';

   var $validate=  array(
   'title'      => array(
   array('rule' => array('minLength', 3),'message' => 'タイトルは 3文字以上入れてね'),
   array('rule' => array('maxLength',20),'message' => 'タイトルは20文字以下でね')
   ),
   'contributor'=> array(
   array('rule' => array('minLength', 3),'message' => '投稿者名は3文字以上入れてね'),
   array('rule' => array('maxLength',15),'message' => '投稿者名は15文字以下でね')
   ),
   'comment'    => array(
   array('rule' => array('minLength', 10),'message' => 'コメントは10文字以上入れてね'),
   array('rule' => array('maxLength',100),'message' => 'コメントは100文字以下でね')
   ));

   function maxLength($data, $max) {
      $check = array_shift($data);
      $length = mb_strlen($check);
      return ($length <= $max);
   }

   function minLength($data, $min) {
      $check = array_shift($data);
      $length = mb_strlen($check);
      return ($length >= $min);
   }
}
?>

長い…もしかしたらもっといいやり方があるのかもしれないけどここはこれでOKとします

さらに本当はこれに加えて半角英数字のみはNG、改行が連続したらNGとかもやりたいのですが正規表現が使えるようなのでこれらもちょっと考えたらできそうです♪




7.書き込み後の動作確認

7.書き込み後の動作確認

ようやくフォームもできた!バリデーションの設定も終わった!w02.gif

さて動かしてみますheart01.gif

保存はうまくいきました。

しかし!文字を少なくしてエラーに引っかかるようにしても、エラーメッセージ表示せずに一覧に飛んでしまいますga-n02.gif
ただ、データの保存はされていないようなので、どうやら検証ルールはきちんと動いている模様…

参照URL:CakePHPマニュアル:CakePHPブログチュートリアル»記事の追加
うえの記事と首っ引きで確認したところ、どうやらコントローラのSaveのあたりに問題がありそうなことに気づきました

if ($this->Post->save($this->data)) {
   $this->flash('Your post has been saved.','/posts');
}

この部分です。Saveがきちんと実行されたときのみ、リダイレクトなりをさせなきゃいけないんですね。
というわけでコントローラは最終的にこうなりました

■/app/controllers/boards_controller.php■編集最後[完成]

<?php
class BoardsController extends AppController
{

   var $name = "Boards";
   var $uses = array("Board");
   var $layout = 'boards';

   function index(){
      $this->set("boards",$this->Board->find('all'));
   }

   function write(){
      if (!empty($this->data['Board'])){
         $data = array();
         $data["title"] = $this->data["Board"]["title"];
         $data["contributor"] = $this->data["Board"]["contributor"];
         $data["comment"] = $this->data["Board"]["comment"];
         if ($this->Board->save($data)) {
            $this->flash('保存完了したよ*:・(*-ω人)・:<br>一覧に戻るにはここをクリック','/boards');
         }
      }
   }
}
?>



AUTHOR

  • footerWrite up a little something about yourself here. Something short and sweet, or longer if you'd like.

FLICKR

  • add flickr code here, or delete this and use the widget version.

TWEETS

  • add twitter code here, or delete this and use the widget version.

Pets