ITの隊長のブログ

ITの隊長のブログです。Rubyを使って仕事しています。最近も色々やっているお(^ω^ = ^ω^)

【CakePHP】FormHelperでselect boxの中のoptionタグにattributeを指定したいとき

久々に早めの帰宅ができたので、ちょっくら走ってきました。やっぱり体動かすって気持ちいいね!

すっきり気分なので、久々にブログ書く。

FormHelperでselect boxの中のoptionタグにattributeを指定したいとき

CakePHPのFormHelperでselect boxを出力したいとき

<?php
...
$this->Form->input('select_field', [
  'type' => 'select',
  'options' => $result
])

こんな感じですよね。このとき、$resultの中身は

<?php
...
$result = [
  $id => $value,
  $id2 => $value2,
  $id3 => $value3,
];

こんな感じのリストが並んでいると思います。これを実行すると

<select name="data[select_field]">
  <option value="$id">$value</option>
  <option value="$id2">$value2</option>
  <option value="$id3">$value3</option>
</select>

とまぁ。こうなりますよね。

さて、今回やりたかったことは、この<option>のタグに属性(attribute)を持たせたいとき、どうするか。

こうしました。

<?php
...
/**
 * @return array|null
 */
public function getDataForSelectList() {
  $data = $this->find('all', [
      'order' => ['User.created' => 'ASC']
  ]);
  $result = [];
  foreach($data as $k => $v) {
      $pack = [
          'name' => $v['User']['users_name'], // <option>ここの値</option>
          'value' => $v['User']['id'],        // <option value="ここの値"></option>
          'data-email' => $v['User']['email'] // <option data-email="ここの値"></option>
      ];
      $result[$k] = $pack;
  }
  return $result;
}

連想配列で、複数keyをもたせればそれが属性になるらしいです。ただし、namevalueは忘れないようにですね。これでうまく動かすことが出来ました。しかしよく出来ているねぇ。

せっかくだからFormHelperのその箇所を読んでみる

  • lib/Cake/View/Helper/FormHelper.php:2775
<?php
...
    protected function _selectOptions($elements = array(), $parents = array(), $showParents = null, $attributes = array()) {
        $select = array();
        $attributes = array_merge(
            array('escape' => true, 'style' => null, 'value' => null, 'class' => null),
            $attributes
        );

このメソッドの中にありました。まずは2809行目

  • lib/Cake/View/Helper/FormHelper.php:2809
<?php
            $htmlOptions = array(); // ここは2786行目
            if (is_array($title) && (!isset($title['name']) || !isset($title['value']))) {
...
            } elseif (is_array($title)) {
                $htmlOptions = $title;
                $name = $title['value'];
                $title = $title['name'];
                unset($htmlOptions['name'], $htmlOptions['value']);
            }

見た感じ。namevalueがセットされているなら、2809行目から処理されると思います。んで、ここでvalue$name<option>でいうvalue属性)へ、name$title<option>タグでいうテキスト)へ値を渡して、unsetしています。

ということは先ほどのコードを実行してここの中を確認すると$htmlOptionsの中には'data-email' => $v['User']['email']の値がまだ残っています。

これが属性の値として渡されるのはここ2873行目

  • lib/Cake/View/Helper/FormHelper.php:2869
<?php
...
                    } else {
                        if ($attributes['escape']) {
                            $name = h($name);
                        }
                        $select[] = $this->Html->useTag('selectoption', $name, $htmlOptions, $title); // 2873行目
                    }

この$this->Html->useTag()は渡される引数$name$htmlOptions$titleをそれぞれ配列かどうか確認して、配列であれば属性としてタグに設置して値をかえしてくれます。つまりは先ほどのunset処理から値が残った$htmlOptionsの中身にある'data-email' => $v['User']['email']が、そのまま属性として<option>へ渡されることになります。