2013-04-05 4 views
6

Ich möchte ein Auswahlfeld in Symfony2 mit Werten aus einer benutzerdefinierten Abfrage füllen. Ich habe versucht, so viel wie möglich zu vereinfachen.symfony2 - Hinzufügen von Auswahlmöglichkeiten aus der Datenbank

-Controller

class PageController extends Controller 
{ 

    public function indexAction() 
    { 
     $fields = $this->get('fields'); 
     $countries = $fields->getCountries(); // returns a array of countries e.g. array('UK', 'France', 'etc') 
     $routeSetup = new RouteSetup(); // this is the entity 
     $routeSetup->setCountries($countries); // sets the array of countries 

     $chooseRouteForm = $this->createForm(new ChooseRouteForm(), $routeSetup); 


     return $this->render('ExampleBundle:Page:index.html.twig', array(
     'form' => $chooseRouteForm->createView() 
    )); 

    } 
} 

ChooseRouteForm

class ChooseRouteForm extends AbstractType 
{ 

    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 

    // errors... ideally I want this to fetch the items from the $routeSetup object 
    $builder->add('countries', 'choice', array(
     'choices' => $this->routeSetup->getCountries() 
    )); 

    } 

    public function getName() 
    { 
    return 'choose_route'; 
    } 
} 

Antwort

18

Sie könnten die Wahlen zum Formular übergeben mit ..

$chooseRouteForm = $this->createForm(new ChooseRouteForm($routeSetup), $routeSetup); 

Dann in Ihrem Formular ..

private $countries; 

public function __construct(RouteSetup $routeSetup) 
{ 
    $this->countries = $routeSetup->getCountries(); 
} 

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder->add('countries', 'choice', array(
     'choices' => $this->countries, 
    )); 
} 

aktualisiert (und verbessert) für 2.8+

Erstens brauchen Sie nicht wirklich in den Ländern als Teil der Route Objekt zu übergeben, wenn sie nicht in der DB gespeichert werden werden.

Wenn Sie die verfügbaren Länder in der Datenbank speichern, können Sie einen Ereignis-Listener verwenden. Wenn nicht (oder wenn Sie keinen Listener verwenden möchten), können Sie die Länder im Optionsbereich hinzufügen.

Optionen verwenden

Im Controller ..

$chooseRouteForm = $this->createForm(
    ChooseRouteForm::class, 
    // Or the full class name if using < php 5.5 
    $routeSetup, 
    array('countries' => $fields->getCountries()) 
); 

Und in Ihrem Formular ..

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder->add('countries', 'choice', array(
     'choices' => $options['countries'], 
    )); 
} 

public function configureOptions(OptionsResolver $resolver) 
{ 
    $resolver 
     ->setDefault('countries', null) 
     ->setRequired('countries') 
     ->setAllowedTypes('countries', array('array')) 
    ; 
} 

Using A Listener (Wenn die Länder Array ist im Modell verfügbar)

Im Controller ..

$chooseRouteForm = $this->createForm(
    ChooseRouteForm::class, 
    // Or the full class name if using < php 5.5 
    $routeSetup 
); 

Und in Ihrem Formular ..

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder 
     ->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) { 
      $form = $event->getForm(); 
      /** @var RouteSetup $routeSetup */ 
      $routeSetup = $event->getData(); 

      if (null === $routeSetup) { 
       throw new \Exception('RouteSetup must be injected into form'); 
      } 

      $form 
       ->add('countries', 'choice', array(
        'choices' => $routeSetup->getCountries(), 
       )) 
      ; 
     }) 
    ; 
} 
+1

So, wie von Symfony 2.8, ist es veraltet, in einer instanziierten Formularklasse zu übergeben. Jetzt müssen Sie stattdessen den vollständig qualifizierten Klassennamen übergeben. Was den Konstruktor überflüssig macht ... Das saugt, weil ich die Optionen nicht wie in meinem Fall vom Controller laden will, dieses Auswahlfeld wird von vielen Controllern benutzt und wäre sinnvoll zu konstruieren die Wahlmöglichkeiten in der Formularklasse, aber wie bekommt man den Doktrinmanager in die Formularklasse ohne die Optionen oder Dienste zu benutzen ...? hack hack hack, es sei denn, ich verpasse etwas, bitte sag das. – Prof83

+1

Um ehrlich zu sein, war das noch nicht der beste Ansatz. Ich werde aktualisieren. – qooplmao

+0

Keine Sorge, dein Beitrag war 2013 und 2.8 ist wie vor ein paar Monaten. Danke für das Update ... Ich werde jetzt damit herumspielen – Prof83

10

kann ich nicht kommentieren oder noch downvote, also werde ich einfach Beantworten Sie die Antwort von Qoop hier: Was Sie vorgeschlagen haben, funktioniert nur, wenn Sie Ihre Formulartypklasse als Dienst verwenden. Sie sollten im Allgemeinen vermeiden, Daten zu Ihrem Formulartyp-Objekt über Konstruktor hinzuzufügen.

Denken Sie an Formulartyp Klasse wie eine Klasse - es ist eine Art der Beschreibung des Formulars. Wenn Sie eine Instanz von Formular (indem Sie es erstellen) erstellen, erhalten Sie das Objekt des Formulars, das durch die Beschreibung in Formulartyp erstellt und dann mit Daten gefüllt wird.

Werfen Sie einen Blick auf diese: http://www.youtube.com/watch?v=JAX13g5orwo - diese Situation wird rund 31 Minuten der Präsentation beschrieben.

Sie sollten Formularereignis FormEvents :: PRE_SET_DATA verwenden und Felder bearbeiten, wenn das Formular mit Daten injiziert wird. Siehe: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#customizing-your-form-based-on-the-underlying-data

+1

Was ist der Vorteil davon? Warum nicht einfach prüfen, ob die Formulardaten '$ routesetup' gesetzt sind? Und wenn nicht, fügen Sie das Feld nicht hinzu/werfen Sie einen netten Fehler? – user2019515

+0

Dies war der Best-Practice-Ansatz. Ich habe den Code in der Frage so korrigiert, dass er funktioniert, anstatt ihn "zu verbessern". Ich habe meine Antwort jetzt mit dem erwähnten 'PRE_SET_DATA'-Ansatz und einem anderen aktualisiert (aufgrund eines neuen Kommentars, im Gegensatz zu mir, ein Verrückter zu sein, der meine Antwort von 2+ Jahren neu liest). – qooplmao