root/trunk/patForms/Element/Number.php

Revision 329, 12.5 kB (checked in by schst, 3 years ago)

Do not format an empty string as if it were a number (fixes bug #198)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 /**
3  * simple test patForms element that builds and validates numbers input fields.
4  *
5  * $Id$
6  *
7  * @package        patForms
8  * @subpackage    Element
9  */
10
11  define( 'PATFORMS_ELEMENT_NUMBER_WARNING_WRONG_FORMAT_STRING', 'patForms:Element:Number:01' );
12  
13 /**
14  * simple textfield patForms element that builds and validates text input fields.
15  *
16  * $Id$
17  *
18  * @package        patForms
19  * @subpackage    Element
20  * @author        gERD Schaufelberger <gerd@php-tools.net>
21  * @author        Sebastian Mordziol <argh@php-tools.net>
22  * @author        Stephan Schmidt <schst@php-tools.net>
23  * @todo        Review getNumberFormat() -> poor "quoting"!
24  * @license        LGPL
25  */
26 class patForms_Element_Number extends patForms_Element
27 {
28    /**
29     * Stores the name of the element - this is used mainly by the patForms
30     * error management and should be set in every element class.
31     * @access    public
32     */
33     var $elementName = 'Number';
34
35    /**
36     * the type of the element - set this to the type of element you are creating
37     * if you want to use the {@link patForms_Element::element2html()} method to
38     * create the final HTML tag for your element.
39     *
40     * @access    public
41     * @see        patForms_Element::element2html()
42     */
43     var $elementType = array(
44         'html'    =>    'input'
45     );
46     
47     /**
48      *    output definition for number
49      *
50      *  @access private
51      *  @var    array    $numberformat
52      */
53     var    $numberformat = false;
54
55    /**
56     * set here which attributes you want to include in the element if you want to use
57     * the {@link patForms_Element::convertDefinition2Attributes()} method to automatically
58     * convert the values from your element definition into element attributes.
59     *
60     * @access    protected
61     * @see        patForms_Element::convertDefinition2Attribute()
62     */
63     var    $attributeDefinition    =    array(   
64             
65             'id'            =>    array(    'required'        =>    false,
66                                         'format'        =>    'string',
67                                         'outputFormats'    =>    array( 'html' ),
68                                     ),
69             'name'            =>    array(    'required'        =>    true,
70                                         'format'        =>    'string',
71                                         'outputFormats'    =>    array( 'html' ),
72                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
73                                     ),
74             'type'            =>    array(    'required'        =>    false,
75                                         'format'        =>    'string',
76                                         'default'        =>    'text',
77                                         'outputFormats'    =>    array( 'html' ),
78                                     ),
79             'title'            =>    array(    'required'        =>    false,
80                                         'format'        =>    'string',
81                                         'outputFormats'    =>    array( 'html' ),
82                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
83                                     ),
84             'description'    =>    array(    'required'        =>    false,
85                                         'format'        =>    'string',
86                                         'outputFormats'    =>    array(),
87                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
88                                     ),
89             'default'        =>    array(    'required'        =>    false,
90                                         'format'        =>    'string',
91                                         'outputFormats'    =>    array(),
92                                     ),
93             'label'            =>    array(    'required'        =>    false,
94                                         'format'        =>    'string',
95                                         'outputFormats'    =>    array(),
96                                     ),
97             'display'        =>    array(    'required'        =>    false,
98                                         'format'        =>    'string',
99                                         'default'        =>    'yes',
100                                         'outputFormats'    =>    array(),
101                                     ),
102             'edit'            =>    array(    'required'        =>    false,
103                                         'format'        =>    'string',
104                                         'default'        =>    'yes',
105                                         'outputFormats'    =>    array(),
106                                     ),
107             'disabled'        =>    array(    'required'        =>    false,
108                                         'format'        =>    'string',
109                                         'default'        =>    'no',
110                                         'outputFormats'    =>    array( 'html' ),
111                                     ),
112             'required'        =>    array(    'required'        =>    false,
113                                         'format'        =>    'string',
114                                         'default'        =>    'yes',
115                                         'outputFormats'    =>    array(),
116                                     ),
117             'value'            =>    array(    'required'        =>    false,
118                                         'format'        =>    'string',
119                                         'outputFormats'    =>    array( 'html' ),
120                                     ),
121             'style'            =>    array(    'required'        =>    false,
122                                         'outputFormats'    =>    array( 'html' ),
123                                         'format'        =>    'string',
124                                     ),
125             'class'            =>    array(    'required'        =>    false,
126                                         'outputFormats'    =>    array( 'html' ),
127                                         'format'        =>    'string',
128                                     ),
129             'onchange'        =>    array(    'required'        =>    false,
130                                         'format'        =>    'string',
131                                         'outputFormats'    =>    array( 'html' ),
132                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
133                                     ),
134             'onclick'        =>    array(    'required'        =>    false,
135                                         'format'        =>    'string',
136                                         'outputFormats'    =>    array( 'html' ),
137                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
138                                     ),
139             'onfocus'        =>    array(    'required'        =>    false,
140                                         'format'        =>    'string',
141                                         'outputFormats'    =>    array( 'html' ),
142                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
143                                     ),
144             'onmouseover'    =>    array(    'required'        =>    false,
145                                         'format'        =>    'string',
146                                         'outputFormats'    =>    array( 'html' ),
147                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
148                                     ),
149             'onmouseout'    =>    array(    'required'        =>    false,
150                                         'format'        =>    'string',
151                                         'outputFormats'    =>    array( 'html' ),
152                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
153                                     ),
154             'onblur'        =>    array(    'required'        =>    false,
155                                         'format'        =>    'string',
156                                         'outputFormats'    =>    array( 'html' ),
157                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
158                                     ),
159             'accesskey'        =>    array(    'required'        =>    false,
160                                         'format'        =>    'string',
161                                         'outputFormats'    =>    array( 'html' ),
162                                     ),
163             'position'        =>    array(    'required'        =>    false,
164                                         'format'        =>    'int',
165                                         'outputFormats'    =>    array(),
166                                     ),
167             'tabindex'        =>    array(    'required'        =>    false,
168                                         'format'        =>    'int',
169                                         'outputFormats'    =>    array( 'html' ),
170                                     ),
171             'max'            =>    array(    'required'        =>    false,
172                                         'format'        =>    'string',
173                                         'outputFormats'    =>    array(),
174                                     ),
175             'min'            =>    array(    'required'        =>    false,
176                                         'format'        =>    'string',
177                                         'outputFormats'    =>    array(),
178                                     ),
179             'format'        =>    array(    'required'        =>    false,
180                                         'format'        =>    'string',
181                                         'setter'        =>  'setValueFormat',
182                                         'outputFormats'    =>    array(),
183                                     ),
184             'numberformat'    =>    array(    'required'        =>    false,
185                                         'format'        =>    'string',
186                                         'default'        =>    '0||',
187                                         'outputFormats'    =>    array(),
188                                     ),
189             'formatseparator'=>    array(    'required'        =>    false,
190                                         'format'        =>    'string',
191                                         'default'        =>    '|',
192                                         'outputFormats'    =>    array(),
193                                     ),
194             'size'            =>    array(    'required'        =>    false,
195                                         'format'        =>    'string',
196                                         'outputFormats'    =>    array( 'html' ),
197                                     ),
198             'maxlength'        =>    array(    'required'        =>    false,
199                                         'format'        =>    'string',
200                                         'outputFormats'    =>    array( 'html' ),
201                                     ),
202         );
203
204     /**
205      *    define error codes an messages for each form element
206      *
207      *  @access private
208      *  @var    array    $validatorErrorCodes
209      */
210     var    $validatorErrorCodes  =   array(
211         'C'    =>    array(
212             1    =>    'This field is required, please complete it.',
213             2    =>    'Value is not a number.',
214             3    =>    'Value is smaller than the minimum of [MIN].',
215             4    =>    'Value is higher than the maximum of [MAX].',
216             5    =>    'The value does not match the required input format.',
217         ),
218         'de' =>    array(
219             1    =>    'Pflichtfeld. Bitte vervollständigen Sie Ihre Angabe.',
220             2    =>    'Wert ist keine Zahl.',
221             3    =>    'Wert zu klein, kleinster erlaubter Wert ist [MIN].',
222             4    =>    'Wert zu groß, größter erlaubter Wert ist [MAX].',
223             5    =>    'Der angegebene Wert entspricht nicht dem gewünschten Eingabeformat.',
224         ),
225         'fr' =>    array(
226             1    =>    'Ce champ est obligatoire.',
227             2    =>    'Pas un nombre.',
228             3    =>    'Valeur trop petite. Valeur minimum admise: [MIN].',
229             4    =>    'Valeur trop grande. Valuer maximum admise: [MAX].',
230             5    =>    'La valeur ne correspond pas au format souhaité.',
231         )
232     );
233
234     /**
235      * Extract the number format from the numberformat-attribute
236      *
237      * This method allows to define the numberformat as a string with
238      * comma seperated values of decimals, decimal-point and thousands seperator.
239      * For using a "," (comma) as separator, it must be quoted: "%,".
240      *
241      * The returned array contains the three format parameters for number_format() in
242      * the same order as the function expects.
243      *
244      * Examples:
245      * <ul>
246      *   <li>"0||" simple integer (default), ex. 1234</li>
247      *   <li>"2|,|." german/french format, ex. "1.234,56"</li>
248      *   <li>"2|.| " english format, ex. "1 234.56" </li>
249      * </ul>
250      *
251      *    @access    private
252      *    @return array $format the extracted number format
253      *    @see number_format()
254      */
255     function getNumberFormat()
256     {
257         if ($this->numberformat) {
258             return $this->numberformat;
259         }
260         
261         $format = explode( $this->attributes['formatseparator'], $this->attributes['numberformat'] );
262         
263         if (count( $format ) !== 3) {
264             patErrorManager::raiseWarning(
265                 PATFORMS_ELEMENT_NUMBER_WARNING_WRONG_FORMAT_STRING,
266                 'Incorrect number format string, using default',
267                 'The number format string has to have three parts, e.g. "0|.| " for the english number format -> "1 234.56", your format string has '.count( $format ).'. Now using the default format, "'.$this->attributeDefinition['numberformat']['default'].'"'
268             );
269             $format = explode( $this->attributes['formatseparator'], $this->attributeDefinition['numberformat']['default'] );
270         }
271         
272         $this->numberformat = $format;
273         return $format;
274     }
275     
276    /**
277     * Manages the value that will be used
278     *
279     * @access    private
280     * @param    mixed    $value    The current raw value
281     * @return    mixed    $value    The value that should be used
282     */
283     function _manageValue( $value )
284     {
285         // if the element has been validated we know the
286         // value is really a number, we can format it according
287         // to the given format.
288         if ($this->valid && $value !== '') {
289             $value = $this->formatNumber($value);
290         }
291         // and return to sender...
292         return $value;
293     }
294         
295    /**
296     * element creation method for the 'HTML' format in the 'default' form mode.
297     *
298     * @access    public
299     * @param    mixed    value of the element
300     * @return    mixed    $element    The element, or false if failed.
301     */
302     function serializeHtmlDefault($value)
303     {
304         if ($this->attributes['edit'] == 'no') {
305             $this->attributes['disabled'] = 'yes';
306         }
307         $value = $this->_manageValue($value);
308         $this->attributes['value'] = $value;
309
310         if ($this->attributes['display'] == 'no') {
311             return $this->createDisplaylessTag( $value );
312         }
313
314         return $this->toHtml();
315     }
316     
317    /**
318     * Formats a number according to the number format set for the element
319     *
320     * @access    private
321     * @param    int        $number    The number to format
322     * @return    string    $number    The formatted number
323     * @see        getNumberFormat()
324     */
325     function formatNumber( $number )
326     {
327         $format = $this->getNumberFormat();
328
329         return number_format( $number, $format[0], $format[1], $format[2] );
330     }
331     
332    /**
333     * element creation method for the 'HTML' format in the 'readonly' form mode.
334     * Very simple; just returns the stored element value.
335     *
336     * @access    public
337     * @param    mixed    value of the element
338     * @return    string    $value    The element's value
339     */
340     function serializeHtmlReadonly( $value )
341     {
342         $this->getAttributesFor($this->getFormat());
343
344         $value = $this->_manageValue($value);
345         $tag = $this->createDisplaylessTag($value);
346         
347         if ($this->attributes['display'] == 'no') {
348             return $tag;
349         }
350         return $value.$tag;
351     }
352
353    /**
354     * validates the element.
355     *
356     * @access    public
357     * @param    mixed    value of the element
358     * @return    bool    $isValid    True if element could be validated, false otherwise.
359     */
360     function validateElement($value)
361     {
362         // required & empty
363         if ($this->attributes['required'] == 'yes' && strlen( $value ) == 0) {
364             $this->addValidationError(1);
365             return false;
366         }
367         
368         $value = $this->inputValueToFloat($value);
369         
370         // only numeric values are accepted
371         if (!is_numeric($value)) {
372             $this->addValidationError(2);
373             return false;
374         }
375
376         // min
377         if (isset($this->attributes['min'] ) && $value < $this->attributes['min']) {
378             $this->addValidationError(3, array( 'min' => $this->attributes['min']));
379             return false;
380         }
381         
382         // max
383         if (isset($this->attributes['max']) && $value > $this->attributes['max']) {
384             $this->addValidationError(4, array('max' => $this->attributes['max']));
385             return false;
386         }
387         
388         // format
389         if (isset($this->attributes['format']) && !$this->validateFormat($value, $this->attributes['format'])) {
390             $this->addValidationError(5);
391             return false;
392         }
393         $this->value = $value;
394         return true;
395     }
396     
397    /**
398     * transforms input value to floating point number
399     *
400     *
401     * @access private
402     * @param string $value the value-string
403     * @return float $value transformed value
404     */
405     function inputValueToFloat($value)
406     {
407         $format    =    $this->getNumberFormat();
408         
409         // remove thousand-seperator
410         $result    = str_replace($format[2], '', $value);
411         
412         // replace decimal-point
413         $result = str_replace( $format[1], '.', $result );
414         
415         // now this should be number!
416         if (!is_numeric($result)) {
417             return $value;
418         }       
419         // cast to float
420         return (float) $result;
421     }
422 }
423 ?>
424
Note: See TracBrowser for help on using the browser.