This version of the documentation is for CakePHP 2.x. Go to latest docs.
Skip to content
Simple Analytics

データソース ​

データソースはモデルとモデルが表現するデータの元(ソース)とを 仲立ちするものです。多くの場合、データは MySQL, PostgreSQL, Microsoft SQL Server といったリレーショナルデータベースから取り出されます。 CakePHP は、以下の一覧にあるようないくつかのデータベース固有の データソース( lib/Cake/Model/Datasource/Database を参照) とともに配布されています。:

  • Mysql
  • Postgres
  • Sqlite
  • Sqlserver

NOTE

上記以外にも、 GitHub 上の CakePHP データソースリポジトリ にコミュニティが開発しているデータソースがあります。

app/Config/database.php でデータベースの接続設定を行うと、 モデルの操作全般において CakePHP は透過的に対応するデータソースを 使用します。このため、それらのデータソースに関する知識がなくても 利用できるようになっています。

前述のソースはどれも DboSource から派生したもので、これにより ほとんどのリレーショナルデータベースで共通な、いくつかのロジックを 集約しています。新しく RDBMS のデータソースを書いてみようという向きには、 まずこれらのどれかを手本にするとよいでしょう (MySQL または SQLite が最もオススメです)。

ただし、多くの人はリモート REST API さらには LDAP サーバといった、 外部ソースに関するデータソースを書くことに興味を持っています。 なので、我々も現在これらに目を向けつつあるところです。

データソースのための基本的な API ​

データソースには少なくとも create, read, update および/または delete メソッドを実装することができ、また 『実装するべき』です。(現時点では、実際の各メソッドの特徴的な性質や 実装の詳細は重要ではありません。これらについては後述しています。)。 これらのメソッド以外については、特に必要でなければ実装する必要はありません。 さらに、もしリードオンリーのデータソースが必要なら、 create, update, delete これら3つの存在意義はありません。

すべての CRUD (CREATE/READ/UPDATE/DELETE) メソッドのために 実装しなければならないメソッド:

  • describe($model)
  • listSources($data = null)
  • calculate($model, $func, $params)
  • 少なくとも以下のうちのひとつ:
    • create(Model $model, $fields = null, $values = null)
    • read(Model $model, $queryData = array(), $recursive = null)
    • update(Model $model, $fields = null, $values = null, $conditions = null)
    • delete(Model $model, $id = null)

モデルではなくデータソース自身の中で $_schema クラス属性を 定義することも可能です(これは非常に有用な場合もあります)。

これはそれほど特殊なケースではありません。 データソースをモデルに結合させてもなお、 Model::find()/save()/delete() はいつも通りに使えます。 また、これらのメソッドを呼ぶときに使われる妥当なデータ および/またはパラメータも、データソース自身に渡されます。 このため、(たとえば Model::find へのオプションであれば 'conditions' のパースや 'limit' さらにはデータソース 自身が使うカスタムパラメータといった)必要と思われるどんな 機能でも実装することができます。

実装例 ​

自らデータソースを書き起こしたいと思う理由でよくあるのは、 いつもの Model::find()/save()/delete() メソッドを使って サードパーティの API にアクセスしたいという場合です。 ここでは架空のリモート JSON ベースの API にアクセスする データソースを書いてみましょう。 FarAwaySource という名前で app/Model/Datasource/FarAwaySource.php に置くことにします:

App::uses('HttpSocket', 'Network/Http');

class FarAwaySource extends DataSource {

/**
 * データソースの説明(オプション)
 */
    public $description = 'A far away datasource';

/**
 * デフォルトの設定オプション。これらは ``app/Config/database.php`` 
 * でカスタマイズされ、 ``__construct()`` の中でマージされます。
 */
    public $config = array(
        'apiKey' => '',
    );

/**
 * create() や update() を行いたい(実装したい)場合、利用できる
 * 項目を指定する必要があります。たとえば固定情報やスキーマの
 * 移行など、CakeSchema でやる場合と同じ配列キーを使います。
 */
    protected $_schema = array(
        'id' => array(
            'type' => 'integer',
            'null' => false,
            'key' => 'primary',
            'length' => 11,
        ),
        'name' => array(
            'type' => 'string',
            'null' => true,
            'length' => 255,
        ),
        'message' => array(
            'type' => 'text',
            'null' => true,
        ),
    );

/**
 * HttpSocket を生成し、設定の調整を行う。
 */
    public function __construct($config) {
        parent::__construct($config);
        $this->Http = new HttpSocket();
    }

/**
 * データソースは通常データベースに接続するので、データベース
 * なしでも動くようにいくらか調整する必要があります。
 */

/**
 * listSources() はキャッシュ操作を行います。あなたはカスタム
 * データソースでも独自のやり方でキャッシュ機構を実装したいと思う
 * かもしれません。とりあえず、単に ``return null`` してください。
 */
    public function listSources($data = null) {
        return null;
    }

/**
 * describe() はモデルに対して ``Model::save()`` のための
 * スキーマを伝えます。
 *
 * モデルごとに異なったスキーマを使いたい場合もあるかもしれませんが、
 * それでも単一のデータソースを使ってください。その場合、モデルに
 * 対して ``schema`` プロパティをセットし、ここでは単に 
 * ``$model->schema`` を返すようにします。
 */
    public function describe($model) {
        return $this->_schema;
    }

/**
 * calculate() はレコード数のカウント方法を決定します。これは
 * ``update()`` と ``delete()`` の動作を決めるのに必要です。
 *
 * ここでは実際にはレコードのカウントはせず、 ``read()`` に渡されるべき
 * 文字列を返します。これが実際のカウント処理を行います。
 * 最も簡単なのは、ここでは単に 'COUNT' という文字列を返しておき、
 * ``read()`` の中で ``$data['fields'] === 'COUNT'`` かどうかを
 * 聞くようにすることです。
 */
    public function calculate(Model $model, $func, $params = array()) {
        return 'COUNT';
    }

/**
 * CRUD のうちの R を実装します。 ``Model::find()`` への呼び出しは
 * ここに来ます。
 */
    public function read(Model $model, $queryData = array(),
        $recursive = null) {
        /**
         * ここでは、前述の calculate() メソッドで返されるカウントの
         * 実際の処理を行います。リモートソースのチェックをするか、
         * またはそれ以外の方法でレコードカウントを取得します。
         * ここでは単に 1 を返しているので、 ``update()`` や
         * ``delete()`` ではレコードが存在するものとみなされます。
         */
        if ($queryData['fields'] === 'COUNT') {
            return array(array(array('count' => 1)));
        }
        /**
         * ここではリモートデータを取得およびデコードして返します。
         */
        $queryData['conditions']['apiKey'] = $this->config['apiKey'];
        $json = $this->Http->get(
            'http://example.com/api/list.json',
            $queryData['conditions']
        );
        $res = json_decode($json, true);
        if (is_null($res)) {
            $error = json_last_error();
            throw new CakeException($error);
        }
        return array($model->alias => $res);
    }

/**
 * CRUD のうちの C を実装します。 ``Model::save()`` への呼び出しのうち
 *  $model->id がセットされないケースがここに来ます。
 */
    public function create(Model $model, $fields = null, $values = null) {
        $data = array_combine($fields, $values);
        $data['apiKey'] = $this->config['apiKey'];
        $json = $this->Http->post('http://example.com/api/set.json', $data);
        $res = json_decode($json, true);
        if (is_null($res)) {
            $error = json_last_error();
            throw new CakeException($error);
        }
        return true;
    }

/**
 * CRUD のうちの U を実装します。 ``Model::save()`` への呼び出しのうち
 *  $model->id がセットされているケースがここに来ます。リモートソース
 *  に依存するためここでは単に ``$this->create()`` をコールできます。
 */
    public function update(Model $model, $fields = null, $values = null,
        $conditions = null) {
        return $this->create($model, $fields, $values);
    }

/**
 * CRUD のうちの D を実装します。 
 * ``Model::delete()`` への呼び出しがここに来ます。
 */
    public function delete(Model $model, $id = null) {
        $json = $this->Http->get('http://example.com/api/remove.json', array(
            'id' => $id[$model->alias . '.id'],
            'apiKey' => $this->config['apiKey'],
        ));
        $res = json_decode($json, true);
        if (is_null($res)) {
            $error = json_last_error();
            throw new CakeException($error);
        }
        return true;
    }

}

データソースを構成するには app/Config/database.php ファイルの中で以下のように追加します:

public $faraway = array(
    'datasource' => 'FarAwaySource',
    'apiKey'     => '1234abcd',
);

そしてモデルの中でデータベースを以下のように使います:

class MyModel extends AppModel {
    public $useDbConfig = 'faraway';
}

これで、使い慣れたモデルのメソッドを使ってリモートソースから データを取り出せるようになります:

// Get all messages from 'Some Person'
$messages = $this->MyModel->find('all', array(
    'conditions' => array('name' => 'Some Person'),
));

TIP

あなたの read メソッドで返される配列のインデックスが数値以外の場合、 find のタイプで 'all' 以外を使うと予期しない結果が返る場合があります。

同様に、新しいメッセージを保存できます:

$this->MyModel->save(array(
    'name' => 'Some Person',
    'message' => 'New Message',
));

以前のメッセージを更新します:

$this->MyModel->id = 42;
$this->MyModel->save(array(
    'message' => 'Updated message',
));

そしてそのメッセージを削除します:

$this->MyModel->delete(42);

データソースのプラグイン化 ​

データソースをパッケージにしてプラグインにすることもできます。

単にあなたのデータソースファイルを Plugin/[YourPlugin]/Model/Datasource/[YourSource].php に置いて、それをプラグイン記法で参照するだけです:

public $faraway = array(
    'datasource' => 'MyPlugin.FarAwaySource',
    'apiKey'     => 'abcd1234',
);

SQL Server に接続する ​

SQL Server のデータソースは、pdo_sqlsrv と呼ばれるマイクロソフトの PHP エクステンションに依存しています。この PHP エクステンションは PHP の基本構成には含まれておらず、別途インストールする必要があります。

また、そのエクステンションが動作するためには SQL Server の ネイティブクライアントがインストールされている必要があります。 そのネイティブクライアントは Windows 用しかないので、 これを Linux, Mac OS, FreeBSD 上で動かすことはできません。

このため、SQL Server が以下のようなエラー:

Error: Database connection "Sqlserver" is missing, or could not be created.

を出す場合は、まず SQL Server の PHP エクステンション pdo_sqlsrv と SQL Server のネイティブクライアントが正しくインストール されているかどうかを確認して下さい。

Released under the MIT License.