2009年7月31日金曜日

Zend_Db_Tableでリレーションの作成

どうも俺@仕事中です。
相変わらずZendFramework使っています。多分11月くらいまで。。。
今日はZend_Db_Tableでリレーション(テーブル間の関連)を表す方法をメモします。

サンプルDB(MySQL)として、スレッド型掲示板を作ります。
CREATE TABLE user (
 id INTEGER AUTO_INCREMENT PRIMARY KEY,
 name
);
CREATE TABLE thread (
 id INTEGER AUTO_INCREMENT PRIMARY KEY,
 user_id INTEGER,
body TEXT
);
CREATE TABLE reply (
 id INTEGER AUTO_INCREMENT PRIMARY KEY,
 user_id INTEGER,
 thread_id ITNEGER,
 body TEXT
);

リレーションは大まかに
user←thread←reply
という感じです。
replyテーブルはuser_idを持ちます。

この場合のZend_Db_Tableは
<?php
class User extends Zend_Db_Table {
 protected $_dependentTables = array(
    "Thread","Reply"); // ThreadクラスとReplyクラスに参照されている
}
class Thread extends Zend_Db_Table {
 protected $_dependentTables = array(
    "Reply"); // Replyクラスに参照されている
 protected $_referenceMap = array(
    "User" => array( // Userクラスを参照している(`Usre`は何でも可)
        "columns" => array("user_id"), // user_idが外部キー
        "refTableClass" => "User", // 参照先クラス名はUser
        "refColumns" => array("id"), // 参照先のキーはid
        "onDelete" => self::RESTRICT, // Userが削除されてもThreadは削除しない
        "onUpdate" => self::CASCADE // Userが更新されたらThreadmo更新する
        )
    );
}
class Reply extends Zend_Db_Table {
 protected $_referenceMap = array(
    "User" => array(
        "columns" => array("user_id"),
        "refTableClass" => "User",
        "refColumns" => array("id"),
        "onDelete" => self::RESTRICT,
        "onUpdate" => self::CASCADE
        ),
    "Thread" => array(
        "columns" => array("thread_id"),
        "refTableClass" => "Thread",
        "refColumns" => array("id"),
        "onDelete" => self::CASCADE,
        "onUpdate" => self::CASCADE
        )
    );
}

となります。
要は
protected $_dependentTables = array();
で参照してきているクラス名
protected $_referenceMap = array();
で参照しているクラス名
を記す事になります。

ではUserオブジェクトから参照されているThread(またはReply)を取得するには
<?php
$thread_rowset = $user->findDependentRowset("Thread");
または
$thread_rowset = $user->findThread();
となります。

Relpyオブジェクトから参照しているUser(またはThread)を取得するには
<?php
$user = $reply->findParentRow("User");
または
$user = $reply->findParentUser();
となります。

ん~、ZendFrameworkなかなかイイねー。

2009年7月17日金曜日

jQueryでクリックされたエレメントの属性を取得する

どうも、俺@仕事中です。

jQuery+Ajaxを使ってインタラクティブなデザインのシステムを構築中なのですが、ちょっとハマったのでめも。

画面にテーブルとか使って、何かデータを一覧表示した場合に、クリックされた要素のvalue値やname属性の値やidの値とか取りたくて、取りたくて、、、取れなくて1時間悩みました。。。

例えば
<td><a href="foo" id="foo_id" value="foo_value">FOO</a></td>
<td><a href="bar" id="bar_id" value="bar_value">BAR</a></td>
のようなテーブルがあるとします。

これでjQueryで'FOO'をクリックした時に、その<a>タグに指定してあるid値やvalue値を取得したい!場合は
$("a").click(function() {
 id = $(this).attr("id"); // idの取得
 val = $(this).attr("value"); // valueの取得
});
という調べたらすぐ分かるような方法で取得できます。

調べ方ってとっても重要ですね!!
以上~~~~。

2009年7月16日木曜日

Zend_Db_SelectでWhere句を取得

どうも俺@残業中です。
引き続きZendFrameworkでアプリ開発を行っております。

Zend_Db_SelectというSQL文を自動生成してくれるクラスが用意されているのですが、
まぁSQLくらい直接書けよ。というツッコミは置いておいて、どうせなら用意されているクラスを利用したい+オブジェクティブに作りたいという事で使ってみました。
<?php $select = $myTable->select();
という感じで、Zend_Db_Selectオブジェトの生成はとても楽です。
ちなみに$myTableというのはZend_Db_Tableクラスを継承したクラスです。

Where句を作成するには
<?php $select->where("id = ?", $id);
のようにすると
WHERE id = $id 
というWhere句が作られます。

OrderBy句は
<?php $select->order("id DESC");
ORDER BY id DESC 
ができます。
超便利ですね。

あとはもう
<?php $select->query();
でZend_Db_Statementオブジェクトを取得しても良し
<?php $myTable->fetchAll($select);
でZend_Db_Rowsetオブジェクトを取得しても良し
<?php $dbAdapter->query($select->__toString());
でZend_Db_Statementオブジェクトを取得しても良し
<?php $dbAdapter->fetchAll($select);
などなど
使い道は無数にありますので、お好きなようにどうぞ。


で、このZend_Db_Selectを使って
「Where句だけ取りたい」
「OrderBy句だけ取りたい」
などあると思います。

その時は
<?php $select->getPart(Zend_Db_Select::WHERE);
でWhere句取得。
<?php $select->getPart(Zend_Db_Select::ORDER);
でOrderBy句取得。
などできちゃいます。
詳しくは、ZendFramework::Select オブジェクトの一部の取得で。


以上どぇーす。

2009年7月9日木曜日

lessコマンドのオプション

どうも俺@仕事中です。
今日はunixコマンド`less`についてメモります。

$ less filename
または
$ cat filename | less
とやると、1画面に収まりきらないファイル内容をページングのように見る事ができる超基本的なコマンドです。

lessコマンドにはいろんなオプションがありますが、普段あまりお目にかからないオプションを書いておきます。
$ less -m filename
画面に常に現在行のパーセンテージを表示

$ less -M filename
画面に常に現在行のパーセンテージと行数を表示

$ less -n filename
行数の計算をしない。大きなサイズのファイルをlessするとき重宝

$ less -N filename
行頭に行数を表示

$ less -r filename
バイナリデータをそのまま表示。日本語ファイルをlessするとき重宝

$ less -R filename
バイナリファイルでも強制的に表示。"xxx" may be a binary file. See it anyway?という質問がされなくなる。

以上でーす。

2009年7月8日水曜日

Zend_Db_Table_AbstractでZend_Cacheを利用して負荷軽減

どうも俺@ZendFrameworkを利用してWEBアプリを開発中です。

Zend_Db_Tableを継承してクラスを作成すれば、すでに様々なメソッドを持ったクラス(Bean)を作成することができます。
<?php
class MyBean extends Zend_Db_Table {
}

で、このZend_Db_Tableの生成は
<?php
$bean = new MyBean();
です。

<?php
var_dump($bean->info());
とすると、そのテーブルに関するメタデータ情報が連想配列で取得できます。

・name => テーブル名
・cols => テーブルのカラム名の配列
・primary => 主キーのカラム名の配列
・metadeta => カラム名とカラムに関する情報を関連付けた連想配列。discribeTable()と同じ内容
・rowClass => 行オブジェクト(Zend_Db_Table_Row)で使用するクラス名
・rowsetClass => 行セットオブジェクト(Zend_Db_Table_Rowset)で使用するクラス名
・referenceMap => このテーブルが参照する親テーブルの情報を含む連想配列
・dependentTables => このテーブルを参照しているテーブルのクラス名配列

で、このZend_Db_Tableですが、生成する度にdiscribetable()というメソッドが呼ばれテーブル情報を取得します。とても便利なのですが、都度DB接続が行われ非効率すぎるのでZend_Cacheを利用してデータをキャッシュさせておきます。
discribeTable()が走るタイミングは
・insert()
・find()
・info()
を呼んだ時だそうです。
※参照 Zend_Db_Table::メタデータのキャッシュ

<?php
$frontendOpt = array("automatic_serialization"=>true);
$backendOpt = array("cache_dir" => "/path/to/cache_dir");
$cache = Zend_Cache::factory("Core", "File", $frontendOpt, $backendOpt);
Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);

これを、index.phpなどに設定しておけばメタデータキャッシュを利用してくれます。

Zend_Cacheについては公式(Zend_Cache)を参照してね。
以上です。

2009年7月4日土曜日

ZendFramework + PostgreSQL で文字化けエラー

どうも俺です。
ZendFramework1.8+PostgreSQL8.3.7でPHP(5.2.6)アプリケーションを作成していたのですが、ハマったのでメモしておきます。

PostgreSQLは、データベース文字コードをSJISで作成できません。
なので携帯サイトでPHP(web)をSJISで作りたい場合は、PHP側の文字コードとPostgreSQL側の文字コードを変換しなければなりません。
一般的にはPostgreSQLは文字コードをEUC-JPかUTF8で作成します。
 $ createdb -E EUC-JP dbname


PHPではクエリを投げる前に
<?php
pg_set_client_encoding($connection, "SJIS");
とかやればイイのですが。。

ZendFrameworkでDB接続を行う場合は一般的に
<?php
$db = Zend_Db::factory("Pdo_Pgsql", array(
                   "host" => "localhost",
                   "dbname" => "dbname"));
のように使うと思います。(俺だけか?w)

この場合、全てのactionメソッドでDB接続をする度に
<?php
$db->query("SET NAMES 'SJIS'");
って処理させるのが面倒くさい!
<?php
Zend_Db::factory();
した際に自動でクライアント文字コードをSJISにしたい!
という事で2時間悩みました。。。

こんな場合はZend_Db::factory()の第2引数のパラメータに
<?php
$db = Zend_Db::factory("Pdo_Pgsql", array(
                   "host" => "localhost",
                   "dbname" => "dbname",
                   "charset" => "SJIS"));
とcharsetパラメータを追加すれば良いみたいです。

以上。・゚・(ノε`)・゚・。

2009年7月1日水曜日

Linuxリダイレクト処理めも

どうも俺です。
今日はLinuxの出力(標準出力、標準エラー出力)についてまとめておこうと思います。

まず、パイプについてですが、とあるコマンドの結果を別のコマンドへ引き継ぐ場合は
$ ls | grep foo
などとします。
これはlsした一覧からfooにマッチするものだけを表示します。

基本的に標準出力は
$ echo 'foo' > foo.log
で、'foo'をfoo.logに書き込みます。
追記書き込みの場合は
$ echo 'foo' >> foo.log
です。

標準出力と標準エラー出力を同じファイルへ書き出すには
csh tcshの場合
$ command >& foo.log
bashの場合
$ command > foo.log 2>&1
です。

標準出力と標準エラー出力を別々のファイルへ書き出すには
csh tcshの場合
$ (command > stdout.log) >& stderr.log
bashの場合
$ command > stdout.log 2> stderr.log
です。

標準出力だけファイルへ書き出して、標準エラー出力は書き出さない場合は
csh tcshの場合
$ (command > foo.log) >& /dev/null
bashの場合
$ command > foo.log 2> /dev/null
です。

とりえあずこれだけあれば、何とかなるはずです。
あとはみなさま調べてみてください。

以上。・゚・(ノε`)・゚・。