From 257000bcb2e9d2ea80b40597a707f1a5b5796ace Mon Sep 17 00:00:00 2001 From: colemanw Date: Thu, 12 Oct 2023 10:06:01 -0400 Subject: [PATCH] APIv4 - Prevent fatal errors when getOptions returns an empty array --- Civi/Api4/Generic/BasicGetFieldsAction.php | 7 ++++--- .../Spec/Provider/EntityTagFilterSpecProvider.php | 2 +- Civi/Api4/Service/Spec/SpecFormatter.php | 2 +- tests/phpunit/api/v4/Action/GetFieldsTest.php | 15 +++++++++++++++ .../api/v4/Custom/BasicCustomFieldTest.php | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Civi/Api4/Generic/BasicGetFieldsAction.php b/Civi/Api4/Generic/BasicGetFieldsAction.php index 895701f2ad..2dc62f8cb0 100644 --- a/Civi/Api4/Generic/BasicGetFieldsAction.php +++ b/Civi/Api4/Generic/BasicGetFieldsAction.php @@ -138,7 +138,7 @@ class BasicGetFieldsAction extends BasicGetAction { if (array_key_exists('label', $fieldDefaults)) { $field['label'] = $field['label'] ?? $field['title'] ?? $field['name']; } - if (!empty($field['options']) && is_array($field['options']) && empty($field['suffixes']) && array_key_exists('suffixes', $field)) { + if (isset($field['options']) && is_array($field['options']) && empty($field['suffixes']) && array_key_exists('suffixes', $field)) { $this->setFieldSuffixes($field); } if (isset($defaults['options'])) { @@ -156,13 +156,14 @@ class BasicGetFieldsAction extends BasicGetAction { * @param array $field */ private function formatOptionList(&$field) { - if (empty($field['options'])) { + $optionsExist = isset($field['options']) && is_array($field['options']); + if (!isset($field['options'])) { $field['options'] = !empty($field['pseudoconstant']); } if (!empty($field['pseudoconstant']['optionGroupName'])) { $field['suffixes'] = CoreUtil::getOptionValueFields($field['pseudoconstant']['optionGroupName']); } - if (!$this->loadOptions || !$field['options']) { + if (!$this->loadOptions || (!$optionsExist && empty($field['pseudoconstant']))) { $field['options'] = (bool) $field['options']; return; } diff --git a/Civi/Api4/Service/Spec/Provider/EntityTagFilterSpecProvider.php b/Civi/Api4/Service/Spec/Provider/EntityTagFilterSpecProvider.php index bdc05f6810..ac900b7299 100644 --- a/Civi/Api4/Service/Spec/Provider/EntityTagFilterSpecProvider.php +++ b/Civi/Api4/Service/Spec/Provider/EntityTagFilterSpecProvider.php @@ -74,7 +74,7 @@ class EntityTagFilterSpecProvider extends \Civi\Core\Service\AutoService impleme $value = array_unique(array_merge($value, $tagTree[$tagID])); } } - $tags = \CRM_Utils_Type::validate(implode(',', $value), 'CommaSeparatedIntegers'); + $tags = $value ? \CRM_Utils_Type::validate(implode(',', $value), 'CommaSeparatedIntegers') : '0'; return "$fieldAlias $operator (SELECT entity_id FROM `civicrm_entity_tag` WHERE entity_table = '$tableName' AND tag_id IN ($tags))"; } diff --git a/Civi/Api4/Service/Spec/SpecFormatter.php b/Civi/Api4/Service/Spec/SpecFormatter.php index 622a11178b..2305f630a4 100644 --- a/Civi/Api4/Service/Spec/SpecFormatter.php +++ b/Civi/Api4/Service/Spec/SpecFormatter.php @@ -164,7 +164,7 @@ class SpecFormatter { $bao = CoreUtil::getBAOFromApiName($spec->getEntity()); $optionLabels = $bao::buildOptions($fieldName, NULL, $values); - if (!is_array($optionLabels) || !$optionLabels) { + if (!is_array($optionLabels)) { $options = FALSE; } else { diff --git a/tests/phpunit/api/v4/Action/GetFieldsTest.php b/tests/phpunit/api/v4/Action/GetFieldsTest.php index 8a3bea82be..1addb7f5e6 100644 --- a/tests/phpunit/api/v4/Action/GetFieldsTest.php +++ b/tests/phpunit/api/v4/Action/GetFieldsTest.php @@ -30,6 +30,7 @@ use Civi\Api4\CustomGroup; use Civi\Api4\Email; use Civi\Api4\EntityTag; use Civi\Api4\OptionValue; +use Civi\Api4\Tag; use Civi\Api4\UserJob; use Civi\Api4\Utils\CoreUtil; use Civi\Test\TransactionalInterface; @@ -232,6 +233,20 @@ class GetFieldsTest extends Api4TestBase implements TransactionalInterface { $this->assertContains('SavedSearch', $tagFields['entity_id']['dfk_entities']); } + public function testEmptyOptionListIsReturnedAsAnArray(): void { + Tag::delete(FALSE) + ->addWhere('used_for', '=', 'civicrm_activity') + ->execute(); + $field = EntityTag::getFields(FALSE) + ->addValue('entity_table', 'civicrm_activity') + ->addWhere('name', '=', 'tag_id') + ->setLoadOptions(TRUE) + ->execute()->single(); + // There are no tags for Activity but it should still be returned as an array + $this->assertIsArray($field['options']); + $this->assertEmpty($field['options']); + } + public function testFiltersAreReturned(): void { $field = Contact::getFields(FALSE) ->addWhere('name', '=', 'employer_id') diff --git a/tests/phpunit/api/v4/Custom/BasicCustomFieldTest.php b/tests/phpunit/api/v4/Custom/BasicCustomFieldTest.php index de375c0333..f70f7c5481 100644 --- a/tests/phpunit/api/v4/Custom/BasicCustomFieldTest.php +++ b/tests/phpunit/api/v4/Custom/BasicCustomFieldTest.php @@ -584,7 +584,7 @@ class BasicCustomFieldTest extends CustomTestBase { ->addWhere('name', '=', 'extends_entity_column_id') ->addValue('extends', 'Contact') ->execute()->first(); - $this->assertFalse($fieldFilteredByContact['options']); + $this->assertEquals([], $fieldFilteredByContact['options']); } public function testExtendsMetadata(): void { -- 2.25.1