These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /* |
||
3 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
4 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
5 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
6 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
7 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
8 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
9 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
10 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
11 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
12 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
13 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
14 | * |
||
15 | * This software consists of voluntary contributions made by many individuals |
||
16 | * and is licensed under the MIT license. For more information, see |
||
17 | * <http://www.doctrine-project.org>. |
||
18 | */ |
||
19 | |||
20 | namespace Doctrine\ORM; |
||
21 | |||
22 | use Exception; |
||
23 | use Doctrine\Common\EventManager; |
||
24 | use Doctrine\DBAL\Connection; |
||
25 | use Doctrine\DBAL\DriverManager; |
||
26 | use Doctrine\DBAL\LockMode; |
||
27 | use Doctrine\ORM\Query\ResultSetMapping; |
||
28 | use Doctrine\ORM\Proxy\ProxyFactory; |
||
29 | use Doctrine\ORM\Query\FilterCollection; |
||
30 | use Doctrine\Common\Util\ClassUtils; |
||
31 | |||
32 | /** |
||
33 | * The EntityManager is the central access point to ORM functionality. |
||
34 | * |
||
35 | * It is a facade to all different ORM subsystems such as UnitOfWork, |
||
36 | * Query Language and Repository API. Instantiation is done through |
||
37 | * the static create() method. The quickest way to obtain a fully |
||
38 | * configured EntityManager is: |
||
39 | * |
||
40 | * use Doctrine\ORM\Tools\Setup; |
||
41 | * use Doctrine\ORM\EntityManager; |
||
42 | * |
||
43 | * $paths = array('/path/to/entity/mapping/files'); |
||
44 | * |
||
45 | * $config = Setup::createAnnotationMetadataConfiguration($paths); |
||
46 | * $dbParams = array('driver' => 'pdo_sqlite', 'memory' => true); |
||
47 | * $entityManager = EntityManager::create($dbParams, $config); |
||
48 | * |
||
49 | * For more information see |
||
50 | * {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html} |
||
51 | * |
||
52 | * You should never attempt to inherit from the EntityManager: Inheritance |
||
53 | * is not a valid extension point for the EntityManager. Instead you |
||
54 | * should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator} |
||
55 | * and wrap your entity manager in a decorator. |
||
56 | * |
||
57 | * @since 2.0 |
||
58 | * @author Benjamin Eberlei <[email protected]> |
||
59 | * @author Guilherme Blanco <[email protected]> |
||
60 | * @author Jonathan Wage <[email protected]> |
||
61 | * @author Roman Borschel <[email protected]> |
||
62 | */ |
||
63 | /* final */class EntityManager implements EntityManagerInterface |
||
64 | { |
||
65 | /** |
||
66 | * The used Configuration. |
||
67 | * |
||
68 | * @var \Doctrine\ORM\Configuration |
||
69 | */ |
||
70 | private $config; |
||
71 | |||
72 | /** |
||
73 | * The database connection used by the EntityManager. |
||
74 | * |
||
75 | * @var \Doctrine\DBAL\Connection |
||
76 | */ |
||
77 | private $conn; |
||
78 | |||
79 | /** |
||
80 | * The metadata factory, used to retrieve the ORM metadata of entity classes. |
||
81 | * |
||
82 | * @var \Doctrine\ORM\Mapping\ClassMetadataFactory |
||
83 | */ |
||
84 | private $metadataFactory; |
||
85 | |||
86 | /** |
||
87 | * The UnitOfWork used to coordinate object-level transactions. |
||
88 | * |
||
89 | * @var \Doctrine\ORM\UnitOfWork |
||
90 | */ |
||
91 | private $unitOfWork; |
||
92 | |||
93 | /** |
||
94 | * The event manager that is the central point of the event system. |
||
95 | * |
||
96 | * @var \Doctrine\Common\EventManager |
||
97 | */ |
||
98 | private $eventManager; |
||
99 | |||
100 | /** |
||
101 | * The proxy factory used to create dynamic proxies. |
||
102 | * |
||
103 | * @var \Doctrine\ORM\Proxy\ProxyFactory |
||
104 | */ |
||
105 | private $proxyFactory; |
||
106 | |||
107 | /** |
||
108 | * The repository factory used to create dynamic repositories. |
||
109 | * |
||
110 | * @var \Doctrine\ORM\Repository\RepositoryFactory |
||
111 | */ |
||
112 | private $repositoryFactory; |
||
113 | |||
114 | /** |
||
115 | * The expression builder instance used to generate query expressions. |
||
116 | * |
||
117 | * @var \Doctrine\ORM\Query\Expr |
||
118 | */ |
||
119 | private $expressionBuilder; |
||
120 | |||
121 | /** |
||
122 | * Whether the EntityManager is closed or not. |
||
123 | * |
||
124 | * @var bool |
||
125 | */ |
||
126 | private $closed = false; |
||
127 | |||
128 | /** |
||
129 | * Collection of query filters. |
||
130 | * |
||
131 | * @var \Doctrine\ORM\Query\FilterCollection |
||
132 | */ |
||
133 | private $filterCollection; |
||
134 | |||
135 | /** |
||
136 | * @var \Doctrine\ORM\Cache The second level cache regions API. |
||
137 | */ |
||
138 | private $cache; |
||
139 | |||
140 | /** |
||
141 | * Creates a new EntityManager that operates on the given database connection |
||
142 | * and uses the given Configuration and EventManager implementations. |
||
143 | * |
||
144 | * @param \Doctrine\DBAL\Connection $conn |
||
145 | * @param \Doctrine\ORM\Configuration $config |
||
146 | * @param \Doctrine\Common\EventManager $eventManager |
||
147 | */ |
||
148 | 2395 | protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager) |
|
149 | { |
||
150 | 2395 | $this->conn = $conn; |
|
151 | 2395 | $this->config = $config; |
|
152 | 2395 | $this->eventManager = $eventManager; |
|
153 | |||
154 | 2395 | $metadataFactoryClassName = $config->getClassMetadataFactoryName(); |
|
155 | |||
156 | 2395 | $this->metadataFactory = new $metadataFactoryClassName; |
|
157 | 2395 | $this->metadataFactory->setEntityManager($this); |
|
158 | 2395 | $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl()); |
|
159 | |||
160 | 2395 | $this->repositoryFactory = $config->getRepositoryFactory(); |
|
161 | 2395 | $this->unitOfWork = new UnitOfWork($this); |
|
162 | 2395 | $this->proxyFactory = new ProxyFactory( |
|
163 | 2395 | $this, |
|
164 | 2395 | $config->getProxyDir(), |
|
165 | 2395 | $config->getProxyNamespace(), |
|
166 | 2395 | $config->getAutoGenerateProxyClasses() |
|
167 | ); |
||
168 | |||
169 | 2395 | if ($config->isSecondLevelCacheEnabled()) { |
|
170 | 283 | $cacheConfig = $config->getSecondLevelCacheConfiguration(); |
|
171 | 283 | $cacheFactory = $cacheConfig->getCacheFactory(); |
|
172 | 283 | $this->cache = $cacheFactory->createCache($this); |
|
173 | } |
||
174 | 2395 | } |
|
175 | |||
176 | /** |
||
177 | * {@inheritDoc} |
||
178 | */ |
||
179 | 1880 | public function getConnection() |
|
180 | { |
||
181 | 1880 | return $this->conn; |
|
182 | } |
||
183 | |||
184 | /** |
||
185 | * Gets the metadata factory used to gather the metadata of classes. |
||
186 | * |
||
187 | * @return \Doctrine\ORM\Mapping\ClassMetadataFactory |
||
188 | */ |
||
189 | 2395 | public function getMetadataFactory() |
|
190 | { |
||
191 | 2395 | return $this->metadataFactory; |
|
192 | } |
||
193 | |||
194 | /** |
||
195 | * {@inheritDoc} |
||
196 | */ |
||
197 | 17 | public function getExpressionBuilder() |
|
198 | { |
||
199 | 17 | if ($this->expressionBuilder === null) { |
|
200 | 17 | $this->expressionBuilder = new Query\Expr; |
|
201 | } |
||
202 | |||
203 | 17 | return $this->expressionBuilder; |
|
204 | } |
||
205 | |||
206 | /** |
||
207 | * {@inheritDoc} |
||
208 | */ |
||
209 | 1 | public function beginTransaction() |
|
210 | { |
||
211 | 1 | $this->conn->beginTransaction(); |
|
212 | 1 | } |
|
213 | |||
214 | /** |
||
215 | * {@inheritDoc} |
||
216 | */ |
||
217 | 216 | public function getCache() |
|
218 | { |
||
219 | 216 | return $this->cache; |
|
220 | } |
||
221 | |||
222 | /** |
||
223 | * {@inheritDoc} |
||
224 | */ |
||
225 | 4 | public function transactional($func) |
|
226 | { |
||
227 | 4 | if (!is_callable($func)) { |
|
228 | 1 | throw new \InvalidArgumentException('Expected argument of type "callable", got "' . gettype($func) . '"'); |
|
229 | } |
||
230 | |||
231 | 3 | $this->conn->beginTransaction(); |
|
232 | |||
233 | try { |
||
234 | 3 | $return = call_user_func($func, $this); |
|
235 | |||
236 | 3 | $this->flush(); |
|
237 | 3 | $this->conn->commit(); |
|
238 | |||
239 | 3 | return $return ?: true; |
|
240 | } catch (Exception $e) { |
||
241 | $this->close(); |
||
242 | $this->conn->rollBack(); |
||
243 | |||
244 | throw $e; |
||
245 | } |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * {@inheritDoc} |
||
250 | */ |
||
251 | 1 | public function commit() |
|
252 | { |
||
253 | 1 | $this->conn->commit(); |
|
254 | 1 | } |
|
255 | |||
256 | /** |
||
257 | * {@inheritDoc} |
||
258 | */ |
||
259 | public function rollback() |
||
260 | { |
||
261 | $this->conn->rollBack(); |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Returns the ORM metadata descriptor for a class. |
||
266 | * |
||
267 | * The class name must be the fully-qualified class name without a leading backslash |
||
268 | * (as it is returned by get_class($obj)) or an aliased class name. |
||
269 | * |
||
270 | * Examples: |
||
271 | * MyProject\Domain\User |
||
272 | * sales:PriceRequest |
||
273 | * |
||
274 | * Internal note: Performance-sensitive method. |
||
275 | * |
||
276 | * @param string $className |
||
277 | * |
||
278 | * @return \Doctrine\ORM\Mapping\ClassMetadata |
||
279 | */ |
||
280 | 1940 | public function getClassMetadata($className) |
|
281 | { |
||
282 | 1940 | return $this->metadataFactory->getMetadataFor($className); |
|
283 | } |
||
284 | |||
285 | /** |
||
286 | * {@inheritDoc} |
||
287 | */ |
||
288 | 939 | public function createQuery($dql = '') |
|
289 | { |
||
290 | 939 | $query = new Query($this); |
|
291 | |||
292 | 939 | if ( ! empty($dql)) { |
|
293 | 934 | $query->setDQL($dql); |
|
294 | } |
||
295 | |||
296 | 939 | return $query; |
|
297 | } |
||
298 | |||
299 | /** |
||
300 | * {@inheritDoc} |
||
301 | */ |
||
302 | 1 | public function createNamedQuery($name) |
|
303 | { |
||
304 | 1 | return $this->createQuery($this->config->getNamedQuery($name)); |
|
305 | } |
||
306 | |||
307 | /** |
||
308 | * {@inheritDoc} |
||
309 | */ |
||
310 | 21 | public function createNativeQuery($sql, ResultSetMapping $rsm) |
|
311 | { |
||
312 | 21 | $query = new NativeQuery($this); |
|
313 | |||
314 | 21 | $query->setSQL($sql); |
|
315 | 21 | $query->setResultSetMapping($rsm); |
|
316 | |||
317 | 21 | return $query; |
|
318 | } |
||
319 | |||
320 | /** |
||
321 | * {@inheritDoc} |
||
322 | */ |
||
323 | 1 | public function createNamedNativeQuery($name) |
|
324 | { |
||
325 | 1 | list($sql, $rsm) = $this->config->getNamedNativeQuery($name); |
|
326 | |||
327 | 1 | return $this->createNativeQuery($sql, $rsm); |
|
328 | } |
||
329 | |||
330 | /** |
||
331 | * {@inheritDoc} |
||
332 | */ |
||
333 | 117 | public function createQueryBuilder() |
|
334 | { |
||
335 | 117 | return new QueryBuilder($this); |
|
336 | } |
||
337 | |||
338 | /** |
||
339 | * Flushes all changes to objects that have been queued up to now to the database. |
||
340 | * This effectively synchronizes the in-memory state of managed objects with the |
||
341 | * database. |
||
342 | * |
||
343 | * If an entity is explicitly passed to this method only this entity and |
||
344 | * the cascade-persist semantics + scheduled inserts/removals are synchronized. |
||
345 | * |
||
346 | * @param null|object|array $entity |
||
347 | * |
||
348 | * @return void |
||
349 | * |
||
350 | * @throws \Doctrine\ORM\OptimisticLockException If a version check on an entity that |
||
351 | * makes use of optimistic locking fails. |
||
352 | * @throws ORMException |
||
353 | */ |
||
354 | 1035 | public function flush($entity = null) |
|
355 | { |
||
356 | 1035 | $this->errorIfClosed(); |
|
357 | |||
358 | 1034 | $this->unitOfWork->commit($entity); |
|
359 | 1025 | } |
|
360 | |||
361 | /** |
||
362 | * Finds an Entity by its identifier. |
||
363 | * |
||
364 | * @param string $entityName The class name of the entity to find. |
||
365 | * @param mixed $id The identity of the entity to find. |
||
366 | * @param integer|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants |
||
367 | * or NULL if no specific lock mode should be used |
||
368 | * during the search. |
||
369 | * @param integer|null $lockVersion The version of the entity to find when using |
||
370 | * optimistic locking. |
||
371 | * |
||
372 | * @return object|null The entity instance or NULL if the entity can not be found. |
||
373 | * |
||
374 | * @throws OptimisticLockException |
||
375 | * @throws ORMInvalidArgumentException |
||
376 | * @throws TransactionRequiredException |
||
377 | * @throws ORMException |
||
378 | */ |
||
379 | 429 | public function find($entityName, $id, $lockMode = null, $lockVersion = null) |
|
380 | { |
||
381 | 429 | $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); |
|
382 | |||
383 | 429 | if ( ! is_array($id)) { |
|
384 | 383 | if ($class->isIdentifierComposite) { |
|
385 | throw ORMInvalidArgumentException::invalidCompositeIdentifier(); |
||
386 | } |
||
387 | |||
388 | 383 | $id = [$class->identifier[0] => $id]; |
|
389 | } |
||
390 | |||
391 | 429 | foreach ($id as $i => $value) { |
|
392 | 429 | View Code Duplication | if (is_object($value) && $this->metadataFactory->hasMetadataFor(ClassUtils::getClass($value))) { |
393 | 7 | $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value); |
|
394 | |||
395 | 7 | if ($id[$i] === null) { |
|
396 | 429 | throw ORMInvalidArgumentException::invalidIdentifierBindingEntity(); |
|
397 | } |
||
398 | } |
||
399 | } |
||
400 | |||
401 | 428 | $sortedId = []; |
|
402 | |||
403 | 428 | View Code Duplication | foreach ($class->identifier as $identifier) { |
0 ignored issues
–
show
|
|||
404 | 428 | if ( ! isset($id[$identifier])) { |
|
405 | 1 | throw ORMException::missingIdentifierField($class->name, $identifier); |
|
406 | } |
||
407 | |||
408 | 427 | $sortedId[$identifier] = $id[$identifier]; |
|
409 | 427 | unset($id[$identifier]); |
|
410 | } |
||
411 | |||
412 | 427 | if ($id) { |
|
413 | 1 | throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id)); |
|
414 | } |
||
415 | |||
416 | 426 | $unitOfWork = $this->getUnitOfWork(); |
|
417 | |||
418 | // Check identity map first |
||
419 | 426 | if (($entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) { |
|
420 | 46 | if ( ! ($entity instanceof $class->name)) { |
|
421 | 1 | return null; |
|
422 | } |
||
423 | |||
424 | switch (true) { |
||
425 | 45 | case LockMode::OPTIMISTIC === $lockMode: |
|
426 | 1 | $this->lock($entity, $lockMode, $lockVersion); |
|
427 | break; |
||
428 | |||
429 | 45 | case LockMode::NONE === $lockMode: |
|
430 | 45 | case LockMode::PESSIMISTIC_READ === $lockMode: |
|
431 | 45 | case LockMode::PESSIMISTIC_WRITE === $lockMode: |
|
432 | $persister = $unitOfWork->getEntityPersister($class->name); |
||
433 | $persister->refresh($sortedId, $entity, $lockMode); |
||
434 | break; |
||
435 | } |
||
436 | |||
437 | 45 | return $entity; // Hit! |
|
438 | } |
||
439 | |||
440 | 407 | $persister = $unitOfWork->getEntityPersister($class->name); |
|
441 | |||
442 | switch (true) { |
||
443 | 407 | case LockMode::OPTIMISTIC === $lockMode: |
|
444 | 1 | if ( ! $class->isVersioned) { |
|
445 | 1 | throw OptimisticLockException::notVersioned($class->name); |
|
446 | } |
||
447 | |||
448 | $entity = $persister->load($sortedId); |
||
449 | |||
450 | $unitOfWork->lock($entity, $lockMode, $lockVersion); |
||
451 | |||
452 | return $entity; |
||
453 | |||
454 | 406 | case LockMode::PESSIMISTIC_READ === $lockMode: |
|
455 | 405 | case LockMode::PESSIMISTIC_WRITE === $lockMode: |
|
456 | 2 | if ( ! $this->getConnection()->isTransactionActive()) { |
|
457 | 2 | throw TransactionRequiredException::transactionRequired(); |
|
458 | } |
||
459 | |||
460 | return $persister->load($sortedId, null, null, [], $lockMode); |
||
461 | |||
462 | default: |
||
463 | 404 | return $persister->loadById($sortedId); |
|
464 | } |
||
465 | } |
||
466 | |||
467 | /** |
||
468 | * {@inheritDoc} |
||
469 | */ |
||
470 | 92 | public function getReference($entityName, $id) |
|
471 | { |
||
472 | 92 | $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); |
|
473 | |||
474 | 92 | if ( ! is_array($id)) { |
|
475 | 49 | $id = [$class->identifier[0] => $id]; |
|
476 | } |
||
477 | |||
478 | 92 | $sortedId = []; |
|
479 | |||
480 | 92 | View Code Duplication | foreach ($class->identifier as $identifier) { |
481 | 92 | if ( ! isset($id[$identifier])) { |
|
482 | throw ORMException::missingIdentifierField($class->name, $identifier); |
||
483 | } |
||
484 | |||
485 | 92 | $sortedId[$identifier] = $id[$identifier]; |
|
486 | 92 | unset($id[$identifier]); |
|
487 | } |
||
488 | |||
489 | 92 | if ($id) { |
|
490 | 1 | throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id)); |
|
491 | } |
||
492 | |||
493 | // Check identity map first, if its already in there just return it. |
||
494 | 91 | View Code Duplication | if (($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) { |
495 | 27 | return ($entity instanceof $class->name) ? $entity : null; |
|
496 | } |
||
497 | |||
498 | 87 | if ($class->subClasses) { |
|
499 | 2 | return $this->find($entityName, $sortedId); |
|
500 | } |
||
501 | |||
502 | 87 | $entity = $this->proxyFactory->getProxy($class->name, $sortedId); |
|
503 | |||
504 | 87 | $this->unitOfWork->registerManaged($entity, $sortedId, []); |
|
505 | |||
506 | 87 | return $entity; |
|
507 | } |
||
508 | |||
509 | /** |
||
510 | * {@inheritDoc} |
||
511 | */ |
||
512 | 4 | public function getPartialReference($entityName, $identifier) |
|
513 | { |
||
514 | 4 | $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); |
|
515 | |||
516 | // Check identity map first, if its already in there just return it. |
||
517 | 4 | View Code Duplication | if (($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) !== false) { |
518 | 1 | return ($entity instanceof $class->name) ? $entity : null; |
|
519 | } |
||
520 | |||
521 | 3 | if ( ! is_array($identifier)) { |
|
522 | 3 | $identifier = [$class->identifier[0] => $identifier]; |
|
523 | } |
||
524 | |||
525 | 3 | $entity = $class->newInstance(); |
|
526 | |||
527 | 3 | $class->setIdentifierValues($entity, $identifier); |
|
528 | |||
529 | 3 | $this->unitOfWork->registerManaged($entity, $identifier, []); |
|
530 | 3 | $this->unitOfWork->markReadOnly($entity); |
|
531 | |||
532 | 3 | return $entity; |
|
533 | } |
||
534 | |||
535 | /** |
||
536 | * Clears the EntityManager. All entities that are currently managed |
||
537 | * by this EntityManager become detached. |
||
538 | * |
||
539 | * @param string|null $entityName if given, only entities of this type will get detached |
||
540 | * |
||
541 | * @return void |
||
542 | * |
||
543 | * @throws ORMInvalidArgumentException if a non-null non-string value is given |
||
544 | * @throws \Doctrine\Common\Persistence\Mapping\MappingException if a $entityName is given, but that entity is not |
||
545 | * found in the mappings |
||
546 | */ |
||
547 | 1254 | public function clear($entityName = null) |
|
548 | { |
||
549 | 1254 | if (null !== $entityName && ! is_string($entityName)) { |
|
550 | 1 | throw ORMInvalidArgumentException::invalidEntityName($entityName); |
|
551 | } |
||
552 | |||
553 | 1253 | $this->unitOfWork->clear( |
|
554 | 1253 | null === $entityName |
|
555 | 1251 | ? null |
|
556 | 1253 | : $this->metadataFactory->getMetadataFor($entityName)->getName() |
|
557 | ); |
||
558 | 1252 | } |
|
559 | |||
560 | /** |
||
561 | * {@inheritDoc} |
||
562 | */ |
||
563 | 19 | public function close() |
|
564 | { |
||
565 | 19 | $this->clear(); |
|
566 | |||
567 | 19 | $this->closed = true; |
|
568 | 19 | } |
|
569 | |||
570 | /** |
||
571 | * Tells the EntityManager to make an instance managed and persistent. |
||
572 | * |
||
573 | * The entity will be entered into the database at or before transaction |
||
574 | * commit or as a result of the flush operation. |
||
575 | * |
||
576 | * NOTE: The persist operation always considers entities that are not yet known to |
||
577 | * this EntityManager as NEW. Do not pass detached entities to the persist operation. |
||
578 | * |
||
579 | * @param object $entity The instance to make managed and persistent. |
||
580 | * |
||
581 | * @return void |
||
582 | * |
||
583 | * @throws ORMInvalidArgumentException |
||
584 | * @throws ORMException |
||
585 | */ |
||
586 | 1031 | View Code Duplication | public function persist($entity) |
587 | { |
||
588 | 1031 | if ( ! is_object($entity)) { |
|
589 | 1 | throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()', $entity); |
|
590 | } |
||
591 | |||
592 | 1030 | $this->errorIfClosed(); |
|
593 | |||
594 | 1029 | $this->unitOfWork->persist($entity); |
|
595 | 1028 | } |
|
596 | |||
597 | /** |
||
598 | * Removes an entity instance. |
||
599 | * |
||
600 | * A removed entity will be removed from the database at or before transaction commit |
||
601 | * or as a result of the flush operation. |
||
602 | * |
||
603 | * @param object $entity The entity instance to remove. |
||
604 | * |
||
605 | * @return void |
||
606 | * |
||
607 | * @throws ORMInvalidArgumentException |
||
608 | * @throws ORMException |
||
609 | */ |
||
610 | 51 | View Code Duplication | public function remove($entity) |
611 | { |
||
612 | 51 | if ( ! is_object($entity)) { |
|
613 | 1 | throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()', $entity); |
|
614 | } |
||
615 | |||
616 | 50 | $this->errorIfClosed(); |
|
617 | |||
618 | 49 | $this->unitOfWork->remove($entity); |
|
619 | 49 | } |
|
620 | |||
621 | /** |
||
622 | * Refreshes the persistent state of an entity from the database, |
||
623 | * overriding any local changes that have not yet been persisted. |
||
624 | * |
||
625 | * @param object $entity The entity to refresh. |
||
626 | * |
||
627 | * @return void |
||
628 | * |
||
629 | * @throws ORMInvalidArgumentException |
||
630 | * @throws ORMException |
||
631 | */ |
||
632 | 19 | View Code Duplication | public function refresh($entity) |
633 | { |
||
634 | 19 | if ( ! is_object($entity)) { |
|
635 | 1 | throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()', $entity); |
|
636 | } |
||
637 | |||
638 | 18 | $this->errorIfClosed(); |
|
639 | |||
640 | 17 | $this->unitOfWork->refresh($entity); |
|
641 | 17 | } |
|
642 | |||
643 | /** |
||
644 | * Detaches an entity from the EntityManager, causing a managed entity to |
||
645 | * become detached. Unflushed changes made to the entity if any |
||
646 | * (including removal of the entity), will not be synchronized to the database. |
||
647 | * Entities which previously referenced the detached entity will continue to |
||
648 | * reference it. |
||
649 | * |
||
650 | * @param object $entity The entity to detach. |
||
651 | * |
||
652 | * @return void |
||
653 | * |
||
654 | * @throws ORMInvalidArgumentException |
||
655 | */ |
||
656 | 13 | public function detach($entity) |
|
657 | { |
||
658 | 13 | if ( ! is_object($entity)) { |
|
659 | 1 | throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()', $entity); |
|
660 | } |
||
661 | |||
662 | 12 | $this->unitOfWork->detach($entity); |
|
663 | 12 | } |
|
664 | |||
665 | /** |
||
666 | * Merges the state of a detached entity into the persistence context |
||
667 | * of this EntityManager and returns the managed copy of the entity. |
||
668 | * The entity passed to merge will not become associated/managed with this EntityManager. |
||
669 | * |
||
670 | * @param object $entity The detached entity to merge into the persistence context. |
||
671 | * |
||
672 | * @return object The managed copy of the entity. |
||
673 | * |
||
674 | * @throws ORMInvalidArgumentException |
||
675 | * @throws ORMException |
||
676 | */ |
||
677 | 42 | View Code Duplication | public function merge($entity) |
678 | { |
||
679 | 42 | if ( ! is_object($entity)) { |
|
680 | 1 | throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()', $entity); |
|
681 | } |
||
682 | |||
683 | 41 | $this->errorIfClosed(); |
|
684 | |||
685 | 40 | return $this->unitOfWork->merge($entity); |
|
686 | } |
||
687 | |||
688 | /** |
||
689 | * {@inheritDoc} |
||
690 | * |
||
691 | * @todo Implementation need. This is necessary since $e2 = clone $e1; throws an E_FATAL when access anything on $e: |
||
692 | * Fatal error: Maximum function nesting level of '100' reached, aborting! |
||
693 | */ |
||
694 | public function copy($entity, $deep = false) |
||
695 | { |
||
696 | throw new \BadMethodCallException("Not implemented."); |
||
697 | } |
||
698 | |||
699 | /** |
||
700 | * {@inheritDoc} |
||
701 | */ |
||
702 | 9 | public function lock($entity, $lockMode, $lockVersion = null) |
|
703 | { |
||
704 | 9 | $this->unitOfWork->lock($entity, $lockMode, $lockVersion); |
|
705 | 2 | } |
|
706 | |||
707 | /** |
||
708 | * Gets the repository for an entity class. |
||
709 | * |
||
710 | * @param string $entityName The name of the entity. |
||
711 | * |
||
712 | * @return \Doctrine\ORM\EntityRepository The repository class. |
||
713 | */ |
||
714 | 155 | public function getRepository($entityName) |
|
715 | { |
||
716 | 155 | return $this->repositoryFactory->getRepository($this, $entityName); |
|
717 | } |
||
718 | |||
719 | /** |
||
720 | * Determines whether an entity instance is managed in this EntityManager. |
||
721 | * |
||
722 | * @param object $entity |
||
723 | * |
||
724 | * @return boolean TRUE if this EntityManager currently manages the given entity, FALSE otherwise. |
||
725 | */ |
||
726 | 24 | public function contains($entity) |
|
727 | { |
||
728 | 24 | return $this->unitOfWork->isScheduledForInsert($entity) |
|
729 | 22 | || $this->unitOfWork->isInIdentityMap($entity) |
|
730 | 24 | && ! $this->unitOfWork->isScheduledForDelete($entity); |
|
731 | } |
||
732 | |||
733 | /** |
||
734 | * {@inheritDoc} |
||
735 | */ |
||
736 | 2395 | public function getEventManager() |
|
737 | { |
||
738 | 2395 | return $this->eventManager; |
|
739 | } |
||
740 | |||
741 | /** |
||
742 | * {@inheritDoc} |
||
743 | */ |
||
744 | 2395 | public function getConfiguration() |
|
745 | { |
||
746 | 2395 | return $this->config; |
|
747 | } |
||
748 | |||
749 | /** |
||
750 | * Throws an exception if the EntityManager is closed or currently not active. |
||
751 | * |
||
752 | * @return void |
||
753 | * |
||
754 | * @throws ORMException If the EntityManager is closed. |
||
755 | */ |
||
756 | 1050 | private function errorIfClosed() |
|
757 | { |
||
758 | 1050 | if ($this->closed) { |
|
759 | 5 | throw ORMException::entityManagerClosed(); |
|
760 | } |
||
761 | 1045 | } |
|
762 | |||
763 | /** |
||
764 | * {@inheritDoc} |
||
765 | */ |
||
766 | 1 | public function isOpen() |
|
767 | { |
||
768 | 1 | return (!$this->closed); |
|
769 | } |
||
770 | |||
771 | /** |
||
772 | * {@inheritDoc} |
||
773 | */ |
||
774 | 2395 | public function getUnitOfWork() |
|
775 | { |
||
776 | 2395 | return $this->unitOfWork; |
|
777 | } |
||
778 | |||
779 | /** |
||
780 | * {@inheritDoc} |
||
781 | */ |
||
782 | public function getHydrator($hydrationMode) |
||
783 | { |
||
784 | return $this->newHydrator($hydrationMode); |
||
785 | } |
||
786 | |||
787 | /** |
||
788 | * {@inheritDoc} |
||
789 | */ |
||
790 | 915 | public function newHydrator($hydrationMode) |
|
791 | { |
||
792 | switch ($hydrationMode) { |
||
793 | 915 | case Query::HYDRATE_OBJECT: |
|
794 | 632 | return new Internal\Hydration\ObjectHydrator($this); |
|
795 | |||
796 | 562 | case Query::HYDRATE_ARRAY: |
|
797 | 36 | return new Internal\Hydration\ArrayHydrator($this); |
|
798 | |||
799 | 531 | case Query::HYDRATE_SCALAR: |
|
800 | 85 | return new Internal\Hydration\ScalarHydrator($this); |
|
801 | |||
802 | 448 | case Query::HYDRATE_SINGLE_SCALAR: |
|
803 | 13 | return new Internal\Hydration\SingleScalarHydrator($this); |
|
804 | |||
805 | 439 | case Query::HYDRATE_SIMPLEOBJECT: |
|
806 | 438 | return new Internal\Hydration\SimpleObjectHydrator($this); |
|
807 | |||
808 | default: |
||
809 | 1 | if (($class = $this->config->getCustomHydrationMode($hydrationMode)) !== null) { |
|
810 | 1 | return new $class($this); |
|
811 | } |
||
812 | } |
||
813 | |||
814 | throw ORMException::invalidHydrationMode($hydrationMode); |
||
815 | } |
||
816 | |||
817 | /** |
||
818 | * {@inheritDoc} |
||
819 | */ |
||
820 | 174 | public function getProxyFactory() |
|
821 | { |
||
822 | 174 | return $this->proxyFactory; |
|
823 | } |
||
824 | |||
825 | /** |
||
826 | * {@inheritDoc} |
||
827 | */ |
||
828 | public function initializeObject($obj) |
||
829 | { |
||
830 | $this->unitOfWork->initializeObject($obj); |
||
831 | } |
||
832 | |||
833 | /** |
||
834 | * Factory method to create EntityManager instances. |
||
835 | * |
||
836 | * @param array|Connection $connection An array with the connection parameters or an existing Connection instance. |
||
837 | * @param Configuration $config The Configuration instance to use. |
||
838 | * @param EventManager $eventManager The EventManager instance to use. |
||
839 | * |
||
840 | * @return EntityManager The created EntityManager. |
||
841 | * |
||
842 | * @throws \InvalidArgumentException |
||
843 | * @throws ORMException |
||
844 | */ |
||
845 | 1257 | public static function create($connection, Configuration $config, EventManager $eventManager = null) |
|
846 | { |
||
847 | 1257 | if ( ! $config->getMetadataDriverImpl()) { |
|
848 | throw ORMException::missingMappingDriverImpl(); |
||
849 | } |
||
850 | |||
851 | 1257 | $connection = static::createConnection($connection, $config, $eventManager); |
|
852 | |||
853 | 1256 | return new EntityManager($connection, $config, $connection->getEventManager()); |
|
854 | } |
||
855 | |||
856 | /** |
||
857 | * Factory method to create Connection instances. |
||
858 | * |
||
859 | * @param array|Connection $connection An array with the connection parameters or an existing Connection instance. |
||
860 | * @param Configuration $config The Configuration instance to use. |
||
861 | * @param EventManager $eventManager The EventManager instance to use. |
||
862 | * |
||
863 | * @return Connection |
||
864 | * |
||
865 | * @throws \InvalidArgumentException |
||
866 | * @throws ORMException |
||
867 | */ |
||
868 | 1257 | protected static function createConnection($connection, Configuration $config, EventManager $eventManager = null) |
|
869 | { |
||
870 | 1257 | if (is_array($connection)) { |
|
871 | return DriverManager::getConnection($connection, $config, $eventManager ?: new EventManager()); |
||
872 | } |
||
873 | |||
874 | 1257 | if ( ! $connection instanceof Connection) { |
|
875 | 1 | throw new \InvalidArgumentException( |
|
876 | 1 | sprintf( |
|
877 | 1 | 'Invalid $connection argument of type %s given%s.', |
|
878 | 1 | is_object($connection) ? get_class($connection) : gettype($connection), |
|
879 | 1 | is_object($connection) ? '' : ': "' . $connection . '"' |
|
880 | ) |
||
881 | ); |
||
882 | } |
||
883 | |||
884 | 1256 | if ($eventManager !== null && $connection->getEventManager() !== $eventManager) { |
|
885 | throw ORMException::mismatchedEventManager(); |
||
886 | } |
||
887 | |||
888 | 1256 | return $connection; |
|
889 | } |
||
890 | |||
891 | /** |
||
892 | * {@inheritDoc} |
||
893 | */ |
||
894 | 631 | public function getFilters() |
|
895 | { |
||
896 | 631 | if (null === $this->filterCollection) { |
|
897 | 631 | $this->filterCollection = new FilterCollection($this); |
|
898 | } |
||
899 | |||
900 | 631 | return $this->filterCollection; |
|
901 | } |
||
902 | |||
903 | /** |
||
904 | * {@inheritDoc} |
||
905 | */ |
||
906 | 40 | public function isFiltersStateClean() |
|
907 | { |
||
908 | 40 | return null === $this->filterCollection || $this->filterCollection->isClean(); |
|
909 | } |
||
910 | |||
911 | /** |
||
912 | * {@inheritDoc} |
||
913 | */ |
||
914 | 750 | public function hasFilters() |
|
915 | { |
||
916 | 750 | return null !== $this->filterCollection; |
|
917 | } |
||
918 | } |
||
919 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.