Zend_Loader_Autoloaderの使い方

れぶろぐ – [Zend] Zend_Loader_Autoloader クラスの正しい使い方

require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->unregisterNamespace(array('Zend_', 'ZendX_'))
           ->setFallbackAutoloader(true);

ZendFrammeworkを使って新しいプログラムを作ることになったので、噂できいていたZend_Loader::registerAutoload();がなくなって、Zend_Loader_Autoloaderを使うようにするってことに対応することにしました。

参考になる記事を見つけたので、メモ代わりに書いておきます。

Zend_Db_Tableでの勘違い

Zend Framework: Documentation

Zend_Db_Table で UPDATE や DELETE の連鎖操作をエミュレートする場合は、 配列 $_dependentTables を親テーブルで宣言し、 従属しているテーブルをそこで指定します。

各従属テーブルのクラス内で、配列 $_referenceMap を宣言します。これは、参照の “ルール” を定義する連想配列となります。 参照ルールとは、リレーションの親テーブルが何になるのか、 従属テーブルのどのカラムと親テーブルのどのカラムが対応するのかを示すものです。

引用した1つめの文章を読み飛ばしてしまっていたため、find~を使うためには、$_referenceMapと$_dependentTablesは、対を成す形式で記述するものだと勘違いしていました。onUpdateとかonDeleteをZendを使って実現しなければ、$_dependentTablesは不要ってことですね。

これだけのことなんですが、かなり「はっ!!」としました。
作っているプログラムの行が少なくなることは見やすくなっていいことです。

Zend_Db_Table の info()

Zend Framework: Documentation

info() メソッドが返す配列のキーについて、 以下にまとめます。

name => テーブルの名前。

cols => テーブルのカラム名を表す配列。

primary => 主キーのカラム名を表す配列。

metadata => カラム名とカラムに関する情報を関連付けた連想配列。 これは describeTable() メソッドが返す情報です。

rowClass => このテーブルインスタンスのメソッドが返す行オブジェクトで使用する 具象クラス名。デフォルトは Zend_Db_Table_Row です。

rowsetClass => このテーブルインスタンスのメソッドが返す行セットオブジェクトで使用する 具象クラス名。デフォルトは Zend_Db_Table_Rowset です。

referenceMap => このテーブルから任意の親テーブルに対する参照の情報を含む連想配列。 項15.8.2. 「リレーションの定義」 を参照ください。

dependentTables => このテーブルを参照しているテーブルのクラス名の配列。 項15.8.2. 「リレーションの定義」 を参照ください。

schema => テーブルのスキーマ (あるいはデータベース、あるいは表領域) の名前。

今まで、colsしかつかってなかったけど、primaryとかも結構使えるんじゃないかと読んでて思ったのでメモ。配列の中からテーブルのプライマリーキーの存在チェックして、存在したらfindで取得するとかに利用できそう。

Zend_Db_Table_Rowsetを拡張する2

以前、Zend_Db_Table_Rowsetを拡張するという記事をあげましたが、
不備というか使いづらい点があったので修正しました。

deleteト等を行う前に、foreach や、更新を行っていると、
rowset内カウンタの関係で、 validでfalseが返ってきたので、
処理の前後に、rewindでカウンタを0に戻す処理を追加しました。

class MyRowset extends Zend_Db_Table_Rowset_Abstract
{
  public function delete()
  {
    $this->rewind();

    if (!$this->valid()) { return; }
    foreach ($this as &$row) { $row->delete(); }
  }

  public function save()
  {
    $this->rewind();

    if (!$this->valid()) { return; }
    foreach ($this as &$row) { $row->save(); }

    $this->rewind();
  }

  public function __set($key, $value)
  {
    $this->rewind();

    if (!$this->valid()) { return; }
    foreach ($this as &$row) { $row->{$key} = $value; }

    $this->rewind();
  }
} 

Zend_Db_Table_Rowsetを拡張する

Zend_Db_Table_Rowsetのデータを削除したり、一括で更新したりするのに
foreach使っていたんですが、めんどうだなーと思って、拡張を考えました。

http://framework.zend.com/manual/ja/zend.db.table.rowset.html#zend.db.table.rowset.extending
上記を参考にして、以下のクラスを追加

class MyRowset extends Zend_Db_Table_Rowset_Abstract
{
    public function delete()
    {
        if (!$this->valid()) { return; }
        foreach ($this as $row) { $row->delete(); }
    }

    public function save()
    {
        if (!$this->valid()) { return; }
        foreach ($this as $row) { $row->save(); }
    }

    public function __set($key, $value)
    {
        if (!$this->valid()) { return; }
        foreach ($this as $row) { $row->{$key} = $value; }
    }
}

まだ動かしてないので、うまくいくかわからないけれど、メモとして残します。

あと、書き込み操作連鎖も初めて使ってます。
http://framework.zend.com/manual/ja/zend.db.table.relationships.html#zend.db.table.relationships.cascading

DBはMySQLで、外部キー制約を付けようと考えたのですが、対象テーブルにないキーが入ってしまうことがあるので、つけることができずに、上記の機能を利用することを考えました。
今までは、MySQLで外部キーつける権限がない時に使えるくらいの認識だったんですが、都合がいい部分だけ外部キー制約つけれるかもってことで、これは使えるんじゃないかと思います。

よく使うようになったメソッド

ZendFrameworkを使うようになってからよく利用するメソッド

・method_exists
・call_user_func_array

modelの中にメソッドがない場合に、中で利用しているオブジェクトの中を
method_existsで調べて、メソッドが存在したら、call_user_func_arrayで呼び出す。
こういう使い方をして、controllerからdaoのメソッドを呼び出しています。

エラー処理も大体パターン化してきたので、近いうちにのせようと思っています。
いろんな指摘をもらえて、よりいいものにできたらと考えています。

Zend_Soapを使ってみた

まだよくわかっていないけど、ドキュメントも英語だったので余計に。(英語苦手です)

wsdlファイルをパラメタに渡して、対象のメソッドをパラメタ渡して実行したら、
とりあえず通信はできたという状況。

使ったのはZend_Soap_Clientだけだから、Server側を作ってみないと、
全体像は見えてこないのかもしれない。
それに加えて、Soapがあまりわかってないから余計に理解が遅い。

XML_RPCとの通信手段としての長所、短所とか後で検索してみようと思う。

うれしい記事

このブログはhetemlで運営していて、
ZendFrameworkの実験もhetemlでやることが多いのです。

以前、hetemlでZendFrameworkが動かないっていう記事を見つけたので、
動きますよーとコメントさせていただいたところ、後日動いたそうなのです!

http://h2o-space.jp/blog/archives/337/comment-page-1
しかも、記事の中に僕の名前まで書いてくださっていました。とてもうれしかった!!

ZendFramework 1.7.5でもメールの件名は文字化け

短い件名だと問題なかったんですが、長くなると後半が化けてしまいました。
ので、今まで通り、Zend/Mail.phpのsetFromとsetSubjectを修正。
setSubjectは以下のように修正しました。

//$this->_subject = $this->_encodeHeader($subject);
mb_language('ja');
$lang = mb_internal_encoding();
mb_internal_encoding('ISO-2022-JP');
$this->_subject = mb_encode_mimeheader($subject, 'ISO-2022-JP');
mb_internal_encoding($lang);

setFromも同じ要領で。

ZendFramework 1.7.5へ

ZendFramework1.5.2から現状不足している機能がなかったので、
そのままバージョンアップしてなかったんですが、今回Zend_Dateの日付計算で
不具合が出たので、最新の1.7.5にバージョンアップしました。

嬉しかった点は、Zend/Mail.phpの中身を編集しなくても
文字化けをしないように設定できるようになった部分。
これをやるのがおっくうでバージョンアップしてなかったのもあったので。
こんなふうにsetEncodingOfHeadersでbase64を指定できるようになってました。

public static function sendInfo($params)
{
  $mail = new Zend_Mail('ISO-2022-JP');
  $mail->setEncodingOfHeaders(Zend_Mime::ENCODING_BASE64);
  $mail->setBodyText(self::_encode(trim($params['body'])), 
            null, 
            Zend_Mime::ENCODING_7BIT)
     ->setSubject(self::_encode($params['subject']))
     ->setFrom('yyyy@yyyy', 'zzzz');
     ->addTo('xxxx@xxxxxx');
     ->send();
}

private static function _encode($str)
{
  return mb_convert_encoding($str, 'ISO-2022-JP', 'UTF-8');
}

少しはまったのが、Zend_Date。new Zend_Date(‘xxxx-xx-xx’)とやると
クラスを生成できてたのですが、Localeがうまく取得できなくなっているようでした。
以前、ソースをおったときは、ブラウザから情報を取得していたし、
今回ざっと見た時もそれっぽい部分があったのですが、なぜかLocaleでエラーになります。

Zend_Registryを使って、’Zend_Locale’に’ja_JP’を設定しておけば、
設定したLocaleを利用してくれるので、index.phpで設定して問題を回避しました。
ソースをちゃんと見たいところですが、今は問題解決が先です。