3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 * This is our base form. It is part of the Form/Controller/StateMachine
30 * trifecta. Each form is associated with a specific state in the state
31 * machine. Each form can also operate in various modes
34 * @copyright CiviCRM LLC (c) 2004-2013
39 require_once 'HTML/QuickForm/Page.php';
40 class CRM_Core_Form
extends HTML_QuickForm_Page
{
43 * The state object that this form belongs to
49 * The name of this form
55 * The title of this form
58 protected $_title = NULL;
61 * The options passed into this form
64 protected $_options = NULL;
67 * The mode of operation for this form
73 * the renderer used for this form
80 * cache the smarty template for efficiency reasons
82 * @var CRM_Core_Smarty
84 static protected $_template;
87 * constants for attributes for various form elements
88 * attempt to standardize on the number of variations that we
89 * use of the below form elements
93 CONST ATTR_SPACING
= ' ';
96 * All checkboxes are defined with a common prefix. This allows us to
97 * have the same javascript to check / clear all the checkboxes etc
98 * If u have multiple groups of checkboxes, you will need to give them different
99 * ids to avoid potential name collision
101 * @var const string / int
103 CONST CB_PREFIX
= 'mark_x_', CB_PREFIY
= 'mark_y_', CB_PREFIZ
= 'mark_z_', CB_PREFIX_LEN
= 7;
106 * Constructor for the basic form page
108 * We should not use QuickForm directly. This class provides a lot
109 * of default convenient functions, rules and buttons
111 * @param object $state State associated with this form
112 * @param enum $action The mode the form is operating in (None/Create/View/Update/Delete)
113 * @param string $method The type of http method used (GET/POST)
114 * @param string $name The name of the form if different from class name
119 function __construct(
121 $action = CRM_Core_Action
::NONE
,
127 $this->_name
= $name;
130 $this->_name
= CRM_Utils_String
::getClassName(CRM_Utils_System
::getClassName($this));
133 $this->HTML_QuickForm_Page($this->_name
, $method);
135 $this->_state
=& $state;
137 $this->_state
->setName($this->_name
);
139 $this->_action
= (int) $action;
141 $this->registerRules();
143 // let the constructor initialize this, should happen only once
144 if (!isset(self
::$_template)) {
145 self
::$_template = CRM_Core_Smarty
::singleton();
149 static function generateID() {
153 * register all the standard rules that most forms potentially use
159 function registerRules() {
160 static $rules = array(
161 'title', 'longTitle', 'variable', 'qfVariable',
162 'phone', 'integer', 'query',
164 'domain', 'numberOfDigit',
165 'date', 'currentDate',
166 'asciiFile', 'htmlFile', 'utf8File',
167 'objectExists', 'optionExists', 'postalCode', 'money', 'positiveInteger',
168 'xssString', 'fileExists', 'autocomplete', 'validContact',
171 foreach ($rules as $rule) {
172 $this->registerRule($rule, 'callback', $rule, 'CRM_Utils_Rule');
177 * Simple easy to use wrapper around addElement. Deal with
178 * simple validation rules
180 * @param string type of html element to be added
181 * @param string name of the html element
182 * @param string display label for the html element
183 * @param string attributes used for this element.
184 * These are not default values
185 * @param bool is this a required field
187 * @return object html element, could be an error object
191 function &add($type, $name, $label = '',
192 $attributes = '', $required = FALSE, $javascript = NULL
194 $element = $this->addElement($type, $name, $label, $attributes, $javascript);
195 if (HTML_QuickForm
::isError($element)) {
196 CRM_Core_Error
::fatal(HTML_QuickForm
::errorMessage($element));
200 if ($type == 'file') {
201 $error = $this->addRule($name, ts('%1 is a required field.', array(1 => $label)), 'uploadedfile');
204 $error = $this->addRule($name, ts('%1 is a required field.', array(1 => $label)), 'required');
206 if (HTML_QuickForm
::isError($error)) {
207 CRM_Core_Error
::fatal(HTML_QuickForm
::errorMessage($element));
215 * This function is called before buildForm. Any pre-processing that
216 * needs to be done for buildForm should be done here
218 * This is a virtual function and should be redefined if needed
225 function preProcess() {}
228 * This function is called after the form is validated. Any
229 * processing of form state etc should be done in this function.
230 * Typically all processing associated with a form should be done
231 * here and relevant state should be stored in the session
233 * This is a virtual function and should be redefined if needed
240 function postProcess() {}
243 * This function is just a wrapper, so that we can call all the hook functions
245 function mainProcess() {
246 $this->postProcess();
248 $this->postProcessHook();
252 * The postProcess hook is typically called by the framework
253 * However in a few cases, the form exits or redirects early in which
254 * case it needs to call this function so other modules can do the needful
255 * Calling this function directly should be avoided if possible. In general a
256 * better way is to do setUserContext so the framework does the redirect
259 function postProcessHook() {
260 CRM_Utils_Hook
::postProcess(get_class($this), $this);
264 * This virtual function is used to build the form. It replaces the
265 * buildForm associated with QuickForm_Page. This allows us to put
266 * preProcess in front of the actual form building routine
273 function buildQuickForm() {}
276 * This virtual function is used to set the default values of
277 * various form elements
281 * @return array reference to the array of default values
284 function setDefaultValues() {}
287 * This is a virtual function that adds group and global rules to
288 * the form. Keeping it distinct from the form to keep code small
289 * and localized in the form building code
296 function addRules() {}
298 function validate() {
299 $error = parent
::validate();
301 $hookErrors = CRM_Utils_Hook
::validate(
303 $this->_submitValues
,
308 if (!is_array($hookErrors)) {
309 $hookErrors = array();
312 CRM_Utils_Hook
::validateForm(
314 $this->_submitValues
,
320 if (!empty($hookErrors)) {
321 $this->_errors +
= $hookErrors;
324 return (0 == count($this->_errors
));
328 * Core function that builds the form. We redefine this function
329 * here and expect all CRM forms to build their form in the function
333 function buildForm() {
334 $this->_formBuilt
= TRUE;
338 $this->assign('translatePermission', CRM_Core_Permission
::check('translate CiviCRM'));
341 $this->controller
->_key
&&
342 $this->controller
->_generateQFKey
344 $this->addElement('hidden', 'qfKey', $this->controller
->_key
);
345 $this->assign('qfKey', $this->controller
->_key
);
349 $this->buildQuickForm();
351 $defaults = $this->setDefaultValues();
352 unset($defaults['qfKey']);
354 if (!empty($defaults)) {
355 $this->setDefaults($defaults);
358 // call the form hook
359 // also call the hook function so any modules can set thier own custom defaults
360 // the user can do both the form and set default values with this hook
361 CRM_Utils_Hook
::buildForm(get_class($this), $this);
367 * Add default Next / Back buttons
369 * @param array array of associative arrays in the order in which the buttons should be
370 * displayed. The associate array has 3 fields: 'type', 'name' and 'isDefault'
371 * The base form class will define a bunch of static arrays for commonly used
379 function addButtons($params) {
382 foreach ($params as $button) {
383 $js = CRM_Utils_Array
::value('js', $button);
384 $isDefault = CRM_Utils_Array
::value('isDefault', $button, FALSE);
386 $attrs = array('class' => 'form-submit default');
389 $attrs = array('class' => 'form-submit');
393 $attrs = array_merge($js, $attrs);
396 if ($button['type'] === 'reset') {
397 $prevnext[] = $this->createElement($button['type'], 'reset', $button['name'], $attrs);
400 if (CRM_Utils_Array
::value('subName', $button)) {
401 $buttonName = $this->getButtonName($button['type'], $button['subName']);
404 $buttonName = $this->getButtonName($button['type']);
407 if (in_array($button['type'], array(
408 'next', 'upload')) && $button['name'] === 'Save') {
409 $attrs = array_merge($attrs, (array('accesskey' => 'S')));
411 $prevnext[] = $this->createElement('submit', $buttonName, $button['name'], $attrs);
413 if (CRM_Utils_Array
::value('isDefault', $button)) {
414 $this->setDefaultAction($button['type']);
417 // if button type is upload, set the enctype
418 if ($button['type'] == 'upload') {
419 $this->updateAttributes(array('enctype' => 'multipart/form-data'));
420 $this->setMaxFileSize();
423 // hack - addGroup uses an array to express variable spacing, read from the last element
424 $spacing[] = CRM_Utils_Array
::value('spacing', $button, self
::ATTR_SPACING
);
426 $this->addGroup($prevnext, 'buttons', '', $spacing, FALSE);
430 * getter function for Name
440 * getter function for State
445 function &getState() {
446 return $this->_state
;
450 * getter function for StateType
455 function getStateType() {
456 return $this->_state
->getType();
460 * getter function for title. Should be over-ridden by derived class
465 function getTitle() {
466 return $this->_title ?
$this->_title
: ts('ERROR: Title is not Set');
470 * setter function for title.
472 * @param string $title the title of the form
477 function setTitle($title) {
478 $this->_title
= $title;
482 * Setter function for options
489 function setOptions($options) {
490 $this->_options
= $options;
494 * getter function for link.
500 $config = CRM_Core_Config
::singleton();
501 return CRM_Utils_System
::url($_GET[$config->userFrameworkURLVar
],
502 '_qf_' . $this->_name
. '_display=true'
507 * boolean function to determine if this is a one form page
512 function isSimpleForm() {
513 return $this->_state
->getType() & (CRM_Core_State
::START | CRM_Core_State
::FINISH
);
517 * getter function for Form Action
522 function getFormAction() {
523 return $this->_attributes
['action'];
527 * setter function for Form Action
534 function setFormAction($action) {
535 $this->_attributes
['action'] = $action;
539 * render form and return contents
544 function toSmarty() {
545 $renderer = $this->getRenderer();
546 $this->accept($renderer);
547 $content = $renderer->toArray();
548 $content['formName'] = $this->getName();
553 * getter function for renderer. If renderer is not set
554 * create one and initialize it
559 function &getRenderer() {
560 if (!isset($this->_renderer
)) {
561 $this->_renderer
= CRM_Core_Form_Renderer
::singleton();
563 return $this->_renderer
;
567 * Use the form name to create the tpl file name
572 function getTemplateFileName() {
573 $ext = CRM_Extension_System
::singleton()->getMapper();
574 if ($ext->isExtensionClass(CRM_Utils_System
::getClassName($this))) {
575 $filename = $ext->getTemplateName(CRM_Utils_System
::getClassName($this));
576 $tplname = $ext->getTemplatePath(CRM_Utils_System
::getClassName($this)) . DIRECTORY_SEPARATOR
. $filename;
579 $tplname = str_replace('_',
581 CRM_Utils_System
::getClassName($this)
588 * Default extra tpl file basically just replaces .tpl with .extra.tpl
589 * i.e. we dont override
594 function overrideExtraTemplateFileName() {
599 * Error reporting mechanism
601 * @param string $message Error Message
602 * @param int $code Error Code
603 * @param CRM_Core_DAO $dao A data access object on which we perform a rollback if non - empty
608 function error($message, $code = NULL, $dao = NULL) {
610 $dao->query('ROLLBACK');
613 $error = CRM_Core_Error
::singleton();
615 $error->push($code, $message);
619 * Store the variable with the value in the form scope
621 * @param string name : name of the variable
622 * @param mixed value : value of the variable
629 function set($name, $value) {
630 $this->controller
->set($name, $value);
634 * Get the variable from the form scope
636 * @param string name : name of the variable
643 function get($name) {
644 return $this->controller
->get($name);
653 function getAction() {
654 return $this->_action
;
660 * @param int $action the mode we want to set the form
665 function setAction($action) {
666 $this->_action
= $action;
670 * assign value to name in template
672 * @param array|string $name name of variable
673 * @param mixed $value value of varaible
678 function assign($var, $value = NULL) {
679 self
::$_template->assign($var, $value);
683 * assign value to name in template by reference
685 * @param array|string $name name of variable
686 * @param mixed $value value of varaible
691 function assign_by_ref($var, &$value) {
692 self
::$_template->assign_by_ref($var, $value);
695 function &addRadio($name, $title, &$values, $attributes = NULL, $separator = NULL, $required = FALSE) {
697 if (empty($attributes)) {
698 $attributes = array('id_suffix' => $name);
701 $attributes = array_merge($attributes, array('id_suffix' => $name));
703 foreach ($values as $key => $var) {
704 $options[] = $this->createElement('radio', NULL, NULL, $var, $key, $attributes);
706 $group = $this->addGroup($options, $name, $title, $separator);
708 $this->addRule($name, ts('%1 is a required field.', array(1 => $title)), 'required');
713 function addYesNo($id, $title, $dontKnow = NULL, $required = NULL, $attribute = NULL) {
714 if (empty($attribute)) {
715 $attribute = array('id_suffix' => $id);
718 $attribute = array_merge($attribute, array('id_suffix' => $id));
721 $choice[] = $this->createElement('radio', NULL, '11', ts('Yes'), '1', $attribute);
722 $choice[] = $this->createElement('radio', NULL, '11', ts('No'), '0', $attribute);
724 $choice[] = $this->createElement('radio', NULL, '22', ts("Don't Know"), '2', $attribute);
726 $this->addGroup($choice, $id, $title);
729 $this->addRule($id, ts('%1 is a required field.', array(1 => $title)), 'required');
733 function addCheckBox($id, $title, $values, $other = NULL,
734 $attributes = NULL, $required = NULL,
735 $javascriptMethod = NULL,
736 $separator = '<br />', $flipValues = FALSE
740 if ($javascriptMethod) {
741 foreach ($values as $key => $var) {
743 $options[] = $this->createElement('checkbox', $var, NULL, $key, $javascriptMethod);
746 $options[] = $this->createElement('checkbox', $key, NULL, $var, $javascriptMethod);
751 foreach ($values as $key => $var) {
753 $options[] = $this->createElement('checkbox', $var, NULL, $key);
756 $options[] = $this->createElement('checkbox', $key, NULL, $var);
761 $this->addGroup($options, $id, $title, $separator);
764 $this->addElement('text', $id . '_other', ts('Other'), $attributes[$id . '_other']);
769 ts('%1 is a required field.', array(1 => $title)),
775 function resetValues() {
776 $data = $this->controller
->container();
777 $data['values'][$this->_name
] = array();
781 * simple shell that derived classes can call to add buttons to
782 * the form with a customized title for the main Submit
784 * @param string $title title of the main button
785 * @param string $type button type for the form after processing
786 * @param string $submitOnce If true, add javascript to next button submit which prevents it from being clicked more than once
791 function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) {
793 if ($backType != NULL) {
796 'name' => ts('Previous'),
799 if ($nextType != NULL) {
806 $nextButton['js'] = array('onclick' => "return submitOnce(this,'{$this->_name}','" . ts('Processing') . "');");
808 $buttons[] = $nextButton;
810 $this->addButtons($buttons);
813 function addDateRange($name, $from = '_from', $to = '_to', $label = 'From:', $dateFormat = 'searchDate', $required = FALSE, $displayTime = FALSE) {
815 $this->addDateTime($name . $from, $label, $required, array('formatType' => $dateFormat));
816 $this->addDateTime($name . $to, ts('To:'), $required, array('formatType' => $dateFormat));
818 $this->addDate($name . $from, $label, $required, array('formatType' => $dateFormat));
819 $this->addDate($name . $to, ts('To:'), $required, array('formatType' => $dateFormat));
823 function addSelect($name, $label, $prefix = NULL, $required = NULL, $extra = NULL, $select = '- select -') {
825 $this->addElement('select', $name . '_id' . $prefix, $label,
827 '' => $select) + CRM_Core_OptionGroup
::values($name), $extra
830 $this->addRule($name . '_id' . $prefix, ts('Please select %1', array(1 => $label)), 'required');
834 $this->addElement('select', $name . '_id', $label,
836 '' => $select) + CRM_Core_OptionGroup
::values($name), $extra
839 $this->addRule($name . '_id', ts('Please select %1', array(1 => $label)), 'required');
845 * Add a widget for selecting/editing/creating/copying a profile form
847 * @param string $name HTML form-element name
848 * @param string $label Printable label
849 * @param string $allowCoreTypes only present a UFGroup if its group_type includes a subset of $allowCoreTypes; e.g. 'Individual', 'Activity'
850 * @param string $allowSubTypes only present a UFGroup if its group_type is compatible with $allowSubypes
851 * @param array $entities
853 function addProfileSelector($name, $label, $allowCoreTypes, $allowSubTypes, $entities) {
855 // FIXME: Instead of adhoc serialization, use a single json_encode()
856 CRM_UF_Page_ProfileEditor
::registerProfileScripts();
857 CRM_UF_Page_ProfileEditor
::registerSchemas(CRM_Utils_Array
::collect('entity_type', $entities));
858 $this->add('text', $name, $label, array(
859 'class' => 'crm-profile-selector',
860 // Note: client treats ';;' as equivalent to \0, and ';;' works better in HTML
861 'data-group-type' => CRM_Core_BAO_UFGroup
::encodeGroupType($allowCoreTypes, $allowSubTypes, ';;'),
862 'data-entities' => json_encode($entities),
866 function addWysiwyg($name, $label, $attributes, $forceTextarea = FALSE) {
867 // 1. Get configuration option for editor (tinymce, ckeditor, pure textarea)
868 // 2. Based on the option, initialise proper editor
869 $editorID = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
,
872 $editor = strtolower(CRM_Utils_Array
::value($editorID,
873 CRM_Core_PseudoConstant
::wysiwygEditor()
875 if (!$editor ||
$forceTextarea) {
876 $editor = 'textarea';
878 if ($editor == 'joomla default editor') {
879 $editor = 'joomlaeditor';
882 if ($editor == 'drupal default editor') {
883 $editor = 'drupalwysiwyg';
886 //lets add the editor as a attribute
887 $attributes['editor'] = $editor;
889 $this->addElement($editor, $name, $label, $attributes);
890 $this->assign('editor', $editor);
892 // include wysiwyg editor js files
893 $includeWysiwygEditor = FALSE;
894 $includeWysiwygEditor = $this->get('includeWysiwygEditor');
895 if (!$includeWysiwygEditor) {
896 $includeWysiwygEditor = TRUE;
897 $this->set('includeWysiwygEditor', $includeWysiwygEditor);
900 $this->assign('includeWysiwygEditor', $includeWysiwygEditor);
903 function addCountry($id, $title, $required = NULL, $extra = NULL) {
904 $this->addElement('select', $id, $title,
906 '' => ts('- select -')) + CRM_Core_PseudoConstant
::country(), $extra
909 $this->addRule($id, ts('Please select %1', array(1 => $title)), 'required');
913 function addSelectOther($name, $label, $options, $attributes, $required = NULL, $javascriptMethod = NULL) {
915 $this->addElement('select', $name . '_id', $label, $options, $javascriptMethod);
918 $this->addRule($name . '_id', ts('Please select %1', array(1 => $label)), 'required');
922 function buildAddressBlock($locationId, $title, $phone,
923 $alternatePhone = NULL, $addressRequired = NULL,
924 $phoneRequired = NULL, $altPhoneRequired = NULL,
927 if (!$locationName) {
928 $locationName = "location";
931 $config = CRM_Core_Config
::singleton();
932 $attributes = CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Address');
934 $location[$locationId]['address']['street_address'] = $this->addElement('text', "{$locationName}[$locationId][address][street_address]", $title,
935 $attributes['street_address']
937 if ($addressRequired) {
938 $this->addRule("{$locationName}[$locationId][address][street_address]", ts("Please enter the Street Address for %1.", array(1 => $title)), 'required');
941 $location[$locationId]['address']['supplemental_address_1'] = $this->addElement('text', "{$locationName}[$locationId][address][supplemental_address_1]", ts('Additional Address 1'),
942 $attributes['supplemental_address_1']
944 $location[$locationId]['address']['supplemental_address_2'] = $this->addElement('text', "{$locationName}[$locationId][address][supplemental_address_2]", ts('Additional Address 2'),
945 $attributes['supplemental_address_2']
948 $location[$locationId]['address']['city'] = $this->addElement('text', "{$locationName}[$locationId][address][city]", ts('City'),
951 if ($addressRequired) {
952 $this->addRule("{$locationName}[$locationId][address][city]", ts("Please enter the City for %1.", array(1 => $title)), 'required');
955 $location[$locationId]['address']['postal_code'] = $this->addElement('text', "{$locationName}[$locationId][address][postal_code]", ts('Zip / Postal Code'),
956 $attributes['postal_code']
958 if ($addressRequired) {
959 $this->addRule("{$locationName}[$locationId][address][postal_code]", ts("Please enter the Zip/Postal Code for %1.", array(1 => $title)), 'required');
962 $location[$locationId]['address']['postal_code_suffix'] = $this->addElement('text', "{$locationName}[$locationId][address][postal_code_suffix]", ts('Add-on Code'),
963 array('size' => 4, 'maxlength' => 12)
965 $this->addRule("{$locationName}[$locationId][address][postal_code_suffix]", ts('Zip-Plus not valid.'), 'positiveInteger');
967 if ($config->includeCounty
) {
968 $location[$locationId]['address']['county_id'] = $this->addElement('select', "{$locationName}[$locationId][address][county_id]", ts('County'),
969 array('' => ts('- select -')) + CRM_Core_PseudoConstant
::county()
973 $location[$locationId]['address']['state_province_id'] = $this->addElement('select', "{$locationName}[$locationId][address][state_province_id]", ts('State / Province'),
974 array('' => ts('- select -')) + CRM_Core_PseudoConstant
::stateProvince()
977 $location[$locationId]['address']['country_id'] = $this->addElement('select', "{$locationName}[$locationId][address][country_id]", ts('Country'),
978 array('' => ts('- select -')) + CRM_Core_PseudoConstant
::country()
980 if ($addressRequired) {
981 $this->addRule("{$locationName}[$locationId][address][country_id]", ts("Please select the Country for %1.", array(1 => $title)), 'required');
986 $location[$locationId]['phone'][1]['phone'] = $this->addElement('text',
987 "{$locationName}[$locationId][phone][1][phone]",
989 CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Phone',
993 if ($phoneRequired) {
994 $this->addRule("{$locationName}[$locationId][phone][1][phone]", ts('Please enter a value for %1', array(1 => $phone)), 'required');
996 $this->addRule("{$locationName}[$locationId][phone][1][phone]", ts('Please enter a valid number for %1', array(1 => $phone)), 'phone');
999 if ($alternatePhone) {
1000 $location[$locationId]['phone'][2]['phone'] = $this->addElement('text',
1001 "{$locationName}[$locationId][phone][2][phone]",
1003 CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Phone',
1007 if ($alternatePhoneRequired) {
1008 $this->addRule("{$locationName}[$locationId][phone][2][phone]", ts('Please enter a value for %1', array(1 => $alternatePhone)), 'required');
1010 $this->addRule("{$locationName}[$locationId][phone][2][phone]", ts('Please enter a valid number for %1', array(1 => $alternatePhone)), 'phone');
1014 public function getRootTitle() {
1018 public function getCompleteTitle() {
1019 return $this->getRootTitle() . $this->getTitle();
1022 static function &getTemplate() {
1023 return self
::$_template;
1026 function addUploadElement($elementName) {
1027 $uploadNames = $this->get('uploadNames');
1028 if (!$uploadNames) {
1029 $uploadNames = array();
1031 if (is_array($elementName)) {
1032 foreach ($elementName as $name) {
1033 if (!in_array($name, $uploadNames)) {
1034 $uploadNames[] = $name;
1039 if (!in_array($elementName, $uploadNames)) {
1040 $uploadNames[] = $elementName;
1043 $this->set('uploadNames', $uploadNames);
1045 $config = CRM_Core_Config
::singleton();
1046 if (!empty($uploadNames)) {
1047 $this->controller
->addUploadAction($config->customFileUploadDir
, $uploadNames);
1051 function buttonType() {
1052 $uploadNames = $this->get('uploadNames');
1053 $buttonType = (is_array($uploadNames) && !empty($uploadNames)) ?
'upload' : 'next';
1054 $this->assign('buttonType', $buttonType);
1058 function getVar($name) {
1059 return isset($this->$name) ?
$this->$name : NULL;
1062 function setVar($name, $value) {
1063 $this->$name = $value;
1067 * Function to add date
1068 * @param string $name name of the element
1069 * @param string $label label of the element
1070 * @param array $attributes key / value pair
1073 * $attributes = array ( 'addTime' => true,
1074 * 'formatType' => 'relative' or 'birth' etc check advanced date settings
1076 * @param boolean $required true if required
1079 function addDate($name, $label, $required = FALSE, $attributes = NULL) {
1080 if (CRM_Utils_Array
::value('formatType', $attributes)) {
1081 // get actual format
1082 $params = array('name' => $attributes['formatType']);
1085 // cache date information
1087 $key = "dateFormat_" . str_replace(' ', '_', $attributes['formatType']);
1088 if (!CRM_Utils_Array
::value($key, $dateFormat)) {
1089 CRM_Core_DAO
::commonRetrieve('CRM_Core_DAO_PreferencesDate', $params, $values);
1090 $dateFormat[$key] = $values;
1093 $values = $dateFormat[$key];
1096 if ($values['date_format']) {
1097 $attributes['format'] = $values['date_format'];
1100 if (CRM_Utils_Array
::value('time_format', $values)) {
1101 $attributes['timeFormat'] = $values['time_format'];
1103 $attributes['startOffset'] = $values['start'];
1104 $attributes['endOffset'] = $values['end'];
1107 $config = CRM_Core_Config
::singleton();
1108 if (!CRM_Utils_Array
::value('format', $attributes)) {
1109 $attributes['format'] = $config->dateInputFormat
;
1112 if (!isset($attributes['startOffset'])) {
1113 $attributes['startOffset'] = 10;
1116 if (!isset($attributes['endOffset'])) {
1117 $attributes['endOffset'] = 10;
1120 $this->add('text', $name, $label, $attributes);
1122 if (CRM_Utils_Array
::value('addTime', $attributes) ||
1123 CRM_Utils_Array
::value('timeFormat', $attributes)
1126 if (!isset($attributes['timeFormat'])) {
1127 $timeFormat = $config->timeInputFormat
;
1130 $timeFormat = $attributes['timeFormat'];
1133 // 1 - 12 hours and 2 - 24 hours, but for jquery widget it is 0 and 1 respectively
1135 $show24Hours = TRUE;
1136 if ($timeFormat == 1) {
1137 $show24Hours = FALSE;
1140 //CRM-6664 -we are having time element name
1141 //in either flat string or an array format.
1142 $elementName = $name . '_time';
1143 if (substr($name, -1) == ']') {
1144 $elementName = substr($name, 0, strlen($name) - 1) . '_time]';
1147 $this->add('text', $elementName, ts('Time'), array('timeFormat' => $show24Hours));
1152 $this->addRule($name, ts('Please select %1', array(1 => $label)), 'required');
1153 if (CRM_Utils_Array
::value('addTime', $attributes) && CRM_Utils_Array
::value('addTimeRequired', $attributes)) {
1154 $this->addRule($elementName, ts('Please enter a time.'), 'required');
1160 * Function that will add date and time
1162 function addDateTime($name, $label, $required = FALSE, $attributes = NULL) {
1163 $addTime = array('addTime' => TRUE);
1164 if (is_array($attributes)) {
1165 $attributes = array_merge($attributes, $addTime);
1168 $attributes = $addTime;
1171 $this->addDate($name, $label, $required, $attributes);
1175 * add a currency and money element to the form
1177 function addMoney($name,
1181 $addCurrency = TRUE,
1182 $currencyName = 'currency',
1183 $defaultCurrency = NULL,
1184 $freezeCurrency = FALSE
1186 $element = $this->add('text', $name, $label, $attributes, $required);
1187 $this->addRule($name, ts('Please enter a valid amount.'), 'money');
1190 $ele = $this->addCurrency($currencyName, NULL, TRUE, $defaultCurrency, $freezeCurrency);
1197 * add currency element to the form
1199 function addCurrency($name = 'currency',
1202 $defaultCurrency = NULL,
1203 $freezeCurrency = FALSE
1205 $currencies = CRM_Core_OptionGroup
::values('currencies_enabled');
1207 $currencies = array(
1208 '' => ts('- select -')) +
$currencies;
1210 $ele = $this->add('select', $name, $label, $currencies, $required);
1211 if ($freezeCurrency) {
1214 if (!$defaultCurrency) {
1215 $config = CRM_Core_Config
::singleton();
1216 $defaultCurrency = $config->defaultCurrency
;
1218 $this->setDefaults(array($name => $defaultCurrency));
1221 function removeFileRequiredRules($elementName) {
1222 $this->_required
= array_diff($this->_required
, array($elementName));
1223 if (isset($this->_rules
[$elementName])) {
1224 foreach ($this->_rules
[$elementName] as $index => $ruleInfo) {
1225 if ($ruleInfo['type'] == 'uploadedfile') {
1226 unset($this->_rules
[$elementName][$index]);
1229 if (empty($this->_rules
[$elementName])) {
1230 unset($this->_rules
[$elementName]);
1236 * Function that can be defined in Form to override or
1237 * perform specific action on cancel action
1241 function cancelAction() {}
1244 * Helper function to verify that required fields have been filled
1245 * Typically called within the scope of a FormRule function
1247 static function validateMandatoryFields($fields, $values, &$errors) {
1248 foreach ($fields as $name => $fld) {
1249 if (!empty($fld['is_required']) && CRM_Utils_System
::isNull(CRM_Utils_Array
::value($name, $values))) {
1250 $errors[$name] = ts('%1 is a required field.', array(1 => $fld['title']));