Browse Source

Merge pull request #10090 from coryjthompson/ticket-8196

Link HasMany associations using a single transaction
Mark Story 9 years ago
parent
commit
f3714ef7c1
2 changed files with 35 additions and 1 deletions
  1. 3 1
      src/ORM/Association/HasMany.php
  2. 32 0
      tests/TestCase/ORM/Association/HasManyTest.php

+ 3 - 1
src/ORM/Association/HasMany.php

@@ -231,7 +231,9 @@ class HasMany extends Association
 
         $sourceEntity->set($property, $currentEntities);
 
-        $savedEntity = $this->saveAssociated($sourceEntity, $options);
+        $savedEntity = $this->connection()->transactional(function () use ($sourceEntity, $options) {
+            return $this->saveAssociated($sourceEntity, $options);
+        });
 
         $ok = ($savedEntity instanceof EntityInterface);
 

+ 32 - 0
tests/TestCase/ORM/Association/HasManyTest.php

@@ -693,4 +693,36 @@ class HasManyTest extends TestCase
         $this->assertSame(4, $this->author->find()->count(), 'Authors should still exist');
         $this->assertSame(3, $articles->find()->count(), 'Articles should still exist');
     }
+
+    /**
+     * Tests that link only uses a single database transaction
+     *
+     * @return void
+     */
+    public function testLinkUsesSingleTransaction()
+    {
+        $articles = TableRegistry::get('Articles');
+        $assoc = $this->author->hasMany('Articles', [
+            'sourceTable' => $this->author,
+            'targetTable' => $articles
+        ]);
+
+        // Ensure author in fixture has zero associated articles
+        $entity = $this->author->get(2, ['contain' => 'Articles']);
+        $initial = $entity->articles;
+        $this->assertCount(0, $initial);
+
+        // Ensure that after each model is saved, we are still within a transaction.
+        $listenerAfterSave = function ($e, $entity, $options) use ($articles) {
+            $this->assertTrue($articles->connection()->inTransaction(), 'Multiple transactions used to save associated models.');
+        };
+        $articles->eventManager()->on('Model.afterSave', $listenerAfterSave);
+
+        $options = ['atomic' => false];
+        $assoc->link($entity, $articles->find('all')->toArray(), $options);
+
+        // Ensure that link was successful.
+        $new = $this->author->get(2, ['contain' => 'Articles']);
+        $this->assertCount(3, $new->articles);
+    }
 }