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

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