ラベル CakePHP の投稿を表示しています。 すべての投稿を表示
ラベル CakePHP の投稿を表示しています。 すべての投稿を表示

2014年1月30日木曜日

CakePHP Ajaxを使う

Ajaxを使って動的にMySQLに接続。テーブルに対する処理を行う。
ボタンが押されたらページ遷移せずにデータをテーブルに追加するor持ってくるなど。

CakePHPにはAjaxヘルパーなるものが存在しているが、どうやら古いものなうえ、
どこかからダウンロードしてこないと使えないようだ。
jQueryを使えば問題なく動作するようなので、jQueryを使用する。

参考サイト

上の参考サイトが分かりやすいがCakePHPを使っていないので、今回は上のサイトの例を
下のサイトを参考にしながらCakePHPに落とし込んで行く。
なので細かい部分は参考サイトを参考に。

テーブルとモデルを作成する


Ajaxで操作するテーブルを作成。

/*---------------------------------------------------------------------------*/
CREATE TABLE `Telephones` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR( 64 ) NOT NULL ,
`phone` VARCHAR( 16 ) NOT NULL ,
PRIMARY KEY ( `id` ) 
);
/*---------------------------------------------------------------------------*/

モデルをDirectoryで作成するとCakePHPのデフォルトのクラスと被るので名前だけ変える。
変えた名前に対応したモデルを作って適当なデータを挿入すればテーブル周りは完了。

jQueryを使用したviewファイルを作成する


jQueryでMySQLに接続。ヒアドキュメントの存在を知ってたけど初めて使ったのでメモ代わりに。

/*---------------------------------------------------------------------------*/
<?php
echo $this->Html->script("jquery-1.10.2.js", array('inline' => false));
$this->Html->scriptStart(array('inline' => false));
echo <<<EOT
$(document).ready(function(){ 
$("#search_results").slideUp(); 
   $("#search_button").click(function(e){ 
       e.preventDefault(); 
       ajax_search(); 
   }); 
   $("#search_term").keyup(function(e){ 
       e.preventDefault(); 
       ajax_search(); 
   }); 
});

function ajax_search(){ 
$("#search_results").show(); 
var search_val=$("#search_term").val(); 
$.post("/hoge/fuga/find", {search_term : search_val}, function(data){
if (data.length>0){ 
$("#search_results").html(data); 
}) 
EOT;
$this->Html->scriptEnd();
/*---------------------------------------------------------------------------*/

普通のphpファイルで操作していた要素をCakePHPのviewファイルに合わせて
書き換えるだけなので難しいことは無いはず。

コントローラにAjaxからアクセスする操作を記述する


上の記述どおりだとFugaControllerにfindメソッドを記述する。

/*---------------------------------------------------------------------------*/
public function find() {
$this->layout = "ajax";
if($this->RequestHandler->isAjax()) {
$term = strip_tags(substr($this->request->data("search_term"), 0, 100));
$sql = "select name,phone
from directory
where name like '%$term%'
or phone like '%$term%'
order by name asc";
$result = $this->Telephone->query($sql);
$string = "";
foreach($result as $row) {
   $string .= "<b>".$row["Telephone"]["name"]."</b> - ";
   $string .= $row["Telephone"]["phone"]."</a>";
   $string .= "<br/>\n";
}
if($string === "") {
$string = "No matches!";
}
$this->set("data", $string);
}
}
/*---------------------------------------------------------------------------*/

これもほぼ参考サイト丸コピ。レイアウトの変更やAjaxからの送信かを確認しているくらい。

ここまでできたら一度ちゃんと動くかを普通にアクセスして確かめたほうがいいと思う。
条件がよくわからないが、エラーがあると普通にエラーメッセージを表示してくれるときと、
500エラーになるときで動作が分かれることがある
最初に普通にエラーメッセージが出てきたので、500エラーが出ている理由が
コントローラ側でエラーを吐いているのだと気づかずにしばらく積んだ。

最後にビューのポストに値を入力して動けば完了。

2014年1月27日月曜日

CakePHP2.x Datepickerを使ってみる

HTMLのフォームに簡単に日付を入力する素敵なjQueryのライブラリがあるそうな。
その名もDatepicker! 早速使ってみよう。

参考サイト

jQueryUIをダウンロードする


サイトから普通にダウンロードしてくる。最新のものをダウンロードしてくれば問題なかろう。
使うのは以下の通り。
  • js/jquery-1.10.2.js
  • js/jquery-ui-1.10.4.custom.min.js
  • development-bundle/ui/jquery.ui.datepicker.js
  • css/ui-lightness/jquery-ui-1.10.4.custom.min.css
ファイルに付いている数値はバージョンなので時期によっては違う。
解凍したzipのフォルダ構成に基づいてファイル名を記述しているので、
これもバージョンによっては違うかも。

テスト用のHTMLを作成する


/*---------------------------------------------------------------------------*/
echo $this->Html->css('jquery-ui-1.10.4.custom.min.css', null, array('inline' => false));
echo $this->Html->script('jquery-1.10.2.js', array('inline' => false));
echo $this->Html->script('jquery-ui-1.10.4.custom.min.js', array('inline' => false));
echo $this->Html->script('jquery.ui.datepicker.js', array('inline' => false));
echo $this->Html->scriptStart(array('inline' => false));
   $(function() {
       $("#datepicker").datepicker();
   });
echo $this->Html->scriptEnd();
echo $this->Form->input("Test", array("type" => "text", "id" => "datepicker"));
/*---------------------------------------------------------------------------*/

テストしていないからエラーが出るかも。
IEだとinlineにfalseを指定してheadタグに構文を記述しないと動かないっぽい。
しかし、ブラウザキャッシュに気づかずテストを繰り返したため、原因は全然別かも。
とりあえずIE8だと動いた。

2014年1月24日金曜日

CakePHP2.x BASIC認証を使ってみた

色々あってCakePHPでBASIC認証を使うことに。パスワードを平文のままサーバに送って処理を
行うためセキュリティはあまりよろしくないとのことなので、ダイジェスト認証ももしかしたらやるかも
しれない。やらないかもしれない。

参考サイト

認証用のユーザーを登録するテーブルを作る


多分usernameとpasswordカラムがあればなんとかなる。

/*---------------------------------------------------------------------------*/
CREATE TABLE IF NOT EXISTS admin_user (
   username VARCHAR(64),
   password VARCHAR(64)
);
/*---------------------------------------------------------------------------*/

でも大抵管理ページのユーザー管理用に使うと思うので、参考サイトのようにそれなりにデータは
持っておいたほうがいいかも。

モデルを作成する


作成したテーブルを操作するモデルを作ろう。
今回は作成したテーブルからしてCakePHPのデフォルトから外れているのでモデルも外れる。

/*---------------------------------------------------------------------------*/
class AdminUser extends AppModel {
public function beforeSave($options = array()) {
$password = &$this->data['User']['password'];
password = AuthComponent::password($password);
return true;
}
}
/*---------------------------------------------------------------------------*/

Authコンポーネントをコントローラに設定する前に、
このモデルを使用して管理ユーザーを作っておくことをオススメする。
パスワード照合の際はハッシュ化された文字列で行うので、テーブル側にもハッシュ化済みの
文字列が入っていないと認証に失敗するからだ。

Authコンポーネントを設定する


AppControllerにAuthコンポーネントを設定する。

/*---------------------------------------------------------------------------*/
class AppController extends Controller {
public $components = array(
"Session",
"Auth" => array(
"loginAction" => array(
"controller" => "AdminUser",
"action" => "login",
"admin" => true,
),
"loginRedirect" => array(
"controller" => "applies",
"actopm" => "index",
"admin" => true,
),
"authenticate" => array(
"Basic" => array("userModel" => "AdminUser"),
),
),
);

public function beforeFileter()
{
$this->Auth->logoutRedirect = $this->webroot;
}
}
/*---------------------------------------------------------------------------*/

loginActionのコントローラに次で作成するコントローラを指定。
認証用のモデルに作成しておいたモデルを指定。

ログイン用コントローラを作成する


ログイン処理用のコントローラ。

/*---------------------------------------------------------------------------*/
class AdminUserController extends AppController
{
public $uses = array("AdminUser");

public function login()
{
if($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
}
else {
$this->Session->setFlash(
__('Username or password is incorrect'),
'default',
array(),
'auth'
);
}
}

public function logout()
{
$this->Auth->logout();
}
}
/*---------------------------------------------------------------------------*/

参考サイトをほぼもろパクリさ! 違いと言えばコントローラとモデル名?


これでちゃんとユーザーを作っていればBASIC認証ができるようになったはず。

2014年1月23日木曜日

CakePHP2.x 環境変数を調べる

CakePHPには環境変数を調べるための便利関数が用意されている。

/*---------------------------------------------------------------------------*/
env("HTTP_HOST");
/*---------------------------------------------------------------------------*/

これで指定した環境変数の中身が返ってくる。

2014年1月14日火曜日

CakePHP2.x 単体テストをやってみる

CakePHP2.x系にはPHPUnitを用いた単体テストが導入されているようだ。
PHPUnitは入っているし、ちょっとやってみた。

参考サイト
テスト - CakePHP Cookbook 2.x ドキュメント

今回はある程度整っている環境に導入するので、モデルの作成とかはすっぽかし。
とりあえずHogeモデルがすでにあると仮定して進める。

開発環境から作成する場合はこの時にスキーマをばっちり使用するとマイグレーションが
簡単になるらしい。

フィクスチャを作成する


このフィクスチャとやら、テスト時に一時的なテーブルを作成してそこで作業してくれるらしい。
テーブルの値に依存していて、テストの度に値を設定しないと、なんていうときに便利そう。
ファイルの作成場所はapp/Test/Fixture。

/*---------------------------------------------------------------------------*/
    class HogeFixture extends CakeTestFixture
    {
        public $import = array(
            "model"           => "Hoge",
            "connection"    => "hoge_db",
        );
    }
/*---------------------------------------------------------------------------*/

importプロパティに値を設定すると、
既存のモデルのスキーマを読み取って勝手にテーブルを作成する。
モデルが存在しないときはmodelではなくtableでテーブル名を指定するといい。
connectionはHogeモデルの接続先データベース。デフォルトのままでいいなら設定不要。

フィクスチャの接続先のデータベースを作る


ここで面倒くさがらずに、フィクスチャにはちゃんと専用のデータベースを用意してあげよう。
というのも、フィクスチャは
  1. 各フィクスチャで必要なテーブルを作成する
  2. フィクスチャにデータが存在すれば、それをテーブルに投入する
  3. テストメソッドを実行する
  4. フィクスチャのテーブルを空にする
  5. データベースからフィクスチャが作成していたテーブルを削除する
という手順を通過するので、仮にフィクスチャで使用するテーブルが指定したデータベースの
既存のテーブルと被っていた場合、発つ鳥後を濁さずと言わんばかりにテーブルを消してから
作業を終えるから。

1回テストを試してからテーブルが削除されているのに気づかず、
「あれ? テーブルがないぞ。接続先間違えてるのか?」なんて全くの見当違いの方向へ
悩んでいた自分のようになりかねない。(え? ならない?)

テストケースを作成する


app/Test/ModelにHogeTest.phpを作成。

/*---------------------------------------------------------------------------*/
    class HogeTest extends CakeTestCase
    {
        public $fixtures = array("app.Hoge");

        public function setUp()
        {
            parent::setUp();
            $this->Hoge ClassRegistry::init("Hoge");
        }

        public function testHoge()
        {
            $result = $this->Hoge->hogeru();
            $this->assertEquals("hogeru", $result);
        }
    }
/*---------------------------------------------------------------------------*/

テストケースのクラスとファイル名には必ず最後にTestをつける必要がある。
fixtureプロパティでさっき作成したHogeフィクスチャを指定。
setUpメソッドでテスト前の初期化を行う。ここではHogeモデルを作成している。
testHogeがテスト時に呼ばれるメソッド。
ひとつのファイルに定義されているものは一度のテストで全て実行される。
Hogeモデルのhogeruメソッドを呼び出している。中身はさっぱり知らないが"hogeru"が返ってくる。
assertEqualsで望みどおりの結果が返ってきているかチェック。
アサーション系のメソッドは他にもあるので状況にあわせて使おう。

テストを行う


http://[ホスト名]/[アプリケーション名]/test.phpにアクセスすると、行えるテストが表示される。
app/Test/Case/[フォルダ名]以下にある末尾にTest.phpが付いたファイルの一覧。
最初はController/Model/Viewの3つしかないが、自分で適当なフォルダを追加することもできる。

今回作成したHogeテストへのリンクがModel/Hogeという風に表示されているはず。
カチッと押せばテスト開始。バーの色でテストの成否を確認できる。緑が成功。赤が失敗。
失敗していたら失敗箇所を修正して緑を目指す。

おまけ:XDebugを導入する(XAMPP)


XDebugをインストールすると、Analyze Code Coverageという機能を使えるようになる。
今回のテストでコードをどれくらい使用したのか色付きで表示してくれる。

XAMPPの最新版には最初から入っており、php.iniのコメントアウトを数行外せばいい。
(多分)[XDebug]セクションが存在すると思うので、そこのコメントアウトを外してやろう。
とりあえず全部外しちゃったけど、特に問題起こってないので多分大丈夫。

apacheを再起動してphpinfoの中にxdebugの項目があればオーケー。

2013年12月10日火曜日

CakePHP2.x ヘルパーでコンポーネントを使用する

MVC的に正しいのかどうかは置いておいて、ヘルパーでコンポーネントを無理やり使った。
他のページを見ると、自分でnewして使用するのが一般的(?)みたいだけど、
正直コントローラがすでに生成しているオブジェクトをわざわざnewするのもどうかと思ったので、
ClassRegistryに格納した。

コントローラ側の処理
ClassRegistryにコントローラが持っているHogeコンポーネントを追加。

/*---------------------------------------------------------------------------*/
ClassRegistry::addObject( "Hoge", $this->Hoge );
/*---------------------------------------------------------------------------*/

ヘルパー側の処理
ClassRegistryからコンポーネントを取得して使用する。

/*---------------------------------------------------------------------------*/
$hogeComponent = ClassRegistry::getObject( "Hoge" );
$hogeComponent->hogeru();
/*---------------------------------------------------------------------------*/

処理として正しいのかどうかは置いておいて、これでヘルパーからコンポーネントが使える。

2013年11月5日火曜日

CakePHP2.x フォルダのファイルを全て削除する

とりあえずwebroot以下にあるhogeフォルダのテキストファイルを削除する。

/*---------------------------------------------------------------------------*/
    App::uses( "Folder", "Utility" ); 
$dir = new Folder( WWW_ROOT."hoge".DS );
$files = $dir->find( '.*\.txt' );
foreach( $files as $file ) {
$file = new File( $dir->pwd().DS.$file );
$file->delete();
}
/*---------------------------------------------------------------------------*/

webroot以下のファイルは基本リソースになるので
プログラムで消す機会はそうそうないとは思うけども。

2013年11月1日金曜日

cakephp2.x 他のコントローラのビューを使用する

ひとつのコントローラから別のコントローラのビューを使用したいときはこうする。

/*---------------------------------------------------------------------------*/
    $this->render( "../controller/view" );
/*---------------------------------------------------------------------------*/

コントローラごとに機能を分けるのが理想であって、極力使わないほうがいいんだろうけど。

2013年10月1日火曜日

CakePHP ページネータの動作をモデルで定義する

正直、ページネータがモデルでなくコントローラにあるのってなんかおかしくない?
あくまでモデルのデータをどうこうしているのであって、コントローラの領分でないような。
と思いつつ使いますが。

通常通りでは普通にモデルからfindを呼んでくるだけのところを、モデルで
以下のメソッドを定義してやれば、自分でデータの取得の動作を定義することができる。

/*---------------------------------------------------------------------------*/

public function paginate( $conditions, $fields, $order, $limit, $page, $recursive, $extra )
public function paginateCount($conditions, $recursive, $extra)

/*---------------------------------------------------------------------------*/

それぞれデータの取得と全体数を取得するときに使うメソッド。
引数の中身はCakePHPを使っているなら名前で大体分かると思う。

2013年9月13日金曜日

CakePHP PageSpeedをChromeで使ってみた

よろしくないなあ、と思いつつサイトの高速化という問題から目を背け続けてきたけど、
いい加減やばいんでない? ということでサイト高速化についてちょこちょこ調べてみた。

参考サイト
表示が速過ぎても、誰も文句は言いません
ついに出た!Chrome版「Page Speed」の使い方

しかし、こうやって情報処理的な調べ物をするたびに、
どれもこれも最低限の専門知識を前提として語ってくるのは困る。
正直、なんちゃってエンジニアな自分にはきついなあ、と思うこともしょっちゅう。

PageSpeed


タイトルにもあるので一番に持ってきた。表示速度を調べた上で問題点も調べてくれるのだとか。
さっそくインストールして実行! なんか色々出てきました。
サイトとは色々違うけどバージョン変わったんかな? それとも別バージョン入れた?
なんにせよなにがなにを示しているのかはわかるのでオーケー。
色で判断で間違ってないよね?

すぐに対応できそうなのとして、色々画像が凝り固まっている部分をエレメントキャッシュ!
...相変わらずそこで怒られるぞい。CakePHP独自のキャッシュには対応してないのかな?
圧縮とかも試してみよう。

JavaScriptを圧縮しよう!


mod_deflateモジュールなるものが必要とな?
うちのxamppには最初から入っていたみたいなのでそのままゴー。
.htcaccessを弄る。以下の一文を追加。

AddOutputFilterByType DEFLATE text/html text/css application/x-javascript

エラー出たー!500エラー。
どうやらCakePHPはヘルパーなりコンポーネントなりを使用してjavascriptを圧縮するのが
正しいよう。この結論に自信はありません。

ちょいと調べて出てきたの。

JSMin Helperが良さそうかな。そのままJavaScript Helperのように使えるとか。
というわけでページからソースをコピペし、jsmin.phpもいただき実行してみた。
オーマイガ。めっさ怒られました。もしかして2.x系には対応していらっしゃらない...?
ソースコードを弄り弄りエラーをひとつずつつぶしていく。
で、なんとか動いた。afterRenderを全部コメントアウトしてみたりしたけど動いた。
PageSpeedにも怒られなくなってちょっとした達成感。
でも大して実行時間が変わっていないような...。
あれ? なんかミスった? それとももっと大きいファイルじゃないと目に見える変化がないのか。
要検証。

2013年9月12日木曜日

CakePHP2.x SmartyViewをいじったメモ

大体アプリケーション部分もできてきたのでぼちぼち負荷テストをはじめたんだけど、
どうしてもスループットが出ない。
どこが原因ぞ? と思い調べてみたらば、RenderringViewが笑える重さを誇っていた。700msて。
で、さらに調べるとSmartyが原因だった。
どこから取ってきたかを忘れたSmartyViewクラスをいじったので、その辺のメモ。

コンパイルを1回こっきりにする

Smartyクラスのcompile_checkにfalseを指定する。
結論から言えばこれだけであっさり早くなったんだけれども、ここにたどり着くまでが大変だった。
最初にこのテストをしたときにソースをさっぱり見ずにやったがためにその後に書いてある
clearCompiledTemplate()の記述に気づかなかった。
こいつのせいでコンパイルチェックを無効にしていても
毎回コンパイルファイルが削除されていたのだ。
そりゃ、そもそもチェックする対象がいなければSmartyもコンパイルせざるをえんでしょう。
こんなくだらないことで1日以上悩んだ。悔しいからメモ。

表示が変わらないページにはページキャッシュを利用しよう

基本的にほとんどのページが動的にデータが入れ替わるので結局見送りになっけんだけども、
せっかく調べたので忘れないうちに。鉄は熱いうちに打て。
ページそのものをキャッシュとしてとっておいてそのページをベーと吐き出してしまう。
ただ、CakePHPを使っていると、ちゃんとキャッシュIDを指定してやらないとどのページも
同じだと判断してくれちゃう。どのコントローラ行っても最初に表示したページのままだぞう。
CakePHPはアドレスでページを判別できるのでキャッシュIDにも同じように指定してやればいい。

$this->cacheid = $this->params->url;

これでオーケー。ただ、クエリが違うだけのページはやっぱり同じページに...。
本格的に利用するつもりならもうちょい調べる必要がありますかも。

2013年8月30日金曜日

CakePHP セッションにデータベースを利用する

複数サーバーを利用するというので、通常のキャッシュを使用すると
お互いに参照先が違うという問題が発生。
CakePHP はデフォルトでデータベースを使ったセッションが提供されている
そうなので使ってみた。

まずは以下のクエリをデータベースで発行。

/*---------------------------------------------------------------------------*/

CREATE TABLE IF NOT EXISTS `cake_sessions` (
    `id` varchar(255) NOT NULL DEFAULT '',
    `data` text NOT NULL,
    `expires` int(11) DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

/*---------------------------------------------------------------------------*/

次に core.php を編集。Session の設定が書いてあるところ。

/*---------------------------------------------------------------------------*/

Configure::write('Session', array(
    'defaults' => 'database',
));

/*---------------------------------------------------------------------------*/

データベースを使用するための設定はこれだけで十分です。
さっそくテスト。

/*---------------------------------------------------------------------------*/
Error: Table app_models for model AppModel was not found in datasource default.
/*---------------------------------------------------------------------------*/

エラー出たよ。なぜか app_models テーブルがないと怒られている。
試しに useTable を書き換えてみたら別のエラーで怒られた。
なので、使用するモデルを自分で指定する。

core.php に追加。

/*---------------------------------------------------------------------------*/

Configure::write('Session', array(
    'defaults' => 'database',
'handler' => array(
'model' => 'CakeSessions'
)
));

/*---------------------------------------------------------------------------*/

CakeSessions というテーブルを作り、そのモデルを呼び出すように変更。
エラーが出ることはなく、セッションもしっかり機能した。

2013年8月20日火曜日

CakePHP saveの罠

MySQL側でtinyintかつ長さを1に設定しているとCakePHPが勝手に論理値と判断する?

saveメソッドを呼び出すと0は0でいいんだけど、1以上の値はなにを渡しても必ず1になる。
だいぶ前に気づいていてMySQL側のtinyintを全部長さ3にしといたつもりだったんだけど
漏れがあってしばらく悩んだ。

2013年8月6日火曜日

CakePHP2.x viewを指定する

$this->render('hoge_view');

CakePHP2.x SplFileInfo::openFileエラー

Warning:
SplFileInfo::openFile
(/www/app/tmp/cache/persistent/myapp_cake_core_cake_console_):
failed to open stream:
Permission denied in /www/lib/Cake/Cache/Engine/FileEngine.php on line 314

とかいうエラーが出るようになった。
ファイルの所有者とアクセスユーザーが違うことで起きるエラーらしい。
umaskを設定すればいいですよ、とのことだが、まずumaskってなんですか?

調べた。
ファイル作成時に、利用できるパーミッションを指定するものだそうな。

アクセスユーザーからもファイルを取得できるようにcore.phpを編集する。

    Cache::config('_cake_core_', array(
        'engine' => $engine,
        'prefix' => $prefix . 'cake_core_',
        'path' => CACHE . 'persistent' . DS,
        'serialize' => ($engine === 'File'),
        'duration' => $duration,
        'mask' => 0666,
    ));
    Cache::config('_cake_model_', array(
        'engine' => $engine,
        'prefix' => $prefix . 'cake_model_',
        'path' => CACHE . 'models' . DS,
        'serialize' => ($engine === 'File'),
        'duration' => $duration,
        'mask' => 0666,
    ));

警告文が出なくなった。

2013年8月5日月曜日

CakePHP2.x findの戻り値

しょっちゅう忘れるのでメモ。

SQL文にエラーがあれば例外を投げてくれるからそのときは気にしなくても
いいんだけど、SQL文がエラーを起こさない場合は配列が返ってくる。
結果が空だろうと何だろうと配列が返ってくる。

findでデータが取得できなければエラーという処理を作りたければ、

    $data = $this->Model->find( "all" );
    if( count( $data ) === 0 ) {}

という風にカウントで配列の個数を取るようにしよう。
findByを使ったときも同じ。

2013年8月1日木曜日

CakePHP2.x Shellを使う(実行編)

せっかくShellを使ってもテストをしないのはよくないということで(当たり前)
コマンドプロンプトなんてほとんど使ったことないけどネットとお友達になりつつ
やってみる。

まずはコマンドプロンプトを開き環境変数のパスを通す。
(xamppはc直下)

    c:\xampp\php>SET PATH=%PATH%;%CD%
    c:\xampp\htcdocs\hoge\app\Console>SET PATH=%PATH%;%CD%

多分現在のディレクトリにパスを通しているんでしょう。きっと。
CDってあるし。
そしてディレクトリをappまで移動して、Shellを実行。

    C:\xampp\htdocs\hoge\app>cake Test

怒られた。細かいメッセージ文は忘れたけど、PHPUnitとかいうのがないとか。
再びネットの海に潜り検索検索。

xamppにPHPUnitをインストールするためにはpearとかいうのを使うらしい。
PEAR(PHP Extension and Application Repository)の略でPHPで利用できる
ライブラリを提供しているサービス。

xampp(というよりもPHP5?)には最初からインストールされているらしいので
アップデートしてからPHPUnitをインストール!

    pear update
    pear install phpunit/PHPUnit

はい怒られましたよ。php_compatがないらしい。これは普通にインストールできそう。

    pear install php_compat

そして再びのインストール!

またしても怒られた。こんどはPHP_Invokerとやらが問題を起こしているらしい。
ご丁寧に警告文に-alldepsオプションを指定しておくれと書いてあったので
オプションを指定してインストール!

    pear install --alldeps phpunit/PHPUnit

今度は成功メッセージが表示されたぞ。ということで早速ちゃんとインストール
されているかの確認もかねてバージョンチェック

    phpunit --version
    Warning: require_once(PHPUnit/Framework/MockObject/Autoload.php)
    fatal error

ほ? PHPUnit/Framework/MockObjectがないとな?
モニターの前で試行錯誤するも答えが見つからず知ってそうな人に泣きつく。
んで、

    pear install --alldeps --force phpunit/phpunit
    pear install --force phpunit/PHPUnit_MockObject

この二つのコマンドを順番に実行したらちゃんとインストールされた。
やったー。ようやくテスト環境が整ったぞ。
 
    C:\xampp\htdocs\hoge\app>cake Test

    Welcome to CakePHP v2.3.5 Console
    ---------------------------------------------------------------
    App : app
    Path: C:\xampp\htdocs\hoge\app\
    ---------------------------------------------------------------
    test message

でけたー!

2013年7月29日月曜日

CakePHP2.x モデルのバインドパラメータ

いちいち調べるのも面倒なので
自分がよく使う使い方のものだけまとめておく

$hasOne = array(
"ModelName" => array(
"type" => "inner",
"className" => "ModelName",
"foreignKey" => false,
"conditions" => array(),
),
);
$model->bindModel( array( "hasOne" => $hasOne ) );

こうして毎回動的に生成するのは果たしてどうなのか。
とはいえ、ページごとにテーブルに求めたいデータというのは異なるものになりがちなので
こうしたほうがいい気がする。

foreignKey を false に指定すると conditions で指定した条件でテーブルが結合される。
最後に、モデルにバインドされているアソシエーションを解除する方法。

$model->unbindModel( array( "hasOne" => array_keys( $model->hasOne ) ) );

アソシエーションの種類により hasOne のところは変化する。

CakePHP2.x シェルを使う

CakePHP2.x系でシェルを使うには

/app/Console/Command/TestShell.php

<?
class TestShell extends AppShell
{
        public function main()
  {
                CakeLog::write( "debug", "test" );
  }
}
?>

テストなので適当にログを吐き出すだけ。
ほとんどコントローラっぽく使えるようだ。

<?
// ※未テスト
class TestShell extends AppShell
{
        public $uses = array( "User" );

public function main()
{
                $this->User->find( "all" );
}
}
?>

あとはこいつをシェルスクリプトから呼び出せばいい。
メソッド名がmainの場合は引数で渡さなくても勝手に解決してくれるみたい。

        $ /app/Console/cake Test -app

さて問題は、シェルスクリプトもそもそもあまりコンソールにも触らない自分は
cronどころかそもそもシェルスクリプトがどういったものなのかすら知らないということだ。

なのであくまでCakePHPのシェルクラスの作り方ページ

参考にしたサイト
http://blog.xao.jp/blog/cakephp/cakephp-2-0-%E3%81%A7-cron-%E3%82%92%E4%BD%BF%E3%81%86/