Skip to content

Commit

Permalink
Merge pull request #28733 from eileenmcnaughton/group_count
Browse files Browse the repository at this point in the history
Clean up  code to add custom data to forms, implement on back office participant form
  • Loading branch information
colemanw authored Feb 4, 2024
2 parents c6236c3 + 23e8c5c commit 083c231
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 45 deletions.
9 changes: 1 addition & 8 deletions CRM/Core/BAO/CustomGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -1700,14 +1700,7 @@ public static function formatGroupTree($groupTree, $groupCount = 1, &$form = NUL
$form->assign('qfKey', $qf);
Civi::cache('customData')->set($qf, $formValues);
}

// hack for field type File
$formUploadNames = $form->get('uploadNames');
if (is_array($formUploadNames)) {
$uploadNames = array_unique(array_merge($formUploadNames, $uploadNames));
}

$form->set('uploadNames', $uploadNames);
$form->registerFileField($uploadNames);
}

return $formattedGroupTree;
Expand Down
17 changes: 17 additions & 0 deletions CRM/Core/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,23 @@ public function postProcessHook() {
CRM_Utils_Hook::postProcess(get_class($this), $this);
}

/**
* Register a field with quick form as supporting a file upload.
*
* @param array $fieldNames
*
* @return void
*/
public function registerFileField(array $fieldNames): void {
// hack for field type File
$formUploadNames = $this->get('uploadNames');
if (is_array($formUploadNames)) {
$fieldNames = array_unique(array_merge($formUploadNames, $fieldNames));
}

$this->set('uploadNames', $fieldNames);
}

/**
* This virtual function is used to build the form.
*
Expand Down
92 changes: 92 additions & 0 deletions CRM/Custom/Form/CustomDataTrait.php
Original file line number Diff line number Diff line change
@@ -1 +1,93 @@
<?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 |
+--------------------------------------------------------------------+
*/

/**
*
* @package CRM
* @copyright CiviCRM LLC https://civicrm.org/licensing
*/

/**
* This trait supports adding custom data to forms.
*
* @internal
*/
trait CRM_Custom_Form_CustomDataTrait {

/**
* Add custom data fields to the form.
*
* This function takes responsibility for registering the appropriate fields with QuickForm.
*
* It does not assign variables to the smarty layer to assist with rendering or setDefaults.
* Those additional steps are not required on the 'main form' when the CustomDataForm is
* being rendered by ajax as that process takes care of the presentation.
*
* However, the fields need to be registered with QuickForm to ensure that on submit
* they are 'accepted' by quick form. Quick form validates the contents of $_POST
* and only fields that have been registered make it through to the values
* available in `$form->getSubmittedValues()`.
*
* @param string $entity
* @param array $filters
*
* @throws \CRM_Core_Exception
*/
protected function addCustomDataFieldsToForm(string $entity, array $filters = []): void {
$fields = civicrm_api4($entity, 'getFields', [
'action' => 'create',
'values' => $filters,
'where' => [
['type', '=', 'Custom'],
['readonly', '=', FALSE],
],
'checkPermissions' => TRUE,
])->indexBy('custom_field_id');

$customGroupSuffixes = [];
foreach ($fields as $field) {
// This default suffix indicates the contact has no existing row in the table.
// It will be overridden below with the id of any row the contact DOES have in the table.
$customGroupSuffixes[$field['table_name']] = '_-1';
}
if (!empty($filters['id'])) {
$query = [];
foreach (array_keys($customGroupSuffixes) as $tableName) {
$query[] = CRM_Core_DAO::composeQuery(
'SELECT %1 as table_name, id FROM %2 WHERE entity_id = %3',
[
1 => [$tableName, 'String'],
2 => [$tableName, 'MysqlColumnNameOrAlias'],
3 => [$filters['id'], 'Integer'],
]
);
}
$tables = CRM_Core_DAO::executeQuery(implode(' UNION ', $query));
while ($tables->fetch()) {
$customGroupSuffixes[$tables->table_name] = '_' . $tables->id;
}
}

foreach ($fields as $field) {
$suffix = $customGroupSuffixes[$field['table_name']];
$elementName = 'custom_' . $field['custom_field_id'] . $suffix;
// Note that passing required = TRUE here does not seem to actually do anything. As long
// as the form opens in pop up mode jquery validation from the ajax form ensures required fields are
// submitted. In non-popup mode however the required is not enforced. This appears to be
// a bug that has been around for a while.
CRM_Core_BAO_CustomField::addQuickFormElement($this, $elementName, $field['custom_field_id'], $field['required']);
if ($field['input_type'] === 'File') {
$this->registerFileField([$elementName]);
}
}
}

}
59 changes: 22 additions & 37 deletions CRM/Event/Form/Participant.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
use EntityLookupTrait;
use CRM_Contact_Form_ContactFormTrait;
use CRM_Event_Form_EventFormTrait;
use CRM_Custom_Form_CustomDataTrait;

/**
* Participant ID - use getParticipantID.
Expand Down Expand Up @@ -211,7 +212,15 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
* @return int|null
*/
public function getEventID(): ?int {
return $this->_eventId ?: ($this->getSubmittedValue('event_id') ? (int) $this->getSubmittedValue('event_id') : NULL);
if (!$this->_eventId) {
if ($this->isFormBuilt()) {
$this->_eventId = $this->getSubmittedValue('event_id');
}
else {
$this->_eventId = $this->getSubmitValue('event_id');
}
}
return $this->_eventId ? (int) $this->_eventId : NULL;
}

/**
Expand Down Expand Up @@ -339,42 +348,6 @@ public function preProcess() {
CRM_Event_Form_EventFees::setDefaultValues($this);
}

// when custom data is included in this page
if (!empty($_POST['hidden_custom'])) {
$eventId = (int) ($_POST['event_id'] ?? 0);
// Custom data of type participant role
// Note: Some earlier commits imply $_POST['role_id'] could be a comma separated string,
// not sure if that ever really happens
if (!empty($_POST['role_id'])) {
foreach ($_POST['role_id'] as $roleID) {
CRM_Custom_Form_CustomData::preProcess($this, $this->getExtendsEntityColumnID('ParticipantRole'), $roleID, 1, 'Participant', $this->_id);
CRM_Custom_Form_CustomData::buildQuickForm($this);
CRM_Custom_Form_CustomData::setDefaultValues($this);
}
}

//custom data of type participant event
CRM_Custom_Form_CustomData::preProcess($this, $this->getExtendsEntityColumnID('ParticipantEventType'), $eventId, 1, 'Participant', $this->_id);
CRM_Custom_Form_CustomData::buildQuickForm($this);
CRM_Custom_Form_CustomData::setDefaultValues($this);

// custom data of type participant event type
$eventTypeId = NULL;
if ($eventId) {
$eventTypeId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $eventId, 'event_type_id', 'id');
}
CRM_Custom_Form_CustomData::preProcess($this, $this->getExtendsEntityColumnID('ParticipantEventType'), $eventTypeId,
1, 'Participant', $this->_id
);
CRM_Custom_Form_CustomData::buildQuickForm($this);
CRM_Custom_Form_CustomData::setDefaultValues($this);

//custom data of type participant, ( we 'null' to reset subType and subName)
CRM_Custom_Form_CustomData::preProcess($this, 'null', 'null', 1, 'Participant', $this->_id);
CRM_Custom_Form_CustomData::buildQuickForm($this);
CRM_Custom_Form_CustomData::setDefaultValues($this);
}

// CRM-4395, get the online pending contribution id.
$this->_onlinePendingContributionId = NULL;
if (!$this->_mode && $this->_id && ($this->_action & CRM_Core_Action::UPDATE)) {
Expand Down Expand Up @@ -580,6 +553,18 @@ public function buildQuickForm() {
return $this->buildEventFeeForm($this);
}

if ($this->isSubmitted()) {
// The custom data fields are added to the form by an ajax form.
// However, if they are not present in the element index they will
// not be available from `$this->getSubmittedValue()` in post process.
// We do not have to set defaults or otherwise render - just add to the element index.
$this->addCustomDataFieldsToForm('Participant', array_filter([
'event_id' => $this->getEventID(),
'role_id' => $_POST['role_id'] ?? NULL,
'id' => $this->getParticipantID(),
]));
}

//need to assign custom data type to the template
$this->assign('customDataType', 'Participant');

Expand Down

0 comments on commit 083c231

Please sign in to comment.