LoginSignup
18
18

More than 5 years have passed since last update.

Zend_Db_Tableをもっと手軽に使う(概要編) #ZFhimekuri

Last updated at Posted at 2012-03-16

Zend Framework 日めくり Calendar 2012」の3日目の記事です。何となくQiitaで書いてみます。

Zend Framework でデータベースを扱う時の定番モジュールがZend_Dbです。公式のQuickStartがわかりやすいんですが、TableDataGatewayをDataMapperから使うというガチガチ厳密な使い方をしているので、「難しそう」「面倒くさそう」という印象を受けるかもしれません。

もうちょっとお手軽に、不真面目に使う書き方を考えてみます。解説を長々と書くとダレそうなので2日間に分割します。今日は概要だけ。

用語の整理

Zend_Dbについて少し解説。主要なクラスはこの3つです。

  • Zend_Db … DAL(PDOのWrapper)
  • Zend_Db_Table … O/R Mapper(Table Data Gateway)
  • Zend_Db_Table_Row … O/R Mapper(Row Data Gateway)

Zend_Dbは言ってしまえばPDOのWrapperで、「どんなデータベースでも同じインターフェースで操作できるよ」というだけの代物。素のPDOより対応データベースが少し多くなっています。インターフェースの統一が主目的であり、極薄でオーバーヘッドもあまり無いので、ZFではとりあえず使っておくといいです。単体で使うことも可能です。

Zend_Db_TableZend_Db_Table_RowがZFにおけるO/R Mapperの部分です。O/R Mapperと聞くとActiveRecordを思い浮かべる人が多いと思いますが、ZFの場合はTable Data Gateway / Row Data Gatewayというデザインパターンを採用しています。
参考: http://otndnld.oracle.co.jp/columns/arai-semi/data_access/2/

ActiveRecordより抽象度が一段低く、「テーブルを1つのクラスとみなす」「テーブル単位で操作を行う」「ドメインロジックを持たない」などの特徴を持ちます。ちょっと長くなりそうなのでこの辺の特徴は追々書きます。

テーブル単位の操作が基本になるので、JOINは基本的に行ってくれません。JOINを多用する場合は向いていませんので、Zend_Dbを直接使ったほうがいいです。しかしテーブル単位の操作に限るのであれば、超便利なコンポーネントです。

サンプルソース

githubに置きました。昔作ったパフォーマンス計測用の適当なアプリにブランチを切ってあります。
https://github.com/hirak/performance/tree/DbTable_test

僕が考える、Zend_Dbをカジュアルに使うポイントは4つ。

  • DBの初期化はapplication.iniに書く
  • スキーマはZend_Db_Table_Definitionを利用してConfigファイルにする。テーブルのクラス定義なんて省略しちゃえ
  • テーブル取得のコードをグローバル関数化して短くする
  • Zend_Db_Table_Row_Abstractを拡張してActiveRecordにしてしまう。これで拡張ポイントができるので、DataMapperは省略してしまえ

Zend_Db_Tableの書き方のサンプル

もろもろ準備が出来上がった場合、Controllerなどからの呼び出しコードはこんな感じになります。Zend_Db_Table_Rowの拡張がベースになるので、Rowクラスを生成して操作を行います。

<?php
//常にZend_Db_Tableを作成するところから開始します。
$posts = AR('posts');

//テーブルクラスにデータを検索してもらったり
$latestPost = $posts->find(1)->current();

//テーブルクラスに新しいRowデータの雛形を作ってもらったり
$newpost = $posts->createRow();
$newpost->title = '新しいポスト';
$newpost->text = '新しい記事だよー';
$newpost->save();

ActiveRecordだとPosts::find(1)みたいにstaticメソッドで検索やinsertを済ませるものがありますが、ZFは操作のために必ずZend_Db_Tableのインスタンスが必要です。

検索(SELECT)

主キーでの検索にはZend_Db_Table::find()を使います。

<?php
//主キーでの検索
list($post) = AR('posts')->find(1);
//もしくは
$post = AR('posts')->find(1)->current();

var_dump($post->toArray());

//$postはそのまま配列風アクセスやオブジェクトアクセスが可能
echo $post->name, "\t", $post['text'], "\n";

キーは複数渡せる仕様なので、戻り値が常にZend_Db_Table_Rowsetになり、配列風になっています。
そのため、先頭の一つしか必要ない場合はlist()を使うか->current()で絞り込む必要があります。個人的にはlistで書くのが好きです。

もうちょっと複雑な検索の場合はZend_Db_Table::fetch()Zend_Db_Table::fetchRow()を使います。こちらはwhereやorderが使えます。

<?php
//複雑な検索
// ORDER BY created DESC LIMIT 1 で最新のPOSTを取得する
$latestPost = $posts->fetchRow(null, 'created DESC');

更新(UPDATE)

テーブルクラスからfindしたりcreateRowしたRowオブジェクトは、「生きています」。編集してsave()すると、そのままDBに保存することが可能です。この辺がRow Data Gatewayの特徴ですね。

<?php
list($post) = $posts->find(1);
$post->title = '修正したよ';
$post->text = '修正した記事だよー';
$post->save();

新規作成(INSERT)

テーブルクラスからcreateRowすると何も入っていない空っぽのデータが作成されます。
こいつにデータを突っ込んでsave()するとINSERT文の効果があります。

<?php
$newPost = $posts->createRow();
$newPost->name = '新しい記事だよー';
$newPost->text = '新しい記事だよー';
$newPost->save();

削除(DELETE)

更新と同じく、Rowを取得してからdeleteすることができます。

<?php
list($post) = $posts->find(1);
$post->delete();

後半・解説編に続く

18
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
18