Ankündigung

Einklappen
Keine Ankündigung bisher.

Symfony 4 Services im extra Ordner / Autowire klappt nicht

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Symfony 4 Services im extra Ordner / Autowire klappt nicht

    Hallo,

    ich habe einen extra Ordner "regulation" auf der selben Ebene wie "src".
    Den Autoloader habe ich passend eingestellt. Das klappt auch alles soweit.

    Code:
     "autoload": {     "psr-4": {         "App\\": "src/",         "Regulation\\": "regulation/"     } },
    In dem Ordner "regulation" befinden sich Formulare. Diese wurden bewusst ausgelagert, da an diese besondere Anforderungen gestellt werden.
    Es wird hier aber Symfony Form normal verwendet.

    In den Formularen benötige ich gelegentlich den EntityManager.
    Laut Doku klappt es ja auch recht einfach wie folgt:

    PHP-Code:
    private $entityManager;

    public function 
    __construct(EntityManagerInterface $entityManager)
    {    
    $this->entityManager $entityManager;

    Das funktioniert aber leider nicht. Ich bekomme immer folgende Exception:
    Too few arguments to function Regulation\Form\DemontageGehaeuseKleinteileType::_ _construct(), 0 passed in C:\Users\***\Projekte\jitpro\vendor\symfony\form\F ormRegistry.php on line 92 and exactly 1 expected

    In den Forms die in src/Form/ liegen klappt es wunderbar.

    Ich vermute, dass ich das irgendwie in der services.yaml bekannt machen muss.
    Aber das wie finde ich irgendwie nicht.

    Hat hier jemand eine Tipp für mich?

  • #2
    Ich hab das selber noch nicht gemacht, da ich finde das sowas auch mit den den "src" Ordner gehört, aber ich denke du müsstest einfach deine service.yaml um den Ordner erweitern.

    Code:
    services:
        # default configuration for services in *this* file
        _defaults:
            autowire: true      # Automatically injects dependencies in your services.
            autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
            public: false       # Allows optimizing the container by removing unused services; this also means
                                # fetching services directly from the container via $container->get() won't work.
                                # The best practice is to be explicit about your dependencies anyway.
    
        # makes classes in src/ available to be used as services
        # this creates a service per class whose id is the fully-qualified class name
        # <--- Diese Sektion kopieren und mit deinem Namespace austauschen und den Pfad anpassen
        App\:
            resource: '../src/*'
            exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'

    Kommentar


    • #3
      Ich hab das selber noch nicht gemacht, da ich finde das sowas auch mit den den "src" Ordner gehört, aber ich denke du müsstest einfach deine service.yaml um den Ordner erweitern.
      Die Dateien sind Kunden bezogen und liegen daher nicht im "src" Ordner.

      Dein Vorschlag klappt leider nicht. Ich denke, dass man damit eher definiert welche Objekte man als Service nutzen kann.
      Ich hatte noch die Variante über Setter ausprobiert.

      Code:
      Regulation\Form\DemontageGehaeuseKleinteileType:
              calls:
                  - method: setEntityManager
                    arguments:
                        - '@doctrine.orm.default_entity_manager'
      PHP-Code:
      private $entityManager;  
      public function 
      setEntityManager(EntityManagerInterface $entityManager)
      {    
          
      $this->entityManager $entityManager;

      Davon abgesehen, das es so nicht praktisch ist für die Aufgabe, ist $this->entityManager immer NULL....
      Also auch nicht zielführend.

      Kommentar


      • #4
        Du könntest ja mal den debug:container Konsolen Befehl ausführen und schauen, ob deine Klassen dem Container bekannt sind. Dies ist eine Voraussetzung damit "autowire" funktioniert.

        Kommentar


        • #5
          Du könntest ja mal den debug:container Konsolen Befehl ausführen und schauen, ob deine Klassen dem Container bekannt sind. Dies ist eine Voraussetzung damit "autowire" funktioniert.
          Die Klasse die hier bekannt sein muss, wäre doch der EntityManager und das ist der Fall. Daher klappt es ja auch beim FormType am normalen Ort.

          Ich vermute, dass es irgendwo einen Setting gibt, wo man definieren kann, in welchem Pfad man die Services verwenden kann/darf.
          Interessant bei dem letzt Ansatz ist, dass er er prüft ob das Objekt die Setter Methode besitzt.
          Aber leider wird da nichts gesetzt.

          Kommentar


          • #6
            Nicht ganz, du möchtest ja das Autowire Feature benutzen, dafür müssen die Klassen konfiguriert sein.
            Gerade die Form Types brauchen ja ua. die passenden Container Tags damit diese als FormType erkannt werden. Standardmäßig sind bei Klassen außerhalb des "src" Ordners das Autowire deaktiviert und die Klassen müssen in der service.yaml oder der DI Configuration des jeweiligen Bundles expliziet bekannt gemacht werden.

            Wenn dies nicht passiert und du einfach nur den FormTyp Klassennamen beim erstellen deines Formulars angibst, mach der Form Generator einfach nur ein "new Klassenname()", weswegen deine Setter auch nicht ausgeführt werden und du die von dir gepostete Fehlermeldung bekommst, wenn du Constructor Parameter hast.

            Dir bleiben daher nur die Möglichkeiten die Autowire Funktion auf deinen Ordner "außerhalb" zu erweitern (mein 1. Vorschlag), oder die FormTypes/Klassen explizit in deiner service.yaml zu konfigurieren und richtig zu Taggen, damit die Form Registry weiß was sie machen soll.

            Kommentar


            • #7
              Dir bleiben daher nur die Möglichkeiten die Autowire Funktion auf deinen Ordner "außerhalb" zu erweitern (mein 1. Vorschlag), oder die FormTypes/Klassen explizit in deiner service.yaml zu konfigurieren und richtig zu Taggen, damit die Form Registry weiß was sie machen soll.
              Die erste Variante ist ja genau das was ich brauche. An der Umsetzung scheitert es noch etwas.

              Beispiel:
              Code:
              Regulation\:
                      resource: '../regulation/*'
                      autowire: true
              Wenn ich mit dem Debugger mir anzeige was Sache ist, werden mir die Objekte angezeigt
              Code:
              php bin/console debug:container Regulation
              
                [6 ] Regulation\Entity\DemontageGehaeuseKleinteile
                [7 ] Regulation\Entity\DemontageInnenringe
                [8 ] Regulation\Entity\Schleifstand
                [9 ] Regulation\Form\DemontageGehaeuseKleinteileType
                [10] Regulation\Form\DemontageInnenringeType
                [11] Regulation\Form\SchleifstandType
              
              Service ID       Regulation\Form\DemontageGehaeuseKleinteileType
                Class            Regulation\Form\DemontageGehaeuseKleinteileType
                Tags             form.type
                Public           no
                Synthetic        no
                Lazy             no
                Shared           yes
                Abstract         no
                Autowired        yes
                Autoconfigured   yes
              Das schaut ja nicht so falsch aus. Es bleibt aber die selbe Fehlermeldung.

              Kommentar


              • #8
                Erstmal solltest du noch deine Entites excluden, der Pfad dort muss nämlich in der Doctrine Konfiguration hinzugefügt werden.
                https://symfony.com/doc/current/refe...de-of-a-bundle

                Und falls das "autowire" dann immer noch nicht funktioniert, dann Probiere doch mal die FormTypes per Hand zu konfigurieren. Ich würde dies auch nicht über den Setter machen, sondern über den Constructor.
                https://symfony.com/doc/current/form...m-as-a-service

                Kommentar


                • #9
                  Danke Zeichen32 für deine Hilfe.

                  Ich habe den Fehler gefunden, aber habe noch nen Brett vorm Kopf.
                  Da ich das nicht mehr verstanden habe, habe ich mir ein TestType gemacht.

                  Beim erstellen des Formulars ist mir dann ein unterschied aufgefallen.
                  Die Formulare werden an Hand von Datenbank Einträgen erstellt.
                  Also eine generische Lösung. Das habe ich mal nachgestellt.

                  PHP-Code:
                    $test $this->createForm(TestType::class); // Formular wird erstellt und auch Injection klappt! 
                  PHP-Code:
                    $test $this->createForm('\App\Reg\TestType'); // Formular wird erstellt aber Injection klappt nicht! 
                  Und mein realer Code ( $formPath ist der gesamte Aufruf inkl. Namespace ):
                  PHP-Code:
                    $form $this->createForm($formPath$workshoporder->getArticlemeasurement()); 
                  Aber wie mache ich das denn jetzt am besten?

                  Lösung:
                  Der führende \ darf hier nicht mit im String stehen.
                  Böse: '\App\Reg\TestType'
                  Gut: ''App\Reg\TestType'

                  Grummel Grummel

                  Kommentar


                  • #10
                    Ich denke das liegt daran, das die Autowire Funktion von Symfony die Klassen automatisch anhand des Klassen Namen im Container registriert.
                    Die Klasse wird also als App\Reg\TestType im Container registiert und nicht als \App\Reg\TestType.

                    Das einfachste wäre daher du speicherst die Klassen Namen ohne die führenden \

                    Kommentar


                    • #11
                      Das einfachste wäre daher du speicherst die Klassen Namen ohne die führenden \
                      $formPath wird bei mir ja eh zusammengebaut und wenn man ein Objekt aufrufen möchte direkt mit Namespace brauch es den führenden \.
                      Deswegen habe ich den da auch mit eingebaut. Die Formulare haben ja auch funktioniert nur das Injection klappte dann nicht.
                      Ein durchaus ungemütlicher Fehler.
                      Gespeichert wird in der DB nur der Klassen Name. Der Namespace baut sich durch andere Logik zusammen. Jetzt halt ohne führenden \.

                      Kommentar


                      • #12
                        Wie gesagt die Autowire Funktion macht im Grunde nichts anderes, als wenn du in deine services.yaml Datei die Klassen per Hand einträgst und als Alias für die Klasse dann App\Reg\TestType einträgst.
                        Wenn du jetzt den Service \App\Reg\TestType abrufen möchtest, existiert dieser nicht, da du ein \ zuviel hast am Anfang.

                        Wenn du dir nämlich mal die magische Konstante App\Reg\TestType::class anschaust,
                        sieht du dass diese ebenfalls den Klassen Namen ohne führendes \ mitgibt.


                        Kommentar


                        • #13
                          Wenn du dir nämlich mal die magische Konstante App\Reg\TestType::class anschaust,
                          sieht du dass diese ebenfalls den Klassen Namen ohne führendes \ mitgibt.
                          So habe ich ja das eigentlich Problem gefunden.

                          Ich bin aber der Meinung, dass man drüber Diskutieren könnte ob Strings mit führenden \ dazu dann führen, dass das Formular dennoch erzeugt wird.
                          Es ist halt nicht ersichtlich auf den ersten Blicken was falsch läuft.

                          Kommentar


                          • #14
                            Zitat von Creator Beitrag anzeigen
                            Ich bin aber der Meinung, dass man drüber Diskutieren könnte ob Strings mit führenden \ dazu dann führen, dass das Formular dennoch erzeugt wird.
                            Es ist halt nicht ersichtlich auf den ersten Blicken was falsch läuft.
                            Ja da bin ich bei dir, du könntest ja mal ein Ticket im Symfony Github eröffnen und das zur Diskussion geben.

                            Kommentar

                            Lädt...
                            X