From 08f845b794cb92804a978457301f2d804f7461db Mon Sep 17 00:00:00 2001 From: colemanw Date: Tue, 22 Aug 2023 13:45:21 -0400 Subject: [PATCH] Afform - Fix prefill action to return correct index when using af-repeat Before: Index was ignored so only the first entity in an af-repeat set could be autofilled After: Index handled correctly --- .../Api4/Action/Afform/AbstractProcessor.php | 8 +- .../phpunit/api/v4/AfformPrefillUsageTest.php | 103 ++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 ext/afform/mock/tests/phpunit/api/v4/AfformPrefillUsageTest.php diff --git a/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php b/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php index fc0451bf34..df07e413f0 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php @@ -102,7 +102,13 @@ abstract class AbstractProcessor extends \Civi\Api4\Generic\AbstractAction { public function loadEntity(array $entity, array $ids) { // Limit number of records based on af-repeat settings // If 'min' is set then it is repeatable, and max will either be a number or NULL for unlimited. - $ids = array_slice($ids, 0, isset($entity['min']) ? $entity['max'] : 1); + if (isset($entity['min']) && isset($entity['max'])) { + foreach (array_keys($ids) as $index) { + if ($index >= $entity['max']) { + unset($ids[$index]); + } + } + } $api4 = $this->_formDataModel->getSecureApi4($entity['name']); $idField = CoreUtil::getIdFieldName($entity['type']); diff --git a/ext/afform/mock/tests/phpunit/api/v4/AfformPrefillUsageTest.php b/ext/afform/mock/tests/phpunit/api/v4/AfformPrefillUsageTest.php new file mode 100644 index 0000000000..11e9746968 --- /dev/null +++ b/ext/afform/mock/tests/phpunit/api/v4/AfformPrefillUsageTest.php @@ -0,0 +1,103 @@ + + +
+
+ + + +
+
+ +
+
+ +
+
+ +EOHTML; + + $this->useValues([ + 'layout' => $layout, + 'permission' => CRM_Core_Permission::ALWAYS_ALLOW_PERMISSION, + ]); + + $cid = $this->saveTestRecords('Contact', [ + 'records' => [ + ['first_name' => 'A', 'last_name' => '_A', 'preferred_communication_method' => [1, 3]], + ['first_name' => 'B', 'last_name' => '_B', 'email_primary.email' => 'b@afform.test'], + ['first_name' => 'C', 'last_name' => '_C'], + ['first_name' => 'D', 'last_name' => '_D', 'email_primary.email' => 'd@afform.test'], + ], + ])->column('id'); + + $this->saveTestRecords('Phone', [ + 'records' => [ + ['contact_id' => $cid[0], 'phone' => '0-1'], + ['contact_id' => $cid[0], 'phone' => '0-2'], + ['contact_id' => $cid[0], 'phone' => '0-3'], + ['contact_id' => $cid[2], 'phone' => '2-1'], + ['contact_id' => $cid[3], 'phone' => '3-1'], + ], + ]); + + $prefill = Civi\Api4\Afform::prefill() + ->setName($this->formName) + ->setArgs(['Individual1' => $cid]) + ->execute() + ->indexBy('name'); + + // Form entity has `max="3"` + $this->assertCount(3, $prefill['Individual1']['values']); + $this->assertEquals('A', $prefill['Individual1']['values'][0]['fields']['first_name']); + $this->assertEquals([1, 3], $prefill['Individual1']['values'][0]['fields']['preferred_communication_method']); + $this->assertEquals('B', $prefill['Individual1']['values'][1]['fields']['first_name']); + $this->assertEquals('C', $prefill['Individual1']['values'][2]['fields']['first_name']); + + // One email should have been filled + $this->assertCount(1, $prefill['Individual1']['values'][1]['joins']['Email']); + $this->assertEquals('b@afform.test', $prefill['Individual1']['values'][1]['joins']['Email'][0]['email']); + $this->assertEmpty($prefill['Individual1']['values'][0]['joins']['Email']); + $this->assertEmpty($prefill['Individual1']['values'][2]['joins']['Email']); + + // Phone join has `max="2"` + $this->assertCount(2, $prefill['Individual1']['values'][0]['joins']['Phone']); + $this->assertCount(1, $prefill['Individual1']['values'][2]['joins']['Phone']); + $this->assertEquals('2-1', $prefill['Individual1']['values'][2]['joins']['Phone'][0]['phone']); + $this->assertEmpty($prefill['Individual1']['values'][1]['joins']['Phone']); + + // Prefill a specific contact for the af-repeat entity + $prefill = Civi\Api4\Afform::prefill() + ->setName($this->formName) + ->setArgs(['Individual1' => [1 => $cid[3]]]) + ->execute() + ->indexBy('name'); + $this->assertCount(1, $prefill['Individual1']['values']); + $this->assertEquals('D', $prefill['Individual1']['values'][1]['fields']['first_name']); + $this->assertEquals('_D', $prefill['Individual1']['values'][1]['fields']['last_name']); + $this->assertEquals('d@afform.test', $prefill['Individual1']['values'][1]['joins']['Email'][0]['email']); + $this->assertEquals('3-1', $prefill['Individual1']['values'][1]['joins']['Phone'][0]['phone']); + + // Form entity has `max="3"` so a forth contact (index 3) is out-of-bounds + $prefill = Civi\Api4\Afform::prefill() + ->setName($this->formName) + ->setArgs(['Individual1' => [3 => $cid[0]]]) + ->execute(); + $this->assertTrue(empty($prefill['Individual1']['values'])); + } + +} -- 2.25.1