FuelPHPのFieldsetをフィールドごとに出力する機能を追加してみた

FuelPHPのよく使う機能をPackageとして切り出してみるその③

## パッケージ名
Fieldset ([Github](https://github.com/ohnaka0410/FuelPHP-Fieldset))

## 概要
Fieldsetクラスにフィールドごとに出力する機能を追加するパッケージ

## 作った動機
Fieldsetクラスを使うと、バリデーション内容をコントローラに書かなくてもよいため、コントローラの肥大化を防ぐことができる。
ただし、フォームをまるごと生成してしまうため、スタンダードなレイアウトのフォームにしか対応できない。
そこで、フィールド毎に分けて生成するようにしてみた。

## 使い方(実装例)
### パッケージの読み込み
```php:fuel/app/config/config.php
return array(
	'always_load'  => array(
		'packages'  => array(
			// パッケージをロード
			'fieldset',
		),
	),
);
```

### フォームのフィールドに合わせてFieldsetクラスを拡張する
```php:fuel/app/classes/fieldset/sample.php
class Fieldset_Sample extends \Fuel\Fieldset\Fieldset
{
	/**
	 * Create Fieldset object
	 *
	 * @param   string    $name    Identifier for this fieldset
	 * @param   array     $config  Configuration array
	 * @return  Fieldset
	 */
	public static function forge($name = null, array $config = array())
	{
		$fieldset = parent::forge(name, config);

		// add name
		$fieldset->add(
			'name',
			'Full name',
			array(
				'type' => 'name',
				'class' => 'pretty_input'
			),
			array(
				array(
					'required'
				),
				array(
					'valid_string',
					array(
						'alpha-numeric',
						'dots',
						'spaces'
					)
				)
			)
		);

	}
}

```

### フォーム用のコントローラを作成する
```php:fuel/app/classes/controller/sample.php
class Controller_Sample extends Controller
{
	/**
	 * Index Action
	 *
	 * @return  string
	 */
	public function action_index()
	{
		$fieldset = Fieldset_Sample::forge();

		$mode = Input::post('button');

		if ($mode === 'confirm')
		{
			// confirm
			$validation = $fieldset->validation();

			if ($validation->run())
			{
				// validation OK
				$fields = $validation->validated();

				// create view
				$view = Presenter::forge('sample/confirm');
				// set fields
				$view->set('fields', $fields);
				// show confirm view
				return Response::forge($view);
			}
			else
			{
				// validation NG

				// set input values
				$fieldset->repopulate();
			}
		}
		else if ($mode === 'exec')
		{
			// exec
			$validation = $fieldset->validation();

			if ($validation->run())
			{
				// validation OK
				$fields = $validation->validated();

				// Do Exec

				// redirect to complete
				Response::redirect('sample/complete', 'location', 303);

			}
			else
			{
				// validation NG

				// set input values
				$fieldset->repopulate();
			}
		}
		else if ($mode === 'back')
		{
			// back

			// set input values
			$fieldset->repopulate();
		}

		// create view
		$view = Presenter::forge('sample/input');
		// set fields
		$view->set_safe('fields', $fieldset->build_field());
		// show confirm view
		return Response::forge($view);
	}

	/**
	 * Complete Action
	 *
	 * @return  string
	 */
	public function action_complete()
	{
		// create view
		$view = Presenter::forge('sample/complete');
		// show complete view
		return Response::forge($view);
	}
}

```

### 入力画面用のView
```php:fuel/app/views/sample/input.php
// input view
<?php echo \Form::open().PHP_EOL; ?>
	<div class="form-group <?php echo \Arr::get($fields, 'name.error_class') ?>">
		<label>Full name</label>
		<?php echo \Arr::get($fields, 'name.field'); ?>
	</div>
	<button type="submit" class="btn btn-default" value="confirm">Confirm</button>
<?php echo \Form::close().PHP_EOL; ?>

```

### 確認画面用のView
```php:fuel/app/views/sample/confirm.php
// confirm view
<?php echo \Form::open().PHP_EOL; ?>
	<div class="form-group <?php echo \Arr::get($fields, 'name.error_class') ?>">
		<label>Full name</label>
		<?php echo \Arr::get($fields, 'name').PHP_EOL; ?>
		<?php echo \Form::hidden('name', \Arr::get($fields, 'name')).PHP_EOL; ?>
	</div>
	<button type="submit" class="btn btn-default" value="back">Back</button>
	<button type="submit" class="btn btn-default" value="exec">Submit</button>
<?php echo \Form::close().PHP_EOL; ?>

```

## まとめ
入力値の取得、デフォルト値の設定、バリデーションをFieldsetクラスに記載することによって、コントローラの見通しがよくなった。