การฉีด Symfony 2 EntityManager ในบริการ


96

ฉันได้สร้างบริการของตัวเองและจำเป็นต้องฉีด EntityManager หลักคำสอน แต่ฉันไม่เห็นว่า__construct()มีการเรียกใช้บริการของฉันและการฉีดไม่ได้ผล

นี่คือรหัสและการกำหนดค่า:

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

}

นี่คือservices.ymlชุดของฉัน

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

ฉันได้นำเข้า. yml นั้นconfig.ymlในแอปของฉันแบบนั้น

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

และเมื่อฉันเรียกใช้บริการในคอนโทรลเลอร์

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

ฉันได้รับวัตถุ (ไม่ใช่ null) แต่$this->emใน UserService เป็นโมฆะและตามที่ฉันได้กล่าวไปแล้วตัวสร้างบน UserService ไม่เคยถูกเรียก

อีกอย่างหนึ่ง Controller และ UserService อยู่ในกลุ่มที่แตกต่างกัน (ฉันต้องการสิ่งนั้นจริงๆเพื่อจัดระเบียบโครงการ) แต่ก็ยัง: ทุกอย่างทำงานได้ดีฉันยังโทรได้

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

ในคอนโทรลเลอร์เดียวกันกับที่ฉันใช้เพื่อรับ UserService และรับอ็อบเจ็กต์ EntityManager ที่ถูกต้อง (ไม่ใช่ null)

ดูเหมือนว่าฉันขาดส่วนกำหนดค่าหรือลิงก์บางส่วนระหว่าง UserService และ Doctrine config


คุณเคยลอง setter injection หรือไม่? มันได้ผล?
gremo

หากโดย 'setter injection' คุณหมายถึงเพิ่มวิธี setter สำหรับ EntityManager ในบริการของฉันและเรียกใช้ตัวควบคุมโดยใช้ $ this-> get ('doctrine.orm.entity_manager') เป็นพารามิเตอร์ใช่ฉันได้ลองแล้วและได้ผล แต่ฉันชอบใช้การฉีดที่เหมาะสมผ่าน config
Andrey Zavarin

2
ฉันหมายถึงสิ่งนี้symfony.com/doc/current/book/…อย่างไรก็ตาม__constructorเป็นข้อผิดพลาด
gremo

อืมฉันยังไม่ได้ลองฉีดเซ็ตเตอร์ __construct แก้ไขปัญหา แต่ยังไงก็ตามขอขอบคุณสำหรับความช่วยเหลือของคุณ!
Andrey Zavarin

คำตอบ:


112

ควรเรียกเมธอด constructor ของคลาสของคุณ__construct()ไม่ใช่__constructor():

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

2
สวัสดีในตัวอย่างนี้ฉันจะเปลี่ยนการเชื่อมต่อจากค่าเริ่มต้นเป็นแบบอื่นได้อย่างไร
ptmr.io

ถูกต้อง แต่จะดีกว่านี้ถ้าคุณใช้อินเทอร์เฟซ public function __construct(EntityManagerInterface $entityManager)
Hugues D

65

สำหรับการอ้างอิงสมัยใหม่ใน Symfony 2.4+ คุณไม่สามารถตั้งชื่ออาร์กิวเมนต์สำหรับวิธี Constructor Injection ได้อีกต่อไป ตามเอกสารที่คุณต้องผ่าน:

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

จากนั้นก็จะพร้อมใช้งานตามลำดับที่แสดงผ่านอาร์กิวเมนต์ (หากมีมากกว่า 1)

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

8
คุณสามารถทำ: app / console container: debug และค้นหาว่าคุณใช้บริการอะไรอยู่ด้วย
Hard Fitness

18

หมายเหตุของ Symfony 3.3 EntityManager เป็นค่าเสื่อมราคา ใช้ 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
ในกรณีที่มีใครสะดุดและสับสน: EntityManager ไม่ได้รับค่าเสื่อมราคาอย่างแน่นอน การใช้อินเทอร์เฟซช่วยในการเดินสายอัตโนมัติและแนะนำ แต่ไม่จำเป็นต้องใช้ และอินเทอร์เฟซนั้นมีมานานแล้ว ไม่มีอะไรใหม่จริงๆที่นี่
Cerad

นี่คือคำตอบ อย่างไรก็ตามโปรดอ้างอิง: stackoverflow.com/questions/22154558/…
tfont

อัปเดตเป็นโซลูชันของฉันเอง วิธีที่เหมาะสมในตอนนี้คือการใช้เอนทิตีและที่เก็บ ตัวจัดการเอนทิตีถูกฉีดเข้าไปในที่เก็บโดยธรรมชาติแล้ว คุณสามารถดูตัวอย่างได้ที่นี่: youtu.be/AHVtOJDTx0M
Robert Saylor

7

ตั้งแต่ปี 2017 และ Symfony 3.3คุณสามารถลงทะเบียน Repository เป็นบริการได้ด้วยข้อดีทั้งหมดที่มี

ตรวจสอบโพสต์ของฉันวิธีใช้ Repository กับ Doctrine as Service ใน Symfonyสำหรับคำอธิบายทั่วไปเพิ่มเติม


ในกรณีเฉพาะของคุณรหัสเดิมที่มีการปรับแต่งจะมีลักษณะดังนี้:

1. ใช้ในบริการหรือคอนโทรลเลอร์ของคุณ

<?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. สร้างที่เก็บแบบกำหนดเองใหม่

<?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. ลงทะเบียนบริการ

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

    Test\CommonBundle\:
       resource: ../../Test/CommonBundle
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.