From 3418aac4664310251c0eb953064adadcdc245467 Mon Sep 17 00:00:00 2001 From: Soliman Date: Tue, 19 Nov 2019 15:29:05 +0100 Subject: [PATCH] Throw OptimisticLockException when connection::commit() returns false --- .scrutinizer.yml | 2 +- .travis.yml | 11 ----- composer.json | 4 +- composer.lock | 48 +++++++++++-------- lib/Doctrine/ORM/UnitOfWork.php | 12 ++++- .../Tests/Mocks/ConnectionCommitFailMock.php | 22 +++++++++ tests/Doctrine/Tests/ORM/UnitOfWorkTest.php | 30 +++++++++++- 7 files changed, 93 insertions(+), 36 deletions(-) create mode 100644 tests/Doctrine/Tests/Mocks/ConnectionCommitFailMock.php diff --git a/.scrutinizer.yml b/.scrutinizer.yml index d05c72cf06..58a0ae9c96 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -3,7 +3,7 @@ build: analysis: environment: php: - version: 7.1 + version: 7.2 cache: disabled: false directories: diff --git a/.travis.yml b/.travis.yml index 9a40fe7d22..f314758d33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ sudo: false language: php php: - - 7.1 - 7.2 - 7.3 - 7.4snapshot @@ -32,16 +31,6 @@ jobs: addons: mariadb: 10.1 - - stage: Test - dist: xenial - env: DB=mysql MYSQL_VERSION=5.7 - php: 7.1 - services: - - mysql - before_script: - - ./tests/travis/install-mysql-$MYSQL_VERSION.sh - sudo: required - - stage: Test dist: xenial env: DB=mysql MYSQL_VERSION=5.7 diff --git a/composer.json b/composer.json index c74e9cff64..dc5c698543 100644 --- a/composer.json +++ b/composer.json @@ -16,13 +16,13 @@ "sort-packages": true }, "require": { - "php": "^7.1", + "php": "^7.2", "ext-pdo": "*", "doctrine/annotations": "^1.8", "doctrine/cache": "^1.9.1", "doctrine/collections": "^1.5", "doctrine/common": "^2.11", - "doctrine/dbal": "^2.9.3", + "doctrine/dbal": "^2.10.0", "doctrine/event-manager": "^1.1", "doctrine/instantiator": "^1.3", "doctrine/persistence": "^1.2", diff --git a/composer.lock b/composer.lock index fc220d2356..506dd61087 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4e24e01f599825550170acce0dda0b49", + "content-hash": "8a38d5db0a7129c5e93e7bda94f7f598", "packages": [ { "name": "doctrine/annotations", @@ -309,31 +309,30 @@ }, { "name": "doctrine/dbal", - "version": "v2.9.3", + "version": "v2.10.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "7345cd59edfa2036eb0fa4264b77ae2576842035" + "reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/7345cd59edfa2036eb0fa4264b77ae2576842035", - "reference": "7345cd59edfa2036eb0fa4264b77ae2576842035", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/0c9a646775ef549eb0a213a4f9bd4381d9b4d934", + "reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934", "shasum": "" }, "require": { "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.1" + "php": "^7.2" }, "require-dev": { - "doctrine/coding-standard": "^5.0", - "jetbrains/phpstorm-stubs": "^2018.1.2", - "phpstan/phpstan": "^0.10.1", - "phpunit/phpunit": "^7.4", - "symfony/console": "^2.0.5|^3.0|^4.0", - "symfony/phpunit-bridge": "^3.4.5|^4.0.5" + "doctrine/coding-standard": "^6.0", + "jetbrains/phpstorm-stubs": "^2019.1", + "phpstan/phpstan": "^0.11.3", + "phpunit/phpunit": "^8.4.1", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -344,7 +343,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.9.x-dev", + "dev-master": "2.10.x-dev", "dev-develop": "3.0.x-dev" } }, @@ -380,14 +379,25 @@ "keywords": [ "abstraction", "database", + "db2", "dbal", + "mariadb", + "mssql", "mysql", - "persistence", + "oci8", + "oracle", + "pdo", "pgsql", - "php", - "queryobject" - ], - "time": "2019-11-02T22:19:34+00:00" + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlanywhere", + "sqlite", + "sqlserver", + "sqlsrv" + ], + "time": "2019-11-03T16:50:43+00:00" }, { "name": "doctrine/event-manager", @@ -2737,7 +2747,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.1", + "php": "^7.2", "ext-pdo": "*" }, "platform-dev": [] diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index f7b32b3809..f28b612754 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -424,10 +424,18 @@ public function commit($entity = null) } } - $conn->commit(); + // Commit failed silently + if ( ! $conn->commit()) { + $object = is_object($entity) ? $entity : null; + + throw new OptimisticLockException('Commit failed', $object); + } } catch (Throwable $e) { $this->em->close(); - $conn->rollBack(); + + if ($conn->isTransactionActive()) { + $conn->rollBack(); + } $this->afterTransactionRolledBack(); diff --git a/tests/Doctrine/Tests/Mocks/ConnectionCommitFailMock.php b/tests/Doctrine/Tests/Mocks/ConnectionCommitFailMock.php new file mode 100644 index 0000000000..c31b50bf4f --- /dev/null +++ b/tests/Doctrine/Tests/Mocks/ConnectionCommitFailMock.php @@ -0,0 +1,22 @@ +name = 'Jasper'; + $user->username = 'Jasper'; $this->_unitOfWork->persist($user); $this->_unitOfWork->commit(); @@ -789,6 +791,32 @@ public function testPreviousDetectedIllegalNewNonCascadedEntitiesAreCleanedUpOnS self::assertCount(1, $persister1->getInserts()); self::assertCount(0, $persister2->getInserts()); } + + /** + * @group #7946 Throw OptimisticLockException when connection::commit() returns false. + */ + public function testCommitThrowOptimisticLockExceptionWhenConnectionCommitReturnFalse(): void + { + // Set another connection mock that fail on commit + $this->_connectionMock = new ConnectionCommitFailMock([], new DriverMock()); + $this->eventManager = $this->getMockBuilder(EventManager::class)->getMock(); + $this->_emMock = EntityManagerMock::create($this->_connectionMock, null, $this->eventManager); + $this->_unitOfWork = new UnitOfWorkMock($this->_emMock); + $this->_emMock->setUnitOfWork($this->_unitOfWork); + + // Setup fake persister and id generator + $userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata(ForumUser::class)); + $userPersister->setMockIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY); + $this->_unitOfWork->setEntityPersister(ForumUser::class, $userPersister); + + // Create a test user + $user = new ForumUser(); + $user->username = 'Jasper'; + $this->_unitOfWork->persist($user); + + $this->expectException(OptimisticLockException::class); + $this->_unitOfWork->commit(); + } } /**