CakePHP1.3.6:Media Plugin1.3RCに挫折して、ファイルアップロードを自作(その1)
ファイルアップロードをやってみようと思い、名高いMedia Pluginを試して、半日がかりでやってみたが、結局挫折。
サイトを見て、おやおやと思ったのが、0.x系から飛んで、1.3RCが出てること。こういうのは経験的に危ない。YUI、Strutsなんかもそうですね。アーキテクチャが変わっちゃって、ググって開発できない可能性が高い。
半日がかりでいじってみたが、mediumヘルパーがmediaヘルパーに変わっていて表示系がうまくいかない。実力的にソースを直すところまでいけないので、挫折した。
PeclのImageMagicを入れるのも、レンタルサーバーで動かすときの障害になりそうだし。
でも、悪いことばかりじゃなく、Media Pluginを触って目からうろこが落ちた。Media PluginにはAttachmentというスキームが同梱されているが、その名の通り、「なんらかのコンテキスト(ドキュメント)の添付としてMadiaを添付する」という考え方になっている。
裏を返せば、「mediaにはなんらかのコンテキストが付随している」ということ。タイトルとかメモとか。
そういうことで、同じ考え方でjpg/png/gifをアップロードして、リサイズするコードを自作した。簡単なコードなのでGDだけでうごく。だが、DRYじゃない。
テーブル
上のことを実現する場合、
- テーブルに属性(テキスト)とmedia(バイナリ)を持たせてしまう。
- テーブルに属性(テキスト)とmediaのメタ情報(在り処、サイズなど)を持たせて、mediaはファイルシステムに持たせる。
がある。GAE/Jを評価した際には(GAEの制約もあって)上の方法をとった。これだととてもシンプルになるが、下の方法が一般的なのかなとも思う。
これらの方法は、属性に対してmediaが1つの場合を想定していて、実際はこれでいいのだと思うが、Media Pluginでは複数のAttachmentが持てるようになっている。
- 属性用とmedia用の2つのテーブルを用意して、media用のテーブルにはメタ情報を持たせる。mediaはファイルシステムに格納する。
今回は、この方法をとることにした。属性用のテーブルと、メタ情報はhasManyの関係になるので、その実験にもなるし。
属性用テーブル
mediaの属性を持たせるテーブルのDDLは以下。
CREATE TABLE IF NOT EXISTS `docs` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `description` text COLLATE utf8_unicode_ci NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
mediaのメタ情報を持たせるテーブルのDDLは以下。
CREATE TABLE IF NOT EXISTS `doc_images` ( `id` int(11) NOT NULL AUTO_INCREMENT, `doc_id` int(11) NOT NULL, `path` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
モデル
/app/modelsにdoc.php, doc_image.phpを作成する。
doc.php
後述のdoc_image.phpとは、hasManyの関係として、docからカスケーディング・デリートがかかるようにする(dependent=>true)。
<?php class Doc extends AppModel { public $name = 'Doc'; public $hasMany = array( "DocImage" => array( 'className' => 'DocImage', 'dependent' => true ) ); public $validate = array( 'title'=>array( 'rule' => 'notEmpty', 'message' =>'入力してください' ) ); } ?>