Merge pull request #5967 from colemanw/CRM-16632
[civicrm-core.git] / CRM / Core / Form.php
index b68f8fef6505e6c6e93a8ab598f7d646cedfa17e..76cc6ba2d1047fb2ab5c8114dcc5993c4d12ae4a 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 4.6                                                |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2014                                |
+ | Copyright CiviCRM LLC (c) 2004-2015                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
@@ -31,7 +31,7 @@
  * machine. Each form can also operate in various modes
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2014
+ * @copyright CiviCRM LLC (c) 2004-2015
  * $Id$
  *
  */
@@ -152,7 +152,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   private $_chainSelectFields = array();
 
   /**
-   * Constructor for the basic form page
+   * Constructor for the basic form page.
    *
    * We should not use QuickForm directly. This class provides a lot
    * of default convenient functions, rules and buttons
@@ -215,7 +215,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Register all the standard rules that most forms potentially use
+   * Register all the standard rules that most forms potentially use.
    *
    * @return void
    */
@@ -361,7 +361,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * The postProcess hook is typically called by the framework
+   * The postProcess hook is typically called by the framework.
    * However in a few cases, the form exits or redirects early in which
    * case it needs to call this function so other modules can do the needful
    * Calling this function directly should be avoided if possible. In general a
@@ -407,7 +407,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Performs the server side validation
+   * Performs the server side validation.
    * @since     1.0
    * @return bool
    *   true if no error found
@@ -515,6 +515,10 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
     foreach ($params as $button) {
       $attrs = array('class' => 'crm-form-submit') + (array) CRM_Utils_Array::value('js', $button);
 
+      if (!empty($button['class'])) {
+        $attrs['class'] .= ' ' . $button['class'];
+      }
+
       if (!empty($button['isDefault'])) {
         $attrs['class'] .= ' default';
       }
@@ -571,7 +575,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Getter function for Name
+   * Getter function for Name.
    *
    * @return string
    */
@@ -580,7 +584,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Getter function for State
+   * Getter function for State.
    *
    * @return object
    */
@@ -589,7 +593,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Getter function for StateType
+   * Getter function for StateType.
    *
    * @return int
    */
@@ -619,7 +623,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Setter function for options
+   * Setter function for options.
    *
    * @param mixed $options
    *
@@ -642,7 +646,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Boolean function to determine if this is a one form page
+   * Boolean function to determine if this is a one form page.
    *
    * @return bool
    */
@@ -651,7 +655,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Getter function for Form Action
+   * Getter function for Form Action.
    *
    * @return string
    */
@@ -660,7 +664,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Setter function for Form Action
+   * Setter function for Form Action.
    *
    * @param string $action
    *
@@ -671,7 +675,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Render form and return contents
+   * Render form and return contents.
    *
    * @return string
    */
@@ -700,7 +704,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Use the form name to create the tpl file name
+   * Use the form name to create the tpl file name.
    *
    * @return string
    */
@@ -711,10 +715,13 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
       $tplname = $ext->getTemplatePath(CRM_Utils_System::getClassName($this)) . DIRECTORY_SEPARATOR . $filename;
     }
     else {
-      $tplname = str_replace('_',
-          DIRECTORY_SEPARATOR,
-          CRM_Utils_System::getClassName($this)
-        ) . '.tpl';
+      $tplname = strtr(
+        CRM_Utils_System::getClassName($this),
+        array(
+          '_' => DIRECTORY_SEPARATOR,
+          '\\' => DIRECTORY_SEPARATOR,
+        )
+      ) . '.tpl';
     }
     return $tplname;
   }
@@ -740,7 +747,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Error reporting mechanism
+   * Error reporting mechanism.
    *
    * @param string $message
    *   Error Message.
@@ -762,7 +769,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Store the variable with the value in the form scope
+   * Store the variable with the value in the form scope.
    *
    * @param string $name
    *   Name of the variable.
@@ -776,7 +783,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Get the variable from the form scope
+   * Get the variable from the form scope.
    *
    * @param string $name
    *   Name of the variable
@@ -788,7 +795,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Getter for action
+   * Getter for action.
    *
    * @return int
    */
@@ -797,7 +804,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Setter for action
+   * Setter for action.
    *
    * @param int $action
    *   The mode we want to set the form.
@@ -809,7 +816,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Assign value to name in template
+   * Assign value to name in template.
    *
    * @param string $var
    *   Name of variable.
@@ -823,7 +830,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Assign value to name in template by reference
+   * Assign value to name in template by reference.
    *
    * @param string $var
    *   Name of variable.
@@ -837,7 +844,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Appends values to template variables
+   * Appends values to template variables.
    *
    * @param array|string $tpl_var the template variable name(s)
    * @param mixed $value
@@ -849,7 +856,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Returns an array containing template variables
+   * Returns an array containing template variables.
    *
    * @param string $name
    *
@@ -874,7 +881,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
     $attributes = $attributes ? $attributes : array();
     $allowClear = !empty($attributes['allowClear']);
     unset($attributes['allowClear']);
-    $attributes += array('id_suffix' => $name);
+    $attributes['id_suffix'] = $name;
     foreach ($values as $key => $var) {
       $options[] = $this->createElement('radio', NULL, NULL, $var, $key, $attributes);
     }
@@ -1025,7 +1032,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Adds a select based on field metadata
+   * Adds a select based on field metadata.
    * TODO: This could be even more generic and widget type (select in this case) could also be read from metadata
    * Perhaps a method like $form->bind($name) which would look up all metadata for named field
    * @param $name
@@ -1278,7 +1285,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Add date
+   * Add date.
    *
    * @code
    * // if you need time
@@ -1376,7 +1383,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   *  Function that will add date and time
+   *  Function that will add date and time.
    */
   public function addDateTime($name, $label, $required = FALSE, $attributes = NULL) {
     $addTime = array('addTime' => TRUE);
@@ -1391,7 +1398,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Add a currency and money element to the form
+   * Add a currency and money element to the form.
    */
   public function addMoney(
     $name,
@@ -1414,7 +1421,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Add currency element to the form
+   * Add currency element to the form.
    */
   public function addCurrency(
     $name = 'currency',
@@ -1441,7 +1448,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Create a single or multiple entity ref field
+   * Create a single or multiple entity ref field.
    * @param string $name
    * @param string $label
    * @param array $props
@@ -1545,14 +1552,14 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Function that can be defined in Form to override or
+   * Function that can be defined in Form to override or.
    * perform specific action on cancel action
    */
   public function cancelAction() {
   }
 
   /**
-   * Helper function to verify that required fields have been filled
+   * Helper function to verify that required fields have been filled.
    * Typically called within the scope of a FormRule function
    */
   public static function validateMandatoryFields($fields, $values, &$errors) {
@@ -1591,13 +1598,13 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
       // from that page
       // we don't really need to set it when $tempID is set because the params have that stored
       $this->set('cid', 0);
-      return $tempID;
+      return (int) $tempID;
     }
 
     $userID = $this->getLoggedInUserContactID();
 
-    if ($tempID == $userID) {
-      return $userID;
+    if (!is_null($tempID) && $tempID === $userID) {
+      return (int) $userID;
     }
 
     //check if this is a checksum authentication
@@ -1614,11 +1621,11 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
       return $tempID;
     }
 
-    return $userID;
+    return is_numeric($userID) ? $userID : NULL;
   }
 
   /**
-   * Get the contact id of the logged in user
+   * Get the contact id of the logged in user.
    */
   public function getLoggedInUserContactID() {
     // check if the user is logged in and has a contact ID
@@ -1689,6 +1696,8 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
    * that small pieces of duplication are not being refactored into separate functions because their only shared parent
    * is this form. Inserting a class FrontEndForm.php between the contribution & event & this class would allow functions like this
    * and a dozen other small ones to be refactored into a shared parent with the reduction of much code duplication
+   *
+   * @param $onlinePaymentProcessorEnabled
    */
   public function addCIDZeroOptions($onlinePaymentProcessorEnabled) {
     $this->assign('nocid', TRUE);
@@ -1732,7 +1741,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Sets form attribute
+   * Sets form attribute.
    * @see CRM.loadForm
    */
   public function preventAjaxSubmit() {
@@ -1740,7 +1749,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Sets form attribute
+   * Sets form attribute.
    * @see CRM.loadForm
    */
   public function allowAjaxSubmit() {
@@ -1748,7 +1757,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
   }
 
   /**
-   * Sets page title based on entity and action
+   * Sets page title based on entity and action.
    * @param string $entityLabel
    */
   public function setPageTitle($entityLabel) {
@@ -1815,43 +1824,46 @@ 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');
           }
         }
+        // Control field not present - fall back to loading default options
         else {
-          $targetField->setAttribute('placeholder', $targetField->getAttribute('data-empty-prompt'));
-          $targetField->setAttribute('disabled', 'disabled');
+          $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);
     }
   }
 
@@ -1860,7 +1872,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';