http://bakery.cakephp.org/articles/view/csv-datasource-for-reading-your-csv-files
を参考にしました。
ここではあるディレクトリを参照するデータソースを作ります。
とりあえずapp/config/database.phpに以下を追加
<?php var $dir = array( 'datasource' => 'dir', 'root' => '/path/to' ); ?>
データソースのクラスファイルはapp/models/datasources以下に_sourceを付けた名前で保存し、
DataSourceクラスを継承して作ります。
app/models/datasources/dir_source.php
<?php class DirSource extends DataSource { var $fields = array( 'name' => array('type' => 'string', 'null' => null, 'default' => null, 'length' => 255, 'key' => 'primary'), 'size' => array('type' => 'integer', 'null' => null, 'default' => null, 'length' => 10)); function __construct($config = null, $autoConnect = true) { parent::__construct($config); if ($autoConnect) { return $this->connect(); } else { return true; } } function connect() { $config = $this->config; uses('Folder'); $this->connection =& new Folder($config['root']); if ($this->connection) { return true; } else { return false; } } function close() { $this->connection->close(); } function listSources() { list($folders, $files) = $this->connection->read(); return $folders; } function describe(&$model) { $cache = parent::describe($model); if ($cache != null) { return $cache; } $fields = $this->fields; $this->__cacheDescription($this->fullTableName($model, false), $fields); return $fields; } function read(&$model, $query = array(), $recursive = null) { uses('File'); $path = Folder::addPathElement($this->connection->pwd(), $model->table); $root = new Folder($path); list($folders, $files) = $root->read(); $results = array(); foreach ($files as $name) { $path = Folder::addPathElement($root->pwd(), $name); $file = new File($path); $result['name'] = $name; $result['size'] = $file->size(); $results[] = array($model->name => $result); } if (!empty($query['fields']['count'])) { $source['count'] = count($results); return array(array($model->name => $source)); } $results = array_slice($results, $query['limit'] * ($query['page'] - 1), $query['limit']); return $results; } function fullTableName(&$model, $quote = true) { if (is_object($model)) { $table = $model->tablePrefix . $model->table; } else if (isset($this->config['prefix'])) { $table = $this->config['prefix'] . strval($model); } else { $table = strval($model); } if ($quote) { return $this->name($table); } return $table; } function calculate(&$model, $func, $params = array()) { return array('count' => true); } } ?>
以下各メソッドについて
$configにはdatabase.phpに設定した変数の内容が入ってきます。
データベースの場合はdriverやpassword等がありますが、自分が作るデータソースの内容により、
基本何でも設定できるので、この値を元にデータソースを初期化します。
$autoConnectはわかりませんwおそらく名前通りでしょう。
なお、親コンストラクタは$configを$this->configに保存します。
扱う対象データとの接続、切断等を行います。
ここではconnetメソッドでディレクトリをopenし、closeメソッドでcloseしています。
Folderオブジェクトの場合は明示的にcloseする必要な無いですが、
closeメソッドが存在しないとエラーが出ます。
データソースの一覧を配列で返します。
要はデータベースで言うところのテーブル一覧です。
ここでは$configの$rootに設定したパスに存在するディレクトリ一覧を返しています。
この中にモデルの$useTable($table)に一致するものが無いと、Missing Database Tableになります。
スキーマというかフィールドの情報を返します。
データベースと同じ形式で持っておくとbakeする時とか色々便利かと思います。
とりあえずファイル名をプライマリキーにしておきました。
モデルのfindからお呼ばれします。
要は好きなデータを返してやれば良いです。
ここではモデルのテーブル(ディレクトリ)の中にあるファイル一覧とファイルサイズを返します。
返す時はいわゆる['モデル名']['カラム名'] => 値の形で返してやるようにします。
最後に現在ページ分を切り出しています。
ここでは省略しましたが、$queryには検索条件やらPaginatorのパラメータやらが入ってきているので、適宜ソートや抽出処理を追加すると良いです。
DboSouceからのコピペです。
これが無いとbakeできませんでしたので。
これで無茶苦茶はまりましたorz
というかたぶん根本的な解決にはなっていないような。。
find('count')した時に呼ばれます。
DBの場合はCOUNT文のSQLとかを返しているようなのですが、
ここではそうはいかないので、countの時はcount配列を挿入してます。
戻り値はreadに渡される$query['fields']の中に入ってくるので、
countがあったらカウント値だけ入れて戻す感じです。
とりあえずこれだけあればBakeできます。
$ cake bake model Welcome to CakePHP v1.2.3.8166 Console --------------------------------------------------------------- App : app Path: /www/cake/app --------------------------------------------------------------- --------------------------------------------------------------- Bake Model Path: /www/cake/app/models/ --------------------------------------------------------------- Use Database Config: (default/dir) [default] > dir Possible Models based on your current database: 1. hoge 2. hogehoge 3. hogehogehoge Enter a number from the list above, type in the name of another model, or 'q' to exit [q] > 1 Given your model named 'Basic', Cake would expect a database table named basics Do you want to use this table? (y/n) [y] > n What is the name of the table (enter "null" to use NO table)? > hoge Would you like to supply validation criteria for the fields in your model? (y/n) [y] > n What is the primaryKey? [name] > Would you like to define model associations (hasMany, hasOne, belongsTo, etc.)? (y/n) [y] > n --------------------------------------------------------------- The following Model will be created: --------------------------------------------------------------- Name: Hoge DB Config: dir Primary Key: name Associations: --------------------------------------------------------------- Look okay? (y/n) [y] > Baking model class for Hoge... Creating file /www/cake/app/models/hoge.php Wrote /www/cake/app/models/hoge.php SimpleTest is not installed. Do you want to bake unit test files anyway? (y/n) [y] > n
<?php
class Hoge extends AppModel {
var $name = 'Hoge';
var $useDbConfig = 'dir';
var $useTable = 'hoge';
var $primaryKey = 'name';
}
?>
もちろんコントローラ、ビューのbakeもできます。
indexはページング処理を含めちゃんと動くはずです(ソートは省略してますが)。
便利とかいう以前に無茶苦茶楽しい。
特にbakeと組み合わせるとヤバイです。
これはしばらく仕事してる場合じゃないな…