2013年10月31日木曜日

CakePHP データ型による input 項目の決定方法

CakePHPのバージョンが 1.x の時も調べたような気がするのだけども、忘れたので備忘録として 2.x の仕組みをさぐる。 正直、ここら辺の実装の仕方は、気に入らない部分なんですよね。 まず、label タグと、input タグが混ざってコード中に隠蔽されていて、デザインの介在する余地が無い。1.x 時よりは、だいぶ良くなっている気がするけど、それでもダーティで、とてもDRYの原則に沿った修正ができるような代物ではない。改造しようと思ったら、ここら辺の仕組みを、ほぼ書き直ししないといけない。もしくは個別に何度も同じ作業を手作業で繰り返しながら個別に指定するかだ。
FormHelper::input( $field, $options );
で呼び出される $options は、テンプレート・ベースでは、通常 null だ。
その場合、FormHelper::_magicOptions($options) により、デフォルトのオプションが構築される。
そして、ここで input タグが text なのか select なのか checkbox なのか・・・と決定されるのである。
やるなら、_magicOptions をラップした public な magicOptions 関数を作成して、テンプレートの Form::input 呼びだし直前で options を取得し、その options の値を元に、デザインを細かく変更できるようにリファクタリングが、一番の近道だろうか?
  protected function _magicOptions($options) {
    $modelKey = $this->model();
    $fieldKey = $this->field();
    $options['type'] = 'text';
    if (isset($options['options'])) {
      $options['type'] = 'select';
    } elseif (in_array($fieldKey, array('psword', 'passwd', 'password'))) {
      $options['type'] = 'password';
    } elseif (in_array($fieldKey, array('tel', 'telephone', 'phone'))) {
      $options['type'] = 'tel';
    } elseif ($fieldKey === 'email') {
      $options['type'] = 'email';
    } elseif (isset($options['checked'])) {
      $options['type'] = 'checkbox';
    } elseif ($fieldDef = $this->_introspectModel($modelKey, 'fields', $fieldKey)) {
      $type = $fieldDef['type'];
      $primaryKey = $this->fieldset[$modelKey]['key'];
      $map = array(
        'string' => 'text', 'datetime' => 'datetime',
        'boolean' => 'checkbox', 'timestamp' => 'datetime',
        'text' => 'textarea', 'time' => 'time',
        'date' => 'date', 'float' => 'number',
        'integer' => 'number'
      );

      if (isset($this->map[$type])) {
        $options['type'] = $this->map[$type];
      } elseif (isset($map[$type])) {
        $options['type'] = $map[$type];
      }
      if ($fieldKey == $primaryKey) {
        $options['type'] = 'hidden';
      }
      if (
        $options['type'] === 'number' &&
        $type === 'float' &&
        !isset($options['step'])
      ) {
        $options['step'] = 'any';
      }
    }

    if (preg_match('/_id$/', $fieldKey) && $options['type'] !== 'hidden') {
      $options['type'] = 'select';
    }

    if ($modelKey === $fieldKey) {
      $options['type'] = 'select';
      if (!isset($options['multiple'])) {
        $options['multiple'] = 'multiple';
      }
    }
    if (in_array($options['type'], array('text', 'number'))) {
      $options = $this->_optionsOptions($options);
    }
    if ($options['type'] === 'select' && array_key_exists('step', $options)) {
      unset($options['step']);
    }
    $options = $this->_maxLength($options);
    return $options;
  }

0 件のコメント: