MDL-53140 forms: Added the float form element to the form API
[moodle.git] / lib / form / float.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * Float type form element
20  *
21  * Contains HTML class for a float type element
22  *
23  * @package   core_form
24  * @category  form
25  * @copyright 2019 Shamim Rezaie <shamim@moodle.com>
26  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27  */
29 defined('MOODLE_INTERNAL') || die();
31 global $CFG;
32 require_once($CFG->libdir . '/form/text.php');
34 /**
35  * Float type form element.
36  *
37  * This is preferred over the text element when working with float numbers, and takes care of the fact that different languages
38  * may use different symbols as the decimal separator.
39  * Using this element, submitted float numbers will be automatically translated from the localised format into the computer format,
40  * and vice versa when they are being displayed.
41  *
42  * @copyright 2019 Shamim Rezaie <shamim@moodle.com>
43  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44  */
45 class MoodleQuickForm_float extends MoodleQuickForm_text {
47     /**
48      * MoodleQuickForm_float constructor.
49      *
50      * @param string $elementName (optional) name of the float field
51      * @param string $elementLabel (optional) float field label
52      * @param string $attributes (optional) Either a typical HTML attribute string or an associative array
53      */
54     public function __construct($elementName = null, $elementLabel = null, $attributes = null) {
55         parent::__construct($elementName, $elementLabel, $attributes);
56         $this->_type = 'float';
57     }
59     /**
60      * Called by HTML_QuickForm whenever form event is made on this element.
61      *
62      * @param string $event Name of event
63      * @param mixed $arg event arguments
64      * @param object $caller calling object
65      * @return bool
66      */
67     public function onQuickFormEvent($event, $arg, &$caller) {
68         switch ($event) {
69             case 'updateValue':
70                 if ($value = $this->_findValue($caller->_constantValues)) {
71                     $value = $this->format_float($value);
72                 }
73                 if (null === $value) {
74                     $value = $this->_findValue($caller->_submitValues);
75                     if (null === $value) {
76                         if ($value = $this->_findValue($caller->_defaultValues)) {
77                             $value = $this->format_float($value);
78                         }
79                     }
80                 }
81                 if (null !== $value) {
82                     parent::setValue($value);
83                 }
84                 return true;
85             case 'createElement':
86                 $caller->setType($arg[0], PARAM_RAW_TRIMMED);
87             default:
88                 return parent::onQuickFormEvent($event, $arg, $caller);
89         }
90     }
92     /**
93      * Checks that the submitted value is a valid float number.
94      *
95      * @param string $value The localised float number that is submitted.
96      * @return string|null Validation error message or null.
97      */
98     public function validateSubmitValue($value) {
99         if (false === unformat_float($value, true)) {
100             return get_string('err_numeric', 'core_form');
101         }
102     }
104     /**
105      * Sets the value of the form element.
106      *
107      * @param string $value Default value of the form element
108      */
109     public function setValue($value) {
110         $value = $this->format_float($value);
111         parent::setValue($value);
112     }
114     /**
115      * Returns the value of the form element.
116      *
117      * @return false|float
118      */
119     public function getValue() {
120         $value = parent::getValue();
121         if ($value) {
122             $value = unformat_float($value, true);
123         }
124         return $value;
125     }
127     /**
128      * Returns a 'safe' element's value.
129      *
130      * @param  array   $submitValues array of submitted values to search
131      * @param  bool    $assoc whether to return the value as associative array
132      * @return mixed
133      */
134     public function exportValue(&$submitValues, $assoc = false) {
135         $value = $this->_findValue($submitValues);
136         if (null === $value) {
137             $value = $this->getValue();
138         } else if ($value) {
139             $value = unformat_float($value, true);
140         }
141         return $this->_prepareValue($value, $assoc);
142     }
144     /**
145      * Used by getFrozenHtml() to pass the element's value if _persistantFreeze is on.
146      *
147      * @return string
148      */
149     public function _getPersistantData() {
150         if (!$this->_persistantFreeze) {
151             return '';
152         } else {
153             $id = $this->getAttribute('id');
154             if (isset($id)) {
155                 // Id of persistant input is different then the actual input.
156                 $id = array('id' => $id . '_persistant');
157             } else {
158                 $id = array();
159             }
161             return '<input' . $this->_getAttrString(array(
162                         'type'  => 'hidden',
163                         'name'  => $this->getAttribute('name'),
164                         'value' => $this->getAttribute('value')
165                     ) + $id) . ' />';
166         }
167     }
169     /**
170      * Given a float, prints it nicely.
171      * This function reserves the number of decimal places.
172      *
173      * @param float|null $value The float number to format
174      * @return string Localised float
175      */
176     private function format_float($value) {
177         if (is_numeric($value)) {
178             if ($value > 0) {
179                 $decimals = strlen($value) - strlen(floor($value)) - 1;
180             } else {
181                 $decimals = strlen($value) - strlen(ceil($value)) - 1;
182             }
183             $value = format_float($value, $decimals);
184         }
185         return $value;
186     }