Come impostare il valore predefinito per il campo modulo in Symfony2?


137

C'è un modo semplice per impostare un valore predefinito per il campo del modulo di testo?


1
sì, ma le risposte fornite in questa domanda non sono soddisfacenti / non funzionano ... Aggiungerò un "Modifica" per spiegare perché :-)
herrjeh42

Sembra che la soluzione 'perfetta' che stai cercando sia quella di avere un'opzione 'default_value' in un campo. La cosa è, al momento no , quindi non credo che la soluzione perfetta che stai cercando esista attualmente. L'unica cosa che symfony fornisce (vedi il link) è l'opzione data. Quindi il if-then è l'unico approccio che posso vedere atm. Anche se ci fosse un'opzione 'default_value' sul campo stesso, immagino che essenzialmente farebbe comunque la stessa cosa internamente.
Crysallus,

Inoltre, ho apportato una correzione alla mia risposta nell'approccio 2 secondo i miei commenti qui sotto. Se ciò risolve il problema di sintassi menzionato al punto 2, potresti voler modificare quel commento. Oppure fammi sapere qual è il problema e risolverò la mia risposta.
Crysallus,

1
@Crone questa domanda è stata posta 2 anni prima
Ondrej Slinták,

1
@ OndrejSlinták Non ho votato per chiudere né come duplicato, ma FYI: non importa quale sia venuto prima, " Se la nuova domanda è una domanda migliore o ha risposte migliori, quindi vota per chiudere la vecchia come duplicato di quello nuovo " .
Jeff Puckett,

Risposte:


105

Può essere utilizzato durante la creazione facilmente con:

->add('myfield', 'text', array(
     'label' => 'Field',
     'empty_data' => 'Default value'
))

11
Per Symfony 2.1 avevo bisogno di cambiare la 'data'chiave in'value'
Edd

175
Questo non solo imposta un valore predefinito, ma forza sempre il valore in qualsiasi contesto. Non quello che definirei un "valore predefinito" ...
Hubert Perron,

4
Ho votato in giù questa soluzione in quanto non è una soluzione al problema (come menzionato sopra Hubert Perron). Sto cercando di ottenere una migliore soluzione in questo post stackoverflow.com/questions/17986481/...
herrjeh42

13
Questo è il valore iniziale, il valore predefinito èempty_data
Pierre de LESPINAY,

3
dataè inutile: sovrascrive il valore salvato. empty_datanon mostra il valore, lo usa su invio di valore vuoto e rende impossibile salvare le scelte non selezionate.
Moldcraft,

115

puoi impostare il valore predefinito con empty_data

$builder->add('myField', 'number', ['empty_data' => 'Default value'])

29
L'impostazione dei dati non sta impostando il valore predefinito. Questa risposta è quella corretta.
Alexei Tenitski,

9
Questo sembra impostare il campo su 1 solo quando è inviato senza valore. Che dire di quando si desidera che il modulo venga visualizzato per impostazione predefinita 1 nell'input quando non è presente alcun valore?
Brian,

Nei miei test empty_data non mi consente di sovrascrivere il valore predefinito da un campo inviato vuoto, ad esempio se si desidera salvare nel database come 0 anziché NULL. Questo bug è ancora eccezionale per quanto posso dire: github.com/symfony/symfony/issues/5906
Chadwick Meyer

63

L'ho contemplato alcune volte in passato, quindi ho pensato di annotare le diverse idee che avevo / usato. Qualcosa potrebbe essere utile, ma nessuna è la soluzione "perfetta" di Symfony2.

Costruttore Nell'entità è possibile eseguire $ this-> setBar ('valore predefinito'); ma questo viene chiamato ogni volta che carichi l'entità (db o no) ed è un po 'disordinato. Funziona tuttavia per ogni tipo di campo in quanto è possibile creare date o qualsiasi altra cosa sia necessaria.

Se le dichiarazioni all'interno di get non lo farei, ma potresti.

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

Fabbrica / istanza . Chiama una funzione statica / classe secondaria che ti fornisce un'entità predefinita precompilata con i dati. Per esempio

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

   return $obj;
}

Non proprio l'ideale dato che dovrai mantenere questa funzione se aggiungi campi aggiuntivi, ma significa che stai separando i setter di dati / default e quello che viene generato dal db. Allo stesso modo puoi avere più getFactories se desideri diversi dati predefiniti.

Entità estese / di riflessione Crea un'entità estesa (ad esempio FooCreate estende Foo) che ti fornisce i dati predefiniti al momento della creazione (tramite il costruttore). Simile all'idea di fabbrica / istanza, solo un approccio diverso: preferisco personalmente i metodi statici.

Imposta i dati prima del modulo di compilazione Nei costruttori / servizi, sai se hai una nuova entità o se è stata popolata dal database. È plausibile quindi chiamare i dati impostati sui diversi campi quando si prende una nuova entità. Per esempio

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

Eventi modulo Quando si crea il modulo, si impostano i dati predefiniti durante la creazione dei campi. Sostituisci questo listener di eventi PreSetData. Il problema è che stai duplicando il carico di lavoro del modulo / duplicando il codice e rendendo più difficile la manutenzione / comprensione.

Moduli estesi Simile agli eventi Modulo, ma si chiama il tipo diverso a seconda che si tratti di una nuova entità / db. Con questo intendo che hai FooType che definisce il tuo modulo di modifica, BarType estende FooType e imposta tutti i dati sui campi. Nel tuo controller scegli semplicemente quale tipo di modulo installare. Questo fa schifo se hai un tema personalizzato e come eventi, crea troppa manutenzione per i miei gusti.

Ramoscello Puoi creare il tuo tema e predefinire i dati usando anche l'opzione value quando lo fai in base al campo. Non c'è nulla che ti impedisca di avvolgerlo in un tema di modulo o se desideri mantenere i tuoi modelli puliti e il modulo riutilizzabile. per esempio

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

JS Sarebbe banale popolare il modulo con una funzione JS se i campi sono vuoti. Ad esempio, potresti fare qualcosa con i segnaposto. Questa è una cattiva, cattiva idea però.

Moduli come servizio Per uno dei grandi progetti basati su moduli che ho realizzato, ho creato un servizio che ha generato tutti i moduli, eseguito tutte le elaborazioni, ecc. Questo perché i moduli dovevano essere utilizzati su più controller in più ambienti e mentre i moduli sono stati generati / gestiti allo stesso modo, sono stati visualizzati / interagiti in modo diverso (ad es. gestione degli errori, reindirizzamenti ecc.). La bellezza di questo approccio è che puoi impostare dati predefiniti, fare tutto ciò di cui hai bisogno, gestire errori genericamente ecc. Ed è tutto incapsulato in un unico posto.

Conclusione A mio modo di vedere, incontrerai più volte lo stesso problema: dove devono risiedere i dati predefiniti?

  • Se lo memorizzi a livello di db / dottrina, cosa succede se non vuoi memorizzare il valore predefinito ogni volta?
  • Se lo memorizzi a livello di entità, cosa succede se desideri riutilizzare quell'entità altrove senza dati in essa contenuti?
  • Se lo memorizzi a livello di entità e aggiungi un nuovo campo, desideri che le versioni precedenti abbiano quel valore predefinito al momento della modifica? Lo stesso vale per l'impostazione predefinita nel DB ...
  • Se lo memorizzi a livello di modulo, è ovvio quando arrivi a mantenere il codice in un secondo momento?
  • Se è nel costruttore cosa succede se si utilizza il modulo in più punti?
  • Se lo spingi a livello di JS, sei andato troppo lontano - i dati non dovrebbero essere nella vista, non importa JS (e stiamo ignorando la compatibilità, il rendering degli errori ecc.)
  • Il servizio è eccezionale se come me lo stai utilizzando in più punti, ma è eccessivo per un semplice modulo di aggiunta / modifica su un sito ...

A tal fine, ho affrontato il problema in modo diverso ogni volta. Ad esempio, un'opzione di "newsletter" del modulo di iscrizione è facilmente (e logicamente) impostata nel costruttore appena prima di creare il modulo. Quando stavo costruendo raccolte di moduli che erano collegate tra loro (ad es. Quali pulsanti di opzione in diversi tipi di modulo collegati insieme) allora ho usato gli ascoltatori di eventi. Quando ho costruito un'entità più complicata (ad esempio una che richiedeva figli o molti dati predefiniti) ho usato una funzione (ad esempio 'getFactory') per crearne l'elemento di cui ho bisogno.

Non credo che esista un approccio "giusto", poiché ogni volta che ho avuto questo requisito è stato leggermente diverso.

In bocca al lupo! Spero di averti dato un po 'di spunti di riflessione in ogni caso e non ho fatto troppe cose;)


potresti dare qualche dettaglio in più su cosa intendevi per "un servizio che ha generato tutti i moduli"? Sto anche lavorando a un progetto veramente centrato sul modulo in questo momento e sarebbe bello avere diverse prospettive su di esso.
user2268997,

2
quando si usa la dottrina, i costruttori non vengono chiamati quando un'entità viene caricata dal db.
NDM,

43

Se è necessario impostare il valore predefinito e il modulo è correlato all'entità, è necessario utilizzare il seguente approccio:

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

In caso contrario, myFieldverrà sempre impostato sul valore predefinito, anziché ottenere il valore dall'entità.


In caso di array anziché entità, è sufficiente sostituire $options['data']->getMyField()con$option['data']['myField']
ggg il

3
Questo è il modo giusto sia per aggiungere / aggiornare, credo. Ma odio Symfony lo rende troppo complesso.
Yarco,

Questa è l'unica buona risposta. Non capisco altre risposte quando guardo il documento. empty_data: Questa opzione determina quale valore restituirà il campo quando il valore inviato è vuoto. Non imposta un valore iniziale
Vincent Decaux il


16

Se il modulo è associato a un'entità, basta impostare il valore predefinito sull'entità stessa utilizzando il metodo di costruzione:

public function __construct()
{
    $this->field = 'default value';
}

Anche così, il tuo modulo può avere campi aggiuntivi che non possono essere associati alla tua entità ( 'mapped' => false). Utilizzare setData(...)per questi.
Dizzley,

12

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

Basta impostare il valore predefinito nell'entità, nella dichiarazione della variabile o nel costruttore:

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

o

class Entity {
    private $color;

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

Approccio 2 da un commento nel link sopra, e anche la risposta di Dmitriy (non quella accettata) da Come impostare il valore predefinito per il campo modulo in Symfony2?

Aggiungi il valore predefinito all'attributo data quando aggiungi il campo con FormBuilder, adattato dalla risposta di Dmitriy.

Si noti che ciò presuppone che la proprietà avrà e avrà il valore null solo quando si tratta di un'entità nuova e non esistente.

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

Il primo funziona (grazie!), Il secondo no (per me): $ options ["data] è sempre impostato, quindi il valore predefinito non verrà mai utilizzato. Mi chiedo ancora se la soluzione numero 1 è il modo previsto per farlo ...
herrjeh42

Hai ragione circa $ opzioni ['dati'] sempre impostate. Se non si inizializza il campo entità, è possibile verificare invece null sul campo, ad es. 'data' => $ options ['data'] -> getColor ()! == null? ecc ... Ciò presuppone che null non sia un valore valido per il campo colore, quindi le entità esistenti non avrebbero mai un valore null per quel campo.
Crysallus,

ah, stupido: l'ho provato con 'isset ($ $ options [' data '] -> getColor ())', ho ricevuto un messaggio di errore "Usarlo per scrivere contesti non è permesso" e ho dimenticato che devo controlla diversamente :-)
herrjeh42

1
In realtà sembra che ci siano occasioni in cui l'immissione dei dati non è impostata. Più sicuro testare entrambi ie isset ($ options ['data']) && $ options ['data'] -> getColor ()! == null? ...
crysallus,

9

È possibile impostare un valore predefinito, ad esempio per il modulo message, in questo modo:

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

Nel caso in cui il tuo modulo sia mappato su un'entità, puoi andare così (es. Nome utente predefinito):

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

$form = $this->createFormBuilder($user)
    ->add('username')
    ->getForm();

2
Preferisco questo metodo, soprattutto perché nella maggior parte delle applicazioni si sta creando un modulo e si passa a un'entità con cui si occupa il modulo.
abilitato il

9

Una soluzione generale per qualsiasi caso / approccio, principalmente utilizzando un modulo senza una classe o quando è necessario accedere a qualsiasi servizio per impostare il valore predefinito:

// 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 registra l'estensione del modulo:

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

Successivamente, possiamo usare l' defaultopzione in qualsiasi campo del modulo:

$formBuilder->add('user', null, array('default' => $this->getUser()));
$formBuilder->add('foo', null, array('default' => 'bar'));

Questo avrebbe dovuto essere accettato come la migliore risposta (aggiornata)
medunes

7

Non usare:

'data' => 'Default value'

Leggi qui: https://symfony.com/doc/current/reference/forms/types/form.html#data

"L'opzione data sostituisce sempre il valore preso dai dati del dominio (oggetto) durante il rendering. Ciò significa che anche il valore dell'oggetto viene sostituito quando il modulo modifica un oggetto già persistente, causando la perdita del valore persistente quando viene inviato il modulo."


Utilizza il seguente:

Diciamo, per questo esempio, hai un Entity Foo, e c'è un campo "attivo" (in questo esempio è CheckBoxType, ma il processo è lo stesso per ogni altro tipo), che vuoi controllare per impostazione predefinita

Nella tua classe FooFormType aggiungi:

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

Questo qui è denaro !! Utilizzare il listener di eventi del modulo per verificare i valori prima di impostarli automaticamente. Questa dovrebbe essere la risposta accettata per i valori predefiniti nei moduli perché funziona sia per le nuove azioni sia per le azioni di modifica.
tlorens,

Questo è il modo corretto di gestirlo e questa dovrebbe essere la risposta accettata.
Bettinz,

Ciò che dici all'inizio non è vero se usi un condizionale / ternario. In questo modo:'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));
     }

});

questa è una bella soluzione Chiamare $event->setData()invece di leggere il campo potrebbe renderlo ancora migliore.
user2268997

5

La mia soluzione:

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

4

Solo così capisco il problema.

Si desidera modificare il modo in cui il modulo viene creato in base ai dati nell'entità. Se l'entità viene creata, utilizzare un valore predefinito. Se l'entità è esistente, utilizzare il valore del database.

Personalmente, penso che la soluzione di @ MolecularMans sia la strada da percorrere. Vorrei effettivamente impostare i valori predefiniti nel costruttore o nella dichiarazione di proprietà. Ma non sembra che ti piaccia questo approccio.

Invece puoi seguire questo: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

Appendi un listener al tuo tipo di modulo e puoi quindi esaminare la tua entità e regolare il builder-> aggiungi le istruzioni di conseguenza in base al fatto che hai un'entità nuova o esistente. Devi ancora specificare i valori predefiniti da qualche parte, anche se potresti semplicemente codificarli nel tuo listener. Oppure passali nel tipo di modulo.

Sembra un sacco di lavoro però. Meglio semplicemente passare l'entità al modulo con i suoi valori predefiniti già impostati.


4

Se stai usando a FormBuilderin symfony 2.7 per generare il modulo, puoi anche passare i dati iniziali al createFormBuildermetodo di Controler

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

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

3

Spesso, per i valori di default di init del modulo, utilizzo i dispositivi. Di causa in questo modo non è più semplice, ma molto comodo.

Esempio:

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

Tuttavia, il campo del tipo symfony ha i dati dell'opzione .

Esempio

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

3

C'è un modo molto semplice, puoi impostare i valori predefiniti come qui:

$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

Se si impostano "dati" nel modulo di creazione, questo valore non verrà modificato quando si modifica l'entità.

La mia soluzione è:

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

Ciao.


Molto più utile di una risposta accettata! Se usi PHP7 + puoi renderlo ancora più ordinato con:'data' => $data['myfield'] ?? 'Default value',
Boykodev

Hai un refuso nella funzione array_key_exists ()
Deadpool,

1

I valori predefiniti vengono impostati configurando l'entità corrispondente. Prima di associare l'entità al modulo impostare il campo di colore su "# 0000FF":

// controller action
$project = new Project();
$project->setColor('#0000FF');
$form = $this->createForm(new ProjectType(), $project);

questo approccio funziona, ma ha lo svantaggio di doverlo fare ogni volta che usi la classe form ed è molto dettagliato (molte istruzioni set). Poiché il componente del modulo è molto elegante, ci deve essere qualcos'altro. Ma grazie comunque :-)
herrjeh42

@ jamie0726 Secondo me è la responsabilità del controller di impostare i valori dell'oggetto ogni volta che è nuovo o recuperato. In questo modo è possibile utilizzare il modulo in diverse situazioni con comportamenti diversi, ad esempio, il nuovo colore potrebbe cambiare a causa dell'utente che ha un ruolo di manager o di supermanager e, poiché si tratta di una logica aziendale, dovrebbe essere controllata dal controller o un servizio, non il modulo. Quindi, come ha affermato Cerad, preferisco anche questa soluzione. È sempre possibile creare un servizio per impostare quei valori predefiniti e nel controller utilizzare quel servizio mantenendolo ASCIUTTO.
saamorim,

Questa è la soluzione che ho scelto, perché si adatta alla logica che penso. I controller generati hanno metodi diversi per la creazione di moduli EDIT e CREATE, e quelli sono quelli in cui ho impostato i dati predefiniti / iniziali per la nuova entità.
alumi,

1

Se quel campo è associato a un'entità (è una proprietà di quell'entità) puoi semplicemente impostare un valore predefinito per essa.

Un esempio:

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

1

Di solito imposto il valore predefinito per un campo specifico nella mia entità:

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

Questo funzionerà per i nuovi record o semplicemente aggiornando quelli esistenti.


Questo non sembra funzionare quando 'empty_data'viene utilizzato un callback per consentire i parametri del costruttore sull'entità.
NDM,

1

Come ha chiesto Brian:

empty_data sembra impostare il campo su 1 solo quando viene inviato senza valore. Che dire di quando si desidera che il modulo venga visualizzato per impostazione predefinita 1 nell'input quando non è presente alcun valore?

puoi impostare il valore predefinito con empty_value

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

0

Ho risolto questo problema aggiungendo valore in attr :

->add('projectDeliveringInDays', null, [
    'attr' => [
          'min'=>'1',
          'value'=>'1'
          ]
     ])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.