CakePHP+Smartyハイブリッドによるラクラク開発

11,298 views

Published on

姫路IT系勉強会 Vol.7
CakePHP+Smartyハイブリッドによるラクラク開発
MVCの栄光を君に!

このダイジェストムービーがYouTubeにあります。
Vol1: http://www.youtube.com/watch?v=Ra6QDfurfzA
Vol2: http://www.youtube.com/watch?v=gbsJjMQOXi8

Published in: Technology
0 Comments
11 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
11,298
On SlideShare
0
From Embeds
0
Number of Embeds
116
Actions
Shares
0
Downloads
0
Comments
0
Likes
11
Embeds 0
No embeds

No notes for slide

CakePHP+Smartyハイブリッドによるラクラク開発

  1. 1. 姫路IT系勉強会 Vol.7CakePHP+Smartyハイブリッド によるラクラク開発 MVCの栄光を君に!
  2. 2. お品書き自己紹介などMVCとは?SmartyCakePHPSmarty+CakePHP
  3. 3. 自己紹介など
  4. 4. 今日のプレゼンは
  5. 5. 太い @architshin と細い @aWebprogrammer
  6. 6. まず太いほうから
  7. 7. @architshin
  8. 8. 本名: 齊藤新三 この顔で→
  9. 9. 「新ちゃん」「新三さん」 とよんでね♡
  10. 10. 特筆すべき点は… ガンヲタです。
  11. 11. 次、細いほう
  12. 12. @aWebprogrammer ※アカウント作った時にネタでつけたやつをいまだに引きずってる・・・o
  13. 13. Perlよりも、Rubyよりも、普通の女子よりも、PHPが好きだー!って 変ジニアです(キリッ ※例外として、天然入ってる人には激しく反応します!
  14. 14. 「ワテさん」とか「変ジニア さん」 と呼んでね♡ ※「田中佳明」って本名もあるけど、こっちの方が馴染んでます
  15. 15. MVCとは?
  16. 16. WEBアプリのサーバーサイドの動きというのは…表示画面 処理 表示画面 処理 表示画面 PHPファイル PHPファイル
  17. 17. 例えば、こんな画面を表示するPHPをデザイナさんにデザインしてもらおうとする…
  18. 18. ソースコードは…<?php else {print("<?xml version="1.0" encoding="UTF-8" ?>n"); ?>$odTotalFloor = $_POST[odTotalFloor]; <p><?php print($count) ?>件ありました。</p>?> <table border="1"><!DOCTYPE html PUBLIC "- <thead>//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1 <tr>-transitional.dtd"> <th>注文コード</th><html xmlns="http://www.w3.org/1999/xhtml"> <th>注文日時</th><head> <th>注文合計金額</th> <title>サンプル01: MVC未分離</title> <th>注文者氏名</th></head> <th>注文者住所</th><body> <th>注文者電話番号</th><h1>Histudy7 サンプル01: MVC未分離</h1> </tr><hr/> </thead><form action="sample01.php" method="post"> <tbody>注文合計が <?php<input type="text" name="odTotalFloor" value="<?php print($odTotalFloor) ?>"/>円 $sql2 = "SELECT * FROM orders WHERE od_total>=:od_total ORDER BY od_total";以上の注文情報を<input type="submit" value="表示"/> $stmt2 = $db->prepare($sql2);</form> $stmt2->bindParam(":od_total", $odTotalFloor);<?php $stmt2->execute();if(is_numeric($odTotalFloor)) { $i = 0; $dsn = "mysql:host=localhost;dbname=histudy7"; while($row = $stmt2->fetch()) { $username = "histudy"; ?> $password = "hihi"; <tr> <td><?php print($row[od_code]) ?></td> try { <td><?php print(strftime(%Y/%m/%d %H:%M:%S,strtotime($row[od_date]))) ? $db = new PDO($dsn, $username, $password); ></td> $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); <td><?php print($row[od_total]) ?></td> $db->query("SET NAMES utf8;"); <td><?php print($row[od_name]) ?></td> $sql1 = "SELECT COUNT(DISTINCT(od_code)) AS count FROM orders WHERE od <td><?php print($row[od_address]) ?></td>_total>=:od_total ORDER BY od_total"; <td><?php print($row[od_tel]) ?></td> $stmt1 = $db->prepare($sql1); </tr> <?php $stmt1->bindParam(":od_total", $odTotalFloor); } $stmt1->execute(); ?> $result1 = $stmt1->fetch(); </tbody> </table> $count = $result1["count"]; <?php if($count == 0) { }?> $db = null;<p>表示すべき情報はありません。</p> }<?php }
  19. 19. こんなのデザインできる デザイナーなんて…
  20. 20. そんな変態ほとんどいない たまにいるけど…
  21. 21. さらに <th>注文者住所</th> <th>注文者電話番号</th> </tr> </thead> <tbody><?php $sql2 = "SELECT * FROM orders WHERE od_total>=:od_total ORDER BY od_total"; $stmt2 = $db->prepare($sql2); $stmt2->bindParam(":od_total", $odTotalFloor); $stmt2->execute(); $i = 0; while($row = $stmt2->fetch()) { SQL文! ここに書いちゃうと、他のPHPファイルで使えない。
  22. 22. 同じSQL文があちらにもこちらにも
  23. 23. 表示画面 PHP 表示画面 PHP 表示画面 ここにも ここにも$sql2 = "SELECT * FROM orders WHERE od_total>=:od_total ORDER BY od_total";
  24. 24. DBに変更があったら…
  25. 25. 各処理PHPからDB処理を分離する!
  26. 26. 表示画面 PHP 表示画面 PHP 表示画面 利用 利用 DB処理 PHP Model
  27. 27. DB操作のクラス(DAO)を作る<?php /**require_once("OrderEntity.class.php"); * 指定金額以上の注文情報を取得するメソッド。 */** * @param integer $odTotalFloor 注文合計下限 * テーブルordersのデータ操作を行うDAOクラス。 * @return array 各要素はOrderEntityオブジェクト * */ */ public function findMoreThanOdTotalFloor($odTotalFloor) {class OrderDAO { $orderEntities = array(); try { /** $this->_db->query("SET NAMES utf8;"); * データソース $sql = "SELECT * FROM orders WHERE od_total>=:od_total ORDER BY * od_total"; * @var PDO $stmt = $this->_db->prepare($sql); */ private $_db; $stmt->bindParam(":od_total", $odTotalFloor); $result = $stmt->execute(); /** while($row = $stmt->fetch()) { * コンストラクタ。データベースへの接続を行う。 $orderEntity = new OrderEntity(); * $odCode = $row[od_code]; */ $orderEntity->setOdCode($odCode); public function __construct() { $orderEntity->setOdDate($row[od_date]); $dsn = "mysql:host=localhost;dbname=histudy7"; $orderEntity->setOdTotal($row[od_total]); $username = "histudy"; $orderEntity->setOdName($row[od_name]); $password = "hihi"; $orderEntity->setOdAddress($row[od_address]); $this->_db = new PDO($dsn, $username, $password); $orderEntity->setOdTel($row[od_tel]); $this->_db- $orderEntities[$odCode] = $orderEntity;>setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } } } catch(PDOException $ex) { /** $expMessage = "<p>DB接続に失敗しました。<hr/>"; * デストラクタ。データベースへの接続解除を行う。 $expMessage .= "例外の中身:Code=".$ex->getCode()."<br/>".$ex- * >getFile()."(".$ex->getLine()."): ".$ex->getMessage()."<br/>".$ex- */ >getTraceAsString(); public function __destruct() { print($expMessage); $this->_db = null; } } return $orderEntities; } } ?>
  28. 28. 重要なところだけ見ると…class OrderDAO { ~ 中略 ~ public function findMoreThanOdTotalFloor($odTotalFloor) { $orderEntities = array(); try { $this->_db->query("SET NAMES utf8;"); $sql = "SELECT * FROM orders WHERE od_total>=:od_total ORDER BY od_total"; $stmt = $this->_db->prepare($sql); $stmt->bindParam(":od_total", $odTotalFloor); $result = $stmt->execute(); while($row = $stmt->fetch()) { さっき出てきたSQL $orderEntity = new OrderEntity(); 文! $odCode = $row[od_code]; $orderEntity->setOdCode($odCode); $orderEntity->setOdDate($row[od_date]); $orderEntity->setOdTotal($row[od_total]); $orderEntity->setOdName($row[od_name]); $orderEntity->setOdAddress($row[od_address]); $orderEntity->setOdTel($row[od_tel]); $orderEntities[$odCode] = $orderEntity; }
  29. 29. エンティティクラスを作る<?php /** * 注文者電話番号/** * @var string * 注文情報エンティティクラス。 */ * private $_odTel; * @author Shinzo SAITO * /** */ * @return integer 注文コードclass OrderEntity { */ /** public function getOdCode() { * 注文コード return $this->_odCode; * @var integer } */ private $_odCode; /** * @param integer $odCode 注文コード /** */ * 注文日時 public function setOdCode($odCode) { つまり、 */ $this->_odCode = $odCode; private $_odDate; } このクラス1コが /** /** テーブルの1行分の * 注文合計金額 * @return mixed 注文日時 * @var integer */ データに対応する */ public function getOdDate() { private $_odTotal; return $this->_odDate; } /** * 注文者氏名 ~ 以下setter/getterがつづく~ * @var string ?> */ private $_odName; /** * 注文者住所 * @var string */ private $_odAddress;
  30. 30. SQLの結果od_code od_date od_total od_name od_address od_tel OrderEntity4 2008/06/07 12:54:21 53500 中谷桃 … …18 2008/06/07 12:54:21 53500 梶原淳 … … OrderEntity32 2008/06/07 12:54:21 53500 森俊之 … … OrderEntity 連想配列に格 納
  31. 31. 表示画面 PHP 表示画面 利用 エンティティDB処理 (の連想配列) PHP
  32. 32. Mが分離された処理PHPは…<?php <section>require_once("OrderEntity.class.php"); <?php if($count == 0) { ?>require_once("OrderDAO.class.php"); <p>表示すべき情報はありません。</p> <?php } else { ?>$orderEntities = array(); <?php print($count) ?>件ありました。$odTotalFloor = $_POST[odTotalFloor]; <table border="1">if(is_numeric($odTotalFloor)) { <thead> $orderDAO = new OrderDAO(); <tr> $orderEntities = $orderDAO->findMoreThanOdTotalFloor($odTotalFloor); <th>注文コード</th>} <th>注文日時</th>$count = count($orderEntities); <th>注文合計金額</th>?> <th>注文者氏名</th> <th>注文者住所</th><!DOCTYPE html> <th>注文者電話番号</th><html> </tr><head> </thead> <meta charset="UTF-8"> <tbody> <title>サンプル02: Mの分離</title> <?php foreach($orderEntities as $key1=>$orderEntity) { ?></head> <tr><body> <td><?php print($orderEntity->getOdCode()) ?></td><header> <td><?php print(strftime(%Y/%m/%d %H:%M:%S,strtotime($order <h1>Histudy7 サンプル02: Mの分離</h1> Entity->getOdDate()))) ?></td></header> <td><?php print($orderEntity->getOdTotal()) ?></td><section> <td><?php print($orderEntity->getOdName()) ?></td> <form action="sample02.php" method="post"> <td><?php print($orderEntity->getOdAddress()) ?></td> 注文合計が <td><?php print($orderEntity->getOdTel()) ?></td><input type="text" name="odTotalFloor" value="<?php print($odTotalFloor) ?> </tr>"/>円以上の注文情報を<input type="submit" value="表示"/> <?php } ?> </form> </tbody></section> </table> <?php } ?> </section> </body> </html>
  33. 33. ををを!見やすくなった!
  34. 34. でも、まだ足らない!
  35. 35. PHPコードを駆逐する! 刹那・F・セイエイ
  36. 36. 例えば、こんな画面のHTMLは… <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>サンプル03: Vの分離</title> </head> <body> <header> <h1>Histudy7 サンプル03: Vの分離</h1> </header> <section> <table border="1"> <tr> <th>注文コード</th> <td>18</td> </tr> <tr> <th>注文日時</th> <td>2008/06/21 12:54:21</td> </tr> <tr> <th>注文合計金額</th> <td>53,500円</td> </tr> <tr> <th>注文者氏名</th> <td>梶原順</td> </tr> <tr> <th>注文者住所</th> <td>京都市伏見区小豆屋町</td> </tr> <tr> <th>注文者電話番号</th> <td>078-846-8767</td> </tr> </table> </section> </body> </html>
  37. 37. このまま使えないかなあ。
  38. 38. DBデータによって変動する部分は…<!DOCTYPE html> <tr><html> <th>注文者氏名</th><head> <td>梶原順</td> <meta charset="UTF-8"> </tr> <title>サンプル03: Vの分離</title> <tr></head> <th>注文者住所</th><body> <td>京都市伏見区小豆屋町</td><header> </tr> <h1>Histudy7 サンプル03: Vの分離</h1> <tr></header> <th>注文者電話番号</th><section> <td>078-846-8767</td> <table border="1"> </tr> <tr> </table> <th>注文コード</th> </section> <td>18</td> </body> </tr> </html> <tr> <th>注文日時</th> <td>2008/06/21 12:54:21</td> </tr> これら、変動する部分を変数化し <tr> <th>注文合計金額</th> て置き換え可能にしてみる <td>53,500円</td> </tr>
  39. 39. 変数化してみると…<!DOCTYPE html> <tr><html> <th>注文者氏名</th><head> <td>#OD_NAME#</td> <meta charset="UTF-8"> </tr> <title>サンプル03: Vの分離</title> <tr></head> <th>注文者住所</th><body> <td>#OD_ADDRESS#</td><header> </tr> <h1>Histudy7 サンプル03: Vの分離</h1> <tr></header> <th>注文者電話番号</th><section> <td>#OD_TEL#</td> <table border="1"> </tr> <tr> </table> <th>注文コード</th> </section> <td>#OD_CODE#</td> </body> </tr> </html> <tr> <th>注文日時</th> <td>#OD_DATE#</td> </tr> このファイルを読み込んで使う <tr> <th>注文合計金額</th> <td>#OD_TOTAL#円</td> </tr>
  40. 40. Controller 表示画面 PHP 表示画面 読込 利用 + 変数置換 エンティティDB処理 (の連想配列) 変数化 PHP HTMLModel View
  41. 41. MVが分離されたControllerは…<?phprequire_once("OrderEntity.class.php");require_once("OrderDAO.class.php");$odCode = $_GET[odCode]; Mからデータ取得$orderDAO = new OrderDAO();$orderEntity = $orderDAO->findyByPK($odCode); Vファイルの読込$htmlTemp = file_get_contents("sample03t.html");$html = str_replace("#OD_CODE#", $orderEntity->getOdCode(), $htmlTemp);$html = str_replace("#OD_DATE#", strftime(%Y/%m/%d %H:%M:%S,strtotime($orderEntity->getOdDate())), $html);$html = str_replace("#OD_TOTAL#", number_format($orderEntity->getOdTotal()), $html);$html = str_replace("#OD_NAME#", $orderEntity->getOdName(), $html);$html = str_replace("#OD_ADDRESS#", $orderEntity->getOdAddress(), $html);$html = str_replace("#OD_TEL#", $orderEntity->getOdTel(), $html);print($html); Vファイルの変数置換?>
  42. 42. じゃあ、これは?
  43. 43. HTMLは…<!DOCTYPE html> <tr><html> <td>18</td><head> <td>2008/06/21 12:54:21</td> <meta charset="UTF-8"> <td>53500</td> <title>サンプル02: Mの分離</title> <td>梶原順</td></head> <td>京都市伏見区小豆屋町</td><body> <td>078-846-8767</td><header> </tr> <h1>Histudy7 サンプル02: Mの分離</h1> <tr></header> <td>32</td><section> <td>2008/07/05 12:54:21</td> <form action="sample02.php" method="post"> <td>53500</td> 注文合計が<input type="text" name="odTotalFloor" value="50000"/> <td>森俊之</td>円以上の注文情報を<input type="submit" value="表示"/> <td>福岡県福岡市博多区</td> </form> <td>078-846-8781</td></section> </tr><section> <tr>11件ありました。 <td>1</td><table border="1"> <td>2008/06/04 12:54:21</td> <thead> <td>56421</td> <tr> <td>後藤武</td> <th>注文コード</th> <td>兵庫県神戸市東灘区住吉町</td> <th>注文日時</th> <td>078-846-8750</td> <th>注文合計金額</th> </tr> <th>注文者氏名</th> ~中略~ <th>注文者住所</th> </tbody> <th>注文者電話番号</th> </table> </tr> </section> </thead> </body> <tbody> </html> <tr> <td>4</td> <td>2008/06/07 12:54:21</td> <td>53500</td> <td>中谷桃</td> <td>和歌山県新宮市あけぼの</td> ル、ループ… <td>078-846-8753</td> </tr>
  44. 44. で、できない…orz
  45. 45. Smarty
  46. 46. またまた、これを例にとると… <table border="1"> <tr> <th>注文コード</th> <td>#OD_CODE#</td> </tr> <tr> <th>注文日時</th> <td>#OD_DATE#</td> </tr> <tr> <th>注文合計金額</th> <td>#OD_TOTAL#円</td>変数が埋め込まれたtable </tr> <tr>タグの部分だけ見てみる <th>注文者氏名</th>と <td>#OD_NAME#</td> </tr> <tr> <th>注文者住所</th> <td>#OD_ADDRESS#</td> </tr> <tr> <th>注文者電話番号</th> <td>#OD_TEL#</td> </tr> </table>
  47. 47. これがSmartyを使うと…<table border="1"> <tr> <th>注文コード</th> <td>{$odCode}</td> </tr> <tr> <th>注文日時</th> <td>{$odDate|date_format:"%Y/%m/%d %H:%M:%S"}</td> </tr> <tr> <th>注文合計金額</th> <td>{$odTotal}円</td> </tr> <tr> {$変数名} <th>注文者氏名</th> <td>{$odName}</td> という記述 </tr> <tr> || <th>注文者住所</th> <td>{$odAddress}</td> テンプレート変数 </tr> <tr> <th>注文者電話番号</th> <td>{$odTel}</td> </tr></table>
  48. 48. Controllerは…<?php Smartyクラスの読require_once("libs/Smarty.class.php"); 込require_once("OrderEntity.class.php");require_once("OrderDAO.class.php"); Smarty利用の準備$oSmarty = new Smarty();$oSmarty->template_dir = "./templates/";$oSmarty->compile_dir = "./templates_c"; Mからデータ取得$odCode = $_GET[odCode];$orderDAO = new OrderDAO(); テンプレートに送るデータを$orderEntity = $orderDAO->findyByPK($odCode); セット$oSmarty->assign("odCode", $orderEntity->getOdCode());$oSmarty->assign("odDate", $orderEntity->getOdDate());$oSmarty->assign("odTotal", number_format($orderEntity->getOdTotal()));$oSmarty->assign("odName", $orderEntity->getOdName());$oSmarty->assign("odAddress", $orderEntity->getOdAddress());$oSmarty->assign("odTel", $orderEntity->getOdTel());$oSmarty->display("sample01.tpl"); Vの表示?>
  49. 49. Smartyの準備1Smartyのサイト(http://www.smarty.net/)から適切なバージョンをダウンロード、解凍。中にあるlibsディレクトリを今から記述するControllerから読み込めるところに配置する。
  50. 50. Smartyの準備2Controllerから読み込めるところにテンプレートファイルを配置するディレクトリを作る。同じく、テンプレートをコンパイルしたものを格納するからディレクトリを作る。
  51. 51. テンプレートの作成HTMLファイルにテンプレート変数を埋め込んだファイル=テンプレートファイルを.tplとして作成し、テンプレートを格納するディレクトリに入れる。
  52. 52. Smartyの読込準備での配置にしたがってlibs/Smarty.class.phpを読み込む。 <?php require_once("libs/Smarty.class.php"); require_once("OrderEntity.class.php"); require_once("OrderDAO.class.php");
  53. 53. Smarty利用の準備Smartyクラスをnew。準備での配置にしたがってテンプレート関連ディレクトリを登録。template_dirフィールドにテンプレートが入っているディレクトリを指定。compile_dirフィールドにコンパイル済みテンプレートを格納するディレクトリを指定。PHPからの書き込み権限を与えておく。 $oSmarty = new Smarty(); $oSmarty->template_dir = "./templates/"; $oSmarty->compile_dir = "./templates_c";
  54. 54. テンプレートに送るデータの セット Smartyクラスのassignメソッドを使ってテンプレー トに埋め込むデータをセット。 第1引数が変数名文字列、第2引数が値。$oSmarty->assign("odCode", $orderEntity->getOdCode());$oSmarty->assign("odDate", $orderEntity->getOdDate());$oSmarty->assign("odTotal", number_format($orderEntity->getOdTotal()));$oSmarty->assign("odName", $orderEntity->getOdName());$oSmarty->assign("odAddress", $orderEntity->getOdAddress());$oSmarty->assign("odTel", $orderEntity->getOdTel());
  55. 55. Vの表示Smartyクラスのdisplayメソッドを使って画面表示。引数はテンプレート名。 $oSmarty->display("sample01.tpl");
  56. 56. ところで…<table border="1"> <tr> <th>注文コード</th> <td>{$odCode}</td> </tr> <tr> <th>注文日時</th> これ、 <td>{$odDate|date_format:"%Y/%m/%d %H:%M:%S"}</td> </tr> <tr> <th>注文合計金額</th> <td>{$odTotal}円</td> </tr> <tr> <th>注文者氏名</th> <td>{$odName}</td> なに? </tr> <tr> <th>注文者住所</th> <td>{$odAddress}</td> </tr> <tr> <th>注文者電話番号</th> <td>{$odTel}</td> </tr></table>
  57. 57. 修飾子 {$変数名|修飾子}という形で変数の値を加工するこ とができる。{$odDate|date_format:"%Y/%m/%d %H:%M:%S"} || 日付のフォーマティングを行う
  58. 58. 修飾子の種類1分類 修正子 説明文字列操作 capitalize 単語の先頭を大文字に変換 lower 小文字に変換 upper 大文字に変換 cat 指定された変数を連結 replace 置き換え regex_replace 正規表現による置換書式設定 date_format 日付の書式設定 string_format 文字列の書式設定 default 初期値の設定
  59. 59. 修飾子の種類2分類 修正子 説明特殊文字処理 strip 空白・改行・タブの削除 strip_tags マークアップタグの削除 nl2br 改行文字を<br/>タグに置換 escape エスケープ処理 spacify 文字の間に空白挿入文字列操作 truncate 指定桁で文字列を切り捨て wordwrap 指定桁でワードラップ indent インデント指定
  60. 60. 修飾子の種類3分類 修正子 説明文章情報 count_characters 文字数取得 count_paragraphs 段落数取得 count_sentences センテンス数取得 count_words 単語数取得詳細は本家サイトのマニュアルを参照。http://www.smarty.net/docs/ja/language.modifiers.tpl
  61. 61. 修飾子は重ねられる{$変数名|修飾子|修飾子|修飾子|…}と複数の修飾子を重ねて使える。 {$odMemo|escape|nl2br|default:"&nbsp"} || エスケープして、改行文字を改行タグに変換する。 さらに、もし値がない場合は空白文字を出力。
  62. 62. じゃあ、これは?
  63. 63. テンプレートファイル(抜粋)は…<section> {if $count == 0} <p>表示すべき情報はありません。</p> 分岐 {else} {$count}件ありました。 <table border="1"> <thead> <tr> <th>注文コード</th> <th>注文日時</th> <th>注文合計金額</th> <th>注文者氏名</th> <th>注文者住所</th> <th>注文者電話番号</th> </tr> ルー </thead> プ <tbody> {foreach from=$orderEntities item="orderEntity"} <tr> <td>{$orderEntity->getOdCode()}</td> <td>{$orderEntity->getOdDate()|date_format:"%Y/%m/%d %H:%M:%S"}</td> <td>{$orderEntity->getOdTotal()|number_format}</td> <td>{$orderEntity->getOdName()}</td> <td>{$orderEntity->getOdAddress()}</td> <td>{$orderEntity->getOdTel()}</td> </tr> {/foreach} </tbody> </table> {/if}</section>
  64. 64. 分岐分岐の書式は{if 条件}~{elseif 条件}~{/if}<section> {if $count == 0} <p>表示すべき情報はありません。</p> {else} {$count}件ありました。 <table border="1"> ~略~ </table> {/if}</section>
  65. 65. ループ ループの書式は {foreach from=配列 item=各要素を格納する変数名} ~ {/foreach}<tbody>{foreach from=$orderEntities item="orderEntity"} <tr> <td>{$orderEntity->getOdCode()}</td> <td>{$orderEntity->getOdDate()|date_format:"%Y/%m/%d %H:%M:%S"}</td> <td>{$orderEntity->getOdTotal()|number_format}</td> <td>{$orderEntity->getOdName()}</td> <td>{$orderEntity->getOdAddress()}</td> <td>{$orderEntity->getOdTel()}</td> </tr>{/foreach}</tbody>
  66. 66. ループのelse {foreach}~{foreachelse}~{/foreach} でループがなかった時の表示が書ける。<tbody>{foreach from=$orderEntities item="orderEntity"} <tr> <td>{$orderEntity->getOdCode()}</td> <td>{$orderEntity->getOdDate()|date_format:"%Y/%m/%d %H:%M:%S"}</td> <td>{$orderEntity->getOdTotal()|number_format}</td> <td>{$orderEntity->getOdName()}</td> <td>{$orderEntity->getOdAddress()}</td> <td>{$orderEntity->getOdTel()}</td> </tr>{foreachelse} <tr> <td colspan=“6”>表示するリストはありません。</td> </tr>{/foreach}</tbody>
  67. 67. ところで、WEBレイアウトって… 共通部分がある
  68. 68. 共通部分を別テンプレートに header.tpl hoge.tpl navi.tpl footer.tpl
  69. 69. 別テンプレートの挿入共通部分を別tplにしてそれを読み込む。{include file="パス"} <header> {include file="layout/header.tpl"} </header>
  70. 70. その他詳細は…本家サイトのマニュアルを参照。http://www.smarty.net/docs/ja/
  71. 71. CakePHP
  72. 72. 再びModelに注目
  73. 73. 例えば、以下のようなテーブルorders フィールド 種別 NOT NULL その他od_code INTEGER YES 主キー / AUTO_INCREMENTod_date DATETIME YESod_total INTEGER YESod_name TEXT YESod_address TEXT YESod_tel TEXT YESmembersフィールド 種別 NOT NULL その他mb_code INTEGER YES 主キー / AUTO_INCREMENTmb_name_last TEXT YESmb_name_first TEXT YESmb_mail TEXT YES
  74. 74. 主キーによる検索SQLは…orders $sql1 = "SELECT * FROM orders WHERE od_code=:od_code";members $sql2 = "SELECT * FROM members WHERE mb_code=:mb_code";
  75. 75. ほとんど同じやん!
  76. 76. ModelクラスのfindByPKメソッドは…<?php <?phpclass OrderDAO { class MemberDAO { public function findyByPK($odCode) { public function findyByPK($mbCode) { $orderEntity = new OrderEntity(); $memberEntity = new MemberEntity(); try { try { $this->_db->query("SET NAMES utf8;"); $this->_db->query("SET NAMES utf8;"); $sql = $sql = "SELECT * FROM orders WHERE od_code=:od_code"; "SELECT * FROM members WHERE mb_code:mb_code"; $stmt = $this->_db->prepare($sql); $stmt = $this->_db->prepare($sql); $stmt->bindParam(":od_code", $odCode); $stmt->bindParam(":mbCode", $mbCode); $result = $stmt->execute(); $result = $stmt->execute(); while($row = $stmt->fetch()) { while($row = $stmt->fetch()) { $orderEntity->setOdCode($row[od_code]); $memberEntity->setMbCode($row[„mb_code]); $orderEntity->setOdDate($row[od_date]); $memberEntity->setMbNameLst($row[„mb_name_last]); $orderEntity->setOdTotal($row[od_total]); $memberEntity->setMbNameFirst($row[„mb_name_first]); $orderEntity->setOdName($row[od_name]); $memberEntity->setMbMail($row[„mb_mail]); $orderEntity->setOdAddress($row[od_address]); } $orderEntity->setOdTel($row[od_tel]); } } catch(PDOException $ex) { } $expMessage = "<p>DB接続に失敗しました。<hr/>"; catch(PDOException $ex) { print($expMessage); $expMessage = "<p>DB接続に失敗しました。 }<hr/>"; return $memberEntity; print($expMessage); } } } return $orderEntity; ?> }}?>
  77. 77. ほとんど同じやん!
  78. 78. Modelは同じようなことを 書くことが多い
  79. 79. 書くのがめんどくさい!
  80. 80. そこで…
  81. 81. すんませんm(_ _)mほんと、もう、ベタで…
  82. 82. またまた、これを例にとると… CakePHPでのソースコードは…
  83. 83. Modelは…<?phpclass Order extends AppModel { var $name = Order; var $primaryKey = od_code;}?>
  84. 84. Controllerは…<?phpclass OrdersController extends AppController { public $name = Orders; function showOneOrder($id) { $data = $this->Order->findByOd_code($id); $this->set(data, $data); }}?>
  85. 85. Viewは…<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>CakePHP Sample01</title></head><body><header> <h1>CakePHP Sample01</h1></header><section> <table border="1"> <tr> <th>注文コード</th> <td><?php print($data[Order][od_code])?></td> </tr> <tr> <th>注文日時</th> <td><?php print(strftime(%Y/%m/%d %H:%M:%S,strtotime($data[Order][od_date])))?></td> </tr> <tr> <th>注文合計金額</th> <td><?php print(number_format($data[Order][od_total]))?>円</td> </tr> <tr> <th>注文者氏名</th> <td><?php print($data[Order][od_name])?></td> </tr> <tr> <th>注文者住所</th> <td><?php print($data[Order][od_address])?></td> </tr> <tr> <th>注文者電話番号</th> <td><?php print($data[Order][od_tel])?></td> </tr> </table></section></body></html>
  86. 86. え?これだけ?
  87. 87. これだけです!
  88. 88. しかも、表示させてみると…
  89. 89. な、なんか、色がついている…
  90. 90. オイシイ!
  91. 91. ということで、ケーキの食べ方
  92. 92. CakePHPの準備CakePHPのサイト(http://cakephp.org/)から適切なバージョンをダウンロード、解凍。この状態ですでに動作する。
  93. 93. TOPを表示させてみると… あかん所を表示してくれるので、 そこに注目する
  94. 94. DB設定をするapp/Config/database.php.dafaultをコピーして、database.phpとし、中を適切に書き換える。 class DATABASE_CONFIG { public $default = array( datasource => Database/Mysql, persistent => false, database.php host => localhost, login => user, password => password, database => database_name, prefix => , //encoding => utf8, ); }
  95. 95. 通常のControllerは… 例えば、こんなアプリと して showList.php showOneLine.php表示画面 処理 表示画面 処理 表示画面http://…/wow/hoge/showList.php http://…/wow/hoge/ showOneLine.php
  96. 96. CakePHPのControllerは… 表示画面 処理 表示画面 処理 表示画面 <?php class HogeController extends AppController { public $name = Hoge; function showList() { … } function showOneLine() { … } } ?>http://…/wow/hoge/showList http://…/wow/hoge/ showOneLine
  97. 97. CakePHPの規約1ひとつのユースケース(機能)でひとつのControllerクラスを作る。各処理はその中のメソッドとして実装する。クラス名は「○○Controller」とし、ファイル名も同様に「○○Controller.php」とする。このファイルをapp/Controllerディレクトリに入れる。
  98. 98. CakePHPの規約2 AppControllerを継承する。 $nameにController名を設定。 URLは http://ドメイン/アプリルート/コントローラー名/メソッド 名<?phpclass HogeController extends AppController { public $name = Hoge; 例えば、 function showList() { これは、 … http://…/wow/hoge/showList }}?>
  99. 99. CakePHPの規約3 Controllerで使用するViewファイルは コントローラー名のディレクトリを app/View/に作成し、 「メソッド名のアンダーバー記 法.ctp」 ファイルとしておく。 例えば、HogeControllerのshowListな ら、 app/View/Hoge/show_list.ctp となる。
  100. 100. index例えば、http://…/wow/hoge/の場合は、メソッド名がない 「コントローラー名/」で終わる場合(メソッド名が ない場合)の処理は、indexメソッドに書く。 Viewファイルは「index.ctp」。
  101. 101. Viewにデータを送る方法 Controllerの各メソッド内で、 $this->set(“変数名”, 値) View側では普通に変数として使用する<?phpclass HogeController extends AppController { function showList() { … <td><?php print($list)?></td> $this->set(„list, $listData); }}?>
  102. 102. Modelの作り方1テーブル名を複数形にする。(ex) members主キーのカラム名をidとする。INTEGER型のAUTO_INCREMENTのサロゲートキーとすると便利。membersフィールド 種別 NOT NULL その他id INTEGER YES 主キー / AUTO_INCREMENTmb_name_last TEXT YESmb_name_first TEXT YESmb_mail TEXT YES
  103. 103. Modelの作り方2 AppModelを継承したクラスを作る。 クラス名、ファイル名は、テーブル名 を単数形にしたものとする。 原則、1テーブル1モデルクラス。 $nameにモデル名を設定する。 このファイルをapp/Modelに置く。<?phpclass Member extends AppModel { public $name = Member;}?>
  104. 104. Modelの使い方$usesフィールドに使用するModel名を配列で設定。↑でModelがControllerに登録されるので、$this->モデル名->モデルのメソッドでDBを操作できる。<?phpclass MemberController extends AppController { モデルの登録 public $name = Member; public $uses = array(Member); function showList() { $memberList = $this->Member->find(all); モデルの操作 $this->set(memberList, $memberList); }}?>
  105. 105. SELECT系基本1データ取得(SELECT)メソッドはfind($type, $params)第1引数$typeは取得の方法。 all: 条件に合う全レコードを取得。 first: 条件に合う最初の1レコードを取得。 list: id番号をキーとして特定のカラムの値だけが収められた配 列を取得。セレクトボックスの生成に便利。 count: レコード数を取得。第1引数を省略すると、firstが適用される。
  106. 106. SELECT系基本2第2引数$paramsはオプション設定の連想配列(省 $params = array( conditions => array(Model.field => $thisValue),略可)。主なものは以下の recursive => 1,通り。 fields => array(Model.field1, DISTINCT Model.field2), conditions: 条件。WHERE order => 句に該当 array(Model.created, Model.field3 DESC), group => array(Model.field), fields: 取得するフィールド limit => 15, page => 3, order: 取得順。ORDER BY offset => 4, に該当。 callbacks => true ) group: グループ化。 GROUP BYに該当。
  107. 107. findの結果Modelの取得結果は連想配列 Array (に格納されている。 [0] => Array ( [Member] => Array ( [id] => 1 [mb_name_last] => 安室 [mb_name_first] => 令 [mb_mail] => rey@amuro.com$memberList = $this->Member->find(all); ) ) [1] => Array ( [Member] => Array ( [id] => 2 [mb_name_last] => 神湯 [mb_name_first] => 美談 [mb_mail] => kamille@bidan.com ) ) )
  108. 108. その他便利なSELECT系findAllByフィールド名(値)で「フィールド=値」の条件に合致する全レコードを取得 $memberList = $this->Member->findAllByMb_name_last("神湯");findByフィールド名(値)で「フィールド=値」の条件に合致する最初の1レコード $oneMember = $this->Member->findById(1);を取得 その他、詳細は本家サイトのマニュアルを参照。 http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
  109. 109. INSERT&UPDATEINSERTとUPDATEは同一のメソッドsave($data, $validate, $fieldList)を使う。引数はすべて省略可。第1引数$dataは登録データの配列。 形式は取得データと同じ。 このデータ内に主キー項目があればUPDATE、なければINSERT。第2引数$validateはデータチェックを行うかどうかをtrueかfalseで指定。第3引数$fieldListはデータ登録のカラムを制限したい場合は配列で指定。
  110. 110. $newMember = array( "mb_name_first"=>"枢木", "mb_name_last"=>"朱雀", "mb_mail"=>"suzaku@kururugi.net" INSERT );$this->Member->save($newMember);$oldMember = array( "id"=>4, "mb_mail"=>"suzaki@kururugi.com" UPDATE );$this->Member->save($oldMember);その他、詳細は本家サイトのマニュアルを参照。http://book.cakephp.org/2.0/en/models/saving-your-data.html
  111. 111. DELETE削除(DELETE)はdelete($id, $cascade) 第1引数$idは主キー値。 $this->Member->delete(4); 第2引数$cascadeは省略可。 関連テーブルのレコードも削除するかどうかをtrueかfalseで指 定。条件指定の削除はdeleteAll($conditions, $cascade, $callbacks) 第1引数$conditionsに条件を表す連想配列を指定。 第2引数第3引数は省略可。 $this->Member->deleteAll(array("mb_mail"=>"suzaki@kururugi.com")); その他、詳細は本家サイトのマニュアルを参照。 http://book.cakephp.org/2.0/en/models/deleting-data.html
  112. 112. その他便利なものなど
  113. 113. RelationRDBのRはリレーション。Modelでリレーションを設定 public $hasMany = array( „Membergroup => array(するには、以下のフィール „className => „Membergroup,ドを設定する。 „foreignKey => „member_id„ ) $hasOne ); $hasMany belongsTo hasAndBelongsToMany詳細は本家サイトのマニュアルを参照。http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
  114. 114. Validation必須チェックや数値 public $validate = array( „mb_name_last => array(チェックなど、Model側 „notempty => array(で各カラムのValidationが „rule => array(„notempty„), „message‟ => „名前(姓)は必須です。できる。 ) )$validateフィールドに );ルールを記述。 詳細は本家サイトのマニュアルを参照。 http://book.cakephp.org/2.0/en/models/data-validation.html
  115. 115. Virtual fieldsカラム同士の値の計算結果など、演算結果で導き出すフィールドも設定できる。$virtualFieldsフィールドにSQLを記述。public $virtualFields = array( „mb_fullname => „CONCAT(Member.mb_last_name, “ ”, Member.mb_first_name)); 詳細は本家サイトのマニュアルを参照。 http://book.cakephp.org/2.0/en/models/virtual-fields.html
  116. 116. Transactionsトランザクション $dataSource = $this->Member->getDataSource(); $dataSource->begin();制御も可能。 $memberResult = $this->Member->save($newMember); $orderResult = $this->Order->save($newOrder);オススメは if(…) {Controllerで制御。 $dataSource->commit(); } else(…) { $dataSource->rallback(); } 詳細は本家サイトのマニュアルを参照。 http://book.cakephp.org/2.0/en/models/transactions.html
  117. 117. 参考書籍CakePHP1.3によるWebアプリケーション開発http://www.amazon.co.jp/dp/4798026646/
  118. 118. え?1.3?
  119. 119. 時代は2系だよ、君! って、誰?
  120. 120. 参考書籍CakePHP2.1によるWebアプリケーション開発http://www.amazon.co.jp/dp/4798034185/
  121. 121. でも、一番いいのは
  122. 122. CakePHP Cookbook 2.xhttp://book.cakephp.org/2.0/en/contents.html
  123. 123. ただし、現状英語のみ!
  124. 124. Smarty+CakePHP
  125. 125. ところで、 CakePHPのViewに注目してみる
  126. 126. たとえば…
  127. 127. ソースコードは…<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>CakePHP Sample02</title></head><body><header> <h1>CakePHP Sample02</h1></header><section><?php if(empty($memberList)) { ?><p>表示すべき情報はありません。</p><?php }else { ?><?php print(count($memberList)) ?>件ありました。<table border="1"> <thead> <tr> <th>会員コード</th> <th>会員名</th> <th>メールアドレス</th> </tr> </thead> <tbody> <?php foreach($memberList as $key=>$member) { ?> <tr> <td><?php print($member[Member][id]) ?></td> <td><?php print($member[Member][mb_name_last]." ".$member[Member][mb_name_first]) ?></td> <td><?php print($member[Member][mb_mail]) ?></td> </tr> <?php } ?> </tbody></table><?php } ?></section></body></html>
  128. 128. PHPソースが混ざってる…
  129. 129. Model-Controllerは便利だが、CakePHP Viewがちょっと… View-Controller分離は完璧だが、Smarty Modelは自分で実装…
  130. 130. そこで…
  131. 131. CakePHP Smarty
  132. 132. 手順←P.444~454に記載。 Smartyライブラリのインストール →所定の場所にlibフォルダを入れる Smartyが使用するディレクトリの用 意 →所定の場所にフォルダを作成 Smarty View Classのインストール →以下のURLからPHPファイルを取得 し所定の位置にいれる http://cakeforge.org/snippet/detail.php?type=snippet&id=6
  133. 133. これでOK!
  134. 134. ただし、CakePHP1.3 + Smarty2.6
  135. 135. 時代はCakePHP2.2 + Smarty3.1 だよ、君! だから、誰?
  136. 136. CakePHP2.2 + Smarty3.1 で試してみる
  137. 137. 情報を求めて SmartyViewClassを取得するURLにアクセス ↑ http://cakeforge.org/snippet/detail.php?type=snippet&id=6
  138. 138. ショ、ショック…
  139. 139. ちなみに… Smarty連携の項目自体 がなくなっていた…
  140. 140. もうええちゅうねん
  141. 141. 困ったときにGoogle先生…
  142. 142. http://bakery.cakephp.org/articles/skler/2011/08/05/cakephp_2_0_0_beta_smarty_3
  143. 143. う、うごかない…
  144. 144. ということで、 不肖新三このソースを改造して とりあえず動くようにしました!
  145. 145. あらためて…
  146. 146. CakePHP+Smarty準備手順1Smartyライブラリのインストール Smartyのサイト (http://www.smarty.net/)から適切 なバージョンをダウンロード、解 凍。 中にあるlibsディレクトリを 「smarty」と名称変更。 cakephpディレクトリのvendors ディレクトリに入れる。
  147. 147. CakePHP+Smarty準備手順2Smartyが使用するディレクトリの用意 テンプレートをコンパイルしたものを 格納する空ディレクトリとして cakephpの app/tmp/smarty/compile として作る。
  148. 148. CakePHP+Smarty準備手順3Smarty View Classのインストール SmartyView.phpファイルを入手し、 cakephpの app/View 直下に配置する。 入手は、この勉強会のサンプル自体を github https://github.com/architshin/histudy7 に置いてあるので、このリポジトリの histudy7/cakesmarty/app/View/SmartyView.php を参照。
  149. 149. CakePHP+Smarty準備手順4default.tplの配置 app/View/Layouts/default.ctp をコピーしてSmarty記法に書き換えた default.tplを作成する。 先のリポジトリのからコピーしても可。
  150. 150. CakePHP+Smarty利用方法Controllerのフィールド$viewClassにSmartyを指定。Viewファイルの拡張子は.tplで保存。あとは、通常の記述方法。 ModelとControllerはCakePHPのルール。 ViewはSmartyのルール。
  151. 151. Controller<?phpclass MemberController extends AppController { public $name = Member; public $uses = array(Member); public $viewClass = Smarty; function showList() { $memberList = $this->Member->find(all); $this->set(memberList, $memberList); $this->set(memberListCount, count($memberList)); }}?>
  152. 152. View: show_list.tpl(一部)<section>{if empty($memberList) }<p>表示すべき情報はありません。</p>{else}{$memberListCount}件ありました。<table border="1"> <thead> <tr> <th>会員コード</th> <th>会員名</th> <th>メールアドレス</th> Smartyでは配列のアクセスは </tr> $member[‘Member’][‘id’] </thead> <tbody> ではなく、 {foreach from=$memberList item="member"} 「.」でつなぐ <tr> <td>{$member.Member.id}</td> <td>{$member.Member.mb_name_last}&nbsp;{$member.Member.mb_name_first}</td> <td>{$member.Member.mb_mail}</td> </tr> {/foreach} </tbody></table>{/if}</section>
  153. 153. ということで、CakePHP+Smarty 便利です!
  154. 154. ぜひ、使ってみてください!
  155. 155. 特にCakePHP2.2 + Smarty3.1
  156. 156. で、バグ報告ください! ただし、対応するかどうかは不明…
  157. 157. 以上です。
  158. 158. 太い新ちゃん
  159. 159.
  160. 160. 細いワテさん
  161. 161. でした
  162. 162. ご清聴ありがとうございまし た!

×