From: Olaf Buddenhagen Date: Thu, 5 Mar 2015 23:43:18 +0000 (+0100) Subject: Make "Chain Select" mechanism robust against missing 'target' form field X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=a3984622f10655af382c6c56050d5178a26683f2;p=civicrm-core.git Make "Chain Select" mechanism robust against missing 'target' form field If removeElement() was invoked on an element that is the 'target' of a 'chainSelect' (which can happen through a form hook in an extension), the chainSelect handling code was subsequently erroring out. Add checks to avoid that. This is related to the CRM-15476 fixes in 8f9c3cbea992320f344d576c8a87c5bab318466c and 14b2ff1521a8c25e363b13723c2979f52ad1cd47 , which already fixed the situation where the 'control' element is missing. --- diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php index fd0ad0d96a..47303ba3b4 100644 --- a/CRM/Core/Form.php +++ b/CRM/Core/Form.php @@ -1768,42 +1768,45 @@ class CRM_Core_Form extends HTML_QuickForm_Page { */ private function preProcessChainSelectFields() { foreach ($this->_chainSelectFields as $control => $target) { - $targetField = $this->getElement($target); - $targetType = $targetField->getAttribute('data-callback') == 'civicrm/ajax/jqCounty' ? 'county' : 'stateProvince'; - $options = array(); - // If the control field is on the form, setup chain-select and dynamically populate options - if ($this->elementExists($control)) { - $controlField = $this->getElement($control); - $controlType = $targetType == 'county' ? 'stateProvince' : 'country'; - - $targetField->setAttribute('class', $targetField->getAttribute('class') . ' crm-chain-select-target'); - - $css = (string) $controlField->getAttribute('class'); - $controlField->updateAttributes(array( - 'class' => ($css ? "$css " : 'crm-select2 ') . 'crm-chain-select-control', - 'data-target' => $target, - )); - $controlValue = $controlField->getValue(); - if ($controlValue) { - $options = CRM_Core_BAO_Location::getChainSelectValues($controlValue, $controlType, TRUE); - if (!$options) { - $targetField->setAttribute('placeholder', $targetField->getAttribute('data-none-prompt')); + // The 'target' might get missing if extensions do removeElement() in a form hook. + if ($this->elementExists($target)) { + $targetField = $this->getElement($target); + $targetType = $targetField->getAttribute('data-callback') == 'civicrm/ajax/jqCounty' ? 'county' : 'stateProvince'; + $options = array(); + // If the control field is on the form, setup chain-select and dynamically populate options + if ($this->elementExists($control)) { + $controlField = $this->getElement($control); + $controlType = $targetType == 'county' ? 'stateProvince' : 'country'; + + $targetField->setAttribute('class', $targetField->getAttribute('class') . ' crm-chain-select-target'); + + $css = (string) $controlField->getAttribute('class'); + $controlField->updateAttributes(array( + 'class' => ($css ? "$css " : 'crm-select2 ') . 'crm-chain-select-control', + 'data-target' => $target, + )); + $controlValue = $controlField->getValue(); + if ($controlValue) { + $options = CRM_Core_BAO_Location::getChainSelectValues($controlValue, $controlType, TRUE); + if (!$options) { + $targetField->setAttribute('placeholder', $targetField->getAttribute('data-none-prompt')); + } + } else { + $targetField->setAttribute('placeholder', $targetField->getAttribute('data-empty-prompt')); + $targetField->setAttribute('disabled', 'disabled'); } - } else { - $targetField->setAttribute('placeholder', $targetField->getAttribute('data-empty-prompt')); - $targetField->setAttribute('disabled', 'disabled'); } + // Control field not present - fall back to loading default options + else { + $options = CRM_Core_PseudoConstant::$targetType(); + } + if (!$targetField->getAttribute('multiple')) { + $options = array('' => $targetField->getAttribute('placeholder')) + $options; + $targetField->removeAttribute('placeholder'); + } + $targetField->_options = array(); + $targetField->loadArray($options); } - // Control field not present - fall back to loading default options - else { - $options = CRM_Core_PseudoConstant::$targetType(); - } - if (!$targetField->getAttribute('multiple')) { - $options = array('' => $targetField->getAttribute('placeholder')) + $options; - $targetField->removeAttribute('placeholder'); - } - $targetField->_options = array(); - $targetField->loadArray($options); } } @@ -1812,7 +1815,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page { */ private function validateChainSelectFields() { foreach ($this->_chainSelectFields as $control => $target) { - if ($this->elementExists($control)) { + if ($this->elementExists($control) && $this->elementExists($target)) { $controlValue = (array)$this->getElementValue($control); $targetField = $this->getElement($target); $controlType = $targetField->getAttribute('data-callback') == 'civicrm/ajax/jqCounty' ? 'stateProvince' : 'country';