[CakePHP] Datasourceを使い倒す

CakePHP Advent Calendar2010 も折り返し点を過ぎました。CakePHP Advent Calendar2010は、ネタの調整などはしていないのですが(してないよね(^^;?)、参考になる話ばかりだし、まだネタがかぶったという話は聞かないので正に「君の当たり前に僕らは感嘆させられるんだ」ですね(^^;。
では、13日目の担当と言う事で...。
*この記事の内容はCakePHP1.3での話になります。

CakePHP1.2までは、Datasourceは app/models/datasources/ 以下に配置しないと動作させることが出来ませんでしたが、CakePHP1.3からはプラグイン配下のDatasouceを使用することが可能になりました。
これは個人的にとても嬉しい修正だったのですが、このあたりの情報をWeb上にあまり見かけないのでまとめてみました。

CakePHP Datasources
CakePHPのCoreに含まれていないデータソースは、PHP Matsuriにも来ていただいた Graham Weldonさんが以下でまとめられています。

ここには、以下の様なデーターソースがまとめられています。

  • Amazon Associates Datasource
  • Array Datasource
  • CSV Datasource
  • SORP Datasource
  • XML-RPC Datasource
  • ADODB Datasource
  • DB2 Datasource
  • Firebird Datasource
  • MySQL Log Datasource
  • ODBC Datasource
  • SQLite3 Datasource
  • SQLServer Datasource
  • Sybase Datasource

他には、CakePHP Advent Carendar2010の一日目を担当されたid:cakephperさん作の MondoDB Datasource なんかも最近はホットなのではないでしょうか?
# 弊社でも使わせていただいております!

Datasourceの使い方(準備編)
使用する為に機能拡張等のインストールが全く必要ない、CSV Datasourceを例に実際にDatasourceを使う方法を解説してみたいと思います。
まずは、pluginsディレクトリに CakePHP Datasources を配置します。

cd APP/plugins/
git clone https://github.com/cakephp/datasources.git

実際のプロジェクトで利用する場合は、 6日目に@tfmagicianさんが紹介されているように git submoduleを使って管理すると良いと思います。

次に、cvsファイルを配置します。今回は APP/tmp/databases/ に下記のファイルを配置します。

  • APP/tmp/databases/advent_calendars.csv

id,target_date,name,url
1,"2010/12/01","cakephper","http://d.hatena.ne.jp/cakephper/20101201/1291166566"
2,"2010/12/02","k1LoW","http://d.hatena.ne.jp/k1LoW/20101202/1291262612"
3,"2010/12/03","shin1x1","http://www.1x1.jp/blog/2010/12/thinking_abount_cakephp_mode.html"
4,"2010/12/04","remore","http://rimuru.lunanet.gr.jp/notes/post/2838/"
5,"2010/12/05","uechoco","http://labs.uechoco.com/blog/2010/12/cakephp-model-lovers.html"
6,"2010/12/06","tfmagician","http://1-byte.jp/2010/12/06/cakephp_with_git/"
7,"2010/12/07","MASA-P","http://blog.ecworks.jp/archives/1323"
8,"2010/12/08","kanonji","http://d.hatena.ne.jp/kanonji/20101208/1291819950"
9,"2010/12/09","lxcy","http://d.hatena.ne.jp/ixcy/20101209/p1"
10,"2010/12/10","mon-sat","http://text.tklabo.net/blog/26/cakephp-environment-tips"
11,"2010/12/11","msng","http://www.msng.info/archives/2010/12/cakephp-error-only-when-debug-level-is-0.php"
12,"2010/12/12","ogaaaan","http://torhamzedd.blogspot.com/2010/12/cakephp-advent-calendar-12st.html"
13,"2010/12/13","kaz29","http://d.hatena.ne.jp/kaz_29/20101213/1292209088"
14,"2010/12/14","camelmasa","-"
15,"2010/12/15","hiromi","-"
16,"2010/12/16","aerith","-"
17,"2010/12/17","nojimage","-"
18,"2010/12/18","halt","-"
19,"2010/12/19","kunit","-"
20,"2010/12/20","connvoi_tyou","-"
21,"2010/12/21","yashio","-"
22,"2010/12/22","knj77","-"
23,"2010/12/23","osakanapower","-"
24,"2010/12/24","akiyan","-"

最後に、database.phpの設定です。今回datasourceはplugins以下に配置しているので下記の様に定義します。

<?php
define('CSV_PATH', TMP.'databases'.DS);

class DATABASE_CONFIG {
var $csv = array(
'driver' => 'Datasources.CsvSource',
'path' => CSV_PATH,
'readonly' => true,
'extension' => 'csv',
'recursive' => false,
);

...
}

これで、準備は完了です。

Datasourceの使い方(使用編)
実際に使用するには、通常のdatasourseを使用する場合とあまり変りないのですが以下のようになります。

  • モデル APP/models/advent_calendar.php

<?php
class AdventCalendar extends AppModel {
public $useDbConfig='csv';
}

  • コントローラ APP/controllers/advent_calendar_controller.php

<?php
class AdventCalendarController extends AppController {
public $name = 'AdventCalendar';
public $helpers = array('Html','Paginator') ;
public function index() {
$results = $this->paginate();
$this->set(compact('results'));
}
}

  • ビュー APP/views/advent_calendar/index.ctp

<div class="advent calendar index">
<h2><?php __('Advent Calendar');?>h2>

<p>
<?php
echo $this->Paginator->counter(array(
'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true)
));
?> p>

<div class="paging">
<?php echo $this->Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?>
| <?php echo $this->Paginator->numbers();?>
|
<?php echo $this->Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?>
div>

<table cellpadding="0" cellspacing="0">
<tr>
<th><?php echo $result['AdventCalendar']['id'];?>th>
<th><?php echo $result['AdventCalendar']['target_date'];?>th>
<th><?php echo $result['AdventCalendar']['name'];?>th>
tr>

<?php
$i = 0;
foreach ($results as $result):
$class = null;
if ($i++ % 2 == 0) {
$class = ' class="altrow"';
}
?>
<tr<?php echo $class;?>>
<td>
<?php echo $result['AdventCalendar']['id']; ?>
td>
<td>
<?php echo $result['AdventCalendar']['target_date']; ?>
td>
<td>
<?php
if (!empty($result['AdventCalendar']['url']) && $result['AdventCalendar']['url'] !== '-' ):
echo $this->Html->link($result['AdventCalendar']['name'], $result['AdventCalendar']['url']);
else:
echo $result['AdventCalendar']['name'];
endif;
?>
td>
tr>
<?php endforeach; ?>
table>

Datasourceの実装によっては通常のRDB用 Datasourceと同じように使えない場合もありますが、基本的な機能は普段CakePHPを使っているのと同じように利用することができます。
参考のために、CSV Datasource以外のDatasourceを使う場合の database.phpの表記サンプルを下記に書いておきます。

<?php
define('TEST_SQLITE_FILE', TMP.'databases'.DS.'test.sqlite3');
...
// SQLite3
public $sqlite3 = array(
'driver' => 'Datasources.DboSqlite3',
'database' => TEST_SQLITE_FILE,
);
...
// mongoDB
public $default_mongo = array(
'driver' => 'mongodb.mongodbSource',
'database' => 'mongotest',
'host' => 'localhost',
'port' => 27017,
/* optional auth fields
'login' => 'mongo',
'password' => 'awesomeness',
*/
);
...

まとめ
如何でしたでしょうか?今後はRDB以外のDatasourceを扱う機会も出てくると思いますので参考になれば嬉しいです。
また、Datasourceをアプリケーションと切り離すことができますので、Datasourceを作成する場合はpluginとして実装するのが良いと思います。そして、可能なのであればgithubなどで公開してみると面白いのではないかと思います。
明日は、@camelmasaさんです。よろしくお願いします〜。