Allow values to be passed to api4 GetFields
authorColeman Watts <coleman@civicrm.org>
Sat, 28 Dec 2019 14:31:40 +0000 (09:31 -0500)
committerColeman Watts <coleman@civicrm.org>
Sat, 28 Dec 2019 22:55:14 +0000 (17:55 -0500)
So far this only filters custom fields by contact type,
but values is now being passed to allow more filtering.

Civi/Api4/Action/CustomValue/GetFields.php
Civi/Api4/Generic/BasicGetFieldsAction.php
Civi/Api4/Generic/DAOGetFieldsAction.php
Civi/Api4/Service/Spec/SpecGatherer.php
ang/api4Explorer/Explorer.html
ang/api4Explorer/Explorer.js
tests/phpunit/api/v4/Action/BaseCustomValueTest.php
tests/phpunit/api/v4/Action/BasicCustomFieldTest.php

index e063f7982f3319ae1ef9786063dab08ed1e303ee..c2ca32a1a84296c3ff0e9de51c2409aef60ebaa9 100644 (file)
@@ -32,7 +32,7 @@ class GetFields extends \Civi\Api4\Generic\DAOGetFieldsAction {
     $fields = $this->_itemsToGet('name');
     /** @var \Civi\Api4\Service\Spec\SpecGatherer $gatherer */
     $gatherer = \Civi::container()->get('spec_gatherer');
-    $spec = $gatherer->getSpec('Custom_' . $this->getCustomGroup(), $this->getAction(), $this->includeCustom);
+    $spec = $gatherer->getSpec('Custom_' . $this->getCustomGroup(), $this->getAction(), $this->includeCustom, $this->values);
     return SpecFormatter::specToArray($spec->getFields($fields), $this->loadOptions);
   }
 
index c0c851661b5d7b8bcfd110cbce55b47734a9caea..5c2b0ccb11f0110f142d8b852164b93ec9ff2098 100644 (file)
@@ -30,6 +30,9 @@ use Civi\Api4\Utils\ActionUtil;
  * @method $this setLoadOptions(bool $value)
  * @method bool getLoadOptions()
  * @method $this setAction(string $value)
+ * @method $this addValue(string $value)
+ * @method $this setValues(array $values)
+ * @method array getValues()
  */
 class BasicGetFieldsAction extends BasicGetAction {
 
@@ -41,10 +44,19 @@ class BasicGetFieldsAction extends BasicGetAction {
   protected $loadOptions = FALSE;
 
   /**
+   * Fields will be returned appropriate to the specified action (get, create, delete, etc.)
+   *
    * @var string
    */
   protected $action = 'get';
 
+  /**
+   * Fields will be returned appropriate to the specified values (e.g. ['contact_type' => 'Individual'])
+   *
+   * @var array
+   */
+  protected $values = [];
+
   /**
    * To implement getFields for your own entity:
    *
index e3a510b4703aa1dcf29216c7fc047ec58e8d2862..edf7684c65e5552a8894885d38eee1c952dec596 100644 (file)
@@ -51,7 +51,7 @@ class DAOGetFieldsAction extends BasicGetFieldsAction {
     if ($fields) {
       $this->includeCustom = strpos(implode('', $fields), '.') !== FALSE;
     }
-    $spec = $gatherer->getSpec($this->getEntityName(), $this->getAction(), $this->includeCustom);
+    $spec = $gatherer->getSpec($this->getEntityName(), $this->getAction(), $this->includeCustom, $this->values);
     return SpecFormatter::specToArray($spec->getFields($fields), $this->loadOptions);
   }
 
index 8a91d09e90897f779092849f128deb42a1aa2015..d10c95ecf1cb2d8e69559cb33df95da3ba3d8859 100644 (file)
@@ -46,18 +46,19 @@ class SpecGatherer {
    *
    * @param string $entity
    * @param string $action
-   * @param $includeCustom
+   * @param bool $includeCustom
+   * @param array $values
    *
    * @return \Civi\Api4\Service\Spec\RequestSpec
    */
-  public function getSpec($entity, $action, $includeCustom) {
+  public function getSpec($entity, $action, $includeCustom, $values = []) {
     $specification = new RequestSpec($entity, $action);
 
     // Real entities
     if (strpos($entity, 'Custom_') !== 0) {
       $this->addDAOFields($entity, $action, $specification);
       if ($includeCustom && array_key_exists($entity, \CRM_Core_SelectValues::customGroupExtends())) {
-        $this->addCustomFields($entity, $specification);
+        $this->addCustomFields($entity, $specification, $values);
       }
     }
     // Custom pseudo-entities
@@ -114,12 +115,18 @@ class SpecGatherer {
   /**
    * @param string $entity
    * @param \Civi\Api4\Service\Spec\RequestSpec $specification
+   * @param array $values
+   * @throws \API_Exception
    */
-  private function addCustomFields($entity, RequestSpec $specification) {
-    $extends = ($entity == 'Contact') ? ['Contact', 'Individual', 'Organization', 'Household'] : [$entity];
+  private function addCustomFields($entity, RequestSpec $specification, $values = []) {
+    $extends = [$entity];
+    if ($entity === 'Contact') {
+      $extends = !empty($values['contact_type']) ? [$values['contact_type'], 'Contact'] : ['Contact', 'Individual', 'Organization', 'Household'];
+    }
     $customFields = CustomField::get()
       ->setCheckPermissions(FALSE)
       ->addWhere('custom_group.extends', 'IN', $extends)
+      ->addWhere('custom_group.is_multiple', '=', '0')
       ->setSelect(['custom_group.name', 'custom_group_id', 'name', 'label', 'data_type', 'html_type', 'is_searchable', 'is_search_range', 'weight', 'is_active', 'is_view', 'option_group_id', 'default_value', 'date_format', 'time_format', 'start_date_years', 'end_date_years', 'help_pre', 'help_post'])
       ->execute();
 
index bbfd35b95962a2b773c34ea6f609b027b11b39bb..927513a5b956841a41e6296d2592861fec2857da 100644 (file)
@@ -74,7 +74,7 @@
             <legend>values<span class="crm-marker" ng-if="availableParams.values.required"> *</span></legend>
             <div class="api4-input form-inline" ng-repeat="clause in params.values" ng-mouseenter="help('value: ' + clause[0], fieldHelp(clause[0]))" ng-mouseleave="help('values', availableParams.values)">
               <input class="collapsible-optgroups form-control" ng-model="clause[0]" crm-ui-select="{formatResult: formatSelect2Item, formatSelection: formatSelect2Item, data: valuesFields, allowClear: true, placeholder: 'Field'}" />
-              <input class="form-control" ng-model="clause[1]" api4-exp-value="{field: clause[0]}" />
+              <input class="form-control" ng-model="clause[1]" api4-exp-value="{field: clause[0], action: action === 'getFields' ? params.action || 'get' : action}" />
             </div>
             <div class="api4-input form-inline">
               <input class="collapsible-optgroups form-control" ng-model="controls.values" crm-ui-select="{formatResult: formatSelect2Item, formatSelection: formatSelect2Item, data: valuesFields}" placeholder="Add value" />
index 28ca9ae1166ac3737382c4e98bf41ac0b4fbd638..982f618d3f361942d3465f2b9ed4c2fe0ac8699e 100644 (file)
       return container;
     }
 
-    function getFieldList(source) {
+    function getFieldList(action) {
       var fields = [],
-        fieldInfo = _.findWhere(getEntity().actions, {name: $scope.action}).fields;
+        fieldInfo = _.findWhere(getEntity().actions, {name: action}).fields;
       formatForSelect2(fieldInfo, fields, 'name', ['description', 'required', 'default_value']);
       return fields;
     }
     };
 
     $scope.valuesFields = function() {
-      var fields = _.cloneDeep($scope.fields);
+      var fields = _.cloneDeep($scope.action === 'getFields' ? getFieldList($scope.params.action || 'get') : $scope.fields);
       // Disable fields that are already in use
       _.each($scope.params.values || [], function(val) {
         (_.findWhere(fields, {id: val[0]}) || {}).disabled = true;
       }
       if ($scope.action) {
         var actionInfo = _.findWhere(actions, {id: $scope.action});
-        $scope.fields = getFieldList();
+        $scope.fields = getFieldList($scope.action);
         if (_.contains(['get', 'update', 'delete', 'replace'], $scope.action)) {
           $scope.fieldsAndJoins = addJoins($scope.fields);
         } else {
         var ts = scope.ts = CRM.ts(),
           multi = _.includes(['IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'], scope.data.op),
           entity = $routeParams.api4entity,
-          action = $routeParams.api4action;
+          action = scope.data.action || $routeParams.api4action;
 
         function destroyWidget() {
           var $el = $(element);
index 2270e0ac3faa95b236688b98049e06e87c38fe20..3ad87d3d5a87d4065383159edc4c9336d0042ce4 100644 (file)
@@ -43,7 +43,7 @@ abstract class BaseCustomValueTest extends UnitTestCase {
       ],
     ];
 
-    $this->dropByPrefix('civicrm_value_mycontact');
+    $this->dropByPrefix('civicrm_value_my');
     $this->cleanup($cleanup_params);
   }
 
index b0f4d02be236ff9c2a604b5e4bdbe86b325df7a7..0c6162cb615b1b540f8fd52e4d236391c62ae2b2 100644 (file)
@@ -34,8 +34,8 @@ class BasicCustomFieldTest extends BaseCustomValueTest {
 
     $customGroup = CustomGroup::create()
       ->setCheckPermissions(FALSE)
-      ->addValue('name', 'MyContactFields')
-      ->addValue('extends', 'Contact')
+      ->addValue('name', 'MyIndividualFields')
+      ->addValue('extends', 'Individual')
       ->execute()
       ->first();
 
@@ -47,39 +47,45 @@ class BasicCustomFieldTest extends BaseCustomValueTest {
       ->addValue('data_type', 'String')
       ->execute();
 
+    // Individual fields should show up when contact_type = null|Individual but not other contact types
+    $getFields = Contact::getFields()->setCheckPermissions(FALSE);
+    $this->assertContains('MyIndividualFields.FavColor', $getFields->execute()->column('name'));
+    $this->assertContains('MyIndividualFields.FavColor', $getFields->setValues(['contact_type' => 'Individual'])->execute()->column('name'));
+    $this->assertNotContains('MyIndividualFields.FavColor', $getFields->setValues(['contact_type' => 'Household'])->execute()->column('name'));
+
     $contactId = Contact::create()
       ->setCheckPermissions(FALSE)
       ->addValue('first_name', 'Johann')
       ->addValue('last_name', 'Tester')
       ->addValue('contact_type', 'Individual')
-      ->addValue('MyContactFields.FavColor', 'Red')
+      ->addValue('MyIndividualFields.FavColor', 'Red')
       ->execute()
       ->first()['id'];
 
     $contact = Contact::get()
       ->setCheckPermissions(FALSE)
       ->addSelect('first_name')
-      ->addSelect('MyContactFields.FavColor')
+      ->addSelect('MyIndividualFields.FavColor')
       ->addWhere('id', '=', $contactId)
-      ->addWhere('MyContactFields.FavColor', '=', 'Red')
+      ->addWhere('MyIndividualFields.FavColor', '=', 'Red')
       ->execute()
       ->first();
 
-    $this->assertEquals('Red', $contact['MyContactFields.FavColor']);
+    $this->assertEquals('Red', $contact['MyIndividualFields.FavColor']);
 
     Contact::update()
       ->addWhere('id', '=', $contactId)
-      ->addValue('MyContactFields.FavColor', 'Blue')
+      ->addValue('MyIndividualFields.FavColor', 'Blue')
       ->execute();
 
     $contact = Contact::get()
       ->setCheckPermissions(FALSE)
-      ->addSelect('MyContactFields.FavColor')
+      ->addSelect('MyIndividualFields.FavColor')
       ->addWhere('id', '=', $contactId)
       ->execute()
       ->first();
 
-    $this->assertEquals('Blue', $contact['MyContactFields.FavColor']);
+    $this->assertEquals('Blue', $contact['MyIndividualFields.FavColor']);
   }
 
   public function testWithTwoFields() {