Symfony FormTypeの使い方(使ったことあるものだけ)

Symfony のフォームタイプについての優しい使い方があまりないので、自分用としても記述しておく。
覚えればやりたい事はシンプルな構造で大体できるので便利！
※自分が実際に利用した範囲でのみ記述しています。

#基本

##コンストラクタを利用する

config/service.yml　に引っ張ってくる項目を追加します。

今回のはサービスコンテナをtypeクラスで利用できるようにする。

```yaml:service.yml
services:
    app.form.type.sample: #コンテナ登録名
        class: AppBundle\Form\Type\SampleType  #クラス指定
        arguments: [ @service_container ] #引数指定
```

typeクラス内にコンストラクタを作成し引数で取得
これでコンテナを利用できる。
コントローラから呼び出して使えばOK

```php:SampleController.php
$SampleEntity = $this->container->get('doctrine')->getRepository('AppBundle:SampleEntity')->find($id);
$form = $this->createForm($this->get('app.form.type.sample'),$SampleEntity);
//Twigへ渡すときは createView()から。
$View = $form->createView();
```

```php:SampleType.php
class SampleType extends AbstractType
{
    private $app;

    public function __construct($app)
    {
        $this->app = $app;
    }
}
```

##ビルドフォーム
ビルドフォームで必要なフォーム項目を生成。細かい内容は下記

```php:SampleType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
}
```

$optionsからセットしたデータを取る場合は、

```php
$data = $options['data'];
```
で取得可能。
$builderでフォームを作っていく。

```php
$builder
	->add('name','text',array(
	    'label' => '名前',
	    'required' => true,
	));
```

##デフォルトオプション
適用するオプションを指定できる。
今回は値セットのクラスを指定して自動でデータセットできるようにする。

```php:SampleType.php
 public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        //エンティティクラスを指定
        'data_class' => 'AppBundle\Entity\SampleEntity',
        //エンティティでセットできる項目以外も許可する。
        'allow_extra_fields' => true,
    ));
}
```

##Type名を指定
```php:SampleType.php
public function getName()
{
    return 'sample';
}
```

#$builderでのフォームの作り方
これがメインです。

```php
->add(name,type,options);
```

が追加する場合の引数。

##name
nameはEntity等をセットする場合にフィールド名として参照されるので、
フィールド名と同じものを指定します。

```php
//この場合はセットしたエンティティで getName()が内部的に呼び出される。
->add('name',type,options)
//これだと getSecondName()が呼び出される。
->add('second_name',type,options);
```

フィールド名というかエンティティのgetterが呼び出されるので、
DBにフィールドがないものでもgetterがあれば指定可能。

##typeとoptions

いろんな機能があります。詳しくはリファレンスを参照
[>Form Types Reference](https://symfony.com/doc/current/reference/forms/types.html)

###type:text

`<input type="text" />`　項目を追加する。
optionsにしているものは他のタイプでも大体使えます。

```php
$builder
    ->add('name','text',array(
        //ラベル
        'label' => 'ラベル名',
        //inputの属性
        'attr' => array(
                    'placeholder' => '例：山田　太郎',
                ),
        //必須項目かどうか
        'required' => true,
        //nameを利用したデータセットを行うかどうか。デフォルトは true
        'mapped' => true,
        //入力制限を設ける。 isValid()でチェックしてくれます。
        'constraints' => array(
            //長さ制限。 Assert\も色々ある。
            new Assert\Length(array(
                //最小2文字
                'min' => 2,
                //最大4文字
                'max' => 4,
                //それぞれに引っかかったときのエラーメッセージ
                'minMessage' => '2文字以上入れてね',
                'maxMessage' => '4文字以下にしてね',
            )),
            //正規表現マッチング
            new Assert\Regex(array(
                'pattern' => '/^[0-9]{3}-[0-9]{4}$/',
                'message' => '3桁 -(ハイフン) 4桁　で入力してね。'
            ))
            //メールアドレスかどうか
            new Assert\Email(array(
                'message' => 'メールアドレスを正しく入力してください。',
            )),
        ),
    ))
```

###type:choice

チェックボックス、ラジオボタン、セレクトボックスを追加する。
expandedとmultipleの組み合わせで変わります。

```php
->add('seibetu','choice',array(
    //選択肢
    'choices' => array(
        // 値 => 表示内容
        'otoko' => '男',
        'onna' => '女',
    ),
    //セットする値 choicesの値を指定
    'data' => array('otoko'),
    'expanded' => true,
    'multiple' => true,
    'required' => true,
    'mapped' => false,
))
```

###type:time , datetime

時刻、日時入力項目を追加する。

```php
->add('start_time','time',array(
    'label' => '開始時間',
    //値の型を指定する。string型　datetime型等
    'input' => 'datetime',
    //項目入力方法を指定　choiceは<select>で選べるようにする
    'widget' => 'choice',
    'required' => true,
))
```

###type:entity

指定のエンティティから選択項目を取得して`<select>`にしてくれる。


```php
->add('seibetu','entity',array(
    'label' => '性別',
    //値を取得するエンティティ
    'class' => 'AppBundle:Master\SeibetuEntity',
    //選択項目の指定。この場合はエンティティで getName()　される。
    'choice_label' => 'name',
    'required' => false,
))
```
Entity上で結合しているテーブル先の項目を出すことが多いかな？

###type:collection

登録する内容により複数指定したい内容がある場合に便利。
javascriptとの連携ができる。
多対多の結合テーブルで相手を複数指定したい時など。

```php
->add('product','collection',array(
    //項目は何のタイプか指定する。
    'type' => 'entity',
    //追加することを許可する
    'allow_add' => true,
    //削除することを許可する
    'allow_delete' => true,
    //inputやselect項目のテンプレートをform内に出力してくれる。
    'prototype' => true,
    //項目の内容オプション 内容は 'type'で指定したタイプのものを使用できる。
    'options' => array(
        'label' => '商品',
        'class' => 'AppBundle:ProductEntity',
        //選択内容を指定する。今回は <select>なので <option>に設定される値を指定
        'choice_label' => function($Item){
            return $Item->getName();
        },
        //未選択時の表示
        'empty_value' => '商品を選択',
        'required' => false,
    ),
))
```

フォームにセットしたSampleEntity上で getProduct()　があればこれで複数選択が可能になる。
prototypeは値がセットされるので、 twig上で`<div>`の属性等にセットすればjavascriptで取得できる。

```html
<div id="collection_item" data-prototype="{{ form_widget(form.casts.vars.prototype) | e }}">
</div>
```

これで、 data-prototype属性に `<select>`のテンプレートが出力される。
`data-prototype="<select><option>米</option><option>パン</option></select>"`

これをjavascriptで取得して、追加ボタンと削除ボタンを作成し、こねこねすればOK
サンプルのjavascript

[>GitHub:Symfony formタイプのコレクションプロトタイプを制御する。 Bootstrapフォーム用](https://gist.github.com/RyosukeMori/6c3a2d43ec012fad72e215a47f56ff2c)

##まだまだいっぱいあるんだけども…。

今回使ったのはこのあたりなので、詳しくはリファレンスを見て下さい。
今回の内容だけ知っていればあとはリファレンスを見て作成できると思います。

$optinos['data']から引っ張ってきて項目と値を作って……。
ということもできるけど、スッキリさせてあとはsymfonyにお任せできる書き方を紹介しました。

他には独自にタイプを作って指定することもできるので、色々やってみるとよいですー！
おわり。