Posts tagged CakePHP

CakePHP アソシエーションのまとめ(2)

0

アソシエーションのまとめ(1) で書いた

< ?php
class User extends AppModel
{
    var $name = 'User';
    var $hasOne = array('Profile' =>
                    array('className' => 'Profile',
                          'conditions' => '',
                          'order' => '',
                          'dependent' => true,
                          'foreignKey' => 'user_id'
                    )
                  );
}
?>

この部分の補足です。
それぞれの意味するところは

var $hasOne = array('関連先のモデル名'=>
                array('className'  => '関連先のモデルのクラス名',
                      'conditions' => '関連を定義するSQL条件の一部',
                      'order'      => '関連先のデータの並び順',
                      'dependent'  => '関連先データの同時削除',
                      'foreignKey' => '関連先テーブル側の外部キー'
                )
              );

conditions は条件を付けて関連付けるモデルのデータを制限するときに指定する。
dependent は関連元のデータが削除されたときに、一緒に関連先のデータも削除するかどうか。
関連先のモデルで関連元のモデルの主キーを定義しているカラム名です。

dependent などはかなり便利に使えそうですね。
アソシエーションのまとめ(1) に書いたように、 foreignKey は CakePHP の命名規則に従っていれば省略可能です。

CakePHP アソシエーションのまとめ(1)

1

CakePHP のアソシエーションのまとめです。
タイトルに (1) とつけたので多分何回か続けます。

アソシエーションとはモデル間のつながりのことです。

例えば、下記のような2つのテーブルがあると

CREATE TABLE users(
    id int unsigned auto_increment primary key,
    nickname varchar(30) NOT NULL,
    created datetime default NULL,
    modified datetime default NULL
);

CREATE TABLE profiles(
    id int unsigned auto_increment primary key,
    user_id int unsigned unique,
    blog_url varchar(256),
    hobby varchar(256),
    created datetime default NULL,
    modified datetime default NULL
);

CakePHP では2つのモデルになります。
User モデルと Profile モデルです。
この2つのモデルは1対1の関係になります。
「一人のユーザは1つのプロファイルを持つ」とういことです。

この2つのモデルの関係を CakePHP に指示するには次のようになります。

< ?php
class User extends AppModel
{
    var $name = 'User';
    var $hasOne = array('Profile' =>
                    array('className' => 'Profile',
                          'conditions' => '',
                          'order' => '',
                          'dependent' => true,
                          'foreignKey' => 'user_id'
                    )
                  );
}
?>

これで、
$this->User->findById($id);とすることにより、

Array
(
    [User] => Array
        (
            [id] => 1
            [nickname] => boze
        )
    [Profile] => Array
        (
            [id] => 1
            [blog_url] => http://www.syuhari.jp/blog
            [hobby] => 読書
        )
);

のようにUser モデルだけでなく、Profileモデルの情報も同時に取得することができます。

CakePHP の命名規則を守っていれば、
var $hasOne = array('Profile');だけでもいけるようです。
※外部キーはモデル名+_id

CakePHP 日本語マニュアル
6.4. アソシエーション

PHPフレームワークのベンチマーク

0

PHPベンチマーク: Zend Framework vs Symfony vs CakePHP vs CodeIgniter vs PHP on TRAX – 徒然なるままにBlog

  • Zend-Framework
  • Symfony
  • CakePHP
  • Codelgniter
  • PHP on TRAX

のベンチマーク結果が載っています。

ただ、

モデル作成を行わないはずなのにCakePHPだけモデルが生成されるようになっていました。
PHPベンチマーク CakePHPでモデルを使用しない | Shin x blog

なので、是非CakePHP もモデル使用しないソースで実行した結果を見てみたいですね。

実行環境が元エントリとは異なるので絶対的な数値にはあまり意味が無いですが、両者を比べるとモデル生成なしの方が20%ほど速いようです。
PHPベンチマーク CakePHPでモデルを使用しない | Shin x blog

モデル使用しないと20% ほど早いそうです。

CakePHP HtmlHelper::tagValue のHTMLエスケープ処理

1

view でモデルの値などを出力する際に
$html->tagValue("Model/hoge");
とすれと、HTMLエスケープ処理をしてくれるので便利です。

ただ、
CakePHP 1.1.15.5144以降はHtmlHelper#tagValueに注意 | Shin x blog
に書かれているように、CakePHP のバージョン1.1.15.5144 からエスケープするかのフラグが追加されたようです。

以前はエスケープしないを選択できなかったので、それはそれで不便な点もありました。
MOONGIFT ブログ ? CakePHP覚書(HTML Helpler)

しかし今回の変更で注意しなければいけないのは、デフォルトでエスケープされていたのがデフォルトでエスケープ処理されなくなったことです。

cake/libs/view/helpers/html.php
function tagValue($fieldName, $escape = false)

以前のようにエスケープ処理させるには
$html->tagValue("Model/hoge", true);
とする必要があります。

また、

ちなみに1.2.0.5147ではtagValueがdeprecatedになっており、代わりにvalueメソッドを使うようになるようです。

ということになるようです。

CakePHP flash メソッドでレイアウトを指定する

2

コントローラ毎にレイアウトを変えていていると flash メソッドは使えないなあと思っていたのですが、下記のようにすることによりレイアウトをコントローラで指定できますね。

/app/app_controller.php に下記の flash メソッドを追加

function flash($message, $url, $pause = 1) {
    $this->autoRender = false;
    $this->autoLayout = false;
    $this->set('url', $this->base . $url);
    $this->set('message', $message);
    $this->set('pause', $pause);
    $this->set('page_title', $message);

    if (file_exists(VIEWS . 'layouts' . DS . $this->layout.'_flash.thtml')) {
        $flash = VIEWS . 'layouts' . DS . $this->layout.'_flash.thtml';
    } elseif ($flash = fileExistsInPath(LIBS . 'view' . DS . 'templates' . DS . "layouts" . DS . 'flash.thtml')) {
    }
    $this->render(null, false, $flash);
}

これで、
/app/views/layouts/指定したレイアウト名_flash.thtml
というレイアウトファイルがあれば、それを使用して
なければ、デフォルトの flash.thtml を使用します。

やっていることはすごく単純でコントローラクラスの flash メソッドをオーバライドして、使用するレイアウトファイルを選択するところで

if (file_exists(VIEWS . 'layouts' . DS . 'flash.thtml')) {
    $flash = VIEWS . 'layouts' . DS . 'flash.thtml';
}

となっていたところを

if (file_exists(VIEWS . 'layouts' . DS . $this->layout.'_flash.thtml')) {
    $flash = VIEWS . 'layouts' . DS . $this->layout.'_flash.thtml';
}

に変更しただけです。

他にいい方法があれば教えてください。

CakePHP コントローラのflash メソッド

2

データを更新した後などに「更新しました」などのメッセージを簡単に出せるのがコントローラのflash メソッド。
コントローラで、
$this->flash('更新しました', '/users');
などとすることにより、メッセージを簡単に出せる。
2つ目の引数は飛び先URL を指定できる。

ちなみにこの flash メソッドは下記のようになっています。
/cake/libs/controller/controller.php

function flash($message, $url, $pause = 1) {
    $this->autoRender = false;
    $this->autoLayout = false;
    $this->set('url', $this->base . $url);
    $this->set('message', $message);
    $this->set('pause', $pause);
    $this->set('page_title', $message);

    if (file_exists(VIEWS . 'layouts' . DS . 'flash.thtml')) {
        $flash = VIEWS . 'layouts' . DS . 'flash.thtml';
    } elseif ($flash = fileExistsInPath(LIBS . 'view' . DS . 'templates' . DS . "layouts" . DS . 'flash.thtml')) {
    }
    $this->render(null, false, $flash);
}

上のソースを見ると分かるように、この flash メソッドのレイアウトは
$layout = "hoge";
とか指定しても指定したレイアウトでは表示されません。

flash メソッドでは flash.thtml というレイアウトを使用することしかできません。
/app/views/layouts/flash.thtml
を探してなければ、
/cake/libs/view/templates/layouts/flash.thtml
のデフォルトのレイアウトを使用します。

また、デフォルトの flash.thtml は

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><?php echo $page_title?></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<?php if(Configure::read() == 0) { ?>
<meta http-equiv="Refresh" content="<?php echo $pause?>;url=<?php echo $url?>"/>
<?php } ?>
<style><!--
P { text-align:center; font:bold 1.1em sans-serif }
A { color:#444; text-decoration:none }
A:HOVER { text-decoration: underline; color:#44E }
--></style>
</head>
<body>
<p><a href="<?php echo $url?>"><?php echo $message?></a></p>
</body>
</html>

のようになっていて、
DEBUG モードで DEBUG = 0 を指定していると meta タグを利用して勝手に画面遷移します。DEBUG モードが 0 以外の場合はメッセージをクリックすると指定したURLに画面遷移します。

非常にシンプルなレイアウトですので、使用するときは、
/app/views/layouts/flash.thtml
にコピーしてカスタマイズした方がよいでしょう。

CakePHP ヘルパーからコンポーネントへのアクセス方法

1

ヘルパーからコンポーネントへのアクセス方法が分からず
教えていただいたのでメモ。

例えば HogeComponent にアクセスしたいヘルパーに
$this->view->controller->HogeComponent->method();というように書けば、HogeComponent の method にアクセスできる。

これで、ヘルパーがかなり使いやすくなりました。

CakePHP デバッグモード

1

デバッグモードのメモ

/app/config/core.php の52行目に
define('DEBUG', 0);と定義されているのがデバッグモード

この値を変更することにより、本番環境、開発環境と切り替えることができる。

DEBUG の値は
0: プロダクションモード。エラーは出力されず、デバッグメッセージも表示されません。
1: 開発モード。 Warnings とエラー、デバッグメッセージを表示します。
2: 開発モード。実行されたSQL 文が表示されます。
3: 開発モード。2に加えて、現在のオブジェクト(通常はコントローラ)のフルダンプも表示されます。

DEBUG=1 で開発を行い、データ取得などの挙動が考えているのと違うときに、
DEBUG=2 にするという感じでやっています。
あまり、 DEBUG=3 を使用していないなあ。コントローラのダンプなので量が多すぎてかえって見づらいので、
debug($hoge);などで必要なときに個別にダンプを出してしまいます。

もちろん本番環境では DEBUG=0 です。

CakePHP キャッシュファイルの使用

1

CakePHP でキャッシュを使用するときに便利なグローバル関数があります。

cache($path, $data, $expires, $target)
$data のデータをキャッシュします。
キャッシュする場所は
$target==”cache” なら /app/tmp/cache/ + $path
$target==”public” なら /webroot/ + $path
になります。$target を指定しなければ $target==”cache” です。
$expires はキャッシュの有効期間です。
内部で
$expires = strtotime($expires, time());
が行われるので、strtotime の Data input formats 形式に準拠したものでなければいけません。
デフォルトは $expires = ‘+1 day’ です。
clearCache($params, $type, $ext)
$paramsが文字列でキャッシュディレクトリかファイル名にマッチする場合はキャッシュから削除されます。
$params が配列の場合は配列内の文字列全てに対して上記の処理が行われます。
対象のディレクトリは $type で指定します。
$type のデフォルトは ‘views’ です。
対象ディレクトリは /app/tmp/cache/ + $type になります。
cache 関数で ‘public’ を指定した場合のクリアはこの関数ではできないようです。

結構簡単にキャッシュ処理ができそうです。

CakePHP グローバル関数

0

PHP のネイティブ関数の短縮表記には下記のようなものがあります。

a() => array()
e() => echo()
low() => strtolower()
up => strtoupper()
r() => str_replace()
am() => array_merge()
h() => htmlspecialchars()

このような短縮表記の関数を独自に定義して開発に使用されている方も多いと思いますが、CakePHP として定義されていると使用しやすいですね。(特に複数人で開発しているときなど、標準であると助かります。)

このほかにも CakePHP には便利な関数が定義されています。

debug($var, $showHtml);
DEBUGレベルが0以外のときに、$varが出力される。
print '<pre>';
print_r($var);
print '</pre>';

のようなことをしてくれます。$showHtmlが TRUE ならブラウザで見やすいように出力してくれます。
aa(‘a’,'b’)
連想配列を作成する。
array('a'=>'b')
をやってくれます。
h($mixed)
文字列を指定して htmlspecialchars をやってくれるが、配列も指定できる。
配列を指定すると再帰的に h() を呼び出している。
pr($var)
print_r をブラウザでみやすいように <pre> で囲んでくれます。echo "<pre>";
print_r($var);
echo "</pre>"
env($key)
環境変数を取得できます。
一番の特徴は PHP_SELF, DOCUMENTO_ROOT をサポートしていないサーバでも動作をエミュレートして値を返してくれます。コードを再配布するときには重宝しそうです。
params($mixed)
文字列を返してくれます。
配列なら一番最初の値、文字列なら文字列、値がなければ NULL を返します。
setUri()
現在のURI を返してくれます。
file_get_contents()
file_put_contents()
この関数が実装されていない PHP4.3 未満のためにエミュレートされています。
stripsslashes_deep($array)
$array は配列を指定。配列の全ての値に対して再帰的に stripslashes を行います。
countdim($array)
$array の配列の次元数を返します。
LogError($message)
CakeLog::write を実行します。
fileExistsInPath($file)
現在のinclude パスから $file で指定されたファイル名があるか探します。
見つかればそのパスを返し、見つからなければ false を返します。
ife($condition, $var1, $var2)
$condition が true なら $var1 を返し、false なら $var2 を返す。

使用しすぎると読みにくいコードになりかねませんが、うまく使用すれば開発効率が上がりそうです。

日本語マニュアル:Chapter 11. Cake のグローバル定数とグローバル関数

Go to Top