CakePHP2.xでAmazon S3を操作するDatasourceを作った。

CakePHP2.xでAmazon S3を操作するDatasourceを作りたい。」の続きです。

正直良く分からずに作っているので、微妙です。でも、Datasourceの作り方についてのドキュメントがあまり詳しくないので、あきらめました。

コンストラクタ

設定は、Config/database.phpに書かれているものが渡ってきます。ここでは、database.phpにAmazonのキーとシークレットを記述しておき、それを元にAmazonS3オブジェクトを作成します。

public function __construct($config = null, $autoConnect = true) {
	parent::__construct($config);
	$this->s3 = new AmazonS3($this->config);
}

describeメソッド

データ構造を教えてるためのメソッドです。

リレーショナルデータベースとかだと、テーブル構造を取得して返すところですが、AmazonS3はただのキーとデータのペアなので、それを返します。

private $fields = array(
	'name' => array(
		'type' => 'string',
		'null' => false,
		'length' => 255,
		'key' => 'primary'
	),
	'path' => array(
		'type' => 'string',
		'null' => true,
		'default' => null,
	),
	'object' => array(
		'type' => 'binary',
		'null' => true,
		'default' => null,
	)
);
 
public function describe(Model $Model) {
	return $this->fields;
}

ここに記述されていないキーは、保存の時に削ぎ落とされてしまうので注意です。ローカルのpathにあるファイルを、S3にnameで指定した場所に置きたい場合などを想定して、こういう構造にしておきました。とりあえずです。

listSourcesメソッド

リレーショナルデータベースでは、テーブル一覧に当たるデータを返します。Amazon S3なのでバケット一覧を返すことにしました。

public function listSources() {
	$response = $this->s3->list_buckets();
	if (!$response->isOK())
		return;
	$bucketNames = array();
	foreach ($response->body->Buckets->Bucket as $bucket)
		$bucketNames[] = strval($bucket->Name);
	return $bucketNames;
}

Modelの$useTable変数は、このlistSourcesの結果に含まれている必要があります。さもないと「テーブルがありません」的なエラーが出ます。

ここでfalseを返しておくと、テーブルの存在チェックを放棄するようなので、面倒だったらfalseを返しておくのもありかもしれません。

calculateメソッド

以下はCakePHPのドキュメントそのものですが、こう記述すると、find(‘count’)を呼び出す際に、オプションのfieldsにCOUNTを入れてくれます。この有無を元に、読み出しメソッドであるread()の処理を振り分けます。

public function calculate(Model $Model, $func, $params = array()) {
	return 'COUNT';
}

Model::save()で保存する時などに、データの存在をcountで判定しているようなので、Model::save()を使うためには、データ数をカウントする処理は必要です。

createメソッド

ここからが本質的なメソッドで、CRUDにしたがって記述していきます。

createメソッドには、データレコードを追加する処理を記述します。

Model::save()が呼ばれた時に呼ばれますが、事前にレコードの存在を確認しており、既存にデータの更新ではcreate()ではなく、update()が呼ばれるそうです。

public function create(Model $Model, $fields = array(), $values = array()) {
	$data = array_combine($fields, $values);
	$this->s3->create_object($Model->table, $data['name'], array(
		'fileUpload' => $data['path'],
		'acl' => AmazonS3::ACL_PUBLIC
	));
	return true;
}

ここでは、指定された名前のオブジェクトをS3にアップロードします。

readメソッド

ここではデータレコードの取得処理を記述します。

fieldsがCOUNTの場合は、データの存在だけ見れれば良いので、get_object_headersで存在確認をしています。そうでなければS3からデータを取得して返します。

public function read(Model $Model, $data = array()) {
 
	$name = $data['conditions'][$Model->alias . '.name'];
	if ($data['fields'] == 'COUNT') {
		$response = $this->s3->get_object_headers($Model->table, $name);
		return array( array( array('count' => $response->isOK() ? 1 : 0)));
	}
 
	$response = $this->s3->get_object($Model->table, $name);
	if (!$response->isOK())
		return null;
	return array( array($Model->alias => array(
				'name' => $name,
				'object' => $response->body
			)));
}

今回は、S3にはアップロードさえできれば良いので、ここのデータの取得はテキトーです。(データをWEBサーバに取得せずとも、データの居場所さえ分かれば、クライアントからアクセスしてもらえるためです。)

updateメソッド

ここには、データの更新処理を記述しますが、Amazon S3のファイル更新は新しくアップロードすれば良いので、create()をそのまま呼び出します。

public function update(Model $Model, $fields = array(), $values = array()) {
	return $this->create($Model, $fields, $values);
}

deleteメソッド

データレコードの削除処理を記述します。

ここでは、単に指定された名前のファイルを削除しているだけです。

public function delete(Model $Model, $conditions = null) {
	$response = $this->s3->delete_object($Model->table, $conditions[$Model->alias . '.name']);
	return $response->isOK();
}

queryメソッド

Model::find()の短縮記法として、findByIdなどがありますよね。これの実現方法はまだ詳しく見ていませんが、Datasourceのquery()メソッドを実装すれば実現できました。

public function query($method, $data, Model $Model) {
	if ($method == 'findByName') {	
		return $Model->find('first', array('conditions' => array($Model->alias . '.name' => $data[0])));
	}
}

完成!

これで、AmazonS3Sourceの完成!

(たぶん)使い方編に続きます。

About katty0324

One comment

Leave a Reply

Scroll To Top