How to Reduce Code Duplication with "inherit_data"

The inherit_data form field option can be very useful when you have some duplicated fields in different entities. For example, imagine you have two entities, a Company and a Customer:

inherit_data フォーム フィールド オプションは、異なるエンティティに重複したフィールドがある場合に非常に便利です。たとえば、Company と Customer という 2 つのエンティティがあるとします。
1
2
3
4
5
6
7
8
9
10
11
12
13
// src/Entity/Company.php
namespace App\Entity;

class Company
{
    private $name;
    private $website;

    private $address;
    private $zipcode;
    private $city;
    private $country;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// src/Entity/Customer.php
namespace App\Entity;

class Customer
{
    private $firstName;
    private $lastName;

    private $address;
    private $zipcode;
    private $city;
    private $country;
}

As you can see, each entity shares a few of the same fields: address, zipcode, city, country.

ご覧のとおり、各エンティティはいくつかの同じフィールド (住所、郵便番号、都市、国) を共有しています。

Start with building two forms for these entities, CompanyType and CustomerType:

これらのエンティティ、CompanyType と CustomerType の 2 つのフォームを作成することから始めます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// src/Form/Type/CompanyType.php
namespace App\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class CompanyType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name', TextType::class)
            ->add('website', TextType::class);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// src/Form/Type/CustomerType.php
namespace App\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class CustomerType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('firstName', TextType::class)
            ->add('lastName', TextType::class);
    }
}

Instead of including the duplicated fields address, zipcode, city and country in both of these forms, create a third form called LocationType for that:

これらの両方のフォームに重複したフィールド address、zipcode、city、country を含める代わりに、LocationType という 3 番目のフォームを作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// src/Form/Type/LocationType.php
namespace App\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class LocationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('address', TextareaType::class)
            ->add('zipcode', TextType::class)
            ->add('city', TextType::class)
            ->add('country', TextType::class);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'inherit_data' => true,
        ]);
    }
}

The location form has an interesting option set, namely inherit_data. This option lets the form inherit its data from its parent form. If embedded in the company form, the fields of the location form will access the properties of the Company instance. If embedded in the customer form, the fields will access the properties of the Customer instance instead. Convenient, eh?

location フォームには、inherit_data という興味深いオプション セットがあります。このオプションを使用すると、フォームは親フォームからデータを継承できます。会社フォームに埋め込まれている場合、場所フォームのフィールドは Company インスタンスのプロパティにアクセスします。顧客フォームに埋め込まれている場合、フィールドは代わりに Customer インスタンスのプロパティにアクセスします。便利でしょ?

Note

ノート

Instead of setting the inherit_data option inside LocationType, you can also (just like with any option) pass it in the third argument of $builder->add().

LocationType 内で inherit_data オプションを設定する代わりに、(他のオプションと同様に) $builder->add() の 3 番目の引数に渡すこともできます。

Finally, make this work by adding the location form to your two original forms:

最後に、場所フォームを 2 つの元のフォームに追加して、これを機能させます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/Form/Type/CompanyType.php
namespace App\Form\Type;

use App\Entity\Company;
use Symfony\Component\Form\AbstractType;

// ...

class CompanyType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        // ...

        $builder->add('foo', LocationType::class, [
            'data_class' => Company::class,
        ]);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// src/Form/Type/CustomerType.php
namespace App\Form\Type;

use App\Entity\Customer;
use Symfony\Component\Form\AbstractType;

class CustomerType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        // ...

        $builder->add('bar', LocationType::class, [
            'data_class' => Customer::class,
        ]);
    }
}

That's it! You have extracted duplicated field definitions to a separate location form that you can reuse wherever you need it.

それでおしまい!重複したフィールド定義を別の場所のフォームに抽出し、必要な場所で再利用できるようにしました。

Caution

注意

Forms with the inherit_data option set cannot have *_SET_DATA event listeners.

inherit_data オプションが設定されたフォームは、*_SET_DATA イベント リスナーを持つことができません。