Symfony 2 EntityManager-Injektion in Betrieb

96

Ich habe meinen eigenen Dienst erstellt und muss die Doktrin EntityManager injizieren, aber ich sehe nicht, dass dies __construct()für meinen Dienst aufgerufen wird, und die Injektion funktioniert nicht.

Hier ist der Code und die Konfiguration:

<?php

namespace Test\CommonBundle\Services;
use Doctrine\ORM\EntityManager;

class UserService {

    /**
     *
     * @var EntityManager 
     */
    protected $em;

    public function __constructor(EntityManager $entityManager)
    {
        var_dump($entityManager);
        exit(); // I've never saw it happen, looks like constructor never called
        $this->em = $entityManager;
    }

    public function getUser($userId){
       var_dump($this->em ); // outputs null  
    }

}

Hier ist services.ymlin meinem Bundle

services:
  test.common.userservice:
    class:  Test\CommonBundle\Services\UserService
    arguments: 
        entityManager: "@doctrine.orm.entity_manager"

Ich habe diese .yml so config.ymlin meine App importiert

imports:
    # a few lines skipped, not relevant here, i think
    - { resource: "@TestCommonBundle/Resources/config/services.yml" }

Und wenn ich den Service im Controller anrufe

    $userservice = $this->get('test.common.userservice');
    $userservice->getUser(123);

Ich erhalte ein Objekt (nicht null), aber $this->emin UserService ist null, und wie bereits erwähnt, wurde der Konstruktor in UserService nie aufgerufen

Eine weitere Sache, Controller und UserService sind in verschiedenen Paketen (ich brauche das wirklich, um das Projekt organisiert zu halten), aber trotzdem: Alles andere funktioniert gut, ich kann sogar anrufen

$this->get('doctrine.orm.entity_manager')

in demselben Controller, den ich verwende, um UserService abzurufen und ein gültiges (nicht null) EntityManager-Objekt abzurufen.

Sieht so aus, als ob mir eine Konfiguration oder eine Verbindung zwischen UserService und Doctrine config fehlt.

Andrey Zavarin
quelle
Haben Sie Setter Injection versucht? Es klappt?
Gremo
Wenn mit 'Setter Injection' gemeint ist, dass die Setter-Methode für EntityManager in meinem Dienst hinzugefügt wird und der Controller mit dem Parameter $ this-> get ('doct.orm.entity_manager') aufgerufen wird, dann habe ich es versucht und es funktioniert. Aber ich mag es wirklich, die richtige Injektion über die Konfiguration zu verwenden
Andrey Zavarin
2
Ich meine das: symfony.com/doc/current/book/… ist sowieso __constructorder Fehler.
Gremo
Ähm, dann habe ich noch keine Setter-Injektion ausprobiert. __construct hat das Problem behoben, aber trotzdem danke für Ihre Hilfe!
Andrey Zavarin

Antworten:

112

Die Konstruktormethode Ihrer Klasse sollte aufgerufen werden __construct(), nicht __constructor():

public function __construct(EntityManager $entityManager)
{
    $this->em = $entityManager;
}
Reichtum
quelle
2
Hallo, in diesem Beispiel, wie kann ich die Verbindung von Standard auf eine andere ändern?
ptmr.io
Richtig, aber es wäre noch besser, wenn Sie eine Schnittstelle verwenden würden. public function __construct(EntityManagerInterface $entityManager)
Hugues D
65

In Symfony 2.4+ können Sie die Argumente für die Constructor Injection-Methode nicht mehr benennen. Gemäß der Dokumentation würden Sie übergeben:

services:
    test.common.userservice:
        class:  Test\CommonBundle\Services\UserService
        arguments: [ "@doctrine.orm.entity_manager" ]

Und dann wären sie in der Reihenfolge verfügbar, in der sie über die Argumente aufgelistet wurden (wenn es mehr als 1 gibt).

public function __construct(EntityManager $entityManager) {
    $this->em = $entityManager;
}
Chadwick Meyer
quelle
8
Sie können Folgendes ausführen: app / console container: debug und herausfinden, welche Dienste Sie ebenfalls ausführen.
Harte Fitness
18

Hinweis ab Symfony 3.3 EntityManager wird abgeschrieben. Verwenden Sie stattdessen EntityManagerInterface.

namespace AppBundle\Service;

use Doctrine\ORM\EntityManagerInterface;

class Someclass {
    protected $em;

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

    public function somefunction() {
        $em = $this->em;
        ...
    }
}
Robert Saylor
quelle
1
Nur für den Fall, dass jemand darüber stolpert und verwirrt ist: Der EntityManager wurde sicherlich nicht abgeschrieben. Die Verwendung der Schnittstelle hilft bei der automatischen Verkabelung und wird empfohlen, ist jedoch keinesfalls erforderlich. Und die Schnittstelle gibt es schon lange. Nichts wirklich Neues hier.
Cerad
Das ist die Antwort. Bitte verweisen Sie jedoch auf: stackoverflow.com/questions/22154558/…
tfont
Update auf meine eigene Lösung. Der richtige Weg sollte jetzt sein, Entitäten und Repositorys zu verwenden. Entity Manager wird natürlich bereits in ein Repository eingefügt. Sie können ein Beispiel hier sehen: youtu.be/AHVtOJDTx0M
Robert Saylor
7

Seit 2017 und Symfony 3.3 können Sie Repository als Service mit all seinen Vorteilen registrieren .

Eine allgemeinere Beschreibung finden Sie in meinem Beitrag Verwendung von Repository mit Doctrine as Service in Symfony .


In Ihrem speziellen Fall würde der Originalcode mit Optimierung folgendermaßen aussehen:

1. Verwenden Sie in Ihren Diensten oder Controller

<?php

namespace Test\CommonBundle\Services;

use Doctrine\ORM\EntityManagerInterface;

class UserService
{
    private $userRepository;

    // use custom repository over direct use of EntityManager
    // see step 2
    public function __constructor(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function getUser($userId)
    {
        return $this->userRepository->find($userId);
    }
}

2. Erstellen Sie ein neues benutzerdefiniertes Repository

<?php

namespace Test\CommonBundle\Repository;

use Doctrine\ORM\EntityManagerInterface;

class UserRepository
{
    private $repository;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->repository = $entityManager->getRepository(UserEntity::class);
    }

    public function find($userId)
    {
        return  $this->repository->find($userId);
    }
}

3. Dienste registrieren

# app/config/services.yml
services:
    _defaults:
        autowire: true

    Test\CommonBundle\:
       resource: ../../Test/CommonBundle
Tomáš Votruba
quelle