Як вбудовувати форми

Дата оновлення перекладу 2023-09-07

Як вбудовувати форми

Часто вам може захотітися побудувати форму, яка міститиме поля з багатьох різних обʼєктів. Наприклад, форма реєстрації може містити дані, що належать обʼєкту User, а також багато обʼєктів Address. На щастя, це просто та природньо за допомогою компонента Форма.

Вбудовування одного обʼєкта

Уявіть, що кожний Task належить простому обʼєкту Category. Почніть, авжеж, зі створення обʼєкта Category:

1
2
3
4
5
6
7
8
9
10
// src/Entity/Category.php
namespace App\Entity;

use Symfony\Component\Validator\Constraints as Assert;

class Category
{
    #[Assert\NotBlank]
    public string $name;
}

Далі, додайте нову властивість category до класу Task:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ...

class Task
{
    // ...

    #[Assert\Type(type: Category::class)]
    #[Assert\Valid]
    protected ?Category $category = null;

    // ...

    public function getCategory(): ?Category
    {
        return $this->category;
    }

    public function setCategory(?Category $category): void
    {
        $this->category = $category;
    }
}

Tip

Обмеження Valid було додано до властивості category. Це створює каскадне включення валідації у відповідну сутність. Якщо ви пропустите це обмеження, то дочірня сутність не буде валідована.

Тепер, коли ваш додаток був оновлений так, щоб відображати нові вимоги, створіть клас форми так, щоб обʼєкт Category можна було змінювати користувачу:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// src/Form/CategoryType.php
namespace App\Form;

use App\Entity\Category;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CategoryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add('name');
    }

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

Кінцева ціль - дозволити Category класу Task підлягати змінам прямо всередині форми задачі. Щоб досягти цього, додайте поле category до обʼєкта TaskType, тип якого - екземпляр нового класу CategoryType:

1
2
3
4
5
6
7
8
9
use App\Form\CategoryType;
use Symfony\Component\Form\FormBuilderInterface;

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

    $builder->add('category', CategoryType::class);
}

Поля з CategoryType тепер можуть бути відоражені на ряду з полями з TaskType.

Відобразіть поля Category таким же чином, як оригінальні поля Task:

1
2
3
4
5
6
7
8
{# ... #}

<h3>Category</h3>
<div class="category">
    {{ form_row(form.category.name) }}
</div>

{# ... #}

Коли користувач відправляє форму, відправлені дані для полів Category використовуються для створення сутності Category, яка потім встановлюється у поле category екземпляру Task.

До екземпляру Category можна отримати доступ через $task->getCategory() і його можна зберегти у базі даних або використовувати так, як вам це потрібно.

Вбудовування колекції форм

Ви також можете вбудувати колекцію форм в одну форму (уявіть форму Category з багатьма підформами Product). Це робитьсся шляхом використання типу поля collection.

Щоб дізнатися більше, дивіться статтю Как вбудувати колекцію форм та довідник CollectionType.