Api4: add calculated field `contact_count` to Group
authorAidan Saunders <aidan.saunders@squiffle.uk>
Tue, 23 May 2023 21:13:11 +0000 (22:13 +0100)
committerAidan Saunders <aidan.saunders@squiffle.uk>
Tue, 23 May 2023 22:06:59 +0000 (23:06 +0100)
This provides the current count of 'added' group members and smart group
members.
Note this does not rebuild the group cache so smart group counts may be
out of date or zero.

See https://stackoverflow.com/questions/47918929/coalesce-for-zero-instead-of-null/47919047#47919047
for the COALESCE(NULLIF()) construct.

Civi/Api4/Service/Spec/Provider/GroupGetSpecProvider.php [new file with mode: 0644]

diff --git a/Civi/Api4/Service/Spec/Provider/GroupGetSpecProvider.php b/Civi/Api4/Service/Spec/Provider/GroupGetSpecProvider.php
new file mode 100644 (file)
index 0000000..a42d7d3
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Api4\Service\Spec\Provider;
+
+use Civi\Api4\Service\Spec\FieldSpec;
+use Civi\Api4\Service\Spec\RequestSpec;
+
+/**
+ * @service
+ * @internal
+ */
+class GroupGetSpecProvider extends \Civi\Core\Service\AutoService implements Generic\SpecProviderInterface {
+
+  /**
+   * @param \Civi\Api4\Service\Spec\RequestSpec $spec
+   *
+   * @throws \CRM_Core_Exception
+   */
+  public function modifySpec(RequestSpec $spec): void {
+    // Number of contacts
+    if (!$spec->getValue('contact_count')) {
+      $field = new FieldSpec('contact_count', 'Group', 'Integer');
+      $field->setLabel(ts('Contact Count'))
+        ->setDescription(ts('Number of contacts in group'))
+        ->setColumnName('id')
+        ->setReadonly(TRUE)
+        ->setSqlRenderer([__CLASS__, 'countContacts']);
+      $spec->addFieldSpec($field);
+    }
+  }
+
+  /**
+   * @param string $entity
+   * @param string $action
+   *
+   * @return bool
+   */
+  public function applies($entity, $action): bool {
+    return $entity === 'Group' && $action === 'get';
+  }
+
+  /**
+   * Generate SQL for counting contacts
+   * in static and smart groups
+   *
+   * @return string
+   */
+  public static function countContacts(array $field): string {
+    return "COALESCE(
+      NULLIF((SELECT COUNT(contact_id) FROM `civicrm_group_contact_cache` WHERE `group_id` = {$field['sql_name']}), 0),
+      (SELECT COUNT(contact_id) FROM `civicrm_group_contact` WHERE `group_id` = {$field['sql_name']} AND `status` = 'Added')
+    )";
+  }
+
+}