Skip to content

Commit

Permalink
APIv4 SortableEntity - Fix sorting custom fields with option groups
Browse files Browse the repository at this point in the history
Before: APIv4 would guess which fields to use for grouping when sorting by weight.
this caused a bug when sorting custom fields which also had an option_group_id, which
was incorrectly guessed to be used for grouping.

After: New `@groupWeightsBy` annotation removes the guesswork.
  • Loading branch information
colemanw committed Feb 7, 2022
1 parent 6c43540 commit 204c3c2
Show file tree
Hide file tree
Showing 11 changed files with 17 additions and 6 deletions.
1 change: 1 addition & 0 deletions Civi/Api4/CustomField.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* @see https://docs.civicrm.org/user/en/latest/organising-your-data/creating-custom-fields/
* @searchable secondary
* @orderBy weight
* @groupWeightsBy custom_group_id
* @since 5.19
* @package Civi\Api4
*/
Expand Down
5 changes: 5 additions & 0 deletions Civi/Api4/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ public static function getFields($checkPermissions = TRUE) {
'data_type' => 'Array',
'description' => 'When joining entities in the UI, which fields should be presented by default in the ON clause',
],
[
'name' => 'group_weights_by',
'data_type' => 'Array',
'description' => 'For sortable entities, what field groupings are used to order by weight',
],
];
}))->setCheckPermissions($checkPermissions);
}
Expand Down
5 changes: 2 additions & 3 deletions Civi/Api4/Generic/Traits/DAOActionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ protected function updateWeight(array &$record) {
/** @var \CRM_Core_DAO|string $daoName */
$daoName = CoreUtil::getInfoItem($this->getEntityName(), 'dao');
$weightField = CoreUtil::getInfoItem($this->getEntityName(), 'order_by');
$grouping = CoreUtil::getInfoItem($this->getEntityName(), 'group_weights_by');
$idField = CoreUtil::getIdFieldName($this->getEntityName());
// If updating an existing record without changing weight, do nothing
if (!isset($record[$weightField]) && !empty($record[$idField])) {
Expand All @@ -339,10 +340,8 @@ protected function updateWeight(array &$record) {
$newWeight = $record[$weightField] ?? NULL;
$oldWeight = empty($record[$idField]) ? NULL : \CRM_Core_DAO::getFieldValue($daoName, $record[$idField], $weightField);

// FIXME: Need a more metadata-ish approach. For now here's a hardcoded list of the fields sortable entities use for grouping.
$guesses = ['option_group_id', 'price_set_id', 'price_field_id', 'premiums_id', 'uf_group_id', 'custom_group_id', 'parent_id', 'domain_id'];
$filters = [];
foreach (array_intersect($guesses, array_keys($daoFields)) as $filter) {
foreach ($grouping ?? [] as $filter) {
$filters[$filter] = $record[$filter] ?? (empty($record[$idField]) ? NULL : \CRM_Core_DAO::getFieldValue($daoName, $record[$idField], $filter));
}
// Supply default weight for new record
Expand Down
1 change: 1 addition & 0 deletions Civi/Api4/MembershipType.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*
* @searchable secondary
* @orderBy weight
* @groupWeightsBy domain_id
* @since 5.27
* @package Civi\Api4
*/
Expand Down
1 change: 1 addition & 0 deletions Civi/Api4/Navigation.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*
* @searchable none
* @orderBy weight
* @groupWeightsBy domain_id,parent_id
* @since 5.19
* @package Civi\Api4
*/
Expand Down
1 change: 1 addition & 0 deletions Civi/Api4/OptionValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* @see \Civi\Api4\OptionGroup
* @searchable secondary
* @orderBy weight
* @groupWeightsBy option_group_id
* @since 5.19
* @package Civi\Api4
*/
Expand Down
1 change: 1 addition & 0 deletions Civi/Api4/PriceField.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*
* @searchable secondary
* @orderBy weight
* @groupWeightsBy price_set_id
* @since 5.27
* @package Civi\Api4
*/
Expand Down
1 change: 1 addition & 0 deletions Civi/Api4/PriceFieldValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*
* @searchable secondary
* @orderBy weight
* @groupWeightsBy price_field_id
* @since 5.27
* @package Civi\Api4
*/
Expand Down
1 change: 1 addition & 0 deletions Civi/Api4/UFField.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* @see \Civi\Api4\UFGroup
* @searchable none
* @orderBy weight
* @groupWeightsBy uf_group_id
* @since 5.19
* @package Civi\Api4
*/
Expand Down
2 changes: 1 addition & 1 deletion Civi/Api4/Utils/ReflectionUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public static function parseDocBlock($comment) {
elseif ($key == 'return') {
$info['return'] = explode('|', $words[0]);
}
elseif ($key == 'options' || $key == 'ui_join_filters') {
elseif ($key == 'options' || $key == 'ui_join_filters' || $key == 'groupWeightsBy') {
$val = str_replace(', ', ',', implode(' ', $words));
$info[$key] = explode(',', $val);
}
Expand Down
4 changes: 2 additions & 2 deletions tests/phpunit/api/v4/Action/BasicCustomFieldTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -423,9 +423,9 @@ public function testUpdateWeights() {
->addValue('extends', 'Individual')
->execute()->first();
$sampleData = [
['label' => 'One'],
['label' => 'One', 'html_type' => 'Select', 'option_values' => ['a' => 'A', 'b' => 'B']],
['label' => 'Two'],
['label' => 'Three'],
['label' => 'Three', 'html_type' => 'Select', 'option_values' => ['c' => 'C', 'd' => 'D']],
['label' => 'Four'],
];
CustomField::save(FALSE)
Expand Down

0 comments on commit 204c3c2

Please sign in to comment.