ラベル ZendFramework の投稿を表示しています。 すべての投稿を表示
ラベル ZendFramework の投稿を表示しています。 すべての投稿を表示

2010年9月15日水曜日

zend frameworkでルーターの設定をiniファイルで行う

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

今日はZendFrameworkでルーティングの設定(Zend_Controller_Router_Route)を直接コードに書かずにiniファイルで行う設定方法の備忘録です。

1)通常のルーティング
$ vim configs/router.ini
-------------------------------
routes.default.type = "Zend_Controller_Router_Route"
routes.default.route = ":controller/:action/*"
routes.default.defaults.module = "module_name" ; モジュール名
routes.default.defaults.controller = "index" ; デフォルトコントローラ名
routes.default.defaults.action = "index" ; デフォルトアクション名

$ vim public/index.php
-------------------------------
$router = Zend_Controller_Front::getInstance()->getRouter();
$config = new Zend_Config_Ini(APPLICATION_PATH . "/configs.router.ini");
$router->addConfig($config, "routes");
これであれば
http://koexuka.blogspot.com/foo/bar/
というURLでアクセスのあった場合、「module_name」モジュールの「foo」コントローラの「bar」アクションが呼ばれます。


2)ホスト名によるルーティング
$ vim configs/router.ini
--------------------------------
; デフォルト
routes.default.type = "Zend_Controller_Router_Route"
routes.default.route = ":controller/:action/*"
routes.default.defaults.module = "module_name"
routes.default.defaults.controller = "index"
routes.default.defaults.action = "index"

; 携帯用
routes.mobile.type = "Zend_Controller_Router_Route_Hostname"
routes.mobile.route = "m.koexuka.blogspot.com"; ホスト名はm
routes.mobile.defaults.module = "mobile"; mobileモジュールへ
routes.mobile.defaults.controller = "index"
routes.mobile.defaults.action = "index"
routes.mobile.chains.path.type = "Zend_Controller_Router_Route"
routes.mobile.chains.path.route = ":controller/:action/*"
routes.mobile.chains.path.defaults.controller = "index"
routes.mobile.chains.path.defaults.action = "index"

$ vim public/index.php
-------------------------------
$router = Zend_Controller_Front::getInstance()->getRouter();
$config = new Zend_Config_Ini(APPLICATION_PATH . "/configs.router.ini");
$router->addConfig($config, "routes");
これで
http://m.koexuka.blogspot.com/foo/bar
というURLでアクセスのあった場合、「mobile」モジュールの「foo」コントローラの「bar」アクションが呼ばれます。


設定ファイルを利用した方がよりスマートだと思います。

以上でぇぇえぇす。

2010年9月10日金曜日

ZendFrameworkでモジュール別Bootstrapを用意すると全て実行されてしまう

どうも、俺@始業です。
忘れないうちにメモメモ。

Zend Frameworkはモジュール別Bootstrap.phpを用意して利用すると、どのモジュールですべてのBootstrapクラスにある_initXX()メソッドが実行されてしまいます。

モジュールの設定
$ vim application.ini
--------------------------------
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.modules[] =

fooモジュールとbarモジュールがあった場合は
$ vim modules/foo/Bootstrap.php
--------------------------------
class Foo_Bootstrap extends Zend_Application_Module_Bootstrap {
protected function _initFoo() {
// 何らかの前処理
}
}

$ vim modules/bar/Bootstrap.php
---------------------------------
class Bar_Bootstrap extends Zend_Application_Module_Bootstrap {
protected function _initBar() {
// 何らかの処理
}
}
↑↑どこのモジュールからでも両方のメソッドが実行されてしまう。
なんかモジュール毎にBootstrap置く意味がないですね。というかこれだったら
application/Bootstra.php内にすべて処理を済ませてしまえば良いのです。

なのでモジュールごとにBootstrapを実行させる方法をめも。
※ココを参考にしました。Phly, boy, phly
要は各Bootstrap内で、プラグインを登録しそこで処理を実行させちゃいなよ、YOU。ということです。
$ vim modules/foo/Bootstrap.php
--------------------------------
class Foo_Bootstrap extends Zend_Application_Module_Bootstrap {
protected function _initFoo() {
$this->bootstrap("FrontController");
$front = $this->getResource("FrontController");
$front->registerPlugin(new My_Plugin_Foo()); // ここでプラグイン登録
}
}

次にプラグインを作成します。
$ vim My/Plugin/Foo.php
--------------------------------
class My_Plugin_Foo extends Zend_Controller_Plugin_Abstract {
/**
* @Override
*/

public function dispatchLoopStartup(Zend_Controller_Requset_Abstract $req) {
if ($req->getModuleName() != "foo") { // ちょっとアナログな感じ、、
return;
}

// ここに処理
}
}
これでOKです。
barモジュールも同様にすれば良いです。
また処理ごとにMy_Plugin_Foo_XXとか My_Plugin_Foo_YYとかクラスを分けた方が分かりやすいと思います。


ただ、注意するのはモジュール内のBootstrapでプラグインを登録する方法だと、
実際に処理が実行されるタイミングがルータが動作した後だったりするので、完全な意味での「前処理」が出来ない場合もあるので注意しましょう。


では、次回はもう1つの方法をメモしときまぁぁす。

2010年9月8日水曜日

zend frameworkでZend_Filterを設定かつZend_Layoutを使うと文字化け

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

タイトルの通り、zend framework(v1.10.8)でZend_Filterを使ってviewにフィルタをかけて(実際は絵文字変換)、さらにZend_Layoutを利用すると文字化けが発生してしまいました。

Zend_Filterはこんな感じ(省略してます)
<?php
class My_View_Filter implements Zend_Filter_Interface {
public function filter($output) {
return mb_convert_encoding($output, "SJIS-win", "UTF-8");
}
}

で、コントローラのinit()メソッドで
public function init() {
$this->view->setFilterPath("My/View", "My_View_")->addFilter("Filter");
}
としてフィルタをセットしています。
レイアウトはapplication.iniの設定で
resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_PATH "/views/layouts"
としてレイアウトを有効にしています。

これだと、どうやらそれぞれのviewスクリプトに対しフィルタがかかり、さらに全てのviewスクリプトを含んだlayout.phtmlでさらにフィルタがかかるという2重フィルタ処理で文字化けが起こっているようです。

※このブログでも言及されていました。骨折り損のくたびれ儲け::ZendFrameworkで携帯 文字化け対応

上記のブログと同じ現象なのでこれで解決かな?と思ったのですが、なぜかうまくいきません。
1)独自のZend_Layout_Controller_Plugin_Layoutを拡張したクラスを作成
<?php
class My_Layout_Controller_Plugin_Layout extends Zend_Layout_Controller_Plugin_layout {
plubic function postDispatch(Zend_Controller_Request_Abstract $request) {
parent::postDispatch($request);
$filter = new My_View_Filter();
$this->getResponse()->setBody($filter->filter($this->getResponse()->getBody()));
}
}

2)application.iniに追記
resources.layout.pluginClass = "My_Layout_Controller_Plugin_Layout"


やり方が間違っているのか、、でも上のpostDispatch()メソッドで親クラスのを一度呼び出してるから文字化けするんじゃ??とも思うのですが、、
正しい方法があれば教えてください><

で、解決方法ですが、↑で作ったクラスなどはそのままにしておいてZend_View_Abstractクラスのrender()メソッドをちょこっと変更すればできます。
public function render($name) {
-- 中略 --
// return $this->_filter(ob_get_clean());
return ob_get_clean();
}


Zend_View_Abstractクラスを拡張しても良いかもしれませんね。

以上でぇぇす。

-- 2010.09.08 追記 --
Zend_Viewクラスを拡張したバージョンを作りました。
まず拡張クラスを作ります。
<?php
class My_View extends Zend_View {
private $_file = null;
// 一応
private $_useViewStream = false;
private $_useViewStreamWrapper = false;

public function render($name) {
$this->_file = $this->_script($name);
unset($name);

ob_start();
$this->_run($this->_file);
return ob_get_clean(); // ここは親クラスと違う
}
}

次はこの拡張Viewクラスを使うようindex.phpか、またはBootstrapに(※この例ではBootstrapを利用)
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
protected function _initView() {
$view = new My_View(array()); // コンストラクタの引数はViewに渡すオプション配列、またはZend_Config
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper("ViewRenderer");
$viewRenderer->setView($view);
}
}

以上でーす。

2010年6月9日水曜日

zend frameworkでレスポンスヘッダを扱う

どうも、俺@定時間際です。

今日は前回「ZendFrameworkでViewを無効化する」のつづきのお話になるのですが、Viewのレンダリングを無効化しレスポンスヘッダを開発者の思うように返す方法についてめもめも。

Zend_Controller_Actionの派生クラス内でレスポンスヘッダを変更する場合は
<?php
$response = $this->getResponse();
$response->setHeader("Content-Type", "image/gif"); // 例えば画像出力
// $response->setRedirect("http://google.co.jp", 302); // 例えばリダイレクト

$response->sendResponse();
これ。

やり方たくさんあるっぽいので、もっと便利な別の方法もできますね。


以上。どぇぇぇす。

2010年6月3日木曜日

ZendFrameworkでViewを無効化する

どうも、俺@仕事中 今日2度目の投稿です。
ZendFrameworkを使っていて、Viewを無効化(Viewレンダリングを無効煮する)方法についてめもめも。

やりたい事は、ZendFrameworkで受け付けたリクエストを処理して別サイトへリダイレクトするだけのコントローラーを作る!というものです。


Zend_Controller_Actionを継承したコントローラを作成し、init()メソッドで
$rediretor = $this->_helper->getHelper("Redirector"); // リダイレクトに関する処理をまとめて行う。
$redirector->setCode(302); // ステータスコードを302にセット
$redirector->setExit(true); // リダイレクトの後exit();を行う。

$this->_helper->getHelper("ViewRenderer")->setNeverRender(true); // viewのレンダリングを行わない。
のようにすれば、リダイレクトの処理とViewのレンダリング無効化を初期処理にて行えます。


詳しくはZend Framework アクションヘルパーまで


以上でぇぇぇす(´・ω・`)

2010年5月19日水曜日

Zend Frameworkでモジュール単位でBootstrap.phpを使うとエラー(Warning)

どうも、俺@残業中です。
今日はZendFrameworkでモジュールディレクトリ直下にBootstrap.phpを設置するとエラーになる対処法です。

ZFのバージョンは1.10.4です。

モジュールディレクトリ下に設置したファイルは
<?php
class Module_Bootstrap extends Zend_Application_Module_Bootstrap {
}
です。
これだと
 Warning: include_once(FrontController.php) [function.include-once]: failed to open stream: No such file or directory in...
というエラーがでます。

どうやらこれ、
http://framework.zend.com/issues/browse/ZF-6658
で上がっているようなバグらしいのですが、バージョン1.9で修正されたような事が書いてあるのです。
あれ?俺は1.10使ってるけど、、、?
で見てると
http://framework.zend.com/issues/browse/ZF-7696
に、
Fixed in r22124
と書かれてます。

それを参考に
# vim Zend/Application/Bootstrap/BootstrapAbstract.php
348 if (false !== $pluginName = $this->_loadPluginResource($plugin, $spec)) {
349 if (0 === strcasecmp($resource, $pluginName)) {
350 return $this->_pluginResources[$pluginName];
351 }
352 continue; // ここ追加
の352行目を追加してあげれば良いようです。(たぶん)


以上でぇぇす。

2010年4月6日火曜日

Zend_Db_Selectの便利な使い方

どうも、俺@風呂上りです。

今日はZend Frameworkで用意されているZend_Db_Selectクラスを使った便利な方法をメモします。
ま、ZendFrameworkの公式にあるので、そちらを参考に!

Zend Frameworkのコンポーネント達はそのフレームワークを利用せずとも、組み込めるように作られているので、そういう使い方もできますよ(´・ω・`)

インスタンスの生成は、
<?php
$select = new Zend_Db_Select(Zend_Db_Adapter $db);
これでZend_Db_Selectのインスタンスが生成されます。

Where句は、
<?php
$select->where("id = ?", $id_param, Zend_Db::INT_TYPE);
// WHERE id=$id_param
で作れます。
続けて書けば、
<?php
$select->where("id = ?", $id_param, Zend_Db::INT_TYPE);
$select->where("name = ?", $name_param);
// WHERE id=$id_param AND name='$name_param'
のようになり、
<?php
$select->where("id = ?", $id_param, Zend_Db::INT_TYPE);
$select->orWhere("name = ?", $name_param);
// WHERE id=$id_param OR name='$name_param'
になります。

Order by句は、
<?php
$select->order("id");
// ORDER BY id

<?php
$select->order("id DESC");
// ORDER BY id DESC
になります。

Limit Offset句は、
<?php
$select->limit(30, 10);
// LIMIT 30 OFFSET 10 または LIMIT 30, 10
でできます。

Group by句は、
<?php
$select->group("id");
// GROUP BY id
です。

で、ここがとても感動したポイントですが、取得したカラムやテーブルの指定する方法は、
<?php
$select->from("foo_table");
// SELECT * FROM foo_table

<?php
$select->from(array("foo" => "foo_table"), "id");
// SELECT foo.id FROM foo_table AS foo
となるのです(´・ω・`)
カラムにエイリアス(別名)をつける場合は、
<?php
$select->from(array("foo" => "foo_table"), array("id_aliase" => "id"));
// SELECT foo.id AS id_aliase FROM foo_table AS foo
です。
途中でカラムを追加するには、
<?php
$select->from(array("foo" => "foo_table"), array("id_aliase" => "id"));
$select->columns("name", "name_aliase");
// SELECT foo.id AS id_aliase, foo.name AS name_aliase FROM foo_table AS foo
です。
一気に大量のカラムを書きたい場合は、
<?php
$select->from(array("foo" => "foo_table"), array("id", "name", "birthday", "address",....));
のようにします。



ということは、これらをまとめると、
<?php
$select = new Zend_Db_Select(Zend_Db_Adapter $db);
$select->from(array("foo" => "foo_table"), array("id", "name"));
$select->where("id IN (". implode(",", $id_list).")");
$select->order("id DESC");
$select->limit(30, 10);
// SELECT foo.id, foo.name FROM foo_table AS foo WHERE id IN (x,x,x,x,x) ORDER BY id DESC LIMIT 30 OFFSET 10;
のようになるわけです。

これにZend_Db_Adapterを利用して、
<?php
$result_set = $db->fetchAll($select);
とかやると、一発で配列でデータを取得できたり、
<?php
$stmt = $db->query($select);
while ($rs = $stmt->fetch()) {
// 処理
}
のように1レコードずつデータ処理を行ったりできます。

ちなみに、クエリ文字列を取得するには、
<?php
$query = $select->__toString();
でできますし、Where句だけ取りたいという場合は
<?php
$wheres = $select->getPart(Zend_Db_Select::WHERE);
// where句すべてを配列で取得できるのであとで、implode()とかやれば使える
で取れます。

いやぁ、超便利ーー(´・ω・`)

2010年1月29日金曜日

Zend_Db_Table_Row::refresh()について

どうも、俺@仕事中@スノボ前です。

今日久しぶりにZend_Framework案件でソース書いてて、抽象クラスZend_Db_Table_Row_Abstractの
protected $_cleanData
protected $_data
って「これわな~に?おいしいの?」と思ってました。

オブジェクトに値をセットしてvar_dump($zend_db_table_row)してみると、両方のフィールドに同じ値がセットされています。
公式にも詳しい説明がなかったのですが、
どうやらこれは、DBからSELECTしてきたデータは「$_creanData」に、後でセットした値が「$_data」に入っているようです。
で、
$zend_db_table_row->refresh()
メソッドを使ってrefresh()すると、$_dataフィールの値がリセットされて$_cleanDataになりました!

つまり、フォームからユーザがデータを入力してエラーチェックした結果、エラーが存在して元に値に戻したいとき、refresh()メソッドで値を元に戻せちゃいます。
なんて便利な!


以上、どえぇぇぇぇす。

2009年10月31日土曜日

Zend_Db_Adapter_Abstractを継承した拡張自作Adapter

どうも、俺@遊び帰宅です。
眠いっす。

Zend Frameworkを使ってWebアプリケーションを作ってて
「あー、DBへのクエリのログ取りたいなー」ってよくあると思います。
特にトランザクションの発生するクエリに関しては、Webプログラマとしては必需品だと思います。

方法はすべてのXXController内でクエリを発行する度に
<?php
// Zend_Db_Adapter_Abstractでクエリ発行
$adapter->query("INSERT INTO foo_table (column) VALUES ('value')");

// Zend_Db_Profiler
$profiler = $adapter->getProfiler();
$queries = $profiler->getQueryProfiles(Zend_Db_Profiler::INSERT);
if (is_array($queries)) {
foreach ($queries as $query) {
file_put_contents($filename, $query->getQuery());
}
}
と、簡単なサンプルを書くとこんな感じでしょうか。

ただ、これだとクエリを発行する度にZend_Db_Profilerを生成し、ログを取得しなければなりません。
面倒くさいです。

そんな面倒くさがりな貴方にはZend_Db_Adapter_Abstractを継承した自作クラスを作成することをオススメします。
例えばPostgreSQLを使っている場合は
<?php
/**
* Zend_Db_Adapter_Pdo_Pgsqlを継承した自作アダプター
*/
class MyPdoPgsql extends Zend_Db_Adapter_Pdo_Pgsql {
/**
* @Override
*/
public function insert($table, array $bind) {
// 略 Zend_Db_Adapter_Pdo_Pgsql::insert()と同じ処理

// Zend_Db_Profilerでログる
$profiler = $adapter->getProfiler();
$queries = $profiler->getQueryProfiles(Zend_Db_Profiler::INSERT);
if (is_array($queries)) {
foreach ($queries as $query) {
file_put_contents($filename, $query->getQuery());
}
}
}


/**
* @Override
*/
public function update($table, array $bind, $where) {
// 略 Zend_Db_Adapter_Pdo_Pgsql::update()と同じ処理

// Zend_Db_Profilerでログる
$profiler = $adapter->getProfiler();
$queries = $profiler->getQueryProfiles(Zend_Db_Profiler::UPDATE);
if (is_array($queries)) {
foreach ($queries as $query) {
file_put_contents($filename, $query->getQuery());
}
}
}

public function delete($table, $where = '') {
// 以下同じ
}
}
このようにinsert/update/deleteメソッドにログ処理を書いてZend_Db_Adapterの子クラスを作成します。

あとはindex.php内の処理でZend_Db_Adapter_Abstractを生成するときに
<?php
$db = new MyPdoPgsql($options);
Zend_Db_Table_Abstract::setDefaultAdapter($db);
のようにデフォルトアダプターをセットしておけば、全てOK!!

基本的にZend FrameworkのクエリはZend_Db_Adapter_Abstractを経由して発行されるので、あとは自動でログを取ってくれます。
他にもトランザクションや例外処理も全てこの中に書けば、面倒なことを書かずに済みますね。


以上、面倒くさがり屋さんへ。

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月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月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パラメータを追加すれば良いみたいです。

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