From cfff80b56ecada03362240656f67b91cd38b08c7 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Wed, 20 Dec 2023 17:35:38 +1300 Subject: [PATCH 1/2] Simplify custom field handling, back office forms --- CRM/Core/BAO/CustomGroup.php | 9 +-- CRM/Core/Form.php | 17 ++++++ CRM/Custom/Form/CustomDataTrait.php | 91 +++++++++++++++++++++++++++++ CRM/Event/Form/Participant.php | 59 +++++++------------ 4 files changed, 131 insertions(+), 45 deletions(-) diff --git a/CRM/Core/BAO/CustomGroup.php b/CRM/Core/BAO/CustomGroup.php index 6064bc262ee1..5a9825bbdb8e 100644 --- a/CRM/Core/BAO/CustomGroup.php +++ b/CRM/Core/BAO/CustomGroup.php @@ -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; diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php index fcab41b3c243..96acca57f6d5 100644 --- a/CRM/Core/Form.php +++ b/CRM/Core/Form.php @@ -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. * diff --git a/CRM/Custom/Form/CustomDataTrait.php b/CRM/Custom/Form/CustomDataTrait.php index b3d9bbc7f371..857de0725d30 100644 --- a/CRM/Custom/Form/CustomDataTrait.php +++ b/CRM/Custom/Form/CustomDataTrait.php @@ -1 +1,92 @@ 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'], + ], + '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]); + } + } + } + +} diff --git a/CRM/Event/Form/Participant.php b/CRM/Event/Form/Participant.php index a95e3159eba7..cc53457a3ba0 100644 --- a/CRM/Event/Form/Participant.php +++ b/CRM/Event/Form/Participant.php @@ -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. @@ -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; } /** @@ -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)) { @@ -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'); From 23e8c5cfd6d0ecba6e57a3c1a088d04049af1b29 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Sun, 4 Feb 2024 10:15:00 +1300 Subject: [PATCH 2/2] Update CRM/Custom/Form/CustomDataTrait.php Co-authored-by: colemanw --- CRM/Custom/Form/CustomDataTrait.php | 1 + 1 file changed, 1 insertion(+) diff --git a/CRM/Custom/Form/CustomDataTrait.php b/CRM/Custom/Form/CustomDataTrait.php index 857de0725d30..fa5ca96fe5f1 100644 --- a/CRM/Custom/Form/CustomDataTrait.php +++ b/CRM/Custom/Form/CustomDataTrait.php @@ -47,6 +47,7 @@ protected function addCustomDataFieldsToForm(string $entity, array $filters = [] 'values' => $filters, 'where' => [ ['type', '=', 'Custom'], + ['readonly', '=', FALSE], ], 'checkPermissions' => TRUE, ])->indexBy('custom_field_id');