Completed
Push — master ( 98e4ef...5952d3 )
by Jáchym
03:01
created

EntityManager   C

Complexity

Total Complexity 40

Size/Duplication

Total Lines 279
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 18

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 40
lcom 2
cbo 18
dl 0
loc 279
rs 6.2762
c 4
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A persist() 0 8 3
A remove() 0 8 3
A __construct() 0 8 2
A bindTracyPanel() 0 4 1
A createQueryBuilder() 0 14 4
A clear() 0 8 3
A flush() 0 15 3
A close() 0 8 2
A safePersist() 0 8 2
A newHydrator() 0 10 2
C create() 0 25 7
A fetch() 0 9 2
A fetchOne() 0 15 4
A handleQueryException() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like EntityManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EntityManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of the Kdyby (http://www.kdyby.org)
5
 *
6
 * Copyright (c) 2008 Filip Procházka ([email protected])
7
 *
8
 * For the full copyright and license information, please view the file license.txt that was distributed with this source code.
9
 */
10
11
namespace Kdyby\Doctrine;
12
13
use Doctrine;
14
use Doctrine\DBAL\DriverManager;
15
use Doctrine\ORM\AbstractQuery;
16
use Doctrine\ORM\ORMException;
17
use Doctrine\ORM\Query;
18
use Kdyby;
19
use Kdyby\Doctrine\Diagnostics\EntityManagerUnitOfWorkSnapshotPanel;
20
use Kdyby\Doctrine\QueryObject;
21
use Kdyby\Doctrine\Tools\NonLockingUniqueInserter;
22
use Kdyby\Persistence;
23
use Nette;
24
25
26
27
/**
28
 * @author Filip Procházka <[email protected]>
29
 *
30
 * @method \Kdyby\Doctrine\Connection getConnection()
31
 * @method \Kdyby\Doctrine\Configuration getConfiguration()
32
 * @method \Kdyby\Doctrine\EntityRepository getRepository($entityName)
33
 */
34
class EntityManager extends Doctrine\ORM\EntityManager implements Persistence\QueryExecutor, Persistence\Queryable
35
{
36
37
	use \Kdyby\StrictObjects\Scream;
38
39
	/**
40
	 * @var NonLockingUniqueInserter
41
	 */
42
	private $nonLockingUniqueInserter;
43
44
	/**
45
	 * @var \Kdyby\Doctrine\Diagnostics\EntityManagerUnitOfWorkSnapshotPanel
46
	 */
47
	private $panel;
48
49
50
51
	protected function __construct(Doctrine\DBAL\Connection $conn, Doctrine\ORM\Configuration $config, Doctrine\Common\EventManager $eventManager)
52
	{
53
		parent::__construct($conn, $config, $eventManager);
54
55
		if ($conn instanceof Kdyby\Doctrine\Connection) {
56
			$conn->bindEntityManager($this);
57
		}
58
	}
59
60
61
62
	/**
63
	 * @internal
64
	 * @param EntityManagerUnitOfWorkSnapshotPanel $panel
65
	 */
66
	public function bindTracyPanel(EntityManagerUnitOfWorkSnapshotPanel $panel)
67
	{
68
		$this->panel = $panel;
69
	}
70
71
72
73
	/**
74
	 * @throws NotSupportedException
75
	 * @return \Kdyby\Doctrine\QueryBuilder
76
	 */
77
	public function createQueryBuilder($alias = NULL, $indexBy = NULL)
78
	{
79
		if ($alias !== NULL || $indexBy !== NULL) {
80
			throw new NotSupportedException('Use EntityRepository for $alias and $indexBy arguments to work.');
81
		}
82
83
		$config = $this->getConfiguration();
84
		if ($config instanceof Configuration) {
85
			$class = $config->getQueryBuilderClassName();
86
			return new $class($this);
87
		}
88
89
		return new QueryBuilder($this);
90
	}
91
92
93
94
	/**
95
	 * @param string|array|null $entityName if given, only entities of this type will get detached
96
	 * @return EntityManager
97
	 */
98
	public function clear($entityName = null)
99
	{
100
		foreach (is_array($entityName) ? $entityName : (func_get_args() + [0 => NULL]) as $item) {
101
			parent::clear($item);
102
		}
103
104
		return $this;
105
	}
106
107
108
109
	/**
110
	 * @param object|array $entity
111
	 * @return EntityManager
112
	 */
113
	public function remove($entity)
114
	{
115
		foreach (is_array($entity) ? $entity : func_get_args() as $item) {
116
			parent::remove($item);
117
		}
118
119
		return $this;
120
	}
121
122
123
124
	/**
125
	 * @param object|array $entity
126
	 * @return EntityManager
127
	 */
128
	public function persist($entity)
129
	{
130
		foreach (is_array($entity) ? $entity : func_get_args() as $item) {
131
			parent::persist($item);
132
		}
133
134
		return $this;
135
	}
136
137
138
139
	/**
140
	 * @param object|array|NULL $entity
141
	 * @return EntityManager
142
	 */
143
	public function flush($entity = null)
144
	{
145
		try {
146
			parent::flush($entity);
147
148
		} catch (\Exception $e) {
149
			if ($this->panel) {
150
				$this->panel->markExceptionOwner($this, $e);
151
			}
152
153
			throw $e;
154
		}
155
156
		return $this;
157
	}
158
159
160
161
	public function close()
162
	{
163
		if ($this->panel) {
164
			$this->panel->snapshotUnitOfWork($this);
165
		}
166
167
		parent::close();
168
	}
169
170
171
172
	/**
173
	 * Tries to persist the given entity and returns FALSE if an unique
174
	 * constaint was violated.
175
	 *
176
	 * Warning: On success you must NOT use the passed entity further
177
	 * in your application. Use the returned one instead!
178
	 *
179
	 * @param $entity
180
	 * @throws \Doctrine\DBAL\DBALException
181
	 * @throws \Exception
182
	 * @return bool|object
183
	 */
184
	public function safePersist($entity)
185
	{
186
		if ($this->nonLockingUniqueInserter === NULL) {
187
			$this->nonLockingUniqueInserter = new NonLockingUniqueInserter($this);
188
		}
189
190
		return $this->nonLockingUniqueInserter->persist($entity);
191
	}
192
193
194
195
	/**
196
	 * @param int $hydrationMode
197
	 * @return Doctrine\ORM\Internal\Hydration\AbstractHydrator
198
	 * @throws \Doctrine\ORM\ORMException
199
	 */
200
	public function newHydrator($hydrationMode)
201
	{
202
		switch ($hydrationMode) {
203
			case Hydration\HashHydrator::NAME:
204
				return new Hydration\HashHydrator($this);
205
206
			default:
207
				return parent::newHydrator($hydrationMode);
208
		}
209
	}
210
211
212
213
	/**
214
	 * Factory method to create EntityManager instances.
215
	 *
216
	 * @param \Doctrine\DBAL\Connection|array $conn
217
	 * @param \Doctrine\ORM\Configuration $config
218
	 * @param \Doctrine\Common\EventManager $eventManager
219
	 * @throws \Doctrine\ORM\ORMException
220
	 * @throws \InvalidArgumentException
221
	 * @throws \Doctrine\ORM\ORMException
222
	 * @return EntityManager
223
	 */
224
	public static function create($conn, Doctrine\ORM\Configuration $config, Doctrine\Common\EventManager $eventManager = NULL)
225
	{
226
		if (!$config->getMetadataDriverImpl()) {
227
			throw ORMException::missingMappingDriverImpl();
228
		}
229
230
		switch (TRUE) {
231
			case (is_array($conn)):
232
				$conn = DriverManager::getConnection(
233
					$conn, $config, ($eventManager ? : new Doctrine\Common\EventManager())
234
				);
235
				break;
236
237
			case ($conn instanceof Doctrine\DBAL\Connection):
238
				if ($eventManager !== NULL && $conn->getEventManager() !== $eventManager) {
239
					throw ORMException::mismatchedEventManager();
240
				}
241
				break;
242
243
			default:
244
				throw new \InvalidArgumentException("Invalid connection");
245
		}
246
247
		return new EntityManager($conn, $config, $conn->getEventManager());
248
	}
249
250
251
252
	/****************** Kdyby\Persistence\QueryExecutor *****************/
253
254
255
256
	/**
257
	 * @param \Kdyby\Persistence\Query|\Kdyby\Doctrine\QueryObject $queryObject
258
	 * @param int $hydrationMode
259
	 * @throws QueryException
260
	 * @return array|\Kdyby\Doctrine\ResultSet
261
	 */
262
	public function fetch(Persistence\Query $queryObject, $hydrationMode = AbstractQuery::HYDRATE_OBJECT)
263
	{
264
		try {
265
			return $queryObject->fetch($this, $hydrationMode);
0 ignored issues
show
Unused Code introduced by
The call to Query::fetch() has too many arguments starting with $hydrationMode.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
266
267
		} catch (\Exception $e) {
268
			throw $this->handleQueryException($e, $queryObject);
269
		}
270
	}
271
272
273
274
	/**
275
	 * @param \Kdyby\Persistence\Query|\Kdyby\Doctrine\QueryObject $queryObject
276
	 *
277
	 * @throws InvalidStateException
278
	 * @throws QueryException
279
	 * @return object|NULL
280
	 */
281
	public function fetchOne(Persistence\Query $queryObject)
282
	{
283
		try {
284
			return $queryObject->fetchOne($this);
285
286
		} catch (Doctrine\ORM\NoResultException $e) {
287
			return NULL;
288
289
		} catch (Doctrine\ORM\NonUniqueResultException $e) { // this should never happen!
290
			throw new InvalidStateException("You have to setup your query calling ->setMaxResult(1).", 0, $e);
291
292
		} catch (\Exception $e) {
293
			throw $this->handleQueryException($e, $queryObject);
294
		}
295
	}
296
297
298
299
	/**
300
	 * @param \Exception $e
301
	 * @param \Kdyby\Persistence\Query $queryObject
302
	 *
303
	 * @throws \Exception
304
	 */
305
	private function handleQueryException(\Exception $e, Persistence\Query $queryObject)
306
	{
307
		$lastQuery = $queryObject instanceof QueryObject ? $queryObject->getLastQuery() : NULL;
308
309
		return new QueryException($e, $lastQuery, '['.get_class($queryObject).'] '.$e->getMessage());
310
	}
311
312
}
313