cakePHPでファイルアップロード機能を自前で実装する

2008/03/27 | cakePHP

「自前で実装する」といってもcakeForgeのスクリプトの中で、いい感じなのを見つけたのでそれを流用するだけなのだが・・・。

以前アップロードを簡単に実現するためのコンポーネントのことを記事に書いたけど、あれはあれで複雑で自分好みにするのは少し面倒だった。であれば「コンポーネントで実現するよりもべた書きしたほうがいいかもしれない」と思い、どういうふうに記述すればいいのか探してみた。そしたらいいお手本があった。

Cheesecake Photoblog

cakeForgeのフォトアルバムを作成するためのスクリプトだ。この中のphotos_controller.php内の記述が参考になる(addの記述の部分)。

ファイルのアップロードについては、まずこんな具合に取り扱っている(その他のフォーム要素の取り扱いと同じ)。
$this->params[‘data’][‘Photo’]

で、ファイル($_FILES)の各変数を処理しないといけないわけだが、それはこんな具合にして対応できるようだ。
$this->params[‘data’][‘Photo’][‘file’]

最終的にコントローラ内では以下の一行が保存処理になっている。
$this->Photo->savePhoto($this->params[‘data’][‘Photo’][‘file’], $thumbSize, $thumbType)

つまりコントローラから、モデル(この場合はPhoto)に対して「保存処理を実行しなさい」という命令を下し、後はモデルにおまかせしてしまっているのだ。本来データの取り扱いはモデルのお仕事なのだから、これはこれで記述の仕方がスマートなように感じる。次にモデル(photo.php)のほうを見てみる。

function savePhoto($fileData,$thumbSize,$thumbType) {
  vendor(‘ccImageResize.class’);
  if (move_uploaded_file($fileData[‘tmp_name’], WWW_ROOT . “img/photos/” . $fileData[‘name’])) {
    $resizer = new ccImageResize;
    if ($resizer->resizeImage(WWW_ROOT . “img/photos/” . $fileData[‘name’], WWW_ROOT . “img/thumbnails/” . $fileData[‘name’],$thumbSize,$thumbType)) {
      return true;
    } else {
      // TODO: Clean up and set error message
      return false;
    }
  } else {
    // TODO: Set error message if move_uploaded_file fails
    return false;
  }
}

別途用意してある画像サイズ変更のためのライブラリが使用されてはいるが、直接関係のあるところは一目瞭然「move_uploaded_file」な部分だ。案外「生」なやり方で書いてある。

でもこのやり方、すごくスマートな気がするので、現在作成中のアプリはこれでいくことにする。

モデルに関係なくSQLを発行する

2008/03/26 | cakePHP

cakePHPではモデル(データベースのテーブル)とコントローラが密接に関連している。だからコントローラでデータベース内のデータを取得する際、通常は(あらかじめどのテーブルを使うか決められた)モデルを介してデータを取得するため、モデルで指定されたデータ以外を取得しようとするとエラーになったりすることがある(単にやり方がまずいだけなのだが)。
こういうときはデータベースに直接SQLを投げるのが手っ取り早い。cakePHPらしからぬ記述にはなってしまうが、個人的にはこれで十分。ノーマルな処理はcakePHPのノーマル処理に従い、一部の例外は直接SQLを発行することで進めることにした。
データベースに直接SQLを投げる方法は以下の記述を使用する。

$db=& ConnectionManager::getDataSource(‘default’);
$result=$db->query($sql);

これ、多分第二引数でキャッシュするか否かをbool値で与えるんだろうと思う(調べるの面倒なのでこのまま続行)。

SQLを書かなくてもプログラムが書けるところがcakePHPのいいところなのだが、直接SQLを書くことができるようになることで、より幅広く使えるようになるはずだ。

直接SQLを発行してみる

2008/03/25 | cakePHP

複雑なSQLを発行したい。
そう考えると、cakePHPで持ってる機能を使うよりも直接SQLを発行したほうが早そうだ。本当はcakePHPのお作法どおりにやりたいけれど、スピード第一。まずは動かしたい。cakePHPで直接SQLを発行する方法はこんな感じ。

$this->Site->query(‘SELECT * FROM sites as Site’,false)

モデルオブジェクトにqueryメソッドでSQLを発行することができる。queryメソッドには第二引数を渡すことができる。このメソッドはデフォルトで第二引数がtrueで渡されているのだが、この値によってSQLの結果をキャッシュするかどうかを決定できるらしい。本番時はtrueでいいのだが、開発時はfalseにして、結果をキャッシュしないほうが都合がいい。

ん〜。難しい。

paginate()をカスタマイズしてみる

2008/03/24 | cakePHP

とりあえず想像だけでpaginate()を試してみることにする。

paginate($object = null, $scope = array(), $whitelist = array())

引数は3つある。しかしまだ意味がよくわからない。スクリプトを少し読んでみた限りでは・・・。

$object    //モデル名?
$scope     //where句とかorder by句?
$whitelist //わかんない

くらいは理解できた。モデル名は配列でも渡せるような感じ。ただしデフォルトがnullということは、nullで渡すと元々コントローラで指定されているモデルが渡されるのだろう(多分)。
こんな風に記述してみた。

//$this->set(‘sites’, $this->paginate());
$this->set(‘sites’, $this->paginate(NULL,array(“Site.url LIKE ‘http%’ ORDER BY Site.title DESC”)));

いちおうこれで正しく動いているように見える。しかしイマイチ美しい書き方ではないように見える。これもおいおい調べていくことにする。

createdとmodified

2008/03/23 | cakePHP

cakePHPではcreatedとmodified(またはupdated)というカラムをdatetime型で用意しておくと、データの挿入・更新時に自動で値を設定してくれる。確かバージョン1.1まではそうだった。しかし1.1と同じように1.2で設定しても値が設定されない。なぜだ!。

どうもテーブルの設定が厳密になったらしい。1.1では当該カラム名でdatetime型でありさえすればよかったのだが、1.2では以下のように設定しなくてはいけない。

カラム名:データ挿入日時はcreated、修正日時はmodifiedかupdated(1.1と同じ)
型:datetime(1.1と同じ)
NULL許可:許可(1.1では関係なかった)
デフォルト値:[空文字](1.1では関係なかった)

こんな些細なことも変わっているのかと思うと、この先が思いやられる。


守谷市(まちの情報ポータル) 無料アンケートレンタルjpForm.net