Как установить значение по умолчанию для поля формы в Symfony2?

138

Есть ли простой способ установить значение по умолчанию для поля текстовой формы?

Ондрей Слинтак
источник
1
да, но ответы, приведенные в этом вопросе, не удовлетворяют / не работают ... Я добавлю «Изменить», чтобы объяснить, почему :-)
herrjeh42 01
Кажется, что «идеальное» решение, которое вам нужно, - это наличие у поля параметра default_value. Дело в том, что в настоящее время это не так, поэтому я не думаю, что идеальное решение, которое вы ищете, в настоящее время существует. Единственное, что предоставляет symfony (см. Ссылку), - это опция данных. Так что «если-то» - это единственный подход, который я могу увидеть. Даже если бы в самом поле была опция default_value, я полагаю, что внутренне оно все равно будет делать то же самое.
crysallus
Кроме того, я внес исправление в свой ответ в подходе 2 в соответствии с моими комментариями ниже. Если это решит проблему с синтаксисом, упомянутую в пункте 2, возможно, вы захотите отредактировать этот комментарий. Или дайте мне знать, в чем проблема, и я исправлю свой ответ.
crysallus
1
@Crone, этот вопрос был задан двумя годами ранее
Ондрей Слинтак,
1
@ OndrejSlinták Я не голосовал за закрытие либо как обман, но к сведению: неважно, какой из них пришел первым: « Если новый вопрос лучше или имеет лучшие ответы, тогда проголосуйте за закрытие старого как дубликата. нового ".
Джефф Пакетт

Ответы:

106

Можно легко использовать при создании:

->add('myfield', 'text', array(
     'label' => 'Field',
     'empty_data' => 'Default value'
))
webda2l
источник
11
Для Symfony 2.1 мне нужно было изменить 'data'ключ на'value'
Эдд
176
Это не только устанавливает значение по умолчанию, но и всегда принудительно устанавливает значение в любом контексте. Не то, что я бы назвал «значением по умолчанию» ...
Хьюберт Перрон
4
Я проголосовал против этого решения, так как это не решение проблемы (как упоминал выше Хуберт Перрон). Я пытаюсь найти лучшее решение в этом сообщении stackoverflow.com/questions/17986481/…
herrjeh42 01
13
Это начальное значение, значение по умолчаниюempty_data
Pierre de LESPINAY
3
dataбесполезно - затирает сохраненное значение. empty_dataне показывает значение, он использует его при отправке пустого значения и делает невозможным сохранение непроверенных вариантов.
moldcraft
115

вы можете установить значение по умолчанию с помощью empty_data

$builder->add('myField', 'number', ['empty_data' => 'Default value'])
rkmax
источник
29
Установочные данные не устанавливают значение по умолчанию. Это правильный ответ.
Алексей Теницкий 03
9
Похоже, что это поле устанавливает значение 1 только тогда, когда оно отправляется без значения. Как насчет того, чтобы форма по умолчанию отображала 1 во входных данных, когда значение отсутствует?
Брайан
В моем тестировании empty_data не позволяет мне переопределить значение по умолчанию из поля, отправленного пустым, например, если вы хотите сохранить в базе данных как 0 вместо NULL. Насколько я могу судить, эта ошибка все еще не решена
Chadwick Meyer
63

Я размышлял об этом несколько раз в прошлом, поэтому решил записать разные идеи, которые у меня были / использовались. Что-то может быть полезно, но ни одно из решений для Symfony2 не является "идеальным".

Конструктор В Entity вы можете сделать $ this-> setBar ('значение по умолчанию'); но это вызывается каждый раз, когда вы загружаете объект (db или нет), и это немного беспорядочно. Однако он работает для каждого типа поля, поскольку вы можете создавать даты или что-то еще, что вам нужно.

Если бы заявления внутри были, я бы не стал, но вы могли бы.

return ( ! $this->hasFoo() ) ? 'default' : $this->foo;

Завод / экземпляр . Вызов статической функции / вторичного класса, который предоставляет вам объект по умолчанию, предварительно заполненный данными. Например

function getFactory() {
    $obj = new static();
    $obj->setBar('foo');
    $obj->setFoo('bar');

   return $obj;
}

Не совсем идеально, учитывая, что вам придется поддерживать эту функцию, если вы добавляете дополнительные поля, но это означает, что вы разделяете установщики данных / default и те, которые генерируются из db. Точно так же у вас может быть несколько getFactories, если вам нужны разные данные по умолчанию.

Сущности Extended / Reflection Создайте расширяющуюся сущность (например, FooCreate extends Foo), которая дает вам данные по умолчанию во время создания (через конструктор). Подобно идее Factory / instance, только другой подход - лично я предпочитаю статические методы.

Установить данные перед формой сборки В конструкторах / сервисах вы знаете, есть ли у вас новый объект или он был заполнен из базы данных. Поэтому правдоподобно вызывать набор данных в разных полях, когда вы захватываете новую сущность. Например

if( ! $entity->isFromDB() ) {
     $entity->setBar('default');
     $entity->setDate( date('Y-m-d');
     ...
}
$form = $this->createForm(...)

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

Расширенные формы Подобно событиям формы, но вы вызываете другой тип в зависимости от того, является ли это сущностью db / new. Под этим я подразумеваю, что у вас есть FooType, который определяет вашу форму редактирования, BarType расширяет FooType this и устанавливает все данные в поля. Затем в вашем контроллере вы просто выбираете, какой тип формы инициировать. Это отстой, если у вас есть настраиваемая тема и, как и события, требуется слишком много обслуживания, на мой вкус.

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

form_widget(form.foo, {attr: { value : default } });

JS Было бы тривиально заполнить форму функцией JS, если поля пусты. Например, вы можете сделать что-нибудь с заполнителями. Но это плохая идея.

Формы как услуга Для одного из больших проектов, основанных на формах, я создал службу, которая генерировала все формы, выполняла всю обработку и т. Д. Это произошло потому, что формы должны были использоваться на нескольких контроллерах в разных средах, а формы генерировались / обрабатывались одинаково, отображались / взаимодействовали по-разному (например, обработка ошибок, перенаправления и т. д.). Прелесть этого подхода заключалась в том, что вы можете использовать данные по умолчанию, делать все, что вам нужно, обрабатывать ошибки в целом и т.д., и все это инкапсулируется в одном месте.

Заключение На мой взгляд, вы снова и снова будете сталкиваться с одной и той же проблемой - где же хранить данные по умолчанию?

  • Если вы сохраните его на уровне db / doctrine, что произойдет, если вы не захотите каждый раз сохранять значение по умолчанию?
  • Если вы сохраните его на уровне сущности, что произойдет, если вы захотите повторно использовать эту сущность в другом месте без каких-либо данных?
  • Если вы сохраните его на уровне сущности и добавите новое поле, хотите ли вы, чтобы предыдущие версии имели это значение по умолчанию при редактировании? То же самое и по умолчанию в БД ...
  • Если вы храните его на уровне формы, станет ли это очевидным, когда вы перейдете к поддержке кода позже?
  • Если он находится в конструкторе, что произойдет, если вы используете форму в нескольких местах?
  • Если вы перейдете на уровень JS, вы зашли слишком далеко - данные не должны быть в представлении, не говоря уже о JS (и мы игнорируем совместимость, ошибки рендеринга и т. Д.)
  • Сервис хорош, если вы, как и я, используете его в нескольких местах, но это излишне для простой формы добавления / редактирования на одном сайте ...

С этой целью я каждый раз подходил к проблеме по-разному. Например, параметр «информационный бюллетень» формы подписки легко (и логично) устанавливается в конструкторе непосредственно перед созданием формы. Когда я создавал коллекции форм, которые были связаны вместе (например, какие переключатели в разных типах форм были связаны вместе), я использовал прослушиватели событий. Когда я построил более сложный объект (например, тот, который требовал дочерних элементов или большого количества данных по умолчанию), я использовал функцию (например, getFactory), чтобы создать его элемент, когда он мне нужен.

Я не думаю, что есть один «правильный» подход, поскольку каждый раз, когда у меня возникало это требование, оно менялось.

Удачи! Надеюсь, я дал вам пищу для размышлений и не слишком много болтал;)

Stefancarlton
источник
Не могли бы вы подробнее рассказать о том, что вы имели в виду, говоря о «сервисе, который генерирует все формы»? Я также работаю сейчас над действительно ориентированным на форму проектом, и было бы здорово иметь разные точки зрения на него.
user2268997
2
при использовании доктрины конструкторы не вызываются, когда объект загружается из базы данных.
NDM
44

Если вам нужно установить значение по умолчанию и ваша форма относится к сущности, вам следует использовать следующий подход:

// buildForm() method
public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder
    ...
    ->add(
        'myField',
        'text',
        array(
            'data' => isset($options['data']) ? $options['data']->getMyField() : 'my default value'
        )
    );
}

В противном случае myFieldвсегда будет установлено значение по умолчанию вместо получения значения от объекта.

Дмитрий
источник
В случае массивов вместо сущностей просто замените $options['data']->getMyField()на$option['data']['myField']
ggg
3
Я думаю, это правильный способ как для добавления, так и для обновления. Но я ненавижу, когда Symfony делает его слишком сложным.
Yarco
Это единственный хороший ответ. Я не понимаю других ответов, когда смотрю документ. empty_data: Этот параметр определяет, какое значение будет возвращать поле, если отправленное значение пусто. Не устанавливает начальное значение
Винсент Деко
19

Вы можете установить значение по умолчанию для связанного поля в вашем классе модели (в определении сопоставления или установить значение самостоятельно).

Кроме того, FormBuilder дает вам возможность установить начальные значения с помощью метода setData () . Конструктор форм передается методу createForm () вашего класса формы.

Также проверьте эту ссылку: http://symfony.com/doc/current/book/forms.html#using-a-form-without-a-class

Якуб Залас
источник
16

Если ваша форма привязана к сущности, просто установите значение по умолчанию для самой сущности, используя метод построения:

public function __construct()
{
    $this->field = 'default value';
}
Юбер Перрон
источник
Даже в этом случае ваша форма может иметь дополнительные поля, которые не будут сопоставлены с вашей сущностью ( 'mapped' => false). Используйте setData(...)для этого.
Диззли,
12

Подход 1 (из http://www.cranespud.com/blog/dead-simple-default-values-on-symfony2-forms/ )

Просто установите значение по умолчанию в своей сущности либо в объявлении переменной, либо в конструкторе:

class Entity {
    private $color = '#0000FF';
    ...
}

или

class Entity {
    private $color;

    public function __construct(){
         $this->color = '#0000FF';
         ...
    }
    ...
}

Подход 2 из комментария в приведенной выше ссылке, а также ответ Дмитрия (не принятый) из Как установить значение по умолчанию для поля формы в Symfony2?

Добавьте значение по умолчанию в атрибут данных при добавлении поля с помощью FormBuilder, адаптированного из ответа Дмитрия.

Обратите внимание: это предполагает, что свойство будет иметь и будет иметь значение null, только если это новая, а не существующая сущность.

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('color', 'text', array(
            'label' => 'Color:',
            'data' => (isset($options['data']) && $options['data']->getColor() !== null) ? $options['data']->getColor() : '#0000FF'
        )
    );
}
Crysallus
источник
Первый работает (спасибо!), Второй нет (для меня): $ options ["data] всегда установлен, поэтому значение по умолчанию никогда не будет использоваться. Мне все еще интересно, является ли решение номер 1 предполагаемым способом чтобы сделать это ...
herrjeh42 01
Вы правы в том, что всегда устанавливаются $ options ['data']. Если вы не инициализируете поле объекта, вы можете вместо этого проверить значение null в поле, например. 'data' => $ options ['data'] -> getColor ()! == null? и т. д. Предполагается, что null не является допустимым значением для поля цвета, поэтому существующие объекты никогда не будут иметь нулевое значение для этого поля.
crysallus
ах, глупый я: я попробовал это с помощью 'isset ($ $ options [' data '] -> getColor ())', я получил сообщение об ошибке о том, что "использование этого в контекстах записи запрещено" и забыл, что я должен проверьте по-другому :-)
herrjeh42
1
На самом деле, кажется, бывают случаи, когда ввод данных не установлен. Безопаснее тестировать оба, т.е. isset ($ options ['data']) && $ options ['data'] -> getColor ()! == null? ...
crysallus 01
9

Вы можете установить значение по умолчанию, например, для формы message, например:

$defaultData = array('message' => 'Type your message here');
$form = $this->createFormBuilder($defaultData)
    ->add('name', 'text')
    ->add('email', 'email')
    ->add('message', 'textarea')
    ->add('send', 'submit')
    ->getForm();

В случае, если ваша форма сопоставлена ​​с сущностью, вы можете сделать это (например, имя пользователя по умолчанию):

$user = new User();
$user->setUsername('John Doe');

$form = $this->createFormBuilder($user)
    ->add('username')
    ->getForm();
Готлиб Ночнабель
источник
2
Я предпочитаю этот метод, тем более что в большинстве приложений вы создаете форму и передаете сущность, с которой она работает.
skrilled
9

Общее решение для любого случая / подхода, в основном за счет использования формы без класса или когда нам нужен доступ к каким-либо службам для установки значения по умолчанию:

// src/Form/Extension/DefaultFormTypeExtension.php

class DefaultFormTypeExtension extends AbstractTypeExtension
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if (null !== $options['default']) {
            $builder->addEventListener(
                FormEvents::PRE_SET_DATA,
                function (FormEvent $event) use ($options) {
                    if (null === $event->getData()) {
                        $event->setData($options['default']);
                    }
                }
            );
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefault('default', null);
    }

    public function getExtendedType()
    {
        return FormType::class;
    }
}

и зарегистрируйте расширение формы:

app.form_type_extension:
    class: App\Form\Extension\DefaultFormTypeExtension
    tags:
        - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType }

После этого мы можем использовать defaultопцию в любом поле формы:

$formBuilder->add('user', null, array('default' => $this->getUser()));
$formBuilder->add('foo', null, array('default' => 'bar'));
Yceruto
источник
Это следовало бы принять как лучший ответ (актуальный)
medunes
7

Не используйте:

'data' => 'Default value'

Читайте здесь: https://symfony.com/doc/current/reference/forms/types/form.html#data

«Параметр данных всегда переопределяет значение, полученное из данных домена (объекта) при визуализации. Это означает, что значение объекта также переопределяется, когда форма редактирует уже сохраненный объект, в результате чего он теряет свое постоянное значение при отправке формы».


Используйте следующее:

Допустим, в этом примере у вас есть Entity Foo и есть поле «active» (в этом примере CheckBoxType, но процесс такой же, как и для всех других типов), которое вы хотите проверять по умолчанию.

В вашем классе FooFormType добавьте:

...
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
...
public function buildForm( FormBuilderInterface $builder, array $options )
{
    ...

    $builder->add('active', CheckboxType::class, array(
        'label' => 'Active',
    ));

    $builder->addEventListener(
        FormEvents::PRE_SET_DATA,
        function(FormEvent $event){                 
            $foo = $event->getData();
            // Set Active to true (checked) if form is "create new" ($foo->active = null)
            if(is_null($foo->getActive())) $foo->setActive(true);
        }
   );
}
public function configureOptions( OptionsResolver $resolver )
{
    $resolver->setDefaults(array(
        'data_class' => 'AppBundle:Foo',
    ));
}
лечение85
источник
Это вот деньги !! Используйте прослушиватель событий формы, чтобы проверить свои значения перед их использованием по умолчанию. Это должен быть принятый ответ для значений по умолчанию в ваших формах, потому что он работает как для действий New, так и для действий Edit.
tlorens
Это правильный способ справиться с этим, и это должен быть принятый ответ.
Bettinz
То, что вы упомянули в начале, неверно, если вы используете условный / тернарный. Как это:'data' => $data['myfield'] ?? 'Default value'
xarlymg89
6
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
     $form = $event->getForm(); 
     $data = $event->getData(); 

     if ($data == null) {
         $form->add('position', IntegerType::class, array('data' => 0));
     }

});
ziiweb
источник
это хорошее решение. Вызов $event->setData()вместо чтения поля может сделать его еще лучше.
user2268997
5

Мое решение:

$defaultvalue = $options['data']->getMyField();
$builder->add('myField', 'number', array(
            'data' => !empty($defaultvalue) ? $options['data']->getMyField() : 0
        )) ;
троколо
источник
4

Просто так я понимаю проблему.

Вы хотите настроить способ построения формы на основе данных в вашей сущности. Если объект создается, используйте какое-то значение по умолчанию. Если объект существует, используйте значение базы данных.

Лично я думаю, что решение @MolecularMans - это правильный путь. Я бы фактически установил значения по умолчанию в конструкторе или в заявлении свойства. Но, похоже, вам не нравится такой подход.

Вместо этого вы можете следовать этому: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

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

Хотя, похоже, много работы. Лучше просто передать сущность в форму с уже установленными значениями по умолчанию.

Cerad
источник
4

Если вы используете FormBuilderв Symfony 2.7 для генерации формы, вы также можете передать начальные данные createFormBuilderметоду Контроллера.

$values = array(
    'name' => "Bob"
);

$formBuilder = $this->createFormBuilder($values);
$formBuilder->add('name', 'text');
Боб
источник
3

Часто для значений формы по умолчанию я использую фикстуры. Конечно, это не самый простой способ, но очень удобный.

Пример:

class LoadSurgeonPlanData implements FixtureInterface
{
    public function load(ObjectManager $manager)
    {
        $surgeonPlan = new SurgeonPlan();

        $surgeonPlan->setName('Free trial');
        $surgeonPlan->setPrice(0);
        $surgeonPlan->setDelayWorkHours(0);
        $surgeonPlan->setSlug('free');

        $manager->persist($surgeonPlan);
        $manager->flush();        
    }   
}

Тем не менее, поле типа symfony содержит данные о параметрах .

пример

$builder->add('token', 'hidden', array(
    'data' => 'abcdef',
));
Михаил Щедраков
источник
3

Есть очень простой способ, вы можете установить значения по умолчанию, как здесь:

$defaults = array('sortby' => $sortby,'category' => $category,'page' => 1);

$form = $this->formfactory->createBuilder('form', $defaults)
->add('sortby','choice')
->add('category','choice')
->add('page','hidden')
->getForm();
Эльзасский
источник
3

Если вы установите «данные» в форме создания, это значение не будет изменено при редактировании вашей сущности.

Мое решение:

public function buildForm(FormBuilderInterface $builder, array $options) {
    // In my example, data is an associated array
    $data = $builder->getData();

    $builder->add('myfield', 'text', array(
     'label' => 'Field',
     'data' => array_key_exits('myfield', $data) ? $data['myfield'] : 'Default value',
    ));
}

До свидания.

Квентин Машард
источник
Намного полезнее, чем принятый ответ! Если вы используете PHP7 +, вы можете сделать его еще более аккуратным с помощью:'data' => $data['myfield'] ?? 'Default value',
Boykodev
У вас опечатка в функции array_key_exists ()
Дэдпул
1

Значения по умолчанию устанавливаются путем настройки соответствующей сущности. Перед привязкой сущности к форме установите для ее поля цвета значение "# 0000FF":

// controller action
$project = new Project();
$project->setColor('#0000FF');
$form = $this->createForm(new ProjectType(), $project);
Молекулярный человек
источник
этот подход работает, но имеет тот недостаток, что вам приходится делать это каждый раз, когда вы используете класс формы, и он очень подробный (множество операторов set). Поскольку компонент формы очень элегантен, должно быть что-то еще. Но все равно спасибо :-)
herrjeh42
@ jamie0726 На мой взгляд, ответственность за установку значений объекта лежит на контроллере, когда он новый или извлекается. Таким образом, вы можете использовать форму в разных ситуациях с различным поведением, например, новый цвет может измениться из-за того, что у пользователя есть роль менеджера или суперменеджера, и, поскольку это бизнес-логика, она должна контролироваться контроллер или услуга, а не форма. Как заявил Серад, я тоже предпочитаю это решение. Вы всегда можете создать службу для установки этих значений по умолчанию и в контроллере использовать эту службу, сохраняя ее СУХОЙ.
saamorim 08
Я выбрал это решение, потому что, как мне кажется, оно соответствует логике. Сгенерированные контроллеры имеют разные методы для создания форм EDIT и CREATE, и именно там я устанавливаю исходные данные по умолчанию для нового объекта.
alumi
1

Если это поле привязано к объекту (является свойством этого объекта), вы можете просто установить для него значение по умолчанию.

Пример:

public function getMyField() {
    if (is_null($this->MyField)) {
        $this->setMyField('my default value');
    }
    return $this->MyField;
}
Андрей Сандулеску
источник
1

Обычно я просто устанавливаю значение по умолчанию для определенного поля в моей сущности:

/**
 * @var int
 * @ORM\Column(type="integer", nullable=true)
 */
protected $development_time = 0;

Это будет работать для новых записей или просто для обновления существующих.

матотей
источник
Это не работает, когда 'empty_data'используется обратный вызов, чтобы разрешить параметры конструктора для объекта.
NDM
1

Как спросил Брайан:

empty_data, похоже, устанавливает для поля значение 1 только тогда, когда оно отправляется без значения. А как насчет того, чтобы форма по умолчанию отображала 1 во входных данных, когда значение отсутствует?

вы можете установить значение по умолчанию с помощью empty_value

$builder->add('myField', 'number', ['empty_value' => 'Default value'])
Snowirbis
источник
0

Я решил эту проблему, добавив значение в attr :

->add('projectDeliveringInDays', null, [
    'attr' => [
          'min'=>'1',
          'value'=>'1'
          ]
     ])
Какса
источник