2014年6月30日月曜日

[CakPHP]ControlloerでsetするとDebugKitのVariablesタブで捕捉されないことがある

※version2.4.9の話

ControllerのCallback関数には、

Controller::beforeFilter()
Controller::beforeRender()
Controller::afterFilter

があるけど、beforeRenderとafterFilterでController::setしてもDebugKitのVariablesタグで捕捉されることはない。afterFilterでsetしてもViewで使えないので全く意味はないが。
beforeRenderでsetしたいケースはあると思う。たとえば、Authの情報をどのページでもsetしているが、logout画面ではする必要がない(したくない)ので、その場合はbeforeRenderにset処理を入れておく。すると、beforeRender以前にlogoutのロジックが終わっているので、Auth情報はセッションからなくなっているので、setせずに済む。

これをbeforeFilterでsetしていると、logout処理の前でセッションからAuth情報がある状態なのでsetされてしまい、View画面で使われてしまったりする。「ログアウトしました。」画面なのに、「マイページ」とか表示されてたりする。

話はそれたけど、beforeRenderでController::setしてもDebugKitのVariablesからは見えないけど、ViewではきちんとRenderされます。


2014年6月7日土曜日

[CakePHP]CakeDC/migrationsの微妙な仕様

ここによるとModelが存在しないテーブルのmigrationは以下のように-fをつけてあげるとできる。これをつけないと、差分として検知されない。
ここでは例えば、Aというテーブルを作成した場合とする。


cake Migrations.migration generate -f

このコマンドから始まるプロンプトを進めて行くと、以下のように

Do you want update the schema.php file? (y/n)

schema.phpを更新するか聞かれて、自分はいつも通り、yを選択する。

で、次にDB定義変更をしてmigrationをする機会が訪れたとする。

今度は普通にModelが存在するテーブルBだったので、以下のように-fはつけない。

cake Migrations.migration generate

そうすると何が起こるかというと、①で作成したテーブルAをdropするmigrationが作成されてしまう。

なぜかというと、②でも-fが有効になっているらしく、ここで生成されるschema.phpにはテーブルAが入ってしまう。migrationの仕組みは現実のDB定義とschema.phpを比較して差分をmigrationファイルとする。なので、③で-fをつけないのからモデルのないテーブルは検知されないため、schema.phpにあるAテーブルは、現実のDBには存在しないよ、となり、じゃあ削除するマイグレーションファイル作りますね、と判断してしまうのだ。

イケてないですね。

なので、 -fをつける場合は②はnを選択したほうがよさそうですね。





[SublimeText] .sublime-projectの属性はシングルクオテーションじゃなくてダブルクオテーションじゃなきゃだめ。

※Sublime Text3の話
"xdebug":
{
  "max_children": 128,
  "max_depth": 5,
  "max_data": 512,
  "debug_layout":
    [
      {
        'rows': [0.0, 1.0],
        'cols': [0.0, 0.6180212590826522, 1.0],
        'cells': [[0, 0, 1, 1], [1, 0, 2, 1]]
      }
    ]
}

こんな感じでシングルクオテーション使ってたら、

Error trying to parse project: Expected value in

というエラーが発生した。なのでダブルクオテーションにしたら直った。

2014年6月6日金曜日

[CakePHP]find()のオプションのpageはlimitと併用しないと恐ろしい事に。。。

※CakePHP2.4.9のお話。
$page = 1;
do{
    $ids = $this->find('list',array(
        'page' => $page,
        'fields' => array('user_id'),
        'conditions' => //ある条件
    ));
    //ある処理
    $page++;
}while (!empty($ids));

こんな感じで、特定の条件全てのレコードに対してある処理をするバッチを作っていて、1pageあたりの数はデフォルト値を当然使ってくれるだろうと思っていたんだけど、これを実行したら、なかなか処理終わらずおかしいなと思ってたら、あるテーブルにありえない数のレコードがインサートされてる。。。無限ループ状態になっていました。あわてて、ApacheとMySQLをシャットダウンして、止めた。

というわけで、デバッグしたら、limitを明示的に定義していないと、実際SQLで使われるoffsetとlimitに値が入らないってことがわかった。

model.php 2942行目
if ($query['page'] > 1 && !empty($query['limit'])) {
    $query['offset'] = ($query['page'] - 1) * $query['limit'];
}
なので、以下のようにlimitを明示的に指定して直った。恐ろしや〜。
$page = 1;
do{
    $ids = $this->find('list',array(
        'page' => $page,
        'limit' => 20,
        'fields' => array('user_id'),
        'conditions' => //ある条件
    ));
    //ある処理
    $page++;
}while (!empty($ids));

[Composer]installer-pathsの優先順位について

Composerでここで説明されているように、packageごとにinstallされるpathをカスタマイズできるんだけど、なかなか反映されなくて困った。

"extra": {
    "installer-paths": {
       "plugins/{$name}/": ["type:cakephp-plugin"],
       "app/Plugin/{$name}/": ["somevendor/some-package"]
    }
}



こんな感じだったんだけど、上記のsome-package(もちろん仮名ね)っていうpluginもcakephp-pluginなんだけど、上にあるcakephp-plugin用のpathが先に適用されてしまったからでした。

なので、以下みたいにしたら適用されました。

"extra": {
    "installer-paths": {
         "app/Plugin/{$name}/": ["somevendor/some-package"],
         "plugins/{$name}/": ["type:cakephp-plugin"]
    }
}

2014年6月5日木曜日

[CakePHP]test.phpのCode coverageが表示されない件

テストケースのファイル名をPost01Test.phpみたいに、番号をつけたらcode coverageが表示されなくなった。テスト自体は正常に実行することができるのに。
なので、番号をつけるのをやめてPostTest.phpに戻した。

2014年6月4日水曜日

[CakePHP]find('list')はDISTINCT使えないのね。

$this->Comment->find('list',array(
  fields' => array('DISTINCT user_id'),
  'conditions' => $conditions,
));


こんな感じでやったら、以下のようなエラーが。

PDOEXCEPTION
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DISTINCT `Comment. user_id` FROM `test`.`comments` AS `Comment` WHERE 1 = 1 ' at line 1



このサイトによると、DISTINCTってSELECTの直後に来ないといけないいたい。でもCakePHPのfind('list')ってデフォルトでは、SELECTの直後でIDを指定しているので、DISTINCTがその後になってしまうんですよね。

なので、group byを使うといいみたい。

$this->Comment->find('list',array(
  fields' => array('user_id'),
  'conditions' => $conditions,
  'gruop' => 'user_id'
));

※Group Byの豆知識
 デフォルトだとGROUP BYで指定されたカラムの昇順になる。いきなり順番変わってびっくりした。ORDER BY を使って任意のカラムの昇順、降順を指定できる。