Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Honor submitted cid value in existing_contact #991

Open
wants to merge 3 commits into
base: 6.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions js/webform_civicrm_contact.js
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With an existing_contact Select widget, locked fields were not actually locked.

Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@
searchingText: "Searching...",
enableHTML: true
};
wfCivi.existingInit(
field,
field.data('civicrm-contact'),
field.data('form-id'),
autocompleteUrl,
toHide,
tokenValues
);
}
else {
var tokenValues = false;
}

wfCivi.existingInit(
field,
field.data('civicrm-contact'),
field.data('form-id'),
autocompleteUrl,
toHide,
tokenValues
);

field.change(function () {
wfCivi.existingSelect(
Expand Down
23 changes: 20 additions & 3 deletions src/WebformCivicrmBase.php
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • $editingSubmission changed to $submission_id to avoid obscuring its actual meaning.
  • Exception -> \Exception: An obvious bug since there is no Exception function in the Drupal\webform_civicrm namespace. Interestingly, this bug caused xdebug in VS Code to crash whenever hovering over a member function (was driving me crazy for a long time).
  • Corrects handling of "-" in existing_contact value (indicating "Create New" was selected".

Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ abstract class WebformCivicrmBase {
protected $line_items = [];
protected $membership_types = [];
protected $loadedContacts = [];
protected $editingSubmission;
protected $submission_id;

// No direct access - storage for variables fetched via __get
private $_payment_processor;
Expand Down Expand Up @@ -75,7 +75,7 @@ function __get($name) {
return \CRM_Utils_System::version();

default:
throw new Exception('Unknown property');
throw new \Exception('Unknown property');
}
}

Expand Down Expand Up @@ -255,12 +255,29 @@ protected function loadContact($c, $exclude = []) {
* @param array $component
* Webform component of type 'civicrm_contact'
*/
protected function findContact($component) {
protected function findContact($component, $cid_submitted_value = null) {
$contactComponent = \Drupal::service('webform_civicrm.contact_component');
$component['#form_key'] = $component['#form_key'] ?? $component['#webform_key'];

list(, $c,) = explode('_', $component['#form_key'], 3);
$filters = $contactComponent->wf_crm_search_filters($this->node, $component);

// If we have a submitted value for the existing contact then no need to
// examine the URL params or default settings.
if (!is_null($cid_submitted_value)) {
if ($this->utils->wf_crm_is_positive($cid_submitted_value)
&& !empty($this->enabled[$component['#form_key']])
&& $contactComponent->wf_crm_contact_access($component, $filters, $cid_submitted_value) != FALSE) {
$this->ent['contact'][$c]['id'] = $cid_submitted_value;
}
else {
// We arrive here if an existing_contact field is blank or set to
// "Create New" ($cid_submitted_value starts with "-").
$this->ent['contact'][$c]['id'] = 0;
}
return;
}

// Start with the url - that trumps everything.
$element_manager = \Drupal::getContainer()->get('plugin.manager.webform.element');
$existing_component_plugin = $element_manager->getElementInstance($component);
Expand Down
56 changes: 32 additions & 24 deletions src/WebformCivicrmPostProcess.php
Copy link
Contributor Author

@bsilvern bsilvern Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • isFieldHiddenByExistingContactSettings() was operating on stale data so added call to $this->getExistingContactIds();
  • Worked around array-to-string conversion warning on submission of a draft.
  • Moved up call to $this->fillDataFromSubmission() so that it is executed prior to saving a draft (stale data was being saved previously).
  • unsetError($name) was throwing an exception. I think this is old Drupal7 code. Deleted that function and added code to validate() to delete the unwanted errors.

Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,36 @@ public function validate($form, FormStateInterface $form_state) {
// Even though this object is destroyed between page submissions, this trick allows us to persist some data - see below
$this->ent = $form_state->get(['civicrm', 'ent']) ?: $this->ent;

$this->getExistingContactIds();

$errors = $this->form_state->getErrors();
foreach ($errors as $key => $error) {
$pieces = $this->utils->wf_crm_explode_key(substr($key, strrpos($key, '][') + 2));
$bracket_pos = strrpos($key, '][');
$pieces = $this->utils->wf_crm_explode_key($bracket_pos === false ? $key : substr($key, $bracket_pos + 2));
if ($pieces) {
[ , $c, $ent, $n, $table, $name] = $pieces;
if ($this->isFieldHiddenByExistingContactSettings($ent, $c, $table, $n, $name)) {
$this->unsetError($key);
$errors_to_clear[$key] = 1;
}
elseif ($table === 'address' && !empty($this->crmValues["civicrm_{$c}_contact_{$n}_address_master_id"])) {
$master_id = $this->crmValues["civicrm_{$c}_contact_{$n}_address_master_id"];
// If widget is checkboxes, need to filter the array
if (!is_array($master_id) || array_filter($master_id)) {
$this->unsetError($key);
$errors_to_clear[$key] = 1;
}
}
}
}

// Clear the unwanted errors
if (!empty($errors_to_clear)) {
$this->form_state->clearErrors();
$errors = array_diff_key($errors, $errors_to_clear);
foreach ($errors as $name => $error_message) {
$this->form_state->setErrorByName($name, $error_message);
}
}

$this->validateThisPage($this->form);

if (!empty($this->data['participant']) && !empty($this->data['participant_reg_type'])) {
Expand Down Expand Up @@ -192,12 +204,28 @@ public function preSave(WebformSubmissionInterface $webform_submission) {
// Fill $this->id from existing contacts
$this->getExistingContactIds();

$this->fillDataFromSubmission();

// If we've loaded a draft, then performing a subsequent Submit or Save
// Draft throws an array-to-string conversion warning in
// Drupal\webform\WebformSubmissionStorage::saveData() caused by
// $webform_submission->data['civicrm'] as arrays are not supported in
// submission data, and the array gets stored simply as the string "Array".
// Deleting the 'civicrm' array has risk as it's not clear if it's used
// later in preSave or in postSave. Safest solution to supress the warning
// is to mark the field as 'webform_computed_twig' so that it won't be
// saved, but will persist in the submission->data array for possible use
// later in this request. The array will not actually be evaluated as a
// twig template as the element has no '#template' property.
if (!empty($webform_submission->getData()['civicrm'])) {
$webform_submission->getWebform()->setElementProperties('civicrm', ['#type' => 'webform_computed_twig']);
}

// While saving a draft, just skip to postSave and write the record
if ($this->submission->isDraft()) {
return;
}

$this->fillDataFromSubmission();
//Fill Custom Contact reference fields.
$this->fillContactRefs(TRUE);

Expand Down Expand Up @@ -2650,26 +2678,6 @@ private function locationIsEmpty($location, $params) {
}
}

/**
* Clears an error against a form element.
* Used to disable validation when this module hides a field
* @see https://api.drupal.org/comment/49163#comment-49163
*
* @param $name string
*/
private function unsetError($name) {
$errors = &drupal_static('form_set_error', []);
$removed_messages = [];
if (isset($errors[$name])) {
$removed_messages[] = $errors[$name];
unset($errors[$name]);
}
$_SESSION['messages']['error'] = array_diff($_SESSION['messages']['error'], $removed_messages);
if (empty($_SESSION['messages']['error'])) {
unset($_SESSION['messages']['error']);
}
}

/**
* Get or set a value from a webform submission
* Always use \Drupal\webform\WebformSubmissionInterface $webform_submission [more reliable according to JR]
Expand Down
Loading
Loading