ContainerRepositoryFactory::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Doctrine\Bundle\DoctrineBundle\Repository;
4
5
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass;
6
use Doctrine\ORM\EntityManagerInterface;
7
use Doctrine\ORM\Mapping\ClassMetadata;
8
use Doctrine\ORM\Repository\RepositoryFactory;
9
use Doctrine\Persistence\ObjectRepository;
10
use Psr\Container\ContainerInterface;
11
use RuntimeException;
12
13
/**
14
 * Fetches repositories from the container or falls back to normal creation.
15
 */
16
final class ContainerRepositoryFactory implements RepositoryFactory
17
{
18
    /** @var ObjectRepository[] */
19
    private $managedRepositories = [];
20
21
    /** @var ContainerInterface */
22
    private $container;
23
24
    /**
25
     * @param ContainerInterface $container A service locator containing the repositories
26
     */
27
    public function __construct(ContainerInterface $container)
28
    {
29
        $this->container = $container;
30
    }
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public function getRepository(EntityManagerInterface $entityManager, $entityName) : ObjectRepository
36
    {
37
        $metadata            = $entityManager->getClassMetadata($entityName);
38
        $repositoryServiceId = $metadata->customRepositoryClassName;
0 ignored issues
show
Bug introduced by
Accessing customRepositoryClassName on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
39
40
        $customRepositoryName = $metadata->customRepositoryClassName;
0 ignored issues
show
Bug introduced by
Accessing customRepositoryClassName on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
41
        if ($customRepositoryName !== null) {
42
            // fetch from the container
43
            if ($this->container->has($customRepositoryName)) {
44
                $repository = $this->container->get($customRepositoryName);
45
46
                if (! $repository instanceof ObjectRepository) {
47
                    throw new RuntimeException(sprintf('The service "%s" must implement ObjectRepository (or extend a base class, like ServiceEntityRepository).', $repositoryServiceId));
48
                }
49
50
                return $repository;
51
            }
52
53
            // if not in the container but the class/id implements the interface, throw an error
54
            if (is_a($customRepositoryName, ServiceEntityRepositoryInterface::class, true)) {
55
                throw new RuntimeException(sprintf('The "%s" entity repository implements "%s", but its service could not be found. Make sure the service exists and is tagged with "%s".', $customRepositoryName, ServiceEntityRepositoryInterface::class, ServiceRepositoryCompilerPass::REPOSITORY_SERVICE_TAG));
56
            }
57
58
            if (! class_exists($customRepositoryName)) {
59
                throw new RuntimeException(sprintf('The "%s" entity has a repositoryClass set to "%s", but this is not a valid class. Check your class naming. If this is meant to be a service id, make sure this service exists and is tagged with "%s".', $metadata->name, $customRepositoryName, ServiceRepositoryCompilerPass::REPOSITORY_SERVICE_TAG));
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
60
            }
61
62
            // allow the repository to be created below
63
        }
64
65
        return $this->getOrCreateRepository($entityManager, $metadata);
0 ignored issues
show
Compatibility introduced by
$metadata of type object<Doctrine\Persiste...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
66
    }
67
68
    private function getOrCreateRepository(
69
        EntityManagerInterface $entityManager,
70
        ClassMetadata $metadata
71
    ) : ObjectRepository {
72
        $repositoryHash = $metadata->getName() . spl_object_hash($entityManager);
73
        if (isset($this->managedRepositories[$repositoryHash])) {
74
            return $this->managedRepositories[$repositoryHash];
75
        }
76
77
        $repositoryClassName = $metadata->customRepositoryClassName ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();
78
79
        return $this->managedRepositories[$repositoryHash] = new $repositoryClassName($entityManager, $metadata);
80
    }
81
}
82