リレーションの貼られていないエンティティをくっつけたFormTypeを作る

はじめての記事ですm(_ _)m

※ この記事はSymfony2.7を対象に書いています。バージョンが違う場合は適宜補完してください。

SymfonyのFormTypeって便利ですよね。
使い方を知っていればたくさん楽できますよね。
知っていなければ苦労してゴチャゴチャのソースが出来ちゃったりします。

ということで、今回はSymfonyのFormTypeについて少し書いてみます。
(直にソース書いたので、コピペしても動かない可能性がｱﾘﾏｽ)

SymfonyのFormTypeはModelとの連携がしやすく、更新処理などの大部分をお任せすることが可能です。

SymfonyのFormTypeはリレーションの貼ってある構造を理解し、勝手にGetterSetterだとかしてくれます。

基本的な形↓

### リレーションを貼っているエンティティの場合

```php

　　　　　　　　// モデル
    class Person {
        public $personName;

        @ORM\OneToOne(targetEntity="Skill") 
        public $skill;
    }

    class Skill {
        public $skillName;

        /* @ORM\OneToOne(targetEntity="Person") */
        public $person;
    }

　　　　　　　　//　フォーム
    class PersonType extends AbstractType {
        public function buildForm(FormBuilderInterface $builder, array $options) {
            $builder
                ->add('personName')
                ->add('skill', new SkillType())
        }
    }

    class SkillType extends AbstractType {
        public function buildForm(FormBuilderInterface $builder, array $options) {
            $builder->add('skillName')
        }

        public function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults(array(
                'data_class' => '..\Skill'
            ));
        }
    }

　　　　　　　　//　Controller
    class MyController extends Controller {
        // ここでフォームを作成
        public function indexAction() {
            $this->createForm(new PersonType(), new Person())
        }
    }
```

上記のようにリレーションが貼られている場合は

Personal（親）
↓
Skill（子供）

という構造でFormTypeを作成することにより、いい感じになります。

では、PersonalとSkillというModelにリレーションが貼られていない場合どうすればいいでしょう。

```php

$this->createForm(new PersonType(), new Person())
$this->createForm(new SkillType(), new Skill())
```
の用に２つFormTypeを作ってゴチャゴチャやるのでしょうか・・・？

否

実はそんな事をする必要はありません。

かんたんに言うと２つのFormTypeをまとめるFormTypeを作ればいいのです。

┌─────────親─────────┐
Personal（子供）　　　　　　　　　Skill（子供）　

とりあえずソース
### リレーションを貼っていないエンティティの場合

```php

　　　　　　　　//　Model
    //　リレーションが貼られていない
    class Person {
        public $personName;
    }
    
    class Skill {
        public $skillName;
    }

　　　　　　　　//　Form
    // PersonとSkillをまとめるクラス
    class ParentType extends AbstractType {
        public function buildForm(FormBuilderInterface     $builder, array $options) {
            $builder
                ->add('person', new PersonType())
                ->add('skill', new SkillType());
        }
    }

    class PersonType extends AbstractType {
        public function buildForm(FormBuilderInterface     $builder, array $options) {
            $builder->add('personName');
        }

        public function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults(array(
                'data_class' => '..\Person'
            ));
        }
    }

    class SkillType extends AbstractType {
        public function buildForm(FormBuilderInterface $builder, array $options) {
            $builder->add('skillName')
        }

        public function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults(array(
                'data_class' => '..\Skill'
            ));
        }
    }

　　　　　　　　//　Controller
    class MyController extends Controller {
        // ここでフォームを作成
        public function indexAction() {
　　　　　　　　　　　　　　　　　　　　　　　　// 親モデルを作成
            $model = [
                'person' => new Person(),
                'skill' => new Skill(),
            ];

            $this->createForm(new ParentType(), $model)
        }
    }
```

上記のような形をとることで、全く関係のないFormTypeをまとめる事ができます。

こうすることにより、複数のFormTypeというインスタンスを作成することなく一括で管理でき、ソースもすっきりします。

FormTypeは基本的にはarray構造を、optionsのdata_classを設定している場合は、そのクラスをもとにという風になっています。

FormTypeは一見複雑に見えるかもしれませんが、構造に関しては簡単で、理解すると汎用性の高い部品だというのが分かるはずです。

（ほかにもFormTypeにはEventListenerや色々な素敵機能があります。気が向くような事があれば、また書くかもしれません。）

それでは、ありがとうございました。