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

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.     public function find($className$id$lockMode null$lockVersion null)
  346.     {
  347.         $class $this->metadataFactory->getMetadataFor(ltrim($className'\\'));
  348.         if ($lockMode !== null) {
  349.             $this->checkLockRequirements($lockMode$class);
  350.         }
  351.         if ( ! is_array($id)) {
  352.             if ($class->isIdentifierComposite) {
  353.                 throw ORMInvalidArgumentException::invalidCompositeIdentifier();
  354.             }
  355.             $id = [$class->identifier[0] => $id];
  356.         }
  357.         foreach ($id as $i => $value) {
  358.             if (is_object($value) && $this->metadataFactory->hasMetadataFor(ClassUtils::getClass($value))) {
  359.                 $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
  360.                 if ($id[$i] === null) {
  361.                     throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
  362.                 }
  363.             }
  364.         }
  365.         $sortedId = [];
  366.         foreach ($class->identifier as $identifier) {
  367.             if ( ! isset($id[$identifier])) {
  368.                 throw ORMException::missingIdentifierField($class->name$identifier);
  369.             }
  370.             $sortedId[$identifier] = $id[$identifier];
  371.             unset($id[$identifier]);
  372.         }
  373.         if ($id) {
  374.             throw ORMException::unrecognizedIdentifierFields($class->namearray_keys($id));
  375.         }
  376.         $unitOfWork $this->getUnitOfWork();
  377.         // Check identity map first
  378.         if (($entity $unitOfWork->tryGetById($sortedId$class->rootEntityName)) !== false) {
  379.             if ( ! ($entity instanceof $class->name)) {
  380.                 return null;
  381.             }
  382.             switch (true) {
  383.                 case LockMode::OPTIMISTIC === $lockMode:
  384.                     $this->lock($entity$lockMode$lockVersion);
  385.                     break;
  386.                 case LockMode::NONE === $lockMode:
  387.                 case LockMode::PESSIMISTIC_READ === $lockMode:
  388.                 case LockMode::PESSIMISTIC_WRITE === $lockMode:
  389.                     $persister $unitOfWork->getEntityPersister($class->name);
  390.                     $persister->refresh($sortedId$entity$lockMode);
  391.                     break;
  392.             }
  393.             return $entity// Hit!
  394.         }
  395.         $persister $unitOfWork->getEntityPersister($class->name);
  396.         switch (true) {
  397.             case LockMode::OPTIMISTIC === $lockMode:
  398.                 $entity $persister->load($sortedId);
  399.                 $unitOfWork->lock($entity$lockMode$lockVersion);
  400.                 return $entity;
  401.             case LockMode::PESSIMISTIC_READ === $lockMode:
  402.             case LockMode::PESSIMISTIC_WRITE === $lockMode:
  403.                 return $persister->load($sortedIdnullnull, [], $lockMode);
  404.             default:
  405.                 return $persister->loadById($sortedId);
  406.         }
  407.     }
  408.     /**
  409.      * {@inheritDoc}
  410.      */
  411.     public function getReference($entityName$id)
  412.     {
  413.         $class $this->metadataFactory->getMetadataFor(ltrim($entityName'\\'));
  414.         if ( ! is_array($id)) {
  415.             $id = [$class->identifier[0] => $id];
  416.         }
  417.         $sortedId = [];
  418.         foreach ($class->identifier as $identifier) {
  419.             if ( ! isset($id[$identifier])) {
  420.                 throw ORMException::missingIdentifierField($class->name$identifier);
  421.             }
  422.             $sortedId[$identifier] = $id[$identifier];
  423.             unset($id[$identifier]);
  424.         }
  425.         if ($id) {
  426.             throw ORMException::unrecognizedIdentifierFields($class->namearray_keys($id));
  427.         }
  428.         // Check identity map first, if its already in there just return it.
  429.         if (($entity $this->unitOfWork->tryGetById($sortedId$class->rootEntityName)) !== false) {
  430.             return ($entity instanceof $class->name) ? $entity null;
  431.         }
  432.         if ($class->subClasses) {
  433.             return $this->find($entityName$sortedId);
  434.         }
  435.         $entity $this->proxyFactory->getProxy($class->name$sortedId);
  436.         $this->unitOfWork->registerManaged($entity$sortedId, []);
  437.         return $entity;
  438.     }
  439.     /**
  440.      * {@inheritDoc}
  441.      */
  442.     public function getPartialReference($entityName$identifier)
  443.     {
  444.         $class $this->metadataFactory->getMetadataFor(ltrim($entityName'\\'));
  445.         // Check identity map first, if its already in there just return it.
  446.         if (($entity $this->unitOfWork->tryGetById($identifier$class->rootEntityName)) !== false) {
  447.             return ($entity instanceof $class->name) ? $entity null;
  448.         }
  449.         if ( ! is_array($identifier)) {
  450.             $identifier = [$class->identifier[0] => $identifier];
  451.         }
  452.         $entity $class->newInstance();
  453.         $class->setIdentifierValues($entity$identifier);
  454.         $this->unitOfWork->registerManaged($entity$identifier, []);
  455.         $this->unitOfWork->markReadOnly($entity);
  456.         return $entity;
  457.     }
  458.     /**
  459.      * Clears the EntityManager. All entities that are currently managed
  460.      * by this EntityManager become detached.
  461.      *
  462.      * @param string|null $entityName if given, only entities of this type will get detached
  463.      *
  464.      * @return void
  465.      *
  466.      * @throws ORMInvalidArgumentException If a non-null non-string value is given.
  467.      * @throws MappingException            If a $entityName is given, but that entity is not
  468.      *                                     found in the mappings.
  469.      */
  470.     public function clear($entityName null)
  471.     {
  472.         if (null !== $entityName && ! is_string($entityName)) {
  473.             throw ORMInvalidArgumentException::invalidEntityName($entityName);
  474.         }
  475.         if ($entityName !== null) {
  476.             @trigger_error(
  477.                 'Calling ' __METHOD__ '() with any arguments to clear specific entities is deprecated and will not be supported in Doctrine ORM 3.0.',
  478.                 E_USER_DEPRECATED
  479.             );
  480.         }
  481.         $this->unitOfWork->clear(
  482.             null === $entityName
  483.                 null
  484.                 $this->metadataFactory->getMetadataFor($entityName)->getName()
  485.         );
  486.     }
  487.     /**
  488.      * {@inheritDoc}
  489.      */
  490.     public function close()
  491.     {
  492.         $this->clear();
  493.         $this->closed true;
  494.     }
  495.     /**
  496.      * Tells the EntityManager to make an instance managed and persistent.
  497.      *
  498.      * The entity will be entered into the database at or before transaction
  499.      * commit or as a result of the flush operation.
  500.      *
  501.      * NOTE: The persist operation always considers entities that are not yet known to
  502.      * this EntityManager as NEW. Do not pass detached entities to the persist operation.
  503.      *
  504.      * @param object $entity The instance to make managed and persistent.
  505.      *
  506.      * @return void
  507.      *
  508.      * @throws ORMInvalidArgumentException
  509.      * @throws ORMException
  510.      */
  511.     public function persist($entity)
  512.     {
  513.         if ( ! is_object($entity)) {
  514.             throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()'$entity);
  515.         }
  516.         $this->errorIfClosed();
  517.         $this->unitOfWork->persist($entity);
  518.     }
  519.     /**
  520.      * Removes an entity instance.
  521.      *
  522.      * A removed entity will be removed from the database at or before transaction commit
  523.      * or as a result of the flush operation.
  524.      *
  525.      * @param object $entity The entity instance to remove.
  526.      *
  527.      * @return void
  528.      *
  529.      * @throws ORMInvalidArgumentException
  530.      * @throws ORMException
  531.      */
  532.     public function remove($entity)
  533.     {
  534.         if ( ! is_object($entity)) {
  535.             throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()'$entity);
  536.         }
  537.         $this->errorIfClosed();
  538.         $this->unitOfWork->remove($entity);
  539.     }
  540.     /**
  541.      * Refreshes the persistent state of an entity from the database,
  542.      * overriding any local changes that have not yet been persisted.
  543.      *
  544.      * @param object $entity The entity to refresh.
  545.      *
  546.      * @return void
  547.      *
  548.      * @throws ORMInvalidArgumentException
  549.      * @throws ORMException
  550.      */
  551.     public function refresh($entity)
  552.     {
  553.         if ( ! is_object($entity)) {
  554.             throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()'$entity);
  555.         }
  556.         $this->errorIfClosed();
  557.         $this->unitOfWork->refresh($entity);
  558.     }
  559.     /**
  560.      * Detaches an entity from the EntityManager, causing a managed entity to
  561.      * become detached.  Unflushed changes made to the entity if any
  562.      * (including removal of the entity), will not be synchronized to the database.
  563.      * Entities which previously referenced the detached entity will continue to
  564.      * reference it.
  565.      *
  566.      * @param object $entity The entity to detach.
  567.      *
  568.      * @return void
  569.      *
  570.      * @throws ORMInvalidArgumentException
  571.      *
  572.      * @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
  573.      */
  574.     public function detach($entity)
  575.     {
  576.         @trigger_error('Method ' __METHOD__ '() is deprecated and will be removed in Doctrine ORM 3.0.'E_USER_DEPRECATED);
  577.         if ( ! is_object($entity)) {
  578.             throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()'$entity);
  579.         }
  580.         $this->unitOfWork->detach($entity);
  581.     }
  582.     /**
  583.      * Merges the state of a detached entity into the persistence context
  584.      * of this EntityManager and returns the managed copy of the entity.
  585.      * The entity passed to merge will not become associated/managed with this EntityManager.
  586.      *
  587.      * @param object $entity The detached entity to merge into the persistence context.
  588.      *
  589.      * @return object The managed copy of the entity.
  590.      *
  591.      * @throws ORMInvalidArgumentException
  592.      * @throws ORMException
  593.      *
  594.      * @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
  595.      */
  596.     public function merge($entity)
  597.     {
  598.         @trigger_error('Method ' __METHOD__ '() is deprecated and will be removed in Doctrine ORM 3.0.'E_USER_DEPRECATED);
  599.         if ( ! is_object($entity)) {
  600.             throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()'$entity);
  601.         }
  602.         $this->errorIfClosed();
  603.         return $this->unitOfWork->merge($entity);
  604.     }
  605.     /**
  606.      * {@inheritDoc}
  607.      */
  608.     public function copy($entity$deep false)
  609.     {
  610.         @trigger_error('Method ' __METHOD__ '() is deprecated and will be removed in Doctrine ORM 3.0.'E_USER_DEPRECATED);
  611.         throw new \BadMethodCallException("Not implemented.");
  612.     }
  613.     /**
  614.      * {@inheritDoc}
  615.      */
  616.     public function lock($entity$lockMode$lockVersion null)
  617.     {
  618.         $this->unitOfWork->lock($entity$lockMode$lockVersion);
  619.     }
  620.     /**
  621.      * Gets the repository for an entity class.
  622.      *
  623.      * @param string $entityName The name of the entity.
  624.      *
  625.      * @return ObjectRepository|EntityRepository The repository class.
  626.      */
  627.     public function getRepository($entityName)
  628.     {
  629.         return $this->repositoryFactory->getRepository($this$entityName);
  630.     }
  631.     /**
  632.      * Determines whether an entity instance is managed in this EntityManager.
  633.      *
  634.      * @param object $entity
  635.      *
  636.      * @return boolean TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
  637.      */
  638.     public function contains($entity)
  639.     {
  640.         return $this->unitOfWork->isScheduledForInsert($entity)
  641.             || $this->unitOfWork->isInIdentityMap($entity)
  642.             && ! $this->unitOfWork->isScheduledForDelete($entity);
  643.     }
  644.     /**
  645.      * {@inheritDoc}
  646.      */
  647.     public function getEventManager()
  648.     {
  649.         return $this->eventManager;
  650.     }
  651.     /**
  652.      * {@inheritDoc}
  653.      */
  654.     public function getConfiguration()
  655.     {
  656.         return $this->config;
  657.     }
  658.     /**
  659.      * Throws an exception if the EntityManager is closed or currently not active.
  660.      *
  661.      * @return void
  662.      *
  663.      * @throws ORMException If the EntityManager is closed.
  664.      */
  665.     private function errorIfClosed()
  666.     {
  667.         if ($this->closed) {
  668.             throw ORMException::entityManagerClosed();
  669.         }
  670.     }
  671.     /**
  672.      * {@inheritDoc}
  673.      */
  674.     public function isOpen()
  675.     {
  676.         return (!$this->closed);
  677.     }
  678.     /**
  679.      * {@inheritDoc}
  680.      */
  681.     public function getUnitOfWork()
  682.     {
  683.         return $this->unitOfWork;
  684.     }
  685.     /**
  686.      * {@inheritDoc}
  687.      */
  688.     public function getHydrator($hydrationMode)
  689.     {
  690.         return $this->newHydrator($hydrationMode);
  691.     }
  692.     /**
  693.      * {@inheritDoc}
  694.      */
  695.     public function newHydrator($hydrationMode)
  696.     {
  697.         switch ($hydrationMode) {
  698.             case Query::HYDRATE_OBJECT:
  699.                 return new Internal\Hydration\ObjectHydrator($this);
  700.             case Query::HYDRATE_ARRAY:
  701.                 return new Internal\Hydration\ArrayHydrator($this);
  702.             case Query::HYDRATE_SCALAR:
  703.                 return new Internal\Hydration\ScalarHydrator($this);
  704.             case Query::HYDRATE_SINGLE_SCALAR:
  705.                 return new Internal\Hydration\SingleScalarHydrator($this);
  706.             case Query::HYDRATE_SIMPLEOBJECT:
  707.                 return new Internal\Hydration\SimpleObjectHydrator($this);
  708.             default:
  709.                 if (($class $this->config->getCustomHydrationMode($hydrationMode)) !== null) {
  710.                     return new $class($this);
  711.                 }
  712.         }
  713.         throw ORMException::invalidHydrationMode($hydrationMode);
  714.     }
  715.     /**
  716.      * {@inheritDoc}
  717.      */
  718.     public function getProxyFactory()
  719.     {
  720.         return $this->proxyFactory;
  721.     }
  722.     /**
  723.      * {@inheritDoc}
  724.      */
  725.     public function initializeObject($obj)
  726.     {
  727.         $this->unitOfWork->initializeObject($obj);
  728.     }
  729.     /**
  730.      * Factory method to create EntityManager instances.
  731.      *
  732.      * @param array|Connection $connection   An array with the connection parameters or an existing Connection instance.
  733.      * @param Configuration    $config       The Configuration instance to use.
  734.      * @param EventManager     $eventManager The EventManager instance to use.
  735.      *
  736.      * @return EntityManager The created EntityManager.
  737.      *
  738.      * @throws \InvalidArgumentException
  739.      * @throws ORMException
  740.      */
  741.     public static function create($connectionConfiguration $configEventManager $eventManager null)
  742.     {
  743.         if ( ! $config->getMetadataDriverImpl()) {
  744.             throw ORMException::missingMappingDriverImpl();
  745.         }
  746.         $connection = static::createConnection($connection$config$eventManager);
  747.         return new EntityManager($connection$config$connection->getEventManager());
  748.     }
  749.     /**
  750.      * Factory method to create Connection instances.
  751.      *
  752.      * @param array|Connection $connection   An array with the connection parameters or an existing Connection instance.
  753.      * @param Configuration    $config       The Configuration instance to use.
  754.      * @param EventManager     $eventManager The EventManager instance to use.
  755.      *
  756.      * @return Connection
  757.      *
  758.      * @throws \InvalidArgumentException
  759.      * @throws ORMException
  760.      */
  761.     protected static function createConnection($connectionConfiguration $configEventManager $eventManager null)
  762.     {
  763.         if (is_array($connection)) {
  764.             return DriverManager::getConnection($connection$config$eventManager ?: new EventManager());
  765.         }
  766.         if ( ! $connection instanceof Connection) {
  767.             throw new \InvalidArgumentException(
  768.                 sprintf(
  769.                     'Invalid $connection argument of type %s given%s.',
  770.                     is_object($connection) ? get_class($connection) : gettype($connection),
  771.                     is_object($connection) ? '' ': "' $connection '"'
  772.                 )
  773.             );
  774.         }
  775.         if ($eventManager !== null && $connection->getEventManager() !== $eventManager) {
  776.             throw ORMException::mismatchedEventManager();
  777.         }
  778.         return $connection;
  779.     }
  780.     /**
  781.      * {@inheritDoc}
  782.      */
  783.     public function getFilters()
  784.     {
  785.         if (null === $this->filterCollection) {
  786.             $this->filterCollection = new FilterCollection($this);
  787.         }
  788.         return $this->filterCollection;
  789.     }
  790.     /**
  791.      * {@inheritDoc}
  792.      */
  793.     public function isFiltersStateClean()
  794.     {
  795.         return null === $this->filterCollection || $this->filterCollection->isClean();
  796.     }
  797.     /**
  798.      * {@inheritDoc}
  799.      */
  800.     public function hasFilters()
  801.     {
  802.         return null !== $this->filterCollection;
  803.     }
  804.     /**
  805.      * @param int $lockMode
  806.      * @param ClassMetadata $class
  807.      * @throws OptimisticLockException
  808.      * @throws TransactionRequiredException
  809.      */
  810.     private function checkLockRequirements(int $lockModeClassMetadata $class): void
  811.     {
  812.         switch ($lockMode) {
  813.             case LockMode::OPTIMISTIC:
  814.                 if (!$class->isVersioned) {
  815.                     throw OptimisticLockException::notVersioned($class->name);
  816.                 }
  817.                 break;
  818.             case LockMode::PESSIMISTIC_READ:
  819.             case LockMode::PESSIMISTIC_WRITE:
  820.                 if (!$this->getConnection()->isTransactionActive()) {
  821.                     throw TransactionRequiredException::transactionRequired();
  822.                 }
  823.         }
  824.     }
  825. }