Symfony 2 EntityManager tiêm vào dịch vụ


96

Tôi đã tạo dịch vụ của riêng mình và tôi cần nhập học thuyết EntityManager, nhưng tôi không thấy điều đó __construct()được gọi trong dịch vụ của mình và việc tiêm không hoạt động.

Đây là mã và cấu hình:

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

}

Đây là services.ymltrong gói của tôi

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

Tôi đã nhập .yml đó config.ymltrong ứng dụng của mình như vậy

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

Và khi tôi gọi dịch vụ trong bộ điều khiển

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

Tôi nhận được một đối tượng (không phải null), nhưng $this->emtrong UserService là null và như tôi đã đề cập, hàm tạo trên UserService chưa bao giờ được gọi

Một điều nữa, Controller và UserService nằm trong các gói khác nhau (tôi thực sự cần nó để giữ cho dự án có tổ chức), nhưng vẫn còn: mọi thứ khác hoạt động tốt, tôi thậm chí có thể gọi

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

trong cùng một bộ điều khiển mà tôi sử dụng để lấy UserService và lấy đối tượng EntityManager hợp lệ (không phải null).

Có vẻ như tôi đang thiếu phần cấu hình hoặc một số liên kết giữa cấu hình UserService và Doctrine.


Bạn đã thử tiêm setter chưa? Nó hoạt động?
gremo

Nếu bằng 'setter injection', bạn có nghĩa là thêm phương thức setter cho EntityManager trên dịch vụ của tôi và gọi trong bộ điều khiển với $ this-> get ('doct.orm.entity_manager') làm tham số, thì có, tôi đã thử và nó hoạt động. Nhưng tôi thực sự thích sử dụng tiêm thích hợp thông qua cấu hình
Andrey Zavarin

2
Ý tôi là: symfony.com/doc/current/book/… dù sao cũng __constructorlà lỗi.
gremo

Ừm, tôi chưa thử tiêm setter. __construct đã khắc phục sự cố, nhưng dù sao, cảm ơn bạn đã giúp đỡ!
Andrey Zavarin

Câu trả lời:


112

Phương thức khởi tạo của lớp bạn nên được gọi __construct(), không phải __constructor():

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

2
Xin chào, trong ví dụ này, làm cách nào để tôi có thể thay đổi kết nối từ mặc định sang bất kỳ kết nối nào khác?
ptmr.io,

Đúng, nhưng sẽ tốt hơn nếu bạn sử dụng một giao diện. public function __construct(EntityManagerInterface $entityManager)
Hugues D

65

Đối với tham chiếu hiện đại, trong Symfony 2.4+, bạn không thể đặt tên cho các đối số cho phương thức Constructor Injection nữa. Theo tài liệu Bạn sẽ nhập:

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

Và sau đó chúng sẽ có sẵn theo thứ tự được liệt kê thông qua các đối số (nếu có nhiều hơn 1).

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

8
Bạn có thể thực hiện: app / console container: debug Và tìm hiểu những dịch vụ bạn đang chạy.
Thể dục chăm chỉ

18

Lưu ý rằng Symfony 3.3 EntityManager được khấu hao. Sử dụng EntityManagerInterface để thay thế.

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
Đề phòng bất kỳ ai tình cờ gặp phải điều này và bối rối: EntityManager chắc chắn không bị giảm giá trị. Sử dụng giao diện giúp tự động nối dây và được khuyến khích nhưng không bắt buộc. Và giao diện đã có từ rất lâu. Không có gì thực sự mới ở đây.
Cerad

Đây là câu trả lời. Tuy nhiên, vui lòng tham khảo: stackoverflow.com/questions/22154558/…
tfont vào

Cập nhật giải pháp của riêng tôi. Cách thích hợp bây giờ là sử dụng Thực thể và Kho lưu trữ. Trình quản lý thực thể đã được đưa vào kho lưu trữ một cách tự nhiên. Bạn có thể xem một ví dụ ở đây: youtu.be/AHVtOJDTx0M
Robert Saylor

7

Kể từ năm 2017 và Symfony 3.3, bạn có thể đăng ký Repository như một dịch vụ , với tất cả những ưu điểm của nó.

Kiểm tra bài đăng của tôi Cách sử dụng Kho lưu trữ với Doctrine as Service trong Symfony để có mô tả chung hơn.


Đối với trường hợp cụ thể của bạn, mã gốc có điều chỉnh sẽ giống như sau:

1. Sử dụng trong các dịch vụ hoặc Bộ điều khiển của bạn

<?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. Tạo kho lưu trữ tùy chỉnh mới

<?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. Đăng ký dịch vụ

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

    Test\CommonBundle\:
       resource: ../../Test/CommonBundle
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.