2015-03-13 7 views
9

Mam definicję formularza, która wykorzystuje dotychczasowy wielki typ pola entity. Za pomocą opcji query_builder wybieram moje wartości i są wyświetlane.Symfony2: Pole formularza encji z pustą wartością

Smutną częścią jest, że muszę wyświetlić domyślną wartość null, taką jak all (jest to forma filtra). Nie podoba mi się opcja choices z entity, ponieważ mam wartości bazy danych, a FormType nie powinien wysyłać zapytań do bazy danych.

Moje dotychczasowe podejście polegało na wdrożeniu niestandardowego typu pola, który rozszerza entity i dodaje pozycję pustą na początku listy. Typ pola jest załadowany i używany, ale niestety nie jest wyświetlana fikcyjna wartość.

Definicja pola:

$builder->add('machine', 'first_null_entity', [ 
    'label' => 'label.machine', 
    'class' => Machine::ident(), 
    'query_builder' => function (EntityRepository $repo) 
    { 
     return $repo->createQueryBuilder('m') 
      ->where('m.mandator = :mandator') 
      ->setParameter('mandator', $this->mandator) 
      ->orderBy('m.name', 'ASC'); 
    } 
]); 

Definicja typu forma:

class FirstNullEntityType extends AbstractType 
{ 

    /** 
    * @var unknown 
    */ 
    private $doctrine; 

    public function __construct(ContainerInterface $container) 
    { 
     $this->doctrine = $container->get('doctrine'); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setRequired('query_builder'); 
     $resolver->setRequired('class'); 
    } 

    public function buildView(FormView $view, FormInterface $form, array $options) 
    { 
     $class = $options['class']; 
     $repo = $this->doctrine->getRepository($class); 

     $builder = $options['query_builder']($repo); 
     $entities = $builder->getQuery()->execute(); 

     // add dummy entry to start of array 
     if($entities) { 
      $dummy = new \stdClass(); 
      $dummy->__toString = function() { 
       return ''; 
      }; 
      array_unshift($entities, $dummy); 
     } 

     $options['choices'] = $entities; 
    } 

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

    public function getParent() 
    { 
     return 'entity'; 
    } 
} 
+0

możesz użyć $ choices [''] = 'All'; w definicji typu formularza –

Odpowiedz

3

Alternatywnym rozwiązaniem byłoby użyć ChoiceList z wyborów, które są generowane z bazy danych, a następnie użyć jej w sposób niestandardowy typ formularza, który pozwoli na empty_value.

Wybór Lista

namespace Acme\YourBundle\Form\ChoiceList; 

use Doctrine\Common\Persistence\ObjectManager; 
use Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList; 
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface; 
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList; 

class MachineChoiceList extends LazyChoiceList 
{ 
    protected $repository; 

    protected $mandator; 

    public function __construct(ObjectManager $manager, $class) 
    { 
     $this->repository = $manager->getRepository($class); 
    } 

    /** 
    * Set mandator 
    * 
    * @param $mandator 
    * @return $this 
    */ 
    public function setMandator($mandator) 
    { 
     $this->mandator = $mandator; 

     return $this; 
    } 

    /** 
    * Get machine choices from DB and convert to an array 
    * 
    * @return array 
    */ 
    private function getMachineChoices() 
    { 
     $criteria = array(); 

     if (null !== $this->mandator) { 
      $criteria['mandator'] = $this->mandator; 
     } 

     $items = $this->repository->findBy($criteria, array('name', 'ASC')); 

     $choices = array(); 

     foreach ($items as $item) { 
      $choices[** db value **] = ** select value **; 
     } 

     return $choices; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    protected function loadChoiceList() 
    { 
     return new SimpleChoiceList($this->getMachineChoices()); 
    } 
} 

Wybór Lista usług (YAML)

acme.form.choice_list.machine: 
    class: Acme\YourBundle\Form\ChoiceList\MachineChoiceList 
    arguments: 
     - @doctrine.orm.default_entity_manager 
     - %acme.model.machine.class% 

klienta Formularz Rodzaj

namespace Acme\YourBundle\Form\Type; 

use Acme\YourBundle\Form\ChoiceList\MachineChoiceList; 
.. 

class FirstNullEntityType extends AbstractType 
{ 
    /** 
    * @var ChoiceListInterface 
    */ 
    private $choiceList; 

    public function __construct(MachineChoiceList $choiceList) 
    { 
     $this->choiceList = $choiceList; 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $choiceList = $this->choiceList; 

     $resolver->setDefault('mandator', null); 

     $resolver->setDefault('choice_list', function(Options $options) use ($choiceList) { 
      if (null !== $options['mandator']) { 
       $choiceList->setMandator($options['mandator']); 
      } 

      return $choiceList; 
     }); 
    } 

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

    public function getParent() 
    { 
     return 'choice'; 
    } 
} 

klienta Formularz Service Type (YAML)

acme.form.type.machine: 
    class: Acme\YourBundle\Form\Type\FirstNullEntityType 
    arguments: 
     - @acme.form.choice_list.machine 
    tags: 
     - { name: form.type, alias: first_null_entity } 

w formularzu

$builder 
    ->add('machine', 'first_null_entity', [ 
     'empty_value' => 'None Selected', 
     'label'   => 'label.machine', 
     'required'  => false, 
    ]) 
; 
+0

Dziękujemy za wspaniałą odpowiedź. W ten sposób muszę zarejestrować zarówno "MachineChoiceList", jak i "FirstNullEntityType" jako usługę i muszę przekazać listę do typu, prawda? – Joshua

+0

Tak, zgadza się. Zaktualizowałem swoje odpowiedzi za pomocą wersji YAML tych usług. – qooplmao

+0

Dziękuję za pomoc. Skończyło się na budowaniu 'ChoiceList' bezpośrednio w polu typu, ponieważ wydaje mi się bardziej elastyczny. Kluczem było rozszerzenie pola wyboru, zgodnie z sugestią. – Joshua

4

Można użyć zastępczy z 2,6

+1

Symbol zastępczy nie działa z 'query_builder' – gondo

24

Oto, co działa w Symfony 3.0.3

use Symfony\Bridge\Doctrine\Form\Type\EntityType;

$builder->add('example' EntityType::class, array(
    'label' => 'Example', 
    'class' => 'AppBundle:Example', 
    'placeholder' => 'Please choose', 
    'empty_data' => null, 
    'required' => false 
)); 
+2

Należy pamiętać o' empty_data => null' nie będzie działać z ChoiceType – dompie