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とかもやりたいのですが正規表現が使えるようなのでこれらもちょっと考えたらできそうです♪




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にはその機能は実装されていない…どうするかというと、ここでバリデーションを作ってあげる必要があるようです…めんどいけど

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




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-バリデーション-

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




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.ビューを作る#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);

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




処理(BlogPet)

きょうぺこぽんは処理しなかった?
でも、あいの未知も勘違いしたかったの♪

*このエントリは、ブログペットの「ぺこぽん」が書きました。




5.ビューを作る#2渡されたデータを表示する

5.ビューを作る#2渡されたデータを表示する

ビューの拡張子は「.ctp」なんですが中身は普通にphpで書くことができます

データは「4.コントローラを作る#3表示用のアクションを作る」で$boardsって変数に入ってビューに渡されてきていますので、ただそれを表示させるphpを書けばすみます

ここではごそっと配列に入れましたので

foreachを使ってとにかく全部echoで表示させます

<?php
foreach ($boards as $board) {
   echo $board["Board"]["id"].":".$board["Board"]["title"]."<br>";
   echo $board["Board"]["comment"]."<br><hr>";
}
?>

◆覚書◆
$名前["テーブル名"]["フィールド名"]
でテーブルの値をひっぱってくれるようです
これは配列とか関係なくなのかどうかちょっとわかんないので留保

こうすると表示される画面は
viewtest
こうなります

確かに表示されてるんですが、画面がCakePHPのものになってます(ヘッダとかSQL文が表示されたりとか)
なので次はこれらを自分専用にカスタマイズしてみたいと思います




5.ビューを作る#1基本

5.ビューを作る

ビューはチラッと作りましたが基本hana05.gif

/app/views/小文字名前の複数形/コントローラのfunction名.ctp

となります
うちの場合で行くとコントローラには「index()」と「write()」があるんで

app/views/boards/index.ctp
app/views/boards/write.ctp

の2つを作ります。

そんで…いくら作ったって見えなきゃ意味無いんで呼び出す時は

http://hogehoge/cakeディレクトリ/名前/function名

になります。うちの場合…

一覧を呼び出す時
http://cake.chorochoro.com/boards
または
http://cake.chorochoro.com/boards/index
書き込みフォームを表示するとき
http://cake.chorochoro.com/boards/write

になります

一覧用はさっき作ったんですが、ビューにテーブルの値を渡す方法を次でまとめてみたいと思います




4.コントローラを作る#5投稿用コントローラ

4.コントローラを作る#5投稿用コントローラ

ちょっと寄り道しちゃいましたが…
ビューできちんと表示されるのを確認できてうれしい気分です

またコントローラに戻って…

次は投稿用のアクションを書いていくんですが、あくまで投稿ボタンを押したときの動きということになるので本当はビューから作った方が良いような気もします

が、ここではやっぱりアクションを考えます

先ほどとは違って、ビューにデータを渡すわけではなくて、ビューのフォームからデータをもらうわけですが…

なんだかとっても簡単みたい…

$this->Model->save($this->data);

こんだけ?こんだけ。
だから…

$this->Board->save($this->data);

にすればとりあえず、ごそっと登録してくれる。

でもこのやり方は「危険なので必要なパラメータのみsaveしましょう」という記事があった
参考URL:http://www.a24loveweb.net/cake/save%E6%99%82%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9/
その記事によると

$data = array();
$data["name"] = $this->data["Model"]["name"];
$this->Model->save($data);

という風にしましょうということなので…

$data = array();
$data["title"] = $this->data["Board"]["title"];
$data["contributor"] = $this->data["Board"]["contributor"];
$data["comment"] = $this->data["Board"]["comment"];
$this->Board->save($data);

としてみました

のでコントローラはこうなりました
■/app/controllers/boards_controller.php■編集

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

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

これはあくまで投稿用→保存用の動作を設定しただけなんで、続けて投稿用のフォームを作ります

次からビューをきちんと見ることにしますonegai03t.gif




4.コントローラを作る#4表示用のビューを作る

4.コントローラを作る#4表示用のビューを作る

ちょっと寄り道で…ビューを作ってみますfutaba.gif
ビューを作る前にテーブルにデータがなければもちろんデータ表示されませんので、直接DBの方から5個くらい適当にテーブルにデータを追加しました。
文字コードはUTF-8を使ってます

で。先ほど作ったコントローラで表示用のアクションは

function index()

としたので表示用のビューの名前は

index.ctp

とします。場所は/app/views内にディレクトリを作って置くようになるので

/app/views/boards/index.ctp

としました

中身はただ単にタイトルを表示させるだけ…なんで
■/app/views/boards/index.ctp■

<?php
foreach ($boards as $board) {
   echo $board["Board"]["id"].":".$board["Board"]["title"]."/".$board["Board"]["contributor"]."<br>";
   echo $board["Board"]["comment"]."<br><hr>";
}
?>

として(ビューの作り方はまた後で復習)

http://cake.chorochoro.com/boards
(表示するには…名前/アクション名 となるので、ホントのアドレスはhttp://cake.chorochoro.com/boards/index です~)

に接続したら見事に表示されました

がっ!…表示したら見事に文字化け!!「????」になってます
テーブルもUTF-8だし、php自体もUTF-8だし出力もUTF-8なのに何故…

調べたところ、インストールの際に設定したapp/config/database.phpに

'encoding' => 'utf8'

を追加すればいいらしい…ということで末尾に追加したところ、きちんと表示されました

viewtest

参考URL:http://www.syuhari.jp/blog/archives/141

すごいです。書いてるのはほとんど1行、2行の話なのに簡単にできてしまった…w03.gif




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