nmtysh.log

Tech系のネタや日々の独り言などを書いています。

FormHelperでoptgroupを使う場合はshowParentsをtrueにする

CakePHPのFormHelperを使ってselectのoptgroup/optionを出力したのですが、一部のoptionが出力されませんでした。

<?php
$options = [
    'AAAA' => [
        1 => 'A',
        2 => 'AA',
        3 => 'AAA',
        4 => 'AAAA' // <- これが出力されない
    ],
    'BBBB' => [
        5 => 'B',
        6 => 'BB',
        7 => 'BBB',
        8 => 'BBBB' // <- これが出力されない
    ]
];
echo $this->Form->input('Select', ['type' => 'select', 'options' => $options]);

最初は不具合かと思い、ソースコードを調べてみました。

そうするとoptionの出力をスキップする怪しいところがありました。

<?php
...
if ($showParents || (!in_array($title, $parents))) {
    $title = ($attributes['escape']) ? h($title) : $title;
    $hasDisabled = !empty($attributes['disabled']);
...

$parents にはoptgroupのlabelが格納されています。
$showParentstrue あるいはoptgroupでその名前が(まだ)使用されていない場合にoptionを出力しているようです。

ここで showParents について調べてみると FormHelper->select() のコメントにこのオプションについての説明がありました。

<?php
/**
 * Returns a formatted SELECT element.
 *
 * ### Attributes:
 *
 * - `showParents` - If included in the array and set to true, an additional option element
 *   will be added for the parent of each option group. You can set an option with the same name
 *   and it's key will be used for the value of the option.
(略)
 * While a nested options array will create optgroups with options inside them.
 * ```
 * $options = array(
 *  1 => 'bill',
 *  'fred' => array(
 *     2 => 'fred',
 *     3 => 'fred jr.'
 *  )
 * );
 * $this->Form->select('Model.field', $options);
 * ```
 *
 * In the above `2 => 'fred'` will not generate an option element. You should enable the `showParents`
 * attribute to show the fred option.
(略)
 */

ラベルと同じoptionを出すには showParentstrue にすることとあります。

<?php
echo $this->Form->input('Select', ['type' => 'select', 'options' => $options, 'showParents' => true]);

showParentstrue にすることで正しく出力されるようになりました。

ドキュメント には書かれていないんですよねこれ。
困った時はまずはソースコードを確認することが一番ですね。