vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php line 431

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