Skip to content

Commit

Permalink
Merge pull request #30140 from colemanw/afformLocBlock
Browse files Browse the repository at this point in the history
dev/core#5053 Afform - Add support for saving event location
  • Loading branch information
colemanw authored Aug 21, 2024
2 parents f393910 + ce7d792 commit b390236
Show file tree
Hide file tree
Showing 30 changed files with 671 additions and 160 deletions.
21 changes: 21 additions & 0 deletions Civi/Api4/Action/LocBlock/Create.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?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\Action\LocBlock;

/**
* @inheritDoc
*/
class Create extends \Civi\Api4\Generic\DAOCreateAction {
use LocBlockSaveTrait;

}
83 changes: 83 additions & 0 deletions Civi/Api4/Action/LocBlock/LocBlockSaveTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?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\Action\LocBlock;

use Civi\Api4\LocBlock;
use Civi\Api4\Utils\CoreUtil;

/**
* Code shared by LocBlock create/update/save actions
*/
trait LocBlockSaveTrait {

/**
* @param array $items
* @return array
*/
protected function write(array $items) {
foreach ($items as &$item) {
self::saveLocations($item);
}
$saved = parent::write($items);
return $saved;
}

/**
* @param array $params
*/
protected function saveLocations(array &$params) {
if (!empty($params['id'])) {
$locBlock = LocBlock::get(FALSE)
->addWhere('id', '=', $params['id'])
->execute()->first();
}
foreach (['Address', 'Email', 'Phone', 'IM'] as $joinEntity) {
foreach (['', '_2'] as $suffix) {
$joinField = strtolower($joinEntity) . $suffix . '_id';
$item = \CRM_Utils_Array::filterByPrefix($params, "$joinField.");
$entityId = $params[$joinField] ?? $locBlock[$joinField] ?? NULL;
if ($item) {
$labelField = CoreUtil::getInfoItem($joinEntity, 'label_field');
// If NULL was given for the main field (e.g. `email`) then delete the record IF it's not in use
if (!empty($params['id']) && $entityId && $labelField && array_key_exists($labelField, $item) && ($item[$labelField] === NULL || $item[$labelField] === '')) {
$referenceCount = CoreUtil::getRefCountTotal($joinEntity, $entityId);
if ($referenceCount <= 1) {
civicrm_api4($joinEntity, 'delete', [
'checkPermissions' => FALSE,
'where' => [
['id', '=', $entityId],
],
]);
}
}
else {
$item['contact_id'] = '';
if ($entityId) {
$item['id'] = $entityId;
}
$saved = civicrm_api4($joinEntity, 'save', [
'checkPermissions' => FALSE,
'records' => [$item],
])->first();
$params[$joinField] = $saved['id'] ?? NULL;
}
}
}
}
}

protected function resolveFKValues(array &$record): void {
// Override parent function with noop to prevent spurious matching
}

}
21 changes: 21 additions & 0 deletions Civi/Api4/Action/LocBlock/Save.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?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\Action\LocBlock;

/**
* @inheritDoc
*/
class Save extends \Civi\Api4\Generic\DAOSaveAction {
use LocBlockSaveTrait;

}
21 changes: 21 additions & 0 deletions Civi/Api4/Action/LocBlock/Update.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?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\Action\LocBlock;

/**
* @inheritDoc
*/
class Update extends \Civi\Api4\Generic\DAOUpdateAction {
use LocBlockSaveTrait;

}
2 changes: 1 addition & 1 deletion Civi/Api4/Generic/Traits/DAOActionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ protected function formatWriteValues(&$record) {
*
* @param array $record
*/
private function resolveFKValues(array &$record): void {
protected function resolveFKValues(array &$record): void {
// Resolve domain id first
uksort($record, function($a, $b) {
return substr($a, 0, 9) == 'domain_id' ? -1 : 1;
Expand Down
28 changes: 28 additions & 0 deletions Civi/Api4/LocBlock.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,37 @@
* Links addresses, emails & phones to Events.
*
* @searchable secondary
* @searchFields address_id.street_address,address_id.city,email_id.email
* @since 5.31
* @package Civi\Api4
*/
class LocBlock extends Generic\DAOEntity {

/**
* @param bool $checkPermissions
* @return Action\LocBlock\Create
*/
public static function create($checkPermissions = TRUE) {
return (new Action\LocBlock\Create('LocBlock', __FUNCTION__))
->setCheckPermissions($checkPermissions);
}

/**
* @param bool $checkPermissions
* @return Action\LocBlock\Update
*/
public static function update($checkPermissions = TRUE) {
return (new Action\LocBlock\Update('LocBlock', __FUNCTION__))
->setCheckPermissions($checkPermissions);
}

/**
* @param bool $checkPermissions
* @return Action\LocBlock\Save
*/
public static function save($checkPermissions = TRUE) {
return (new Action\LocBlock\Save('LocBlock', __FUNCTION__))
->setCheckPermissions($checkPermissions);
}

}
16 changes: 16 additions & 0 deletions Civi/Api4/Utils/CoreUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,22 @@ public static function getRefCount(string $entityName, $entityId): array {
return $dao->getReferenceCounts();
}

/**
* Gets total number of references
*
* @param string $entityName
* @param $entityId
* @return int
* @throws NotImplementedException
*/
public static function getRefCountTotal(string $entityName, $entityId): int {
$total = 0;
foreach ((array) self::getRefCount($entityName, $entityId) as $ref) {
$total += $ref['count'] ?? 0;
}
return $total;
}

/**
* @return array
*/
Expand Down
30 changes: 30 additions & 0 deletions ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ public static function getFields($entityName, $params = []) {
}
$params['values']['state_province_id'] = \Civi::settings()->get('defaultContactStateProvince');
}
// Exclude LocBlock fields that will be replaced by joins (see below)
if ($params['action'] === 'create' && $entityName === 'LocBlock') {
$joinParams = $params;
// Omit the fk fields (email_id, email_2_id, phone_id, etc)
// As we'll add their joined fields below
$params['where'][] = ['fk_entity', 'IS NULL'];
}
$fields = (array) civicrm_api4($entityName, 'getFields', $params);
// Add implicit joins to search fields
if ($params['action'] === 'get') {
Expand All @@ -117,6 +124,29 @@ public static function getFields($entityName, $params = []) {
}
}
}
// Add LocBlock joins (e.g. `email_id.email`, `address_id.street_address`)
if ($params['action'] === 'create' && $entityName === 'LocBlock') {
// Exclude fields that don't apply to locBlocks
$joinParams['where'][] = ['name', 'NOT IN', ['id', 'is_primary', 'is_billing', 'location_type_id', 'contact_id']];
foreach (['Address', 'Email', 'Phone', 'IM'] as $joinEntity) {
$joinEntityFields = (array) civicrm_api4($joinEntity, 'getFields', $joinParams);
$joinEntityLabel = CoreUtil::getInfoItem($joinEntity, 'title');
// LocBlock entity includes every join twice (e.g. `email_2_id.email`, `address_2_id.street_address`)
foreach ([1 => '', 2 => '_2'] as $number => $suffix) {
$joinField = strtolower($joinEntity) . $suffix . '_id';
foreach ($joinEntityFields as $joinEntityField) {
if (strtolower($joinEntity) === $joinEntityField['name']) {
$joinEntityField['label'] .= " $number";
}
else {
$joinEntityField['label'] = "$joinEntityLabel $number {$joinEntityField['label']}";
}
$joinEntityField['name'] = "$joinField." . $joinEntityField['name'];
$fields[] = $joinEntityField;
}
}
}
}
// Index by name
$fields = array_column($fields, NULL, 'name');
$idField = CoreUtil::getIdFieldName($entityName);
Expand Down
5 changes: 5 additions & 0 deletions ext/afform/admin/afformEntities/LocBlock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php
return [
'type' => 'join',
'repeat_max' => 1,
];
12 changes: 7 additions & 5 deletions ext/afform/admin/ang/afGuiEditor/afGuiEntity.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,13 @@
}
item['af-join'] = block.join_entity;
item['#children'] = [{"#tag": directive}];
item['af-repeat'] = ts('Add');
item['af-copy'] = ts('Copy');
item.min = '1';
if (typeof joinEntity.repeat_max === 'number') {
item.max = '' + joinEntity.repeat_max;
if (joinEntity.repeat_max !== 1) {
item['af-repeat'] = ts('Add');
item['af-copy'] = ts('Copy');
item.min = '1';
if (typeof joinEntity.repeat_max === 'number') {
item.max = '' + joinEntity.repeat_max;
}
}
}
$scope.blockList.push(item);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
};

$scope.isRepeatable = function() {
return ctrl.join ||
return (ctrl.join && $scope.getRepeatMax() !== 1) ||
(block.directive && afGui.meta.blocks[block.directive].repeat) ||
(ctrl.node['af-fieldset'] && ctrl.editor.getEntityDefn(ctrl.editor.getEntity(ctrl.node['af-fieldset'])) !== false);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</select>
<button type="button" class="btn btn-default btn-xs" ng-if="block && !block.layout" ng-click="saveBlock()" title="{{:: ts('Save block') }}">{{:: ts('Save...') }}</button>
<div class="btn-group pull-right" title="">
<af-gui-container-multi-toggle ng-if="!ctrl.loading && ($ctrl.join || $ctrl.node['af-repeat'])" entity="$ctrl.getFieldEntityType()" class="btn-group"></af-gui-container-multi-toggle>
<af-gui-container-multi-toggle ng-if="!ctrl.loading && ($ctrl.join || $ctrl.node['af-repeat']) && isRepeatable()" entity="$ctrl.getFieldEntityType()" class="btn-group"></af-gui-container-multi-toggle>
<div class="btn-group" af-gui-menu>
<button type="button" class="btn btn-default btn-xs dropdown-toggle af-gui-add-element-button" data-toggle="dropdown" title="{{:: ts('Configure') }}">
<span><i class="crm-i fa-gear"></i></span>
Expand Down
10 changes: 7 additions & 3 deletions ext/afform/core/Civi/Afform/Behavior/ContactAutofill.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public static function onAfformPrefill(AfformPrefillEvent $event): void {
if (!$id && $autoFillMode === 'user' && !$event->getApiRequest()->getArgs()) {
$id = \CRM_Core_Session::getLoggedInContactID();
if ($id) {
$event->getApiRequest()->loadEntity($entity, [$id]);
$event->getApiRequest()->loadEntity($entity, [['id' => $id]]);
}
}
// Autofill by relationship
Expand All @@ -123,8 +123,12 @@ public static function onAfformPrefill(AfformPrefillEvent $event): void {
->addWhere('far_contact_id', '=', $relatedContact)
->addWhere('near_contact_id.is_deleted', '=', FALSE)
->addWhere('is_current', '=', TRUE)
->execute()->column('near_contact_id');
$event->getApiRequest()->loadEntity($entity, $relations);
->execute();
$relatedIds = [];
foreach ($relations as $relation) {
$relatedIds[] = ['id' => $relation['near_contact_id']];
}
$event->getApiRequest()->loadEntity($entity, $relatedIds);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion ext/afform/core/Civi/Afform/Behavior/GroupSubscription.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public static function onAfformPrefill(AfformPrefillEvent $event): void {
$cid = $event->getEntityIds($contact)[0] ?? NULL;
}
if ($cid) {
$event->getApiRequest()->loadEntity($subscriptionEntity, [$cid]);
$event->getApiRequest()->loadEntity($subscriptionEntity, [['contact_id' => $cid]]);
}
}

Expand Down
Loading

0 comments on commit b390236

Please sign in to comment.