Uploaded image for project: 'CiviCRM'
  1. CiviCRM
  2. CRM-5516

Editing a contact while using hook_civicrm_customFieldOptions causes silent data destruction

    Details

    • Type: Bug
    • Status: Done/Fixed
    • Priority: Critical
    • Resolution: Fixed/Completed
    • Affects Version/s: 2.2.9
    • Fix Version/s: 3.0.3
    • Component/s: CiviCRM API, Core CiviCRM
    • Labels:
      None

      Description

      (The following has been observed in CiviCRM 2.2.8. The issue is closely tied to the implementation of CRM_Core_BAO_CustomOption::getCustomOption. This code appears the same in 2.2.8 and trunk (r25452), so newer releases are probably affected.)

      hook_civicrm_customFieldOptions allows third-party developers to programmaticly populate the list of options in a select, multi-select, or similar custom data field. The documentation specifies the contract:

      hook_civicrm_customFieldOptions($fieldID, &$options)

      Although this doesn't indicate the format of $options, a developer can use standard debugging techniques and quickly observe that $options follows an "obvious" format – array keys are codes, and array values are printable labels, e.g.

      function mymodule_civicrm_customFieldOptions($fieldID, &$options) {
      if ($fieldID == 123)

      { $options['0000ff'] = ts('Blue'); $options['00ff00'] = ts('Green'); }

      }

      Proceeding with this format of $options, a developer can implement the hook so that it appears to function correctly. For example, "civicrm/contact/add" will display the right options in field #123 and (upon submission) it will store selections for field #123 in the appropriate database record. "civicrm/contact/view" will then display the correct selections for field #123.

      However, if a user edits an existing contact with "civicrm/contact/add", the previous selection for field #123 is not restored. When the user submits, he unwittingly erases the selection from the database.

      I believe the problem is in CRM_Core_BAO_CustomOption::getCustomOption. getCustomOption() expects a different, undocumented contract for hook_civicrm_customFieldOptions, and an "obvious" hook implementation (above) will corrupt $options. A quick read of getCustomOption() suggests the following implementation would comply with the undocumented contract:

      function mymodule_civicrm_customFieldOptions($fieldID, &$options, $frobnicate = FALSE ) {
      if ($fieldID == 123) {
      if ($frobnicate)

      { $options[0] = array('id' => 0, 'value' => '0000ff', 'label' => ts('Blue')); $options[1] = array('id' => 1, 'value' => '00ff00', 'label' => ts('Green')); }

      else

      { $options['0000ff'] = ts('Blue'); $options['00ff00'] = ts('Green'); }

      }
      }

      However, this is unlikely to work because CRM_Utils_Hook::customFieldOptions() does not pass along the $frobnicate parameter.

        Attachments

          Activity

            People

            • Assignee:
              lobo Donald A. Lobo
              Reporter:
              timotten Tim Otten
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: