|
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 LGPL. For more information, see |
|
17 * <http://www.doctrine-project.org>. |
|
18 */ |
|
19 |
|
20 namespace Doctrine\ORM; |
|
21 |
|
22 use Closure, Exception, |
|
23 Doctrine\Common\EventManager, |
|
24 Doctrine\Common\Persistence\ObjectManager, |
|
25 Doctrine\DBAL\Connection, |
|
26 Doctrine\DBAL\LockMode, |
|
27 Doctrine\ORM\Mapping\ClassMetadata, |
|
28 Doctrine\ORM\Mapping\ClassMetadataFactory, |
|
29 Doctrine\ORM\Query\ResultSetMapping, |
|
30 Doctrine\ORM\Proxy\ProxyFactory; |
|
31 |
|
32 /** |
|
33 * The EntityManager is the central access point to ORM functionality. |
|
34 * |
|
35 * @since 2.0 |
|
36 * @author Benjamin Eberlei <kontakt@beberlei.de> |
|
37 * @author Guilherme Blanco <guilhermeblanco@hotmail.com> |
|
38 * @author Jonathan Wage <jonwage@gmail.com> |
|
39 * @author Roman Borschel <roman@code-factory.org> |
|
40 */ |
|
41 class EntityManager implements ObjectManager |
|
42 { |
|
43 /** |
|
44 * The used Configuration. |
|
45 * |
|
46 * @var Doctrine\ORM\Configuration |
|
47 */ |
|
48 private $config; |
|
49 |
|
50 /** |
|
51 * The database connection used by the EntityManager. |
|
52 * |
|
53 * @var Doctrine\DBAL\Connection |
|
54 */ |
|
55 private $conn; |
|
56 |
|
57 /** |
|
58 * The metadata factory, used to retrieve the ORM metadata of entity classes. |
|
59 * |
|
60 * @var Doctrine\ORM\Mapping\ClassMetadataFactory |
|
61 */ |
|
62 private $metadataFactory; |
|
63 |
|
64 /** |
|
65 * The EntityRepository instances. |
|
66 * |
|
67 * @var array |
|
68 */ |
|
69 private $repositories = array(); |
|
70 |
|
71 /** |
|
72 * The UnitOfWork used to coordinate object-level transactions. |
|
73 * |
|
74 * @var Doctrine\ORM\UnitOfWork |
|
75 */ |
|
76 private $unitOfWork; |
|
77 |
|
78 /** |
|
79 * The event manager that is the central point of the event system. |
|
80 * |
|
81 * @var Doctrine\Common\EventManager |
|
82 */ |
|
83 private $eventManager; |
|
84 |
|
85 /** |
|
86 * The maintained (cached) hydrators. One instance per type. |
|
87 * |
|
88 * @var array |
|
89 */ |
|
90 private $hydrators = array(); |
|
91 |
|
92 /** |
|
93 * The proxy factory used to create dynamic proxies. |
|
94 * |
|
95 * @var Doctrine\ORM\Proxy\ProxyFactory |
|
96 */ |
|
97 private $proxyFactory; |
|
98 |
|
99 /** |
|
100 * The expression builder instance used to generate query expressions. |
|
101 * |
|
102 * @var Doctrine\ORM\Query\Expr |
|
103 */ |
|
104 private $expressionBuilder; |
|
105 |
|
106 /** |
|
107 * Whether the EntityManager is closed or not. |
|
108 * |
|
109 * @var bool |
|
110 */ |
|
111 private $closed = false; |
|
112 |
|
113 /** |
|
114 * Creates a new EntityManager that operates on the given database connection |
|
115 * and uses the given Configuration and EventManager implementations. |
|
116 * |
|
117 * @param Doctrine\DBAL\Connection $conn |
|
118 * @param Doctrine\ORM\Configuration $config |
|
119 * @param Doctrine\Common\EventManager $eventManager |
|
120 */ |
|
121 protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager) |
|
122 { |
|
123 $this->conn = $conn; |
|
124 $this->config = $config; |
|
125 $this->eventManager = $eventManager; |
|
126 |
|
127 $metadataFactoryClassName = $config->getClassMetadataFactoryName(); |
|
128 $this->metadataFactory = new $metadataFactoryClassName; |
|
129 $this->metadataFactory->setEntityManager($this); |
|
130 $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl()); |
|
131 |
|
132 $this->unitOfWork = new UnitOfWork($this); |
|
133 $this->proxyFactory = new ProxyFactory($this, |
|
134 $config->getProxyDir(), |
|
135 $config->getProxyNamespace(), |
|
136 $config->getAutoGenerateProxyClasses()); |
|
137 } |
|
138 |
|
139 /** |
|
140 * Gets the database connection object used by the EntityManager. |
|
141 * |
|
142 * @return Doctrine\DBAL\Connection |
|
143 */ |
|
144 public function getConnection() |
|
145 { |
|
146 return $this->conn; |
|
147 } |
|
148 |
|
149 /** |
|
150 * Gets the metadata factory used to gather the metadata of classes. |
|
151 * |
|
152 * @return Doctrine\ORM\Mapping\ClassMetadataFactory |
|
153 */ |
|
154 public function getMetadataFactory() |
|
155 { |
|
156 return $this->metadataFactory; |
|
157 } |
|
158 |
|
159 /** |
|
160 * Gets an ExpressionBuilder used for object-oriented construction of query expressions. |
|
161 * |
|
162 * Example: |
|
163 * |
|
164 * <code> |
|
165 * $qb = $em->createQueryBuilder(); |
|
166 * $expr = $em->getExpressionBuilder(); |
|
167 * $qb->select('u')->from('User', 'u') |
|
168 * ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2))); |
|
169 * </code> |
|
170 * |
|
171 * @return Doctrine\ORM\Query\Expr |
|
172 */ |
|
173 public function getExpressionBuilder() |
|
174 { |
|
175 if ($this->expressionBuilder === null) { |
|
176 $this->expressionBuilder = new Query\Expr; |
|
177 } |
|
178 return $this->expressionBuilder; |
|
179 } |
|
180 |
|
181 /** |
|
182 * Starts a transaction on the underlying database connection. |
|
183 * |
|
184 * @deprecated Use {@link getConnection}.beginTransaction(). |
|
185 */ |
|
186 public function beginTransaction() |
|
187 { |
|
188 $this->conn->beginTransaction(); |
|
189 } |
|
190 |
|
191 /** |
|
192 * Executes a function in a transaction. |
|
193 * |
|
194 * The function gets passed this EntityManager instance as an (optional) parameter. |
|
195 * |
|
196 * {@link flush} is invoked prior to transaction commit. |
|
197 * |
|
198 * If an exception occurs during execution of the function or flushing or transaction commit, |
|
199 * the transaction is rolled back, the EntityManager closed and the exception re-thrown. |
|
200 * |
|
201 * @param Closure $func The function to execute transactionally. |
|
202 */ |
|
203 public function transactional(Closure $func) |
|
204 { |
|
205 $this->conn->beginTransaction(); |
|
206 |
|
207 try { |
|
208 $return = $func($this); |
|
209 |
|
210 $this->flush(); |
|
211 $this->conn->commit(); |
|
212 |
|
213 return $return ?: true; |
|
214 } catch (Exception $e) { |
|
215 $this->close(); |
|
216 $this->conn->rollback(); |
|
217 |
|
218 throw $e; |
|
219 } |
|
220 } |
|
221 |
|
222 /** |
|
223 * Commits a transaction on the underlying database connection. |
|
224 * |
|
225 * @deprecated Use {@link getConnection}.commit(). |
|
226 */ |
|
227 public function commit() |
|
228 { |
|
229 $this->conn->commit(); |
|
230 } |
|
231 |
|
232 /** |
|
233 * Performs a rollback on the underlying database connection. |
|
234 * |
|
235 * @deprecated Use {@link getConnection}.rollback(). |
|
236 */ |
|
237 public function rollback() |
|
238 { |
|
239 $this->conn->rollback(); |
|
240 } |
|
241 |
|
242 /** |
|
243 * Returns the ORM metadata descriptor for a class. |
|
244 * |
|
245 * The class name must be the fully-qualified class name without a leading backslash |
|
246 * (as it is returned by get_class($obj)) or an aliased class name. |
|
247 * |
|
248 * Examples: |
|
249 * MyProject\Domain\User |
|
250 * sales:PriceRequest |
|
251 * |
|
252 * @return Doctrine\ORM\Mapping\ClassMetadata |
|
253 * @internal Performance-sensitive method. |
|
254 */ |
|
255 public function getClassMetadata($className) |
|
256 { |
|
257 return $this->metadataFactory->getMetadataFor($className); |
|
258 } |
|
259 |
|
260 /** |
|
261 * Creates a new Query object. |
|
262 * |
|
263 * @param string The DQL string. |
|
264 * @return Doctrine\ORM\Query |
|
265 */ |
|
266 public function createQuery($dql = "") |
|
267 { |
|
268 $query = new Query($this); |
|
269 if ( ! empty($dql)) { |
|
270 $query->setDql($dql); |
|
271 } |
|
272 return $query; |
|
273 } |
|
274 |
|
275 /** |
|
276 * Creates a Query from a named query. |
|
277 * |
|
278 * @param string $name |
|
279 * @return Doctrine\ORM\Query |
|
280 */ |
|
281 public function createNamedQuery($name) |
|
282 { |
|
283 return $this->createQuery($this->config->getNamedQuery($name)); |
|
284 } |
|
285 |
|
286 /** |
|
287 * Creates a native SQL query. |
|
288 * |
|
289 * @param string $sql |
|
290 * @param ResultSetMapping $rsm The ResultSetMapping to use. |
|
291 * @return NativeQuery |
|
292 */ |
|
293 public function createNativeQuery($sql, ResultSetMapping $rsm) |
|
294 { |
|
295 $query = new NativeQuery($this); |
|
296 $query->setSql($sql); |
|
297 $query->setResultSetMapping($rsm); |
|
298 return $query; |
|
299 } |
|
300 |
|
301 /** |
|
302 * Creates a NativeQuery from a named native query. |
|
303 * |
|
304 * @param string $name |
|
305 * @return Doctrine\ORM\NativeQuery |
|
306 */ |
|
307 public function createNamedNativeQuery($name) |
|
308 { |
|
309 list($sql, $rsm) = $this->config->getNamedNativeQuery($name); |
|
310 return $this->createNativeQuery($sql, $rsm); |
|
311 } |
|
312 |
|
313 /** |
|
314 * Create a QueryBuilder instance |
|
315 * |
|
316 * @return QueryBuilder $qb |
|
317 */ |
|
318 public function createQueryBuilder() |
|
319 { |
|
320 return new QueryBuilder($this); |
|
321 } |
|
322 |
|
323 /** |
|
324 * Flushes all changes to objects that have been queued up to now to the database. |
|
325 * This effectively synchronizes the in-memory state of managed objects with the |
|
326 * database. |
|
327 * |
|
328 * @throws Doctrine\ORM\OptimisticLockException If a version check on an entity that |
|
329 * makes use of optimistic locking fails. |
|
330 */ |
|
331 public function flush() |
|
332 { |
|
333 $this->errorIfClosed(); |
|
334 $this->unitOfWork->commit(); |
|
335 } |
|
336 |
|
337 /** |
|
338 * Finds an Entity by its identifier. |
|
339 * |
|
340 * This is just a convenient shortcut for getRepository($entityName)->find($id). |
|
341 * |
|
342 * @param string $entityName |
|
343 * @param mixed $identifier |
|
344 * @param int $lockMode |
|
345 * @param int $lockVersion |
|
346 * @return object |
|
347 */ |
|
348 public function find($entityName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null) |
|
349 { |
|
350 return $this->getRepository($entityName)->find($identifier, $lockMode, $lockVersion); |
|
351 } |
|
352 |
|
353 /** |
|
354 * Gets a reference to the entity identified by the given type and identifier |
|
355 * without actually loading it, if the entity is not yet loaded. |
|
356 * |
|
357 * @param string $entityName The name of the entity type. |
|
358 * @param mixed $identifier The entity identifier. |
|
359 * @return object The entity reference. |
|
360 */ |
|
361 public function getReference($entityName, $identifier) |
|
362 { |
|
363 $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); |
|
364 |
|
365 // Check identity map first, if its already in there just return it. |
|
366 if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) { |
|
367 return ($entity instanceof $class->name) ? $entity : null; |
|
368 } |
|
369 if ($class->subClasses) { |
|
370 $entity = $this->find($entityName, $identifier); |
|
371 } else { |
|
372 if ( ! is_array($identifier)) { |
|
373 $identifier = array($class->identifier[0] => $identifier); |
|
374 } |
|
375 $entity = $this->proxyFactory->getProxy($class->name, $identifier); |
|
376 $this->unitOfWork->registerManaged($entity, $identifier, array()); |
|
377 } |
|
378 |
|
379 return $entity; |
|
380 } |
|
381 |
|
382 /** |
|
383 * Gets a partial reference to the entity identified by the given type and identifier |
|
384 * without actually loading it, if the entity is not yet loaded. |
|
385 * |
|
386 * The returned reference may be a partial object if the entity is not yet loaded/managed. |
|
387 * If it is a partial object it will not initialize the rest of the entity state on access. |
|
388 * Thus you can only ever safely access the identifier of an entity obtained through |
|
389 * this method. |
|
390 * |
|
391 * The use-cases for partial references involve maintaining bidirectional associations |
|
392 * without loading one side of the association or to update an entity without loading it. |
|
393 * Note, however, that in the latter case the original (persistent) entity data will |
|
394 * never be visible to the application (especially not event listeners) as it will |
|
395 * never be loaded in the first place. |
|
396 * |
|
397 * @param string $entityName The name of the entity type. |
|
398 * @param mixed $identifier The entity identifier. |
|
399 * @return object The (partial) entity reference. |
|
400 */ |
|
401 public function getPartialReference($entityName, $identifier) |
|
402 { |
|
403 $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); |
|
404 |
|
405 // Check identity map first, if its already in there just return it. |
|
406 if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) { |
|
407 return ($entity instanceof $class->name) ? $entity : null; |
|
408 } |
|
409 if ( ! is_array($identifier)) { |
|
410 $identifier = array($class->identifier[0] => $identifier); |
|
411 } |
|
412 |
|
413 $entity = $class->newInstance(); |
|
414 $class->setIdentifierValues($entity, $identifier); |
|
415 $this->unitOfWork->registerManaged($entity, $identifier, array()); |
|
416 |
|
417 return $entity; |
|
418 } |
|
419 |
|
420 /** |
|
421 * Clears the EntityManager. All entities that are currently managed |
|
422 * by this EntityManager become detached. |
|
423 * |
|
424 * @param string $entityName |
|
425 */ |
|
426 public function clear($entityName = null) |
|
427 { |
|
428 if ($entityName === null) { |
|
429 $this->unitOfWork->clear(); |
|
430 } else { |
|
431 //TODO |
|
432 throw new ORMException("EntityManager#clear(\$entityName) not yet implemented."); |
|
433 } |
|
434 } |
|
435 |
|
436 /** |
|
437 * Closes the EntityManager. All entities that are currently managed |
|
438 * by this EntityManager become detached. The EntityManager may no longer |
|
439 * be used after it is closed. |
|
440 */ |
|
441 public function close() |
|
442 { |
|
443 $this->clear(); |
|
444 $this->closed = true; |
|
445 } |
|
446 |
|
447 /** |
|
448 * Tells the EntityManager to make an instance managed and persistent. |
|
449 * |
|
450 * The entity will be entered into the database at or before transaction |
|
451 * commit or as a result of the flush operation. |
|
452 * |
|
453 * NOTE: The persist operation always considers entities that are not yet known to |
|
454 * this EntityManager as NEW. Do not pass detached entities to the persist operation. |
|
455 * |
|
456 * @param object $object The instance to make managed and persistent. |
|
457 */ |
|
458 public function persist($entity) |
|
459 { |
|
460 if ( ! is_object($entity)) { |
|
461 throw new \InvalidArgumentException(gettype($entity)); |
|
462 } |
|
463 $this->errorIfClosed(); |
|
464 $this->unitOfWork->persist($entity); |
|
465 } |
|
466 |
|
467 /** |
|
468 * Removes an entity instance. |
|
469 * |
|
470 * A removed entity will be removed from the database at or before transaction commit |
|
471 * or as a result of the flush operation. |
|
472 * |
|
473 * @param object $entity The entity instance to remove. |
|
474 */ |
|
475 public function remove($entity) |
|
476 { |
|
477 if ( ! is_object($entity)) { |
|
478 throw new \InvalidArgumentException(gettype($entity)); |
|
479 } |
|
480 $this->errorIfClosed(); |
|
481 $this->unitOfWork->remove($entity); |
|
482 } |
|
483 |
|
484 /** |
|
485 * Refreshes the persistent state of an entity from the database, |
|
486 * overriding any local changes that have not yet been persisted. |
|
487 * |
|
488 * @param object $entity The entity to refresh. |
|
489 */ |
|
490 public function refresh($entity) |
|
491 { |
|
492 if ( ! is_object($entity)) { |
|
493 throw new \InvalidArgumentException(gettype($entity)); |
|
494 } |
|
495 $this->errorIfClosed(); |
|
496 $this->unitOfWork->refresh($entity); |
|
497 } |
|
498 |
|
499 /** |
|
500 * Detaches an entity from the EntityManager, causing a managed entity to |
|
501 * become detached. Unflushed changes made to the entity if any |
|
502 * (including removal of the entity), will not be synchronized to the database. |
|
503 * Entities which previously referenced the detached entity will continue to |
|
504 * reference it. |
|
505 * |
|
506 * @param object $entity The entity to detach. |
|
507 */ |
|
508 public function detach($entity) |
|
509 { |
|
510 if ( ! is_object($entity)) { |
|
511 throw new \InvalidArgumentException(gettype($entity)); |
|
512 } |
|
513 $this->unitOfWork->detach($entity); |
|
514 } |
|
515 |
|
516 /** |
|
517 * Merges the state of a detached entity into the persistence context |
|
518 * of this EntityManager and returns the managed copy of the entity. |
|
519 * The entity passed to merge will not become associated/managed with this EntityManager. |
|
520 * |
|
521 * @param object $entity The detached entity to merge into the persistence context. |
|
522 * @return object The managed copy of the entity. |
|
523 */ |
|
524 public function merge($entity) |
|
525 { |
|
526 if ( ! is_object($entity)) { |
|
527 throw new \InvalidArgumentException(gettype($entity)); |
|
528 } |
|
529 $this->errorIfClosed(); |
|
530 return $this->unitOfWork->merge($entity); |
|
531 } |
|
532 |
|
533 /** |
|
534 * Creates a copy of the given entity. Can create a shallow or a deep copy. |
|
535 * |
|
536 * @param object $entity The entity to copy. |
|
537 * @return object The new entity. |
|
538 * @todo Implementation need. This is necessary since $e2 = clone $e1; throws an E_FATAL when access anything on $e: |
|
539 * Fatal error: Maximum function nesting level of '100' reached, aborting! |
|
540 */ |
|
541 public function copy($entity, $deep = false) |
|
542 { |
|
543 throw new \BadMethodCallException("Not implemented."); |
|
544 } |
|
545 |
|
546 /** |
|
547 * Acquire a lock on the given entity. |
|
548 * |
|
549 * @param object $entity |
|
550 * @param int $lockMode |
|
551 * @param int $lockVersion |
|
552 * @throws OptimisticLockException |
|
553 * @throws PessimisticLockException |
|
554 */ |
|
555 public function lock($entity, $lockMode, $lockVersion = null) |
|
556 { |
|
557 $this->unitOfWork->lock($entity, $lockMode, $lockVersion); |
|
558 } |
|
559 |
|
560 /** |
|
561 * Gets the repository for an entity class. |
|
562 * |
|
563 * @param string $entityName The name of the entity. |
|
564 * @return EntityRepository The repository class. |
|
565 */ |
|
566 public function getRepository($entityName) |
|
567 { |
|
568 $entityName = ltrim($entityName, '\\'); |
|
569 if (isset($this->repositories[$entityName])) { |
|
570 return $this->repositories[$entityName]; |
|
571 } |
|
572 |
|
573 $metadata = $this->getClassMetadata($entityName); |
|
574 $customRepositoryClassName = $metadata->customRepositoryClassName; |
|
575 |
|
576 if ($customRepositoryClassName !== null) { |
|
577 $repository = new $customRepositoryClassName($this, $metadata); |
|
578 } else { |
|
579 $repository = new EntityRepository($this, $metadata); |
|
580 } |
|
581 |
|
582 $this->repositories[$entityName] = $repository; |
|
583 |
|
584 return $repository; |
|
585 } |
|
586 |
|
587 /** |
|
588 * Determines whether an entity instance is managed in this EntityManager. |
|
589 * |
|
590 * @param object $entity |
|
591 * @return boolean TRUE if this EntityManager currently manages the given entity, FALSE otherwise. |
|
592 */ |
|
593 public function contains($entity) |
|
594 { |
|
595 return $this->unitOfWork->isScheduledForInsert($entity) || |
|
596 $this->unitOfWork->isInIdentityMap($entity) && |
|
597 ! $this->unitOfWork->isScheduledForDelete($entity); |
|
598 } |
|
599 |
|
600 /** |
|
601 * Gets the EventManager used by the EntityManager. |
|
602 * |
|
603 * @return Doctrine\Common\EventManager |
|
604 */ |
|
605 public function getEventManager() |
|
606 { |
|
607 return $this->eventManager; |
|
608 } |
|
609 |
|
610 /** |
|
611 * Gets the Configuration used by the EntityManager. |
|
612 * |
|
613 * @return Doctrine\ORM\Configuration |
|
614 */ |
|
615 public function getConfiguration() |
|
616 { |
|
617 return $this->config; |
|
618 } |
|
619 |
|
620 /** |
|
621 * Throws an exception if the EntityManager is closed or currently not active. |
|
622 * |
|
623 * @throws ORMException If the EntityManager is closed. |
|
624 */ |
|
625 private function errorIfClosed() |
|
626 { |
|
627 if ($this->closed) { |
|
628 throw ORMException::entityManagerClosed(); |
|
629 } |
|
630 } |
|
631 |
|
632 /** |
|
633 * Check if the Entity manager is open or closed. |
|
634 * |
|
635 * @return bool |
|
636 */ |
|
637 public function isOpen() |
|
638 { |
|
639 return (!$this->closed); |
|
640 } |
|
641 |
|
642 /** |
|
643 * Gets the UnitOfWork used by the EntityManager to coordinate operations. |
|
644 * |
|
645 * @return Doctrine\ORM\UnitOfWork |
|
646 */ |
|
647 public function getUnitOfWork() |
|
648 { |
|
649 return $this->unitOfWork; |
|
650 } |
|
651 |
|
652 /** |
|
653 * Gets a hydrator for the given hydration mode. |
|
654 * |
|
655 * This method caches the hydrator instances which is used for all queries that don't |
|
656 * selectively iterate over the result. |
|
657 * |
|
658 * @param int $hydrationMode |
|
659 * @return Doctrine\ORM\Internal\Hydration\AbstractHydrator |
|
660 */ |
|
661 public function getHydrator($hydrationMode) |
|
662 { |
|
663 if ( ! isset($this->hydrators[$hydrationMode])) { |
|
664 $this->hydrators[$hydrationMode] = $this->newHydrator($hydrationMode); |
|
665 } |
|
666 |
|
667 return $this->hydrators[$hydrationMode]; |
|
668 } |
|
669 |
|
670 /** |
|
671 * Create a new instance for the given hydration mode. |
|
672 * |
|
673 * @param int $hydrationMode |
|
674 * @return Doctrine\ORM\Internal\Hydration\AbstractHydrator |
|
675 */ |
|
676 public function newHydrator($hydrationMode) |
|
677 { |
|
678 switch ($hydrationMode) { |
|
679 case Query::HYDRATE_OBJECT: |
|
680 $hydrator = new Internal\Hydration\ObjectHydrator($this); |
|
681 break; |
|
682 case Query::HYDRATE_ARRAY: |
|
683 $hydrator = new Internal\Hydration\ArrayHydrator($this); |
|
684 break; |
|
685 case Query::HYDRATE_SCALAR: |
|
686 $hydrator = new Internal\Hydration\ScalarHydrator($this); |
|
687 break; |
|
688 case Query::HYDRATE_SINGLE_SCALAR: |
|
689 $hydrator = new Internal\Hydration\SingleScalarHydrator($this); |
|
690 break; |
|
691 case Query::HYDRATE_SIMPLEOBJECT: |
|
692 $hydrator = new Internal\Hydration\SimpleObjectHydrator($this); |
|
693 break; |
|
694 default: |
|
695 if ($class = $this->config->getCustomHydrationMode($hydrationMode)) { |
|
696 $hydrator = new $class($this); |
|
697 break; |
|
698 } |
|
699 throw ORMException::invalidHydrationMode($hydrationMode); |
|
700 } |
|
701 |
|
702 return $hydrator; |
|
703 } |
|
704 |
|
705 /** |
|
706 * Gets the proxy factory used by the EntityManager to create entity proxies. |
|
707 * |
|
708 * @return ProxyFactory |
|
709 */ |
|
710 public function getProxyFactory() |
|
711 { |
|
712 return $this->proxyFactory; |
|
713 } |
|
714 |
|
715 /** |
|
716 * Factory method to create EntityManager instances. |
|
717 * |
|
718 * @param mixed $conn An array with the connection parameters or an existing |
|
719 * Connection instance. |
|
720 * @param Configuration $config The Configuration instance to use. |
|
721 * @param EventManager $eventManager The EventManager instance to use. |
|
722 * @return EntityManager The created EntityManager. |
|
723 */ |
|
724 public static function create($conn, Configuration $config, EventManager $eventManager = null) |
|
725 { |
|
726 if (!$config->getMetadataDriverImpl()) { |
|
727 throw ORMException::missingMappingDriverImpl(); |
|
728 } |
|
729 |
|
730 if (is_array($conn)) { |
|
731 $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ?: new EventManager())); |
|
732 } else if ($conn instanceof Connection) { |
|
733 if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { |
|
734 throw ORMException::mismatchedEventManager(); |
|
735 } |
|
736 } else { |
|
737 throw new \InvalidArgumentException("Invalid argument: " . $conn); |
|
738 } |
|
739 |
|
740 return new EntityManager($conn, $config, $conn->getEventManager()); |
|
741 } |
|
742 } |