Zend_FormのデコレータとZend_Config_Xmlに関する困ったメモ

Zend_Formに定義ファイルでデコレータを流し込む際のハマりどころについてメモしておきます。
XMLでの指定についてなのですが、まず、XMLのルートノードについては基本的になんでもよいのですが、第1階層はセクションとして扱われます。
セクション直下の動作では、セクションを配列のキーにしてエントリーが子要素になってわかりやすいのですが、第2階層以下では列挙型にするときの動作に差が出ます。
以下の記述では、セクション直下以降での設定を前提にしています。

基本の1

<decorators>
	<decorator value="HtmlTag">
		<options>
			<tag value="div" />
		</options>
	</decorator>
</decorators>

これは、Zend_Form等にdecoratorsを設定で流し込むときに使える書き方です。
HtmlTagというデコレータにオプションでtag=>divを設定したものがロードされます。

simplexml_load_file等の仕様でデータ構造とXML記法的なギャップについて

http://d.hatena.ne.jp/noopable/20090325/1237933832
こちらで書いた、simplexml_load_file関係の挙動に関連しているのですが、デコレータを増やすとどうなるか

<decorators>
	<decorator first="HtmlTag">
		<options>
			<tag value="p" />
		</options>
	</decorator>
	<decorator second="HtmlTag">
		<options>
			<tag value="div" />
		</options>
	</decorator>
</decorators>

これで、動作してくれるとよいのですが、simplexml_load_file、およびZend_Config_Xmlの仕様(?)でdecoratorというエントリーが二つあると、decorator配下にキーなしで配列が組み込まれます。
結果としてこの書き方では動作しません。
代わりに、

<decorators>
	<decorator first="HtmlTag">
		<options>
			<tag value="p" />
		</options>
	</decorator>
</decorators>
<decorators>
	<decorator second="HtmlTag">
		<options>
			<tag value="div" />
		</options>
	</decorator>
</decorators>

配列の記法的に本来的にはdecorators以下に配列としてスタックしてほしいわけですが、Zend_Config_Xmlでそれを実現するには、親側のdecoratorsを並べる必要があります。
これで、動いてくれるとよいのですが、この書き方ではやはり動作しません。ここからはZend_Form関係のaddDecorators内の仕様の影響です。動くように書くには

<decorators>
	<decorator first="HtmlTag">

	</decorator>
	<options>
		<tag value="p" />
	</options>
</decorators>
<decorators>
	<decorator second="HtmlTag">
	</decorator>
	<options>
		<tag value="div" />
	</options>
</decorators>

オプションを入れ子にせず、外に出します。単数のときは、入れ子にする必要があり、複数使うときは入れ子から出さなければいけません。
ですので、入れ子から出した場合は単独では使えません

<decorators>
	<decorator first="HtmlTag">

	</decorator>
	<options>
		<tag value="p" />
	</options>
</decorators>

調整できるか

Zend_Config_Xmlで、その辺の動作をさせている部分は、Zend_Config::_toArray内の配列の構築部分です。

<?php
                if (array_key_exists($key, $config)) {
                    if (!is_array($config[$key]) || !array_key_exists(0, $config[$key])) {
                        $config[$key] = array($config[$key]);
                    }

                    $config[$key][] = $value;
                } else {
                    $config[$key] = $value;
                }

こんな感じで、既にキーがあるとき(同じ親の下で同じキーが重複した場合)配列を数値添字で結合していきます。
Zend_Config_Xmlではzfというnamespaceが使えるので、namespaceを使って、特定の要素をcollection用に数値添字にするように書き換えれば問題は減りそうですが、当面、書き方を覚えて対応しておくことにしました。