diff --git a/application/Espo/ORM/Repository/RDBRepository.php b/application/Espo/ORM/Repository/RDBRepository.php index 42c59be376..3b2c5472e4 100644 --- a/application/Espo/ORM/Repository/RDBRepository.php +++ b/application/Espo/ORM/Repository/RDBRepository.php @@ -50,6 +50,8 @@ class RDBRepository extends Repository protected $hookMediator; + protected $transactionManager; + public function __construct( string $entityType, EntityManager $entityManager, EntityFactory $entityFactory, ?HookMediator $hookMediator = null ) { @@ -62,6 +64,8 @@ class RDBRepository extends Repository $this->seed = $this->entityFactory->create($entityType); $this->hookMediator = $hookMediator ?? (new EmptyHookMediator()); + + $this->transactionManager = new RDBTransactionManager($entityManager->getTransactionManager()); } protected function getMapper() : Mapper @@ -639,8 +643,6 @@ class RDBRepository extends Repository $builder = new RDBSelectBuilder($this->entityManager, $this->entityType, $query); return $builder; - - //return $builder->clone($query); } /** diff --git a/application/Espo/ORM/Repository/RDBTransactionManager.php b/application/Espo/ORM/Repository/RDBTransactionManager.php new file mode 100644 index 0000000000..fc9cd2dd7c --- /dev/null +++ b/application/Espo/ORM/Repository/RDBTransactionManager.php @@ -0,0 +1,93 @@ +transactionManager = $transactionManager; + } + + public function isStarted() : bool + { + return $this->level > 0; + } + + public function start() + { + if ($this->isStarted()) { + throw new RuntimeException("Can't start a transaction more than once."); + } + + $this->transactionManager->start(); + + $this->level = $this->transactionManager->getLevel(); + } + + public function commit() + { + if (!$this->isStarted()) { + throw new RuntimeException("Can't commit not started transaction."); + } + + while ($this->transactionManager->getLevel() >= $this->level) { + $this->transactionManager->commit(); + } + + $this->level = 0; + } + + public function rollback() + { + if (!$this->isStarted()) { + throw new RuntimeException("Can't rollback not started transaction."); + } + + while ($this->transactionManager->getLevel() >= $this->level) { + $this->transactionManager->rollback(); + } + + $this->level = 0; + } +} diff --git a/tests/unit/Espo/ORM/Repository/RDBTransactionManagerTest.php b/tests/unit/Espo/ORM/Repository/RDBTransactionManagerTest.php new file mode 100644 index 0000000000..e44b629182 --- /dev/null +++ b/tests/unit/Espo/ORM/Repository/RDBTransactionManagerTest.php @@ -0,0 +1,113 @@ +wrappee = $this->getMockBuilder(TransactionManager::class)->disableOriginalConstructor()->getMock(); + + $this->manager = new RDBTransactionManager($this->wrappee); + } + + + public function testStartOnce() + { + + $this->wrappee + ->expects($this->once()) + ->method('start'); + + $this->manager->start(); + } + + public function testException() + { + $this->wrappee + ->expects($this->once()) + ->method('start'); + + $this->wrappee + ->expects($this->once()) + ->method('getLevel') + ->will($this->returnValue(1)); + + $this->expectException(RuntimeException::class); + + $this->manager->start(); + + $this->manager->start(); + } + + public function testCommit() + { + $this->wrappee + ->expects($this->at(0)) + ->method('start'); + + $this->wrappee + ->expects($this->at(1)) + ->method('getLevel') + ->will($this->returnValue(1)); + + $this->wrappee + ->expects($this->at(2)) + ->method('getLevel') + ->will($this->returnValue(2)); + + $this->wrappee + ->expects($this->at(3)) + ->method('commit'); + + $this->wrappee + ->expects($this->at(4)) + ->method('getLevel') + ->will($this->returnValue(1)); + + $this->wrappee + ->expects($this->at(5)) + ->method('commit'); + + + $this->manager->start(); + + $this->manager->commit(); + } +}