Passed
Push — master ( 513ae1...064a73 )
by Dominik
02:44
created

DoctrineOrmManagerRegistry::validateName()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
ccs 0
cts 6
cp 0
rs 9.8666
cc 3
nc 4
nop 3
crap 12
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\ServiceProvider\Registry;
6
7
use Doctrine\Common\Persistence\ManagerRegistry;
8
use Doctrine\Common\Persistence\ObjectManager;
9
use Doctrine\Common\Persistence\ObjectRepository;
10
use Doctrine\DBAL\Connection;
11
use Doctrine\ORM\EntityManager;
12
use Doctrine\ORM\EntityRepository;
13
use Doctrine\ORM\ORMException;
14
use Doctrine\ORM\Proxy\Proxy;
15
use Pimple\Container;
16
17
final class DoctrineOrmManagerRegistry implements ManagerRegistry
18
{
19
    /**
20
     * @var Container
21
     */
22
    private $container;
23
24
    /**
25
     * @var Container|Connection[]
26
     */
27
    private $connections;
28
29
    /**
30
     * @var string
31
     */
32
    private $defaultConnectionName;
33
34
    /**
35
     * @var Container|EntityManager[]
36
     */
37
    private $originalManagers;
38
39
    /**
40
     * @var EntityManager[]
41
     */
42
    private $resetManagers = [];
43
44
    /**
45
     * @var string
46
     */
47
    private $defaultManagerName;
48
49
    /**
50
     * @var string
51
     */
52
    private $proxyInterfaceName;
53
54
    /**
55
     * @param Container $container
56
     * @param string    $proxyInterfaceName
57
     */
58
    public function __construct(Container $container, $proxyInterfaceName = Proxy::class)
59
    {
60
        $this->container = $container;
61
        $this->proxyInterfaceName = $proxyInterfaceName;
62
    }
63
64
    /**
65
     * @return string
66
     */
67
    public function getDefaultConnectionName(): string
68
    {
69
        $this->loadConnections();
70
71
        return $this->defaultConnectionName;
72
    }
73
74
    /**
75
     * @param string|null $name
76
     *
77
     * @return Connection
78
     *
79
     * @throws \InvalidArgumentException
80
     */
81
    public function getConnection($name = null): Connection
82
    {
83
        $this->loadConnections();
84
85
        $name = $name ?? $this->getDefaultConnectionName();
86
87
        if (!isset($this->connections[$name])) {
88
            throw new \InvalidArgumentException(sprintf('Missing connection with name "%s".', $name));
89
        }
90
91
        return $this->connections[$name];
92
    }
93
94
    /**
95
     * @return Connection[]
96
     */
97
    public function getConnections(): array
98
    {
99
        $this->loadConnections();
100
101
        $connections = array();
102
        foreach ($this->connections->keys() as $connectionName) {
103
            $connections[$connectionName] = $this->connections[$connectionName];
104
        }
105
106
        return $connections;
107
    }
108
109
    /**
110
     * @return string[]
111
     */
112
    public function getConnectionNames(): array
113
    {
114
        $this->loadConnections();
115
116
        return $this->connections->keys();
117
    }
118
119
    /**
120
     * @return string
121
     */
122
    public function getDefaultManagerName(): string
123
    {
124
        $this->loadManagers();
125
126
        return $this->defaultManagerName;
127
    }
128
129
    /**
130
     * @param string|null $name
131
     *
132
     * @return EntityManager|ObjectManager
133
     */
134
    public function getManager($name = null): ObjectManager
135
    {
136
        $this->loadManagers();
137
138
        $name = $name ?? $this->getDefaultManagerName();
139
140
        if (!isset($this->originalManagers[$name])) {
141
            throw new \InvalidArgumentException(sprintf('Missing manager with name "%s".', $name));
142
        }
143
144
        return $this->resetManagers[$name] ?? $this->originalManagers[$name];
145
    }
146
147
    /**
148
     * @return EntityManager[]|ObjectManager[]
149
     */
150
    public function getManagers(): array
151
    {
152
        $this->loadManagers();
153
154
        $managers = array();
155
        foreach ($this->originalManagers->keys() as $managerName) {
156
            $managers[$managerName] = $this->resetManagers[$managerName] ?? $this->originalManagers[$managerName];
157
        }
158
159
        return $managers;
160
    }
161
162
    /**
163
     * @return array
164
     */
165
    public function getManagerNames(): array
166
    {
167
        $this->loadManagers();
168
169
        return $this->originalManagers->keys();
170
    }
171
172
    /**
173
     * @param string|null $name
174
     *
175
     * @return EntityManager|ObjectManager
176
     */
177
    public function resetManager($name = null)
178
    {
179
        $this->loadManagers();
180
181
        $name = $name ?? $this->getDefaultManagerName();
182
183
        if (!isset($this->originalManagers[$name])) {
184
            throw new \InvalidArgumentException(sprintf('Missing manager with name "%s".', $name));
185
        }
186
187
        $originalManager = $this->originalManagers[$name];
188
189
        $this->resetManagers[$name] = EntityManager::create(
190
            $originalManager->getConnection(),
191
            $originalManager->getConfiguration(),
192
            $originalManager->getEventManager()
193
        );
194
195
        return $this->resetManagers[$name];
196
    }
197
198
    /**
199
     * @param string $alias
200
     *
201
     * @return string
202
     *
203
     * @throws ORMException
204
     */
205
    public function getAliasNamespace($alias): string
206
    {
207
        foreach ($this->getManagerNames() as $name) {
208
            try {
209
                return $this->getManager($name)->getConfiguration()->getEntityNamespace($alias);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Common\Persistence\ObjectManager as the method getConfiguration() does only exist in the following implementations of said interface: Doctrine\ORM\Decorator\EntityManagerDecorator, Doctrine\ORM\EntityManager.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
210
            } catch (ORMException $e) {
211
                // throw the exception only if no manager can solve it
212
            }
213
        }
214
        throw ORMException::unknownEntityNamespace($alias);
215
    }
216
217
    /**
218
     * @param string $persistentObject
219
     * @param null   $persistentManagerName
220
     *
221
     * @return EntityRepository|ObjectRepository
222
     */
223
    public function getRepository($persistentObject, $persistentManagerName = null): ObjectRepository
224
    {
225
        return $this->getManager($persistentManagerName)->getRepository($persistentObject);
226
    }
227
228
    /**
229
     * @param string $class
230
     *
231
     * @return EntityManager|ObjectManager|null
232
     */
233
    public function getManagerForClass($class)
234
    {
235
        $proxyClass = new \ReflectionClass($class);
236
        if ($proxyClass->implementsInterface($this->proxyInterfaceName)) {
237
            $class = $proxyClass->getParentClass()->getName();
238
        }
239
240
        foreach ($this->getManagerNames() as $managerName) {
241
            if (!$this->getManager($managerName)->getMetadataFactory()->isTransient($class)) {
242
                return $this->getManager($managerName);
243
            }
244
        }
245
    }
246
247
    private function loadConnections()
248
    {
249
        if (null === $this->connections) {
250
            $this->connections = $this->container['doctrine.dbal.dbs'];
251
            $this->defaultConnectionName = $this->container['doctrine.dbal.dbs.default'];
252
        }
253
    }
254
255
    private function loadManagers()
256
    {
257
        if (null === $this->originalManagers) {
258
            $this->originalManagers = $this->container['doctrine.orm.ems'];
259
            $this->defaultManagerName = $this->container['doctrine.orm.ems.default'];
260
        }
261
    }
262
}
263