Формы

Формы

Формы являются одним из наиболее часто неправильно используемых компонентов в связи с их широким применением и бесконечным списком функций. В этой главе мы покажем вам некоторые наилучшие практики, чтобы вы могли использовать преимущества форм для быстрой работы.

Построение форм

Best Practice

Определяйте ваши формы как PHP-классы.

Компонент Формы позволяет вам строить формы прямо внутри вашего кода контроллера. Это абсолютно норамльно, если вам не нужно использовать форму повторно где-либо ещё. Но для систематизации и повторного использования мы рекомендуем вам определять каждую форму в собственном PHP-классе:

 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
28
29
30
namespace AppBundle\Form;

use AppBundle\Entity\Post;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;

class PostType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title')
            ->add('summary', TextareaType::class)
            ->add('content', TextareaType::class)
            ->add('authorEmail', EmailType::class)
            ->add('publishedAt', DateTimeType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Post::class,
        ));
    }
}

Best Practice

Определите классы типов формы в пространство имён AppBundle\Form, разве что вы не используете другие пользовательские классы вроде преобразователей данных.

Чтобы использовать класс, используйте createForm() и передайте полное имя класса:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// ...
use AppBundle\Form\PostType;

// ...
public function newAction(Request $request)
{
    $post = new Post();
    $form = $this->createForm(PostType::class, $post);

    // ...
}

Регистрация форм как сервисов

Вы можете также зарегистрировать ваш тип формы как сервис. Это необходимо только если ваш тип формы требует внедрения некоторых зависимостей контейнером, иначе это излишне и мы не рекомендуем делать это для всех классов типов формы.

Конфигурация кнопки формы

Классы формы должны пытаться быть независимыми по отношению к тому где они будут использованы. Это делает их повторное использвание позже легче.

Best Practice

Добавляйте кнопки в шаблны, а не в классы форм или контроллеры.

Компонент Форм Symfony позволяет вам добавлять кнопки в качестве полей вашей формы. Это хороший способ упростить шаблон, отображающий вашу форму. Но если вы добавляете кнопки напрямую в ваш класс формы, это сильно ограничит спектр действий этой формы:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class PostType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            // ...
            ->add('save', SubmitType::class, array('label' => 'Create Post'))
        ;
    }

    // ...
}

Эта форма могла быть создана для написания постов, но если бы вы хотели использовать её повторно для редактирования постов, то ярлык кнопки был бы неверным. Вместо этого, некоторые разрботчики конфигурируют кнопки формы в контроллере:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace AppBundle\Controller\Admin;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use AppBundle\Entity\Post;
use AppBundle\Form\PostType;

class PostController extends Controller
{
    // ...

    public function newAction(Request $request)
    {
        $post = new Post();
        $form = $this->createForm(PostType::class, $post);
        $form->add('submit', SubmitType::class, array(
            'label' => 'Create',
            'attr'  => array('class' => 'btn btn-default pull-right')
        ));

        // ...
    }
}

Это также важная ошибка, так как вы смешиваете разметку презентации (ярлыки, CSS классы и т.д.) с чистым PHP-кодом. Разделение вопросов всегда является хорошей практикой, так что поместите всё, ксающееся просмотра, в слой просмотра:

1
2
3
4
5
6
{{ form_start(form) }}
    {{ form_widget(form) }}

    <input type="submit" value="Create"
           class="btn btn-default pull-right" />
{{ form_end(form) }}

Отображение формы

Существует множество способов отобразить вашу форму, начиная с отображения всего в одной строке, до отображения каждой части каждого поля независимо. Лучший способ зависит от того, какая настраиваемость вам нужна.

Один из наиболее простых способов - который особенно полезен во время разработки - отобразить теги формы и использовать функцию form_widget(), чтобы отобразить все поля:

1
2
3
{{ form_start(form, {'attr': {'class': 'my-form-class'} }) }}
    {{ form_widget(form) }}
{{ form_end(form) }}

Если вам нужно больше контроля над тем, как отображаются ваши поля, то вам стоит удалить функцию form_widget(form) и отобразить ваши поля по-отдельности. См. How to Customize Form Rendering, чтобы узнать больше информации об этом и о том, как вы можете контролировать то как отображается форма на глоабльном уровне, используя тематизацию форм.

Обработка отправок формы

Обработка отправки формы обычно следует схожему шаблону:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public function newAction(Request $request)
{
    // build the form ...

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($post);
        $em->flush();

        return $this->redirect($this->generateUrl(
            'admin_post_show',
            array('id' => $post->getId())
        ));
    }

    // отобразить шаблон
}

На самом деле, тут стоит отметить только две вещи. Во-первых, мы рекомендуем, чтобы вы использовали одно действие для отображения формы и для обработки отправки формы. Например, вы могли бы иметь newAction(), которое только отображает форму, и createAction(), которое только обрабатывает отправку формы. Оба этих действия будут практически одинаковы. Так что намного проще позволить newAction() делать всё.

Во-вторых, мы рекомендуем использовать $form->isSubmitted() в утверждении if для ясности. Технически, это не обязательно, так как isValid() вначале вызывает isSubmitted(). Но без этого, поток не считывается нормально, так как он выглядит как будто бы форма всегда обрабатывается (даже при запросе GET).

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.