Injeksi Symfony 2 EntityManager dalam layanan

96

Saya telah membuat layanan saya sendiri dan saya perlu memasukkan EntityManager doktrin, tetapi saya tidak melihat itu __construct()dipanggil di layanan saya, dan injeksi tidak berfungsi.

Ini kode dan konfigurasinya:

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

}

Ini services.ymldi bundel saya

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

Saya telah mengimpor .yml itu di config.ymlaplikasi saya seperti itu

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

Dan ketika saya memanggil layanan di pengontrol

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

Saya mendapatkan objek (bukan null), tetapi $this->emdi UserService adalah null, dan seperti yang telah saya sebutkan, konstruktor di UserService tidak pernah dipanggil

Satu hal lagi, Controller dan UserService berada dalam bundel yang berbeda (saya benar-benar membutuhkannya agar proyek tetap teratur), tetapi tetap saja: semuanya berfungsi dengan baik, saya bahkan dapat menelepon

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

dalam kontroler yang sama yang saya gunakan untuk mendapatkan UserService dan mendapatkan objek EntityManager yang valid (bukan null).

Sepertinya saya kehilangan bagian konfigurasi atau beberapa link antara UserService dan konfigurasi Doctrine.

Andrey Zavarin
sumber
Sudahkah Anda mencoba injeksi penyetel? Berhasil?
gremo
Jika dengan 'injeksi penyetel' yang Anda maksud menambahkan metode penyetel untuk EntityManager pada layanan saya dan memanggil pengontrol dengan $ this-> get ('doktrin.orm.entity_manager') sebagai parameter, maka ya, saya sudah mencoba dan berhasil. Tetapi saya sangat suka menggunakan injeksi yang tepat melalui konfigurasi
Andrey Zavarin
2
Maksud saya ini: symfony.com/doc/current/book/… bagaimanapun __constructorjuga kesalahannya.
gremo
Um, daripada saya belum mencoba injeksi penyetel. __construct memperbaiki masalah, tapi bagaimanapun, terima kasih atas bantuan Anda!
Andrey Zavarin

Jawaban:

112

Metode konstruktor kelas Anda harus dipanggil __construct(), bukan __constructor():

public function __construct(EntityManager $entityManager)
{
    $this->em = $entityManager;
}
kekayaan
sumber
2
Hai, dalam contoh ini, bagaimana saya bisa mengubah koneksi dari default ke yang lain?
ptmr.io
Benar, tetapi akan lebih baik jika Anda menggunakan antarmuka. public function __construct(EntityManagerInterface $entityManager)
Pelukan D
65

Untuk referensi modern, di Symfony 2.4+, Anda tidak dapat lagi memberi nama argumen untuk metode Injeksi Konstruktor. Menurut dokumentasi Anda akan meneruskan:

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

Dan kemudian mereka akan tersedia dalam urutan mereka terdaftar melalui argumen (jika ada lebih dari 1).

public function __construct(EntityManager $entityManager) {
    $this->em = $entityManager;
}
Chadwick Meyer
sumber
8
Anda dapat melakukan: app / console container: debug Dan mencari tahu layanan apa yang Anda jalankan juga.
Hard Fitness
18

Catatan pada Symfony 3.3 EntityManager disusutkan. Gunakan EntityManagerInterface sebagai gantinya.

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
sumber
1
Untuk berjaga-jaga jika ada yang tersandung dan bingung: EntityManager jelas belum disusutkan. Menggunakan antarmuka membantu dengan kabel otomatis dan disarankan tetapi sama sekali tidak diperlukan. Dan antarmukanya sudah ada sejak lama. Tidak ada yang benar-benar baru di sini.
Cerad
Inilah jawabannya. Namun, harap lakukan referensi: stackoverflow.com/questions/22154558/…
tfont
Perbarui ke solusi saya sendiri. Cara yang tepat sekarang adalah dengan menggunakan Entitas dan Repositori. Pengelola Entitas sudah secara alami dimasukkan ke dalam repositori. Anda dapat melihat contohnya di sini: youtu.be/AHVtOJDTx0M
Robert Saylor
7

Sejak 2017 dan Symfony 3.3 Anda dapat mendaftarkan Repositori sebagai layanan , dengan segala kelebihan yang dimilikinya.

Periksa posting saya Cara menggunakan Repositori dengan Doctrine as Service di Symfony untuk penjelasan yang lebih umum.


Untuk kasus khusus Anda, kode asli dengan penyetelan akan terlihat seperti ini:

1. Gunakan dalam layanan atau Kontroler Anda

<?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. Buat repositori kustom baru

<?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. Daftarkan layanan

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

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