Iniezione di Symfony 2 EntityManager in servizio


96

Ho creato il mio servizio e ho bisogno di iniettare doctrine EntityManager, ma non vedo che __construct()viene chiamato sul mio servizio e l'iniezione non funziona.

Ecco il codice e le configurazioni:

<?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  
    }

}

Qui è services.ymlnel mio pacchetto

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

Ho importato quel .yml config.ymlnella mia app in questo modo

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

E quando chiamo l'assistenza nel controller

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

Ottengo un oggetto (non nullo), ma $this->emin UserService è nullo e, come ho già detto, il costruttore su UserService non è mai stato chiamato

Un'altra cosa, Controller e UserService sono in bundle diversi (ne ho davvero bisogno per mantenere il progetto organizzato), ma comunque: tutto il resto funziona bene, posso persino chiamare

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

nello stesso controller che uso per ottenere UserService e ottenere un oggetto EntityManager valido (non nullo).

Sembra che mi manchi un pezzo di configurazione o qualche collegamento tra UserService e Doctrine config.


Hai provato l'iniezione di setter? Funziona?
gremo

Se per 'setter injection' intendi aggiungere il metodo setter per EntityManager sul mio servizio e chiamare il controller con $ this-> get ('doctrine.orm.entity_manager') come parametro, allora sì, ho provato e funziona. Ma mi piace molto usare l'iniezione corretta tramite configurazione
Andrey Zavarin

2
Voglio dire questo: symfony.com/doc/current/book/… comunque __constructorè l'errore.
gremo

Ehm, non ho provato l'iniezione di Setter. __construct ha risolto il problema, ma comunque grazie per il tuo aiuto!
Andrey Zavarin

Risposte:


112

Il metodo di costruzione della tua classe dovrebbe essere chiamato __construct(), non __constructor():

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

2
Ciao, in questo esempio, come potrei cambiare la connessione da predefinita a qualsiasi altra?
ptmr.io

Giusto, ma sarebbe ancora meglio se usassi un'interfaccia. public function __construct(EntityManagerInterface $entityManager)
Hugues D,

65

Per riferimento moderno, in Symfony 2.4+, non puoi più nominare gli argomenti per il metodo Constructor Injection. Secondo la documentazione passeresti:

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

E poi sarebbero disponibili nell'ordine in cui sono stati elencati tramite gli argomenti (se ce ne sono più di 1).

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

8
Puoi fare un: app / console container: debug e scoprire anche quali servizi stai eseguendo.
Hard Fitness

18

Nota a partire da Symfony 3.3 EntityManager è deprezzato. Usa invece 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;
        ...
    }
}

1
Nel caso qualcuno si imbattesse in questo e fosse confuso: l'EntityManager non è stato certamente ammortizzato. L'utilizzo dell'interfaccia aiuta con il cablaggio automatico ed è consigliato ma non è assolutamente necessario. E l'interfaccia esiste da molto tempo. Niente di veramente nuovo qui.
Cerad

Questa è la risposta. Tuttavia, si prega di fare riferimento: stackoverflow.com/questions/22154558/...
TFont

Aggiorna alla mia soluzione. Il modo corretto ora dovrebbe essere quello di utilizzare entità e archivi. Entity Manager è già naturalmente iniettato in un repository. Puoi vedere un esempio qui: youtu.be/AHVtOJDTx0M
Robert Saylor

7

Dal 2017 e Symfony 3.3 puoi registrare Repository come servizio , con tutti i suoi vantaggi che ha.

Controlla il mio post Come usare il repository con Doctrine as Service in Symfony per una descrizione più generale.


Nel tuo caso specifico, il codice originale con messa a punto sarebbe simile a questo:

1. Usa nei tuoi servizi o 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. Crea un nuovo repository personalizzato

<?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. Registrare i servizi

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

    Test\CommonBundle\:
       resource: ../../Test/CommonBundle
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.