From: kissifrot <kissifrot@gmail.com>
Date: Thu, 24 Oct 2024 19:56:47 +0200
Subject: Fix compatibility with DBAL 4.x

Bug: https://github.com/symfony/security-acl/pull/122
Origin: vendor, https://github.com/kissifrot/security-acl/commit/f50a430193c8a53b9f74ae6dd6b899acc3577533
---
 Dbal/MutableAclProvider.php           | 18 +++++++++++++++---
 Dbal/Schema.php                       | 12 ++++++------
 Tests/Dbal/MutableAclProviderTest.php |  4 ++--
 composer.json                         |  2 +-
 4 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/Dbal/MutableAclProvider.php b/Dbal/MutableAclProvider.php
index 0d69ca6..a7e8c88 100644
--- a/Dbal/MutableAclProvider.php
+++ b/Dbal/MutableAclProvider.php
@@ -36,6 +36,7 @@ use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
 class MutableAclProvider extends AclProvider implements MutableAclProviderInterface, PropertyChangedListener
 {
     private $propertyChanges;
+    private $transactionStarted = false;
 
     /**
      * {@inheritdoc}
@@ -80,7 +81,12 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
      */
     public function deleteAcl(ObjectIdentityInterface $oid)
     {
-        $this->connection->beginTransaction();
+        // DBAL 4.0 does not support nested transactions, so we need to keep track of the transaction state
+        // @see https://github.com/doctrine/dbal/pull/5383 and https://github.com/doctrine/dbal/pull/5401
+        if (!$this->transactionStarted) {
+            $this->connection->beginTransaction();
+            $this->transactionStarted = true;
+        }
         try {
             foreach ($this->findChildren($oid, true) as $childOid) {
                 $this->deleteAcl($childOid);
@@ -92,9 +98,15 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
             $this->deleteObjectIdentityRelations($oidPK);
             $this->deleteObjectIdentity($oidPK);
 
-            $this->connection->commit();
+            if ($this->transactionStarted) {
+                $this->connection->commit();
+                $this->transactionStarted = false;
+            }
         } catch (\Exception $e) {
-            $this->connection->rollBack();
+            if ($this->transactionStarted) {
+                $this->connection->rollBack();
+                $this->transactionStarted = false;
+            }
 
             throw $e;
         }
diff --git a/Dbal/Schema.php b/Dbal/Schema.php
index 56ea9dc..ff9ee01 100644
--- a/Dbal/Schema.php
+++ b/Dbal/Schema.php
@@ -94,9 +94,9 @@ final class Schema extends BaseSchema
         $table->addUniqueIndex(['class_id', 'object_identity_id', 'field_name', 'ace_order']);
         $table->addIndex(['class_id', 'object_identity_id', 'security_identity_id']);
 
-        $table->addForeignKeyConstraint($this->getTable($this->options['class_table_name']), ['class_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
-        $table->addForeignKeyConstraint($this->getTable($this->options['oid_table_name']), ['object_identity_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
-        $table->addForeignKeyConstraint($this->getTable($this->options['sid_table_name']), ['security_identity_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
+        $table->addForeignKeyConstraint($this->getTable($this->options['class_table_name'])->getName(), ['class_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
+        $table->addForeignKeyConstraint($this->getTable($this->options['oid_table_name'])->getName(), ['object_identity_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
+        $table->addForeignKeyConstraint($this->getTable($this->options['sid_table_name'])->getName(), ['security_identity_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
     }
 
     /**
@@ -116,7 +116,7 @@ final class Schema extends BaseSchema
         $table->addUniqueIndex(['object_identifier', 'class_id']);
         $table->addIndex(['parent_object_identity_id']);
 
-        $table->addForeignKeyConstraint($table, ['parent_object_identity_id'], ['id']);
+        $table->addForeignKeyConstraint($table->getName(), ['parent_object_identity_id'], ['id']);
     }
 
     /**
@@ -137,8 +137,8 @@ final class Schema extends BaseSchema
             // MS SQL Server does not support recursive cascading
             $action = 'NO ACTION';
         }
-        $table->addForeignKeyConstraint($oidTable, ['object_identity_id'], ['id'], ['onDelete' => $action, 'onUpdate' => $action]);
-        $table->addForeignKeyConstraint($oidTable, ['ancestor_id'], ['id'], ['onDelete' => $action, 'onUpdate' => $action]);
+        $table->addForeignKeyConstraint($oidTable->getName(), ['object_identity_id'], ['id'], ['onDelete' => $action, 'onUpdate' => $action]);
+        $table->addForeignKeyConstraint($oidTable->getName(), ['ancestor_id'], ['id'], ['onDelete' => $action, 'onUpdate' => $action]);
     }
 
     /**
diff --git a/Tests/Dbal/MutableAclProviderTest.php b/Tests/Dbal/MutableAclProviderTest.php
index d29a0d9..91e95f9 100644
--- a/Tests/Dbal/MutableAclProviderTest.php
+++ b/Tests/Dbal/MutableAclProviderTest.php
@@ -263,7 +263,7 @@ class MutableAclProviderTest extends TestCase
         ;
         $con
             ->expects($this->never())
-            ->method('executeUpdate')
+            ->method('executeStatement')
         ;
 
         $provider = new MutableAclProvider($con, new PermissionGrantingStrategy(), []);
@@ -536,7 +536,6 @@ class MutableAclProviderTest extends TestCase
             ],
             $configuration
         );
-        $this->connection->setNestTransactionsWithSavepoints(true);
 
         // import the schema
         $schema = new Schema($this->getOptions());
@@ -547,6 +546,7 @@ class MutableAclProviderTest extends TestCase
 
     protected function tearDown(): void
     {
+        $this->connection->close();
         $this->connection = null;
     }
 
diff --git a/composer.json b/composer.json
index 33c5bac..a2c4d6e 100644
--- a/composer.json
+++ b/composer.json
@@ -26,7 +26,7 @@
         "doctrine/cache": "^1.11|^2.0",
         "doctrine/common": "^2.2|^3",
         "doctrine/persistence": "^1.3.3|^2|^3",
-        "doctrine/dbal": "^2.13.1|^3.1",
+        "doctrine/dbal": "^2.13.1|^3.1|^4",
         "psr/log": "^1|^2|^3"
     },
     "autoload": {
