ZendFramework入門・その6データベースを扱う・その1 ― 2007年09月23日 15時09分51秒
はじめに
またも1週間のご無沙汰になりましたが、前回の予告どおり、データベース機能の説明に入ります。
DBMSに関しては、前回に予告したとおりSQLiteを対象としますので、先にこちらの番外編を参考にして、コンソールアプリケーションを導入しておくとよいでしょう。
また、この記事はあくまでZend Framework入門ですので、SQLに関する細かい説明などはあまりしない予定です(まぁ、シンプルな使い方しかしない予定ですが)。データベースになれていない方は、他のSQL入門記事なども参考にされるとよいと思います。
それでは本文へまいりましょう。
データベース関連クラス
Zend Frameworkのデータベース機能はZend_Db名前空間に集約されていて、以下のようなクラス群で構成されています。
クラス名 | 役割 |
---|---|
Zend_Db_Adapter | DBアダプタ。データベースへの接続やZend_Db_Statement・Zend_Db_Selectのファクトリとして機能する、Zend_Dbの主要クラス。 すべてのDBアダプタは抽象クラス「Zend_Db_Adapter_Abstract」から派生し、DBMSごとの機能の違いを吸収する |
Zend_Db_Statement | DBMSへの問い合わせを行うステートメントオブジェクト。Zend_Db_Adapterと同様に、基本の抽象クラスから派生した固有のクラスがDBMS間の違いを吸収する。主にZend_Db_Adapter::query()をファクトリとしてインスタンスを取得する |
Zend_Db_Select | オブジェクト操作によるSELECTステートメントを組み立てるためのビルダクラスで、__toString()による文字列化でSQLステートメントを出力する |
Zend_Db_Table | データベースの表(Table)を表現する抽象クラスで、Zend_DbにおけるO/Rマッピングを実現する。基本的にはDBMS上のテーブルと対になるクラスをZend_Db_Tableから派生させる。データベースへの問い合わせや更新もこのクラス(および関連のRow/Rowset)から行えるが、扱い方がZend_Db_AdapterやZend_Db_Statementと異なる点に注意 |
Zend_Db_Table_Row | データベースの行(Row)を表現する抽象クラス。Zend_Db_Tableの操作により生成される。データベースの列(Column)に相当するプロパティを備えており、プロパティ値の変更 → save()メソッドの実行 で行を更新することができる。 |
Zend_Db_Table_Rowset | 複数のZend_Db_Rowを扱うためのIteratorクラスで、Zend_Db_Tableによる問い合わせの結果として取得する。 |
アプリケーション構成
今回は「zdb1」という名前のアプリケーションを作成しましょう。構成はシンプルに、以下のようにします。
- htdocs/
- zdb1/
- application/
- controllers/
- IndexController.php
- views/
- index/
- index.phtml
- index/
- controllers/
- index.php
- .htaccess
- zdb1.db
- create_table.sql
- application/
- zdb1/
肝心のアプリケーションですが、ものすごくシンプルなブックマークにしてみます。以下の情報を扱うことにします。
- タイトル
- URL
- 登録日時
- コメント
キー | カラム | 型 | 備考 |
---|---|---|---|
PK | id | INTEGER | AUTO INCREMENT |
title | VACHAR (100) | ||
IDX1 | url | VARCHAR (255) | |
IDX2 | registDate | TIMESTAMP | |
comment | TEXT |
データベースを作成する
まずはテーブルを作成する「create_table.sql」です。テーブル作成とインデックスの作成、初期データの挿入をしています。
CREATE TABLE bookmarks ( id INTEGER PRIMARY KEY, title VARCHAR (100), url VARCHAR(255), registDate TIMESTAMP, comment TEXT ); CREATE INDEX idx_bookmarks_1 ON bookmarks(url); CREATE INDEX idx_bookmarks_2 ON bookmarks(registDate); INSERT INTO bookmarks ( title, url, registDate, comment ) VALUES ( 'dara-j', 'http://dara-j.asablo.jp/blog/', ( select datetime('now') ), 'だらだらとしたブログ' ); INSERT INTO bookmarks ( title, url, registDate, comment ) VALUES ( 'dara-clip', 'http://dara-j.tumblr.com/', ( select datetime('now') ), 'dara-jのtumblr。ぬこ分多目。' );
作成したcreate_table.sqlをsqlite3で以下の要領で実行する手順です。 まずは今回のアプリケーションディレクトリからコマンドプロンプトを起動します。この例では D:\wwwroot\zdb1 がそれにあたります。そして、そこからsqlite3を実行します。
D:\wwwroot\zdb1>sqlite3 zdb1.db SQLite version 3.4.2 Enter ".help" for instructions sqlite>次に、「.read」コマンドで、先ほど作成したcreate_table.sqlを実行します。
sqlite> .read create_table.sql
sqlite>
.readコマンドはエラーがなければなにも表示しないので、sqlite_master(メタデータテーブル)を確認してみます。
sqlite> select * from sqlite_master; table|bookmarks|bookmarks|2|CREATE TABLE bookmarks ( id INTEGER PRIMARY KEY, title VARCHAR (100), url VARCHAR(255), registDate TIMESTAMP, comment TEXT ) index|idx_bookmarks_1|bookmarks|3|CREATE INDEX idx_bookmarks_1 ON bookmarks(url) index|idx_bookmarks_2|bookmarks|4|CREATE INDEX idx_bookmarks_2 ON bookmarks(regi stDate) sqlite>テーブル・2つのインデックスとも定義されていればOKです。ついでに同時に実行したinsertが正常にできているかを、以下のように確認します。
sqlite> select * from bookmarks; 1|dara-j|http://dara-j.asablo.jp/blog/|2007-09-23 05:01:25|だらだらとしたブログ 2|dara-clip|http://dara-j.tumblr.com/|2007-09-23 05:01:25|dara-jのtumblr。ぬこ分 多目。 sqlite>datetime()関数は、CURRENT_TIMESTAMPと同様にロケールを考慮しないので、GMTでデータが挿入されてしまいますが、これは初期データなのでまぁ気にしないでください(^^; 確認できたらsqlite3を終了しましょう。
sqlite> .quit
データベースへ接続の接続と基本的な問い合わせ
今度はPHP側のコードを作成していきましょう。まず起動スクリプト「index.php」ですが、これは「ZendFramework入門・その2 アクションメソッドの追加とリンクの扱い方」で決定したものをそのまま流用できます(つまり、zf2のもの)。
IndexControllerは次のようになります。
<?php require_once 'Zend/Controller/Action.php'; // Zend_Dbをrequre require_once 'Zend/Db.php'; // IndexController class IndexController extends Zend_Controller_Action { // initメソッド。初期化処理用のフックメソッド // アクセスレベルが「public」な点に注意 public function init() { // リクエストオブジェクト(Zend_Controller_Request_Abstract)を取得 $request = $this->getRequest(); // ベースURLを取得 $baseUrl = getApplicationUrl( $request ); // ビューへ割り当てる $this->view->assign( 'baseUrl', $baseUrl ); } // indexアクション public function indexAction() { // Zend_Db_Adapterを生成 $db = Zend_Db::factory( // Zend_Db_Adapter_Pdo_Sqlite クラスを使用する "Pdo_Sqlite", // 生成パラメータ。SQLiteは接続先を示す'dbname'のみでOK array( 'dbname' => 'zdb1.db' ) ); // SELECTステートメントを実行 $result = $db->fetchAll( 'SELECT * FROM bookmarks ORDER BY registDate DESC' ); // 実行結果をビューへ割り当てる $this->view->assign( 'rows', $result ); } }
- Zend_Dbを使用するために、'Zend/Db.php'をrequireしている
- Zend_Db_Adapterを取得するためにZend_Db::factoryスタティックメソッドを使用している
- Zend_Db_Adapter::fetchAll()メソッドでSQLステートメントを実行している
クラス名は暗黙で「Zend_Db_Adapter_」プレフィックスがつけられますので、今回の例の「PdoSqlite」はZend_Db_Adapter_Pdo_Sqlite」を作成することを意味しています。
第二引数の初期化パラメータ配列ですが、SQLiteの場合は他のオプションがほとんどないのでキー'dbname'のみを指定していますが、他のDBMSの場合は「username」「password」などがあります。たとえばローカルで動作しているMySQLのスキーマ「mydb」に接続する場合は以下のようになります。
$db = Zend_Db::factory( "Pdo_MySql", array( 'host' => 'localhost', // 接続するMySQLサーバのホスト名 'dbname' => 'mydb', // 接続するデータベース(スキーマ) 'username' => 'mysqluser', // 接続するユーザID 'password' => 'passwd' // 接続パスワード ) );
そして、index.phtmlです。まずは、Zend_Db_Adapter::fetchAll()が何を返すのかを単純に確認するため、以下のようにvar_dump()を使ったシンプルな実装をしてみましょう。(手抜き、ともいう)
<html> <head> <title>zdb1</title> <!-- base要素の出力。末尾の「/」に注意 --> <base href="<?php echo $this->baseUrl; ?>/"></base> </head> <body> <h3> bookmarksの内容 </h3> <hr> <!-- var_dumpしてみる --> <pre> <?php var_dump( $this->rows ); ?> </pre> </body> </html>
bookmarksの内容
array(2) { [0]=> array(5) { ["id"]=> string(1) "2" ["title"]=> string(9) "dara-clip" ["url"]=> string(25) "http://dara-j.tumblr.com/" ["registDate"]=> string(19) "2007-09-23 05:01:25" ["comment"]=> string(28) "dara-jのtumblr。ぬこ分多目。" } [1]=> array(5) { ["id"]=> string(1) "1" ["title"]=> string(6) "dara-j" ["url"]=> string(29) "http://dara-j.asablo.jp/blog/" ["registDate"]=> string(19) "2007-09-23 05:01:25" ["comment"]=> string(20) "だらだらとしたブログ" } }
これを単純なテーブル表示にするには、index.phtmlを以下のように変更します。
<html> <head> <title>zdb1</title> <!-- base要素の出力。末尾の「/」に注意 --> <base href="<?php echo $this->baseUrl; ?>/"></base> </head> <body> <h3> bookmarksの内容 </h3> <hr> <!-- テーブルで表示 --> <table border="1" cellpadding="0" cellspacing="0"> <?php foreach( $this->rows as $i => $row ) { if( $i == 0 ) { // 最初の行のみ ?> <tr> <?php // ヘッダ行出力 foreach( $row as $key => $value ) { echo '<th>' . $this->escape( $key ) . '</th>'; } ?> </tr> <?php // if 終わり } ?> <tr> <?php // 行出力 foreach( $row as $key => $value ) { echo '<td>' . $this->escape( $value ) . '</td>'; } ?> </tr> <?php // foreach終わり } ?> </table> </body> </html>
実行結果は各自で確認してみてください。
Zend_Db_Adapter::fetchAll
参考までにですが、Zend_Db_Adapter::fetchAllについて少し解説します。Zend_Db_Adapter::fetchAllメソッドは以下のように定義されています。
/** * Fetches all SQL result rows as a sequential array. * Uses the current fetchMode for the adapter. * * @param string|Zend_Db_Select $sql An SQL SELECT statement. * @param mixed $bind Data to bind into SELECT placeholders. * @return array */ public function fetchAll($sql, $bind = array())
そして、肝心の処理内容は、以下のように記述されています。
$stmt = $this->query($sql, $bind); $result = $stmt->fetchAll($this->_fetchMode); return $result;
あとがき&次回予告
ともかくデータベースの内容を表示するところまでやってみましたが、いかがでしたでしょうか?
このままでは面白くもなんともないので、次回はこれにデータを追加する機能を作成してみたいと思います。そのために「Zend_Db_Table」の解説をする予定です。
それではまた次回。
コメント
トラックバック
このエントリのトラックバックURL: http://dara-j.asablo.jp/blog/2007/09/23/1815491/tb
※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※なお、送られたコメントはブログの管理者が確認するまで公開されません。