Browse Source

Fix dirty associations that use formatResults

When a joined association uses formatResults the parent entity should
not be marked dirty if the result formatter modifieds the association
entity.

While this may not be the optimal place to do this performance wise it
does solve the problem and I'd like to revise the dirty/clean flagging
that happens multiple times during association construction anyways.

Refs #14062
Mark Story 6 years ago
parent
commit
165bdab680

+ 7 - 1
src/ORM/Association.php

@@ -1282,7 +1282,13 @@ abstract class Association
             }
 
             /** @var \Cake\Collection\CollectionInterface $results */
-            return $results->insert($property, $extracted);
+            return $results
+                ->insert($property, $extracted)
+                ->map(function ($result) {
+                    $result->clean();
+
+                    return $result;
+                });
         }, Query::PREPEND);
     }
 

+ 23 - 0
tests/TestCase/ORM/Association/BelongsToTest.php

@@ -445,4 +445,27 @@ class BelongsToTest extends TestCase
         $this->assertSame('mariano', $result->author->name);
         $this->assertSame(['author'], array_keys($result->toArray()), 'No other properties included.');
     }
+
+    /**
+     * Test that formatResults in a joined association finder doesn't dirty
+     * the root entity.
+     *
+     * @return void
+     */
+    public function testAttachToFormatResultsNoDirtyResults()
+    {
+        $this->setAppNamespace('TestApp');
+        $articles = $this->getTableLocator()->get('Articles');
+        $articles->belongsTo('Authors')
+            ->setFinder('formatted');
+
+        $query = $articles->find()
+            ->where(['Articles.id' => 1])
+            ->contain('Authors');
+        $result = $query->firstOrFail();
+
+        $this->assertNotEmpty($result->author);
+        $this->assertNotEmpty($result->author->formatted);
+        $this->assertFalse($result->isDirty(), 'Record should be clean as it was pulled from the db.');
+    }
 }

+ 1 - 0
tests/test_app/TestApp/Model/Table/ArticlesTable.php

@@ -31,6 +31,7 @@ class ArticlesTable extends Table
      * Find published
      *
      * @param \Cake\ORM\Query $query The query
+     * @param array $options The options
      * @return \Cake\ORM\Query
      */
     public function findPublished($query, array $options = [])

+ 18 - 0
tests/test_app/TestApp/Model/Table/AuthorsTable.php

@@ -34,4 +34,22 @@ class AuthorsTable extends Table
 
         return $query;
     }
+
+    /**
+     * Finder that applies a formatter to test dirty associations
+     *
+     * @param \Cake\ORM\Query $query The query
+     * @param array $options The options
+     * @return \Cake\ORM\Query
+     */
+    public function findFormatted(Query $query, array $options = [])
+    {
+        return $query->formatResults(function ($results) {
+            return $results->map(function ($author) {
+                $author->formatted = $author->name . '!!';
+
+                return $author;
+            });
+        });
+    }
 }