2016-07-27 20 views
1

Ich habe ein System implementiert, mit dem ein Administrator einige zusätzliche Verhaltensweisen (die eigentlich Symfony Services sind) aus einem Formular konfigurieren kann. Im Moment war ich mit einem EntityType, um die Admin wählen Sie einen oder mehrere-Dienste aus einer Tabelle in der Datenbank.Angezeigte Services in Symfony ChoiceType anzeigen

$builder->add('services', EntityType::class, array(
'class' => 'AppBundle:Services', 
'multiple' => true, 
)); 

Aber da ich die Dienste in Symfony selbst Registrierung Ich dachte nur, dass es einen Weg geben, die Dienste aus dem Behälter (oder ähnlich) zu erhalten und ein neues ServiceTagType so I don ‚t haben sie sowohl in der data base hinzuzufügen und die services.yml und ich kann so etwas tun:

$builder->add('services', ServiceTagType::class, array(
'tag' => 'some.service.tag', 
'multiple' => true, 
)); 

hier Lesen und dort fand ich heraus, dass Sie Tag Dienste, aber Sie kann nur die getaggte Dienste Liste bekommen, wenn der Container kompiliert wird ... Ich habe Probleme, einen Workaround zu finden, aber es hat keinen Nutzen gebracht.

+2

In Ihrem Compiler Pass Sie können mit Tags Dienst in Ihrem ServiceTagType injizieren und ServiceTagType als Service nutzen in deiner Form – bourvill

Antwort

2

Zunächst einmal müssen Sie die ServiceTagType erstellen (ich nehme an, es wird die ChoiceType und nicht die EntityType verlängern):

Wie einen benutzerdefinierten Typ erstellen ist here dokumentiert.

// src/AppBundle/Form/Type/ServiceTagType.php 
namespace AppBundle\Form\Type; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\OptionsResolver\OptionsResolver; 
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; 

class ServiceTagType extends AbstractType 
{ 
    private $tags; 

    public function setTags($tags) 
    { 
     $this->tags = $tags; 
    } 

    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefaults(array(
      'choices' => $this->tags 
     )); 
    } 

    public function getParent() 
    { 
     return ChoiceType::class; 
    } 
} 

Registrieren ServiceTagType als Service

# services.yml 
app.form_type.service_tag: 
    class: AppBundle\Form\Type\ServiceTagType 
    tags: 
     - { name: form.type } 

Dann (Weil Sie die Tags mit setter injection zur Verfügung stellen müssen), wie Bourvill vorschlagen, können Sie Ihre Tags in einem Compiler pass sammeln.

use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 
use Symfony\Component\DependencyInjection\Reference; 

class TagsCompilerPass implements CompilerPassInterface 
{ 
    public function process(ContainerBuilder $container) 
    { 
     if (!$container->has('app.form_type.service_tag')) { 
      return; 
     } 

     $definition = $container->findDefinition(
      'app.form_type.service_tag' 
     ); 

     $taggedServicesIds = array_keys($container->findTaggedServiceIds(
      'app.tagged_for_service_tag_type' 
     )); 

     $taggedServices = array_fill_keys($taggedServicesIds ,$taggedServicesIds); 

     $definition->addMethodCall('setTags',$taggedServices); 
    } 
} 

Und vergessen Sie nicht zu register this Compiler pass

Um einen CompilerPass im FullStack Rahmen zu registrieren:

class AppBundle extends Bundle 
{ 
    public function build(ContainerBuilder $container) 
    { 
     parent::build($container); 

     $container->addCompilerPass(new TagsCompilerPass()); 
    } 
} 
+0

Upvote für eine tolle Antwort @Alsatian! –

+0

Wow! Nette und komplette Antwort, vielen Dank. – Astaroth