Completed
Pull Request — master (#658)
by Magnus
03:34
created

RepositoryAliasPass::hasConflictingServices()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 18
rs 9.2
cc 4
eloc 9
nc 4
nop 2
1
<?php
2
3
/*
4
 * This file is part of the Doctrine Bundle
5
 *
6
 * (c) Fabien Potencier <[email protected]>
7
 * (c) Doctrine Project, Benjamin Eberlei <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler;
14
15
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
16
use Doctrine\ORM\Mapping\ClassMetadata;
17
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
18
use Symfony\Component\DependencyInjection\ContainerBuilder;
19
use Symfony\Component\DependencyInjection\Definition;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpKernel\Kernel;
22
23
/**
24
 * Class to register repositories as services
25
 *
26
 * @author Magnus Nordlander <[email protected]>
27
 */
28
class RepositoryAliasPass implements CompilerPassInterface
29
{
30
    /**
31
     * {@inheritDoc}
32
     */
33
    public function process(ContainerBuilder $container)
34
    {
35
        if (!$container->hasParameter('doctrine.entity_managers')) {
36
            return;
37
        }
38
39
        $entityManagers = $container->getParameter('doctrine.entity_managers');
40
        $customRepositories = [];
41
42
        foreach ($entityManagers as $name => $serviceName) {
43
            $metadataDriverService = sprintf('doctrine.orm.%s_metadata_driver', $name);
44
45
            if (!$container->has($metadataDriverService)) {
46
                continue;
47
            }
48
49
            /** @var MappingDriver $metadataDriver */
50
            $metadataDriver = $container->get($metadataDriverService);
51
            $entityClassNames = $metadataDriver->getAllClassNames();
52
53
            foreach ($entityClassNames as $entityClassName) {
54
                $classMetadata = new ClassMetadata($entityClassName);
55
                $metadataDriver->loadMetadataForClass($entityClassName, $classMetadata);
56
57
                if ($classMetadata->customRepositoryClassName) {
58
                    $customRepositories[$classMetadata->customRepositoryClassName][] = [
59
                        0 => $entityClassName,
60
                        1 => $name,
61
                    ];
62
                }
63
            }
64
        }
65
66
        foreach ($customRepositories as $repositoryClass => $entities) {
67
            if ($container->has($repositoryClass)) {
68
                continue;
69
            }
70
71
            if (count($entities) !== 1) {
72
                $this->log($container, "Cannot auto-register repository \"".$repositoryClass."\": Entity belongs to multiple entity managers.");
73
                continue;
74
            }
75
76
            if ($this->hasConflictingServices($container, $repositoryClass)) {
77
                $this->log($container, "Cannot auto-register repository \"".$repositoryClass."\": There are already services for the repository class.");
78
                continue;
79
80
            }
81
82
            $definition = $container->register($repositoryClass, $repositoryClass)
83
                ->setFactory([new Reference('doctrine'), 'getRepository'])
84
                ->setArguments($entities[0])
85
                ->setPublic(false)
86
            ;
87
88
            if (Kernel::MAJOR_VERSION <= 2 && Kernel::MINOR_VERSION <= 7) {
89
                $definition->setScope('prototype');
0 ignored issues
show
Bug introduced by
The method setScope() does not seem to exist on object<Symfony\Component...cyInjection\Definition>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
90
            } else {
91
                $definition->setShared(false);
92
            }
93
        }
94
95
    }
96
97
    private function hasConflictingServices(ContainerBuilder $container, $repositoryClass)
98
    {
99
        if (Kernel::MAJOR_VERSION >= 4) {
100
            return false;
101
        }
102
103
        $parameterBag = $container->getParameterBag();
104
105
        foreach ($container->getDefinitions() as $id => $definition) {
106
            $defClass = $parameterBag->resolveValue($definition->getClass());
107
108
            if ($defClass == $repositoryClass) {
109
                return true;
110
            }
111
        }
112
113
        return false;
114
    }
115
116
    private function log(ContainerBuilder $container, $message)
117
    {
118
        if (method_exists($container, 'log')) {
119
            $container->log($this, $message);
120
        }
121
    }
122
}
123