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さんです。よろしくお願いします〜。