CakePHPを1.3でやってみての色々をメモ

ネット上で散見する情報などは1.2とか1.1だったりするので、公式のAPIソースコードに直接当たった方がいい感じ。
時間短縮の為にと思って、CakaPHPポケットリファレンスを買ったが、1.3には対応していないので、今回はそれほど役に立たなかった。


以下、箇条書き。


Modelを削除するdelというメソッドがあったが、なくなってdeleteに変更。


findAll()はなくなった。find('all');

echo $this-Form->textarea('Task.content',array(.....));

第一引数はフィールドネームのstring。1.1までは、$this->Html->textarea 'Task/content'
1.2では'Task.content'。
また、'Task.'を省略可能。この場合は、$this->dataが入っていることが前提。
その場合、viewに出力時、data[Task][content]と出力してくれる。


View::renderElementは1.3ではなくなってView::elementになっていた。


フォームの入力要素を取得するメソッド。
$this->Html->tagValue()はなくなった。
1.3では
$this->Html->value('name');
を使う。
確認画面などで使う。
なお、なぜこのメソッドが必要になるかというと、ビューには配列で変数が渡ってきているため。
Railsの場合はモデルのエンティティを使うと思うので、使わない。


jsHelperというものが1.3から新たに用意された。
これで標準でもjQueryが使える。
コントローラーにて。

var $components = array('RequestHandler');
var $helpers = array('Util', 'Js' => array('Jquery'));


jsHelperを使用する場合、下記メソッドをビューで読んでおかないと動かなくてはまる。

<?php echo $this->Js->writeBuffer(); ?>

あるいは、$js->link()や、$js->submit()など、その場にリンクタグやボタンを表示するメソッドの場合は、

echo $js->link('LINK',リンクURL,array('update'=>'#update-div','buffer'=>false));

のように、オプションでバッファを使用するかどうかを設定できる。falseにしたらバッファは使用しないで、その場にスクリプトも出力される。
あとでまとめてwriteBufferする必要は無くなる。

JsHelplerを使うとかえって面倒だったので、結局ヘルパーを殆ど使用せず、JavaScriptを直接書いた。
JavaScriptわかっているならその方が早い。変なところで時間とられないし。


paginationのajax
(jsHelperを使用する場合)

//controllerにて
  var $components = array('RequestHandler');
  var $helpers = array('Js' => array('Jquery'));

layoutまたはviewにて
Html->script('jquery-1.4.2.min'); ?>

viewにて

<?php$this->Paginator->
        options(array(
            'update' => '#update',
            'evalScripts' => true));
?>

viewの先頭にでも

ajaxで表示するエレメントid

      <div id="update">
    <div class="paging">   
<?php echo $this->Paginator->next(__('next', true) . ' >>', array('rel'=>'next'), null, array('class' => 'disabled')); ?>
</div>
      </div>

末尾にでも

    <?php    echo $this->Js->writeBuffer();
    ?>

</body>

$this-Form->input(..)で自動判別処理してtextやselectが使用されている。
ex.Category hasmany Food
のfoodのviewにて $this->Form->input('category_id');としていると、selectが生成されている。
なお、前提として、categoriesなarrayがControllerで用意されていなければいけない。


cakephpにおいて、命名規則の規約から外れるコントローラー名を使用する場合。
モデルを使用しない場合は
var $uses = null;
モデルを使用する場合は
var $uses =array('Hoge','Fuga');
とする。


任意のレイアウトを使用する場合は
app/views/layouts/下にレイアウトファイルを作成する。
ex. app/views/layouts/hoge.ctp
コントローラー側ではvar $layout="hoge"と指定する。
Railsと違って明示的にコントローラー側で指定する必要がある。


複数モデルへのfindでのconditionでの条件指定に注意。
例えばDBのテーブル名が親がcategoriesで子供がfoodsの場合。
modelはCategoryでFoodである。
コントローラーで例えばFoodを主体として取ってくるときに仮に親のカラムを条件とした場合
以下のようになる。

$this->Food->find('all',array('conditions'=>array(Category.name'=>$name)))

categories.nameではないので注意。
これはselect文発行時に....from foods as Food LEFT JOIN categories AS `Category`等の用に
モデルにあわせて別名をつけてられるから。



同じフィールド名を使って複数のフィールドを定義する場合、次のような方法で配列を生成すると、 saveAll() で一度に保存することができる。

  <?php
   echo$this->Form->input('Modelname.0.fieldname');
   echo$this->Form->input('Modelname.1.fieldname');
   ?>
  //result 
  <input type="text" id="Modelname0Fieldname" name="data[Modelname][0][fieldname]">
  <input type="text" id="Modelname1Fieldname" name="data[Modelname][1][fieldname]">

実際にやる場合は以下のような感じになる。

<?php echo $this->Form->radio('Quantity.'.$food['Food']['id'].'.id',$radioValues,array('legend'=>false)); ?>

cakephpでのカンターキャッシュ
Category Entry
categories entries

categoriesにentry_countカラムを作成
Entryモデルに以下のように記述

var $belongsTo = array(
  'Category' => array('counterCache' =>true)
);

cake consoleでは変数を使ったりという風に完全にインタラクティブに操作できないっぽい?
で、saveで軽くはまった。
通常のsave

$this->User->save(array("User"=>array("name"=>"hoge")));

cake console上

User->save(array("name"=>"hoge"));

実際のメソッドとコンソール上では引数の指定の仕方が違う。


DBのカラムがdatetimeのパラメータとして2010-08-03とか渡してもちゃんと保存されてた。
selectboxだとdatetime=>array('year'=>'2010','month'=>'08','day'=>'03')とかなってるが、
裏でよしなに処理されていると思うが、コードは追いかけなかった。


「Submitボタンを押した」や「リンクをクリックした」などの、イベント本来の動作を抑制するアレ。

echo $this->Form->create('Task',array('default'=>false)); 

'default'=>false
で、event.returnValue=false;がセットされる。


cakephpRailsクローンと聞いていたけど、結構違かった。
RubyPHPの文化の違いという感じで興味深かった。


cakephpのモデルはマッピングされたオブジェクトモデルではない。

 $newtask= new Task(); 
 $newtask->id=null; 
 $this->data['Task']['content']=$content; 
 $newtask->save($this->data); 
  //下で$this->setに$newtaskを渡すのはペケ。
 //read()してやらないと駄目。
  $this->set('task',$newtask->read()); 

上記でnewtaskは各エンティティーをもっているようなデータではなく、idを持ったモデル操作のインスタンスモデル。
イメージとしては、むしろ、スタティックメソッド(クラスメソッド)を扱うインスタンスモデル。Rails的にいえば、Task.xxxxxといったクラスメソッド的。
よって、new Taskとしても新しいレコードをnewするRailsとは異なる。
$task= $newtask->read();等としても、
$taskは配列が返ってきているため、$taskに対しては、後はモデル的な操作はできない。
上記のようにcakephpのモデルはdaoという感じなので、RailsのARっぽい物を想定していると相当戸惑う。
もう一例。
$this->Task->create();
このメソッドも新規作成対象のモデルを用意している訳ではない。
モデルが保持しているidをfalseに、保存するdata配列を空に、validationエラーの配列を空にといった処理を行っている。



ログデバッグ。ログを保存。

$this->log($birthdate,LOG_DEBUG);


cakephpのscaffoldで生成されるaddは、Railsでいうと、newとcreateが一緒になっている。
これにconfirmをつけようとすると、ごちゃっとしがちなので、分離しておいた方がいいかも。


確認画面を用意した上でのvalidateでは、render前に親モデルのセレクトボックス用のデータなどしっかり用意しておく。

        if (!$this->User->validates()) {
          $doctors = $this->User->Doctor->find('list');
          $this->set(compact('doctors'));
          $this->render();
        } else {...........

redirectやurl等の関数でのarray()オプションにはまりがち。

$this->Html->link('リンク',array('controller'=>'users','action'=>'edit',$user['User']['id']);

こんなかんじ。
id部分だけなぜか連想配列ではなく、直接渡す。リファレンスで見るとパラメーターがmixedとなっているやつ。
mixedとなっているやつは、何を渡せばいいのかわかりづらいのでソースコード見ないとわからない事も結構ある。


imageとlinkを使う方法。
1.3ではimageタグだけで出来るように変更になっているもよう

$this->Html->image('item/image.jpg',array('alt'=>'image','url'=>array('action'=>'actin_method')));

こんな感じ。


ある PHP 変数が特定の クラス のオブジェクトのインスタンスであるかどうかを調べるにはinstanceofを使用する*1

*1:php5から