-->

How can i inject class inside custom repository -

2019-08-05 05:31发布

问题:

I have custom repository class in which i must inject class that helps me to upload file, and erase file if needed. I expanded EntityRepository constructor, but i don't know how to add third argument inside custom repository class.

    class NewRepository extends EntityRepository
    {

        protected $fileUploader;



        public function __construct(EntityManager $em, Mapping\ClassMetadata $class,FileUploader $fileUploader)
        {
            parent::__construct($em, $class);
        }

        public function create($data, Item $item = null)
        {
            $em = $this->getEntityManager();
            if(!$item) $item = new Item();

            if(isset($data['file'])) {
                $image = $this->fileUploader->setFile($data['file'])->uploadFile();
                $data['filename'] = $image['filename'];
                $data['image_url'] = $image['file_url'];
            }

            $item->setTitle($data['title']);
            $item->setDescription($data['description']);

            $em->persist($item);
            $em->flush($item);

            return $item;
        }

    }

I always get error that third argument passed to constructor is null.

回答1:

Since version 2.4 Doctrine uses a RepositoryFactory for instantiating repositories and as a starter provides you with DefaultRepositoryFactory. To be able to inject additional dependencies into your repositories you need to roll your own implementation of aforementioned factory (I'm omitting all the use statements for brevity):

class YourRepositoryFactory implements RepositoryFactory
{
    private $fileUploader;

    public function __construct(FileUploader $fileUploader)
    {
        $this->fileUploader = $fileUploader;
    }

    public function getRepository(EntityManagerInterface $entityManager, $entityName)
    {
        $repositoryHash = $entityManager->getClassMetadata($entityName)->getName() . spl_object_hash($entityManager);
        if (isset($this->repositoryList[$repositoryHash])) {
            return $this->repositoryList[$repositoryHash];
        }
        return $this->repositoryList[$repositoryHash] = $this->createRepository($entityManager, $entityName);
    }

    private function createRepository(EntityManagerInterface $entityManager, $entityName)
    {
        /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
        $metadata            = $entityManager->getClassMetadata($entityName);
        $repositoryClassName = $metadata->customRepositoryClassName
            ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();

        switch ($repositoryClassName) {
            case NewRepository::class:
                return new $repositoryClassName($entityManager, $metadata, $this->fileUploader);
            default:
                return new $repositoryClassName($entityManager, $metadata);
        }
    }
}

After registering your factory as a service in the way you prefer you need to adjust doctrine configuration with:

doctrine:
    orm:
        repository_factory: name.of.your.factory.service

And you're good to go!