Como definir o valor padrão para o campo de formulário no Symfony2?

137

Existe uma maneira fácil de definir um valor padrão para o campo de formulário de texto?

Ondrej Slinták
fonte
1
sim, mas as respostas dadas nesta questão não está satisfazendo / não funcionam ... I irá adicionar um "Edit" para explicar porque :-)
herrjeh42
Parece que a solução 'perfeita' que você procura é que um campo tenha a opção 'default_value'. A coisa é que, atualmente, não existe , então não acho que exista a solução perfeita que você está procurando. A única coisa que o symfony fornece (veja o link) é a opção de dados. Portanto, o if-then é a única abordagem que eu posso ver no caixa eletrônico. Mesmo se houvesse uma opção 'default_value' no próprio campo, imagino que essencialmente faria a mesma coisa internamente de qualquer maneira.
Crysallus
Além disso, corrigi minha resposta na abordagem 2, conforme meus comentários abaixo. Se isso resolver o problema de sintaxe mencionado no ponto 2, convém editar esse comentário. Ou deixe-me saber qual é o problema e corrigirei minha resposta.
Crysallus
1
@Crone esta pergunta foi feita 2 anos antes
Ondrej Slinták
1
@ OndrejSlinták Eu não votei para fechar como burro, mas para sua informação: não importa qual foi a primeira, " Se a nova pergunta for uma pergunta melhor ou tiver melhores respostas, vote para fechar a antiga como duplicada do novo. "
Jeff Puckett

Respostas:

105

Pode ser usado durante a criação facilmente com:

->add('myfield', 'text', array(
     'label' => 'Field',
     'empty_data' => 'Default value'
))
webda2l
fonte
11
Para o Symfony 2.1, eu precisei mudar a 'data'chave para'value'
Edd
175
Isso não apenas define um valor padrão, mas também sempre força o valor em qualquer contexto. Não o que eu chamaria de um "valor padrão" ...
Hubert Perron
4
Eu diminuí a votação desta solução, pois ela não é uma solução para o problema (como Hubert Perron mencionado acima). Eu estou tentando obter uma melhor solução neste post stackoverflow.com/questions/17986481/...
herrjeh42
13
Este é o valor inicial, o valor padrão éempty_data
Pierre de LESPINAY
3
dataé inútil - substitui o valor salvo. empty_datanão mostra o valor, ele é usado no envio de valor vazio e torna impossível salvar opções desmarcadas.
Moldcraft
115

você pode definir o valor padrão com empty_data

$builder->add('myField', 'number', ['empty_data' => 'Default value'])
rkmax
fonte
29
Definir dados não está definindo o padrão. Esta resposta é a correta.
Alexei Tenitski
9
Isso parece definir apenas o campo para 1 quando é enviado sem valor. E quando você deseja que o formulário seja padrão para exibir 1 na entrada quando nenhum valor estiver presente?
27714 Brian
Nos meus testes, empty_data não me permite substituir o valor padrão de um campo enviado vazio, por exemplo, se você deseja salvar no banco de dados como 0 em vez de NULL. Este bug está ainda em aberto, tanto quanto eu posso dizer: github.com/symfony/symfony/issues/5906
Chadwick Meyer
63

Eu já contemplei isso algumas vezes no passado, então pensei em anotar as diferentes idéias que tive / usei. Algo pode ser útil, mas nenhuma é a solução "perfeita" do Symfony2.

Construtor Na Entidade, você pode fazer $ this-> setBar ('valor padrão'); mas isso é chamado toda vez que você carrega a entidade (db ou não) e fica um pouco confuso. No entanto, funciona para todos os tipos de campos, pois você pode criar datas ou qualquer outra coisa que precisar.

Se declarações dentro de get's eu não, mas você poderia.

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

Fábrica / instância . Chame uma função estática / classe secundária que fornece uma entidade padrão previamente preenchida com dados. Por exemplo

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

   return $obj;
}

Não é realmente ideal, pois você terá que manter essa função se adicionar campos extras, mas isso significa que você está separando os configuradores de dados / padrão e o que é gerado a partir do banco de dados. Da mesma forma, você pode ter vários getFactories caso deseje diferentes dados padrão.

Entidades estendidas / de reflexão Crie uma Entidade estendida (por exemplo, FooCreate estende Foo) que fornece os dados padrão no momento da criação (por meio do construtor). Semelhante à idéia de fábrica / instância, apenas uma abordagem diferente - prefiro métodos estáticos pessoalmente.

Definir dados antes do formulário de compilação Nos construtores / serviço, você sabe se possui uma nova entidade ou se foi preenchida a partir do banco de dados. Portanto, é plausível chamar dados do conjunto nos diferentes campos quando você pega uma nova entidade. Por exemplo

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

Eventos do formulário Ao criar o formulário, você define os dados padrão ao criar os campos. Você substitui esse ouvinte de evento PreSetData de uso. O problema é que você está duplicando a carga de trabalho do formulário / duplicando o código e dificultando a manutenção / compreensão.

Formulários estendidos Semelhante aos eventos de Formulário, mas você chama o tipo diferente, dependendo se é uma entidade db / new. Com isso, quero dizer que você tem o FooType, que define seu formulário de edição, o BarType estende o FooType e define todos os dados para os campos. No seu controlador, basta escolher o tipo de formulário a ser instalado. Isso é péssimo se você tiver um tema personalizado e, como eventos, criar muita manutenção para o meu gosto.

Twig Você pode criar seu próprio tema e usar como padrão os dados usando a opção de valor também ao fazê-lo por campo. Não há nada que impeça que você envolva isso em um tema de formulário, caso deseje manter seus modelos limpos e o formulário reutilizável. por exemplo

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

JS Seria trivial preencher o formulário com uma função JS se os campos estiverem vazios. Você poderia fazer algo com espaços reservados, por exemplo. Essa é uma péssima idéia, no entanto.

Formulários como um serviço Para um dos grandes projetos baseados em formulários que criei, criei um serviço que gerava todos os formulários, fazia todo o processamento etc. Isso acontecia porque os formulários eram para serem usados ​​em vários controladores em vários ambientes e enquanto os formulários foram gerados / manipulados da mesma maneira, foram exibidos / interagiram de maneira diferente (por exemplo, tratamento de erros, redirecionamentos etc.). A vantagem dessa abordagem foi que você pode usar como padrão os dados, fazer tudo o que precisa, lidar com os erros genericamente, etc, e tudo está encapsulado em um só lugar.

Conclusão A meu ver, você encontrará o mesmo problema várias vezes - onde estão os dados padrão?

  • Se você armazená-lo no nível db / doutrina, o que acontece se você não quiser armazenar o padrão todas as vezes?
  • Se você armazená-lo no nível da entidade, o que acontece se você quiser reutilizar essa entidade em outro lugar sem nenhum dado nela?
  • Se você armazená-lo no nível de entidade e adicionar um novo campo, deseja que as versões anteriores tenham esse valor padrão na edição? O mesmo vale para o padrão no banco de dados ...
  • Se você o armazena no nível do formulário, é óbvio quando você mantém o código posteriormente?
  • Se estiver no construtor, o que acontece se você usar o formulário em vários locais?
  • Se você empurrá-lo para o nível JS, você foi longe demais - os dados não devem estar na visão, não importa o JS (e estamos ignorando a compatibilidade, erros de renderização etc.)
  • O serviço é ótimo se, como eu, você o está usando em vários lugares, mas é um exagero para um simples formulário de adição / edição em um site ...

Para esse fim, abordei o problema de forma diferente a cada vez. Por exemplo, uma opção "boletim informativo" do formulário de inscrição é configurada facilmente (e logicamente) no construtor antes de criar o formulário. Quando eu estava criando coleções de formulários vinculadas (por exemplo, quais botões de opção em diferentes tipos de formulários vinculados), usei Ouvintes de Eventos. Quando criei uma entidade mais complicada (por exemplo, uma que exigisse filhos ou muitos dados padrão), usei uma função (por exemplo, 'getFactory') para criar o elemento conforme necessário.

Não acho que exista uma abordagem "correta", pois toda vez que tenho esse requisito, ele é um pouco diferente.

Boa sorte! Espero ter dado a você alguma opinião sobre o assunto e não divagado demais;)

stefancarlton
fonte
você poderia dar um pouco mais de detalhes sobre o que você quis dizer sobre 'um serviço que gerou todos os formulários'? Também estou trabalhando em um projeto realmente centrado em formulários agora e seria ótimo ter perspectivas diferentes sobre ele.
user2268997
2
ao usar a doutrina, os construtores não são chamados quando uma entidade é carregada do banco de dados.
NDM
43

Se você precisar definir o valor padrão e seu formulário estiver relacionado à entidade, use a seguinte abordagem:

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

Caso contrário, myFieldsempre será definido como valor padrão, em vez de obter valor da entidade.

Dmitriy
fonte
No caso de matrizes em vez de entidades, substitua-as $options['data']->getMyField()por$option['data']['myField']
ggg 29/11
3
Esse é o caminho certo para adicionar / atualizar, eu acho. Mas eu odeio Symfony torná-lo muito complexo.
Yarco
Esta é a única boa resposta. Não entendo outras respostas quando olho para o documento. empty_data: Esta opção determina qual valor o campo retornará quando o valor enviado estiver vazio. Ele não define um valor inicial
Vincent Decaux 19/06
16

Se seu formulário estiver vinculado a uma entidade, basta definir o valor padrão na própria entidade usando o método de construção:

public function __construct()
{
    $this->field = 'default value';
}
Hubert Perron
fonte
Mesmo assim, seu formulário pode ter campos adicionais não mapeados para sua entidade ( 'mapped' => false). Use setData(...)para estes.
Dizzley
12

Abordagem 1 (em http://www.cranespud.com/blog/dead-simple-default-values-on-symfony2-forms/ )

Basta definir o valor padrão em sua entidade, na declaração da variável ou no construtor:

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

ou

class Entity {
    private $color;

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

Abordagem 2 de um comentário no link acima, e também a resposta de Dmitriy (não a aceita) em Como definir o valor padrão para o campo de formulário no Symfony2?

Adicione o valor padrão ao atributo de dados ao adicionar o campo com o FormBuilder, adaptado da resposta de Dmitriy.

Observe que isso pressupõe que a propriedade terá e terá apenas o valor nulo quando for uma entidade nova e não existente.

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
fonte
O primeiro funciona (obrigado!), O segundo não funciona (para mim): $ options ["data] é sempre definido, portanto o valor padrão nunca será usado. Ainda estou me perguntando se a solução número 1 é a maneira pretendida Para fazer isso ...
herrjeh42
Você está certo sobre $ options ['data'] sempre sendo definido. Se você não inicializar o campo da entidade, poderá testar nulo no campo, por exemplo. 'data' => $ options ['data'] -> getColor ()! == null? etc ... Isso pressupõe que nulo não é um valor válido para o campo de cores; portanto, as entidades existentes nunca teriam um valor nulo para esse campo.
Crysallus
ah, estúpido: tentei com 'isset ($ $ options [' data '] -> getColor ())', recebi uma mensagem de erro sobre "não é permitido usá-lo em contextos de escrita" e esqueci que tenho que verificá-lo de forma diferente :-)
herrjeh42
1
Na verdade, parece haver ocasiões em que a entrada de dados não está definida. Mais seguro para testar, por exemplo, isset ($ options ['data']) && $ options ['data'] -> getColor ()! == null? ...
crysallus
9

Você pode definir um valor padrão, por exemplo, para o formulário message, assim:

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

Caso seu formulário seja mapeado para uma Entidade, você pode seguir este exemplo (por exemplo, nome de usuário padrão):

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

$form = $this->createFormBuilder($user)
    ->add('username')
    ->getForm();
Gottlieb Notschnabel
fonte
2
Eu prefiro esse método, especialmente porque na maioria dos aplicativos você está criando um formulário e passando em uma entidade com a qual o formulário lida.
skrilled
9

Uma solução geral para qualquer caso / abordagem, principalmente usando um formulário sem classe ou quando precisamos acessar qualquer serviço para definir o valor padrão:

// 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;
    }
}

e registre a extensão do formulário:

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

Depois disso, podemos usar a defaultopção em qualquer campo de formulário:

$formBuilder->add('user', null, array('default' => $this->getUser()));
$formBuilder->add('foo', null, array('default' => 'bar'));
yceruto
fonte
Isto deveria ter sido aceite como a melhor resposta (up-to-date)
medunes
7

Não use:

'data' => 'Default value'

Leia aqui: https://symfony.com/doc/current/reference/forms/types/form.html#data

"A opção de dados sempre substitui o valor obtido dos dados do domínio (objeto) durante a renderização. Isso significa que o valor do objeto também é substituído quando o formulário edita um objeto já persistente, fazendo com que perca seu valor persistente quando o formulário é enviado."


Use o seguinte:

Digamos que, neste exemplo, você tenha um Entity Foo e haja um campo "ativo" (neste exemplo é CheckBoxType, mas o processo é o mesmo para todos os outros tipos), que você deseja que seja verificado por padrão

Na sua classe FooFormType, adicione:

...
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',
    ));
}
cure85
fonte
Isso aqui é dinheiro !! Use o ouvinte de eventos do formulário para verificar seus valores antes de padronizá-los. Essa deve ser a resposta aceita para os valores padrão nos seus formulários, pois funciona para as ações Novas e Editar.
Tlens
Esta é a maneira correta de lidar com isso e essa deve ser a resposta aceita.
Bettinz
O que você mencionou no início não é verdade se você usar um condicional / ternário. Assim:'data' => $data['myfield'] ?? 'Default value'
xarlymg89 18/02
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
fonte
Esta é uma boa solução. Ligar em $event->setData()vez de ler o campo pode torná-lo ainda melhor.
precisa saber é o seguinte
5

Minha solução:

$defaultvalue = $options['data']->getMyField();
$builder->add('myField', 'number', array(
            'data' => !empty($defaultvalue) ? $options['data']->getMyField() : 0
        )) ;
trocolo
fonte
4

Só assim eu entendo o problema.

Você deseja ajustar a maneira como o formulário é criado com base nos dados da sua entidade. Se a entidade estiver sendo criada, use algum valor padrão. Se a entidade existir, use o valor do banco de dados.

Pessoalmente, acho que a solução da @ MolecularMans é o caminho a percorrer. Na verdade, eu definiria os valores padrão no construtor ou na declaração de propriedade. Mas você não parece gostar dessa abordagem.

Em vez disso, você pode seguir isto: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

Você pendura um ouvinte no seu tipo de formulário e, em seguida, pode examinar sua entidade e ajustar as instruções construtor-> add de acordo com a inclusão de uma entidade nova ou existente. Você ainda precisa especificar seus valores padrão em algum lugar, embora possa codificá-los no seu ouvinte. Ou passe-os para o tipo de formulário.

Parece muito trabalho embora. Melhor apenas passar a entidade para o formulário com os valores padrão já definidos.

Cerad
fonte
4

Se você estiver usando um FormBuilderno symfony 2.7 para gerar o formulário, também poderá passar os dados iniciais para o createFormBuildermétodo do Controler

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

$formBuilder = $this->createFormBuilder($values);
$formBuilder->add('name', 'text');
Prumo
fonte
3

Freqüentemente, para valores padrão init do formulário, eu uso equipamentos. De causa desta maneira não é mais fácil, mas muito confortável.

Exemplo:

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();        
    }   
}

No entanto, o campo do tipo symfony tem os dados da opção .

Exemplo

$builder->add('token', 'hidden', array(
    'data' => 'abcdef',
));
Mikhail Shchedrakov
fonte
3

Existe uma maneira muito simples, você pode definir padrões como aqui:

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

$form = $this->formfactory->createBuilder('form', $defaults)
->add('sortby','choice')
->add('category','choice')
->add('page','hidden')
->getForm();
Alsaciano
fonte
3

Se você definir 'dados' em seu formulário de criação, esse valor não será modificado ao editar sua entidade.

Minha solução é:

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',
    ));
}

Tchau.

Quentin Machard
fonte
Muito mais útil do que uma resposta aceita! Se você usa o PHP7 +, você pode torná-lo ainda mais 'data' => $data['myfield'] ?? 'Default value',
limpo
Você tem um erro de digitação na função array_key_exists () #
Deadpool
1

Os valores padrão são definidos configurando a entidade correspondente. Antes de vincular a entidade ao formulário, defina seu campo de cores como "# 0000FF":

// controller action
$project = new Project();
$project->setColor('#0000FF');
$form = $this->createForm(new ProjectType(), $project);
Molecular Man
fonte
Essa abordagem funciona, mas tem a desvantagem de que você precisa fazer isso toda vez que usa a classe de formulário e é muito detalhada (muitas instruções definidas). Como o componente do formulário é muito elegante, deve haver algo mais. Mas obrigado de qualquer maneira :-)
herrjeh42
@ jamie0726 Na minha opinião, é responsabilidade do controlador definir os valores do objeto sempre que novo ou buscado. Dessa forma, é possível usar o formulário em diferentes situações com comportamentos diferentes, por exemplo, a nova cor pode mudar devido ao usuário ter uma função de gerente ou super-gerente e, como essa é uma lógica de negócios, deve ser controlada pelo controlador ou um serviço, não o formulário. Então, como Cerad afirmou, eu também prefiro esta solução. Você sempre pode criar um serviço para definir esses valores padrão e, no controlador, usar esse serviço, mantendo-o SECO.
saamorim
Essa é a solução que eu escolhi, porque se encaixa na lógica que penso. Os controladores gerados têm métodos diferentes para criar formulários EDIT e CREATE, e é aí que eu defino os dados padrão / iniciais para a nova entidade.
Alumi
1

Se esse campo estiver vinculado a uma entidade (é uma propriedade dessa entidade), você pode apenas definir um valor padrão para ela.

Um exemplo:

public function getMyField() {
    if (is_null($this->MyField)) {
        $this->setMyField('my default value');
    }
    return $this->MyField;
}
Andrei Sandulescu
fonte
1

Normalmente, apenas defino o valor padrão para um campo específico na minha entidade:

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

Isso funcionará para novos registros ou apenas para atualizar os existentes.

matotej
fonte
Isso não parece funcionar quando 'empty_data'um retorno de chamada é usado para permitir parâmetros de construtor na entidade.
NDM
1

Como Brian perguntou:

empty_data parece definir apenas o campo para 1 quando é enviado sem valor. E quando você deseja que o formulário seja padrão para exibir 1 na entrada quando nenhum valor estiver presente?

você pode definir o valor padrão com empty_value

$builder->add('myField', 'number', ['empty_value' => 'Default value'])
Snowirbis
fonte
0

Resolvi esse problema, adicionando valor no attr :

->add('projectDeliveringInDays', null, [
    'attr' => [
          'min'=>'1',
          'value'=>'1'
          ]
     ])
Kaxa
fonte