/** * Acquire a lock on the given entity. * * @param object $entity * @param int $lockMode * @param int $lockVersion * * @throws ORMInvalidArgumentException * @throws TransactionRequiredException * @throws OptimisticLockException * * @return void */ public function lock($entity, $lockMode, $lockVersion = null) { if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) { throw ORMInvalidArgumentException::entityNotManaged($entity); } $class = $this->em->getClassMetadata(get_class($entity)); switch ($lockMode) { case \Doctrine\DBAL\LockMode::OPTIMISTIC: if (!$class->isVersioned) { throw OptimisticLockException::notVersioned($class->name); } if ($lockVersion === null) { return; } $entityVersion = $class->reflFields[$class->versionField]->getValue($entity); if ($entityVersion != $lockVersion) { throw OptimisticLockException::lockFailedVersionMissmatch($entity, $lockVersion, $entityVersion); } break; case \Doctrine\DBAL\LockMode::PESSIMISTIC_READ: case \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE: if (!$this->em->getConnection()->isTransactionActive()) { throw TransactionRequiredException::transactionRequired(); } $oid = spl_object_hash($entity); $this->getEntityPersister($class->name)->lock(array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), $lockMode); break; default: // Do nothing } }
/** * Acquire a lock on the given entity. * * @param object $entity * @param int $lockMode * @param int $lockVersion */ public function lock($entity, $lockMode, $lockVersion = null) { if ($this->getEntityState($entity) != self::STATE_MANAGED) { throw new InvalidArgumentException("Entity is not MANAGED."); } $entityName = get_class($entity); $class = $this->em->getClassMetadata($entityName); if ($lockMode == \Doctrine\DBAL\LockMode::OPTIMISTIC) { if (!$class->isVersioned) { throw OptimisticLockException::notVersioned($entityName); } if ($lockVersion != null) { $entityVersion = $class->reflFields[$class->versionField]->getValue($entity); if ($entityVersion != $lockVersion) { throw OptimisticLockException::lockFailedVersionMissmatch($entity, $lockVersion, $entityVersion); } } } else { if (in_array($lockMode, array(\Doctrine\DBAL\LockMode::PESSIMISTIC_READ, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE))) { if (!$this->em->getConnection()->isTransactionActive()) { throw TransactionRequiredException::transactionRequired(); } $oid = spl_object_hash($entity); $this->getEntityPersister($class->name)->lock(array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), $lockMode); } } }
/** * Acquires an optimistic lock within a pessimistic lock transaction. For * use in fail-fast scenarios; guaranteed to throw an exception on * concurrent modification attempts. The one to first acquire the write lock * will update the version field, leading subsequent acquisitions of the * optimistic lock to fail. * * FIXME: Only works on entities implementing VersionLockable and does not * work in conjunction with the Doctrine @Version column. * * @param int $id * @param mixed $lockVersion * @param callback($entity, Doctrine\ORM\EntityManager, Repository) $callback * @return mixed callback return type * @throws OptimisticLockException */ public function useWithPessimisticVersionLock($id, $lockVersion, $callback) { return $this->useWithPessimisticWriteLock($id, function (VersionLockable $entity, EntityManager $em, $self) use($lockVersion, $callback) { if ($entity->getVersion() !== $lockVersion) { // FIXME: This isn't the appropriate exception type. throw OptimisticLockException::lockFailedVersionMissmatch($entity, $lockVersion, $entity->getVersion()); } $entity->incrementVersion(); return $callback($entity, $em, $self); }); }