1<?php
2
3namespace Doctrine\Persistence;
4
5use InvalidArgumentException;
6use ReflectionClass;
7use function class_exists;
8use function explode;
9use function interface_exists;
10use function sprintf;
11use function strpos;
12
13/**
14 * Abstract implementation of the ManagerRegistry contract.
15 */
16abstract class AbstractManagerRegistry implements ManagerRegistry
17{
18    /** @var string */
19    private $name;
20
21    /** @var string[] */
22    private $connections;
23
24    /** @var string[] */
25    private $managers;
26
27    /** @var string */
28    private $defaultConnection;
29
30    /** @var string */
31    private $defaultManager;
32
33    /** @var string */
34    private $proxyInterfaceName;
35
36    /**
37     * @param string   $name
38     * @param string[] $connections
39     * @param string[] $managers
40     * @param string   $defaultConnection
41     * @param string   $defaultManager
42     * @param string   $proxyInterfaceName
43     */
44    public function __construct($name, array $connections, array $managers, $defaultConnection, $defaultManager, $proxyInterfaceName)
45    {
46        $this->name               = $name;
47        $this->connections        = $connections;
48        $this->managers           = $managers;
49        $this->defaultConnection  = $defaultConnection;
50        $this->defaultManager     = $defaultManager;
51        $this->proxyInterfaceName = $proxyInterfaceName;
52    }
53
54    /**
55     * Fetches/creates the given services.
56     *
57     * A service in this context is connection or a manager instance.
58     *
59     * @param string $name The name of the service.
60     *
61     * @return ObjectManager The instance of the given service.
62     */
63    abstract protected function getService($name);
64
65    /**
66     * Resets the given services.
67     *
68     * A service in this context is connection or a manager instance.
69     *
70     * @param string $name The name of the service.
71     *
72     * @return void
73     */
74    abstract protected function resetService($name);
75
76    /**
77     * Gets the name of the registry.
78     *
79     * @return string
80     */
81    public function getName()
82    {
83        return $this->name;
84    }
85
86    /**
87     * {@inheritdoc}
88     */
89    public function getConnection($name = null)
90    {
91        if ($name === null) {
92            $name = $this->defaultConnection;
93        }
94
95        if (! isset($this->connections[$name])) {
96            throw new InvalidArgumentException(sprintf('Doctrine %s Connection named "%s" does not exist.', $this->name, $name));
97        }
98
99        return $this->getService($this->connections[$name]);
100    }
101
102    /**
103     * {@inheritdoc}
104     */
105    public function getConnectionNames()
106    {
107        return $this->connections;
108    }
109
110    /**
111     * {@inheritdoc}
112     */
113    public function getConnections()
114    {
115        $connections = [];
116        foreach ($this->connections as $name => $id) {
117            $connections[$name] = $this->getService($id);
118        }
119
120        return $connections;
121    }
122
123    /**
124     * {@inheritdoc}
125     */
126    public function getDefaultConnectionName()
127    {
128        return $this->defaultConnection;
129    }
130
131    /**
132     * {@inheritdoc}
133     */
134    public function getDefaultManagerName()
135    {
136        return $this->defaultManager;
137    }
138
139    /**
140     * {@inheritdoc}
141     *
142     * @throws InvalidArgumentException
143     */
144    public function getManager($name = null)
145    {
146        if ($name === null) {
147            $name = $this->defaultManager;
148        }
149
150        if (! isset($this->managers[$name])) {
151            throw new InvalidArgumentException(sprintf('Doctrine %s Manager named "%s" does not exist.', $this->name, $name));
152        }
153
154        return $this->getService($this->managers[$name]);
155    }
156
157    /**
158     * {@inheritdoc}
159     */
160    public function getManagerForClass($class)
161    {
162        // Check for namespace alias
163        if (strpos($class, ':') !== false) {
164            [$namespaceAlias, $simpleClassName] = explode(':', $class, 2);
165            $class                              = $this->getAliasNamespace($namespaceAlias) . '\\' . $simpleClassName;
166        }
167
168        $proxyClass = new ReflectionClass($class);
169
170        if ($proxyClass->implementsInterface($this->proxyInterfaceName)) {
171            $parentClass = $proxyClass->getParentClass();
172
173            if (! $parentClass) {
174                return null;
175            }
176
177            $class = $parentClass->getName();
178        }
179
180        foreach ($this->managers as $id) {
181            $manager = $this->getService($id);
182
183            if (! $manager->getMetadataFactory()->isTransient($class)) {
184                return $manager;
185            }
186        }
187    }
188
189    /**
190     * {@inheritdoc}
191     */
192    public function getManagerNames()
193    {
194        return $this->managers;
195    }
196
197    /**
198     * {@inheritdoc}
199     */
200    public function getManagers()
201    {
202        $dms = [];
203        foreach ($this->managers as $name => $id) {
204            $dms[$name] = $this->getService($id);
205        }
206
207        return $dms;
208    }
209
210    /**
211     * {@inheritdoc}
212     */
213    public function getRepository($persistentObjectName, $persistentManagerName = null)
214    {
215        return $this
216            ->selectManager($persistentObjectName, $persistentManagerName)
217            ->getRepository($persistentObjectName);
218    }
219
220    /**
221     * {@inheritdoc}
222     */
223    public function resetManager($name = null)
224    {
225        if ($name === null) {
226            $name = $this->defaultManager;
227        }
228
229        if (! isset($this->managers[$name])) {
230            throw new InvalidArgumentException(sprintf('Doctrine %s Manager named "%s" does not exist.', $this->name, $name));
231        }
232
233        // force the creation of a new document manager
234        // if the current one is closed
235        $this->resetService($this->managers[$name]);
236
237        return $this->getManager($name);
238    }
239
240    private function selectManager(string $persistentObjectName, ?string $persistentManagerName = null) : ObjectManager
241    {
242        if ($persistentManagerName !== null) {
243            return $this->getManager($persistentManagerName);
244        }
245
246        return $this->getManagerForClass($persistentObjectName) ?? $this->getManager();
247    }
248}
249
250class_exists(\Doctrine\Common\Persistence\AbstractManagerRegistry::class);
251interface_exists(ObjectManager::class);
252