2016-05-03 43 views
6

Ho un'entità Product. Il mio prodotto può avere più nomi in diverse lingue. Un nome in francese, un nome in inglese, ecc. Non voglio usare una traduzione automatica.Symfony3: Tipo scelta campo riempito con matrice di oggetti

L'utente dovrà scrivere i nomi nella forma del prodotto e selezionare la lingua corrispondente. Può aggiungere tanti nomi come vuole grazie a un pulsante Aggiungi.

Tutte le lingue vengono creati dall'utente amministratore (in un'altra forma). Quindi, Language è anche un'entità che ha un nome (es: inglese) e un codice (es: EN).

Ho creato l'entità ProductName che ha un nome e una lingua (conformi a ciò che l'utente scrive nel modulo Prodotto).

In tal caso, non è necessario associare Entità ProductName all'entità Language. Voglio solo il codice della lingua. Quindi, a mio ProductName entità, ho questo immobile:

/** 
* @ORM\Column(name="Language_Code", type="string", length=2) 
*/ 
private $language; 

La mia forma del prodotto (ProductType) ha un campo CollectionType al fine di aggiungere diversi nomi.

// Form/ProductType.php 

    ->add('infos',  CollectionType::class, array(
     'entry_type' => ProductInfosType::class, 
     'allow_add'  => true, 
     'allow_delete' => true, 
     'prototype'  => true, 
     'label'   => false, 
     'mapped'  => false 
    )) 

E forma ProductInfosType ha 2 campi:

// Form/ProductInfosType.php 

     ->add('name',   TextType::class, array(
      'attr'    => array('size' => 40) 
     )) 
     ->add('language',  EntityType::class, array(
      'placeholder'  => '', 
      'class'    => 'AppBundle:Language', 
      'choice_label'  => 'code', 
      'attr'    => array('class' => 'lang'), 
      'query_builder'  => function (EntityRepository $er) { 
       return $er->createQueryBuilder('l')->orderBy('l.code', 'ASC'); 
      } 
     )) 

Così, quando vado sulla mia pagina del modulo, ho un blocco che contiene un campo di testo di input (Nome) e un campo di selezione (la lingua). Il campo di selezione è come questo:

<select id="product_infos_0_language" required="required" name="product[infos][0][language]"> 
    <option value=""></option> 
    <option value="DE">DE</option> 
    <option value="EN">EN</option> 
    <option value="ES">ES</option> 
    <option selected="selected" value="FR">FR</option> 
</select> 

A questo punto, tutto funziona bene. Ho creato un pulsante di aggiunta in modo che l'utente possa aggiungere altri nomi, ecc ...

Tuttavia, quando invio il modulo, quando controllo i dati del modulo nel mio ProductController, ho notato che non corrisponde a quello che desidera memorizzare nel database.

print_r($form->get('infos')->getData()); 

// returns : 
Array 
(
    [0] => AppBundle\Entity\ProductName Object 
     ( 
      [language:AppBundle\Entity\ProductName:private] => AppBundle\Entity\Language Object 
       (
        [code:AppBundle\Entity\Language:private] => FR 
        [name:AppBundle\Entity\Language:private] => Français 
       ) 

      [name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin 
     ) 
) 

Quello che vorrei è:

Array 
(
    [0] => AppBundle\Entity\ProductName Object 
     ( 
      [language:AppBundle\Entity\ProductName:private] => FR  
      [name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin 
     ) 
) 

Non voglio l'oggetto linguaggio ma direttamente il codice della lingua!

Ecco perché penso che non dovrei usare EntityField nel campo ProductNameType ma nel campo ChoiceType.

Come posso caricare tutte le lingue memorizzate in dB nel campo scelta? Spero che questa spiegazione sia più comprensibile ;-)

+0

Se ho capito bene: hai provato a creare un metodo '__toString()' che restituisce la proprietà 'code' dell'entità' Language'? – Delphine

+0

No. Non penso che mi aiuti. Il codice della mia lingua è già una stringa. Es: Nome = inglese e codice = EN. Invece di ottenere una lingua oggetto quando invio il mio modulo, voglio solo il codice che ho selezionato nel mio elenco. – Felurian

+0

Non capisco cosa intendi per "ottenere" dopo l'invio – Delphine

risposta

6

ho trovato la soluzione grazie a questo post: Passing data to buildForm() in Symfony 2.8/3.0

ProductController.php: trasmettere dati personalizzati come opzione nel metodo createForm().

// ... 

// build the form 
$em = $this->getDoctrine()->getManager(); 
$product = new Product(); 
$languages = $em->getRepository('AppBundle:Language')->findAllOrderedByCode(); 

$form = $this->createForm(ProductType::class, $product, array(
    'languages' => $languages 
)); 

ProductType forma: trasmettere dati personalizzati nelle opzioni resolver

public function configureOptions(OptionsResolver $resolver) { 
    $resolver->setDefaults(array(
     'data_class' => 'AppBundle\Entity\Product', 
     'languages' => null 
    )); 
} 

Poi, nella funzione buildForm(), aggiungere un'opzione entry_options nel campo CollectionType:

$builder->add('infos', CollectionType::class, array(
    'entry_type' => ProductInfosType::class, 
    'entry_options' => array('languages' => $options['languages']), 
    'allow_add'  => true, 
    'allow_delete' => true, 
    'prototype'  => true, 
    'label'   => false, 
    'by_reference' => false 
)); 

Modulo ProductInfosType: passa i dati personalizzati nella o pzioni resolver (esattamente come nella ProductForm)

public function configureOptions(OptionsResolver $resolver) { 
    $resolver->setDefaults(array(
     'data_class' => 'AppBundle\Entity\ProductName', 
     'languages' => null 
    )); 
} 

Ora, si hanno due alternative: o si desidera che il modulo restituisce entità o stringhe semplici.

Nel mio esempio, voglio solo il codice della lingua (come FR, EN, ecc.).

Caso 1: restituire solo il codice della lingua quando il modulo viene inviato:

// Form/ProductInfosType.php 

// ... 

// Convert array of objects in an array of strings 
$choices = array(); 
foreach ($options['languages'] as $lang) { 
    $code = $lang->getCode(); 
    $choices[$code] = $code; 
} 

$builder->add('language', ChoiceType::class, array(
    'placeholder'  => '', 
    'choices'   => $choices 
)); 

// returns : 
Array 
(
    [0] => AppBundle\Entity\ProductName Object 
     ( 
      [name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin 
      [language:AppBundle\Entity\ProductName:private] => FR  
     ) 
) 

Caso 2: tornare Lingua Entità quando il modulo viene inviato:

// Form/ProductInfosType.php 

// ... 

$builder->add('language', ChoiceType::class, array(
    'placeholder'  => '', 
    'choices'   => $options['languages'], 
    'choice_label'  => 'code', 
    'choice_value'  => 'code' 
)); 

// returns : 
Array 
(
    [0] => AppBundle\Entity\ProductName Object 
     ( 
      [name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin 
      [language:AppBundle\Entity\ProductName:private] => AppBundle\Entity\Language Object 
       (
        [code:AppBundle\Entity\Language:private] => FR 
        [name:AppBundle\Entity\Language:private] => Français 
       )  
     ) 
) 

Con questa soluzione, non abbiamo bisogno di creare il nostro modulo come servizio per passare il gestore di entità come argomento. Tutto è gestito nel controller e nelle opzioni del modulo.

1

È necessario utilizzare choice_value di EntityType.

'choice_value' => function ($language) { 
    return $language->getCode(); 
}, 

EDIT: Dopo aver letto la tua modifica, hai davvero ragione, non utilizzare EntityType ma ChoiceType. Per popolare choices, penso che dovresti iniettare LanguageRepository all'interno del modulo utilizzando DependencyInjection e quindi creare una query nel tuo repository per recuperare tutti i codici di lingua.

+0

No, ho già i codici come valori delle mie opzioni di selezione. Non cambia i dati del mio modulo. – Felurian

+0

Ho modificato il mio post per spiegare meglio il mio problema ;-) – Felurian

+0

Va bene, quindi ho modificato anche la mia risposta. – Terenoth