| 1 | <?php |
|---|
| 2 | /** |
|---|
| 3 | * simple test patForms element that builds and validates numbers input fields. |
|---|
| 4 | * |
|---|
| 5 | * $Id$ |
|---|
| 6 | * |
|---|
| 7 | * @access protected |
|---|
| 8 | * @package patForms |
|---|
| 9 | * @subpackage Element |
|---|
| 10 | */ |
|---|
| 11 | |
|---|
| 12 | define( 'PATFORMS_ELEMENT_NUMBER_WARNING_WRONG_FORMAT_STRING', 'patForms:Element:Number:01' ); |
|---|
| 13 | |
|---|
| 14 | /** |
|---|
| 15 | * simple textfield patForms element that builds and validates text input fields. |
|---|
| 16 | * |
|---|
| 17 | * $Id$ |
|---|
| 18 | * |
|---|
| 19 | * @access protected |
|---|
| 20 | * @package patForms |
|---|
| 21 | * @subpackage Element |
|---|
| 22 | * @author gERD Schaufelberger <gerd@php-tools.net> |
|---|
| 23 | * @author Sebastian Mordziol <argh@php-tools.net> |
|---|
| 24 | * @todo Review getNumberFormat() -> poor "quoting"! |
|---|
| 25 | * @license LGPL |
|---|
| 26 | */ |
|---|
| 27 | class patForms_Element_Number extends patForms_Element |
|---|
| 28 | { |
|---|
| 29 | /** |
|---|
| 30 | * Stores the name of the element - this is used mainly by the patForms |
|---|
| 31 | * error management and should be set in every element class. |
|---|
| 32 | * @access public |
|---|
| 33 | */ |
|---|
| 34 | var $elementName = 'Number'; |
|---|
| 35 | |
|---|
| 36 | /** |
|---|
| 37 | * the type of the element - set this to the type of element you are creating |
|---|
| 38 | * if you want to use the {@link patForms_Element::element2html()} method to |
|---|
| 39 | * create the final HTML tag for your element. |
|---|
| 40 | * |
|---|
| 41 | * @access public |
|---|
| 42 | * @see patForms_Element::element2html() |
|---|
| 43 | */ |
|---|
| 44 | var $elementType = array( |
|---|
| 45 | 'html' => 'input' |
|---|
| 46 | ); |
|---|
| 47 | |
|---|
| 48 | /** |
|---|
| 49 | * output definition for number |
|---|
| 50 | * |
|---|
| 51 | * @access private |
|---|
| 52 | * @var array $numberformat |
|---|
| 53 | */ |
|---|
| 54 | var $numberformat = false; |
|---|
| 55 | |
|---|
| 56 | /** |
|---|
| 57 | * set here which attributes you want to include in the element if you want to use |
|---|
| 58 | * the {@link patForms_Element::convertDefinition2Attributes()} method to automatically |
|---|
| 59 | * convert the values from your element definition into element attributes. |
|---|
| 60 | * |
|---|
| 61 | * @access protected |
|---|
| 62 | * @see patForms_Element::convertDefinition2Attribute() |
|---|
| 63 | */ |
|---|
| 64 | var $attributeDefinition = array( |
|---|
| 65 | |
|---|
| 66 | 'id' => array( 'required' => false, |
|---|
| 67 | 'format' => 'string', |
|---|
| 68 | 'outputFormats' => array( 'html' ), |
|---|
| 69 | ), |
|---|
| 70 | 'name' => array( 'required' => true, |
|---|
| 71 | 'format' => 'string', |
|---|
| 72 | 'outputFormats' => array( 'html' ), |
|---|
| 73 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 74 | ), |
|---|
| 75 | 'type' => array( 'required' => false, |
|---|
| 76 | 'format' => 'string', |
|---|
| 77 | 'default' => 'text', |
|---|
| 78 | 'outputFormats' => array( 'html' ), |
|---|
| 79 | ), |
|---|
| 80 | 'title' => array( 'required' => false, |
|---|
| 81 | 'format' => 'string', |
|---|
| 82 | 'outputFormats' => array( 'html' ), |
|---|
| 83 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 84 | ), |
|---|
| 85 | 'description' => array( 'required' => false, |
|---|
| 86 | 'format' => 'string', |
|---|
| 87 | 'outputFormats' => array(), |
|---|
| 88 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 89 | ), |
|---|
| 90 | 'default' => array( 'required' => false, |
|---|
| 91 | 'format' => 'string', |
|---|
| 92 | 'outputFormats' => array(), |
|---|
| 93 | ), |
|---|
| 94 | 'label' => array( 'required' => false, |
|---|
| 95 | 'format' => 'string', |
|---|
| 96 | 'outputFormats' => array(), |
|---|
| 97 | ), |
|---|
| 98 | 'display' => array( 'required' => false, |
|---|
| 99 | 'format' => 'string', |
|---|
| 100 | 'default' => 'yes', |
|---|
| 101 | 'outputFormats' => array(), |
|---|
| 102 | ), |
|---|
| 103 | 'edit' => array( 'required' => false, |
|---|
| 104 | 'format' => 'string', |
|---|
| 105 | 'default' => 'yes', |
|---|
| 106 | 'outputFormats' => array(), |
|---|
| 107 | ), |
|---|
| 108 | 'disabled' => array( 'required' => false, |
|---|
| 109 | 'format' => 'string', |
|---|
| 110 | 'default' => 'no', |
|---|
| 111 | 'outputFormats' => array( 'html' ), |
|---|
| 112 | ), |
|---|
| 113 | 'required' => array( 'required' => false, |
|---|
| 114 | 'format' => 'string', |
|---|
| 115 | 'default' => 'yes', |
|---|
| 116 | 'outputFormats' => array(), |
|---|
| 117 | ), |
|---|
| 118 | 'value' => array( 'required' => false, |
|---|
| 119 | 'format' => 'string', |
|---|
| 120 | 'outputFormats' => array( 'html' ), |
|---|
| 121 | ), |
|---|
| 122 | 'style' => array( 'required' => false, |
|---|
| 123 | 'outputFormats' => array( 'html' ), |
|---|
| 124 | 'format' => 'string', |
|---|
| 125 | ), |
|---|
| 126 | 'class' => array( 'required' => false, |
|---|
| 127 | 'outputFormats' => array( 'html' ), |
|---|
| 128 | 'format' => 'string', |
|---|
| 129 | ), |
|---|
| 130 | 'onchange' => array( 'required' => false, |
|---|
| 131 | 'format' => 'string', |
|---|
| 132 | 'outputFormats' => array( 'html' ), |
|---|
| 133 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 134 | ), |
|---|
| 135 | 'onclick' => array( 'required' => false, |
|---|
| 136 | 'format' => 'string', |
|---|
| 137 | 'outputFormats' => array( 'html' ), |
|---|
| 138 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 139 | ), |
|---|
| 140 | 'onfocus' => array( 'required' => false, |
|---|
| 141 | 'format' => 'string', |
|---|
| 142 | 'outputFormats' => array( 'html' ), |
|---|
| 143 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 144 | ), |
|---|
| 145 | 'onmouseover' => array( 'required' => false, |
|---|
| 146 | 'format' => 'string', |
|---|
| 147 | 'outputFormats' => array( 'html' ), |
|---|
| 148 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 149 | ), |
|---|
| 150 | 'onmouseout' => array( 'required' => false, |
|---|
| 151 | 'format' => 'string', |
|---|
| 152 | 'outputFormats' => array( 'html' ), |
|---|
| 153 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 154 | ), |
|---|
| 155 | 'onblur' => array( 'required' => false, |
|---|
| 156 | 'format' => 'string', |
|---|
| 157 | 'outputFormats' => array( 'html' ), |
|---|
| 158 | 'modifiers' => array( 'insertSpecials' => array() ), |
|---|
| 159 | ), |
|---|
| 160 | 'accesskey' => array( 'required' => false, |
|---|
| 161 | 'format' => 'string', |
|---|
| 162 | 'outputFormats' => array( 'html' ), |
|---|
| 163 | ), |
|---|
| 164 | 'position' => array( 'required' => false, |
|---|
| 165 | 'format' => 'int', |
|---|
| 166 | 'outputFormats' => array(), |
|---|
| 167 | ), |
|---|
| 168 | 'tabindex' => array( 'required' => false, |
|---|
| 169 | 'format' => 'int', |
|---|
| 170 | 'outputFormats' => array( 'html' ), |
|---|
| 171 | ), |
|---|
| 172 | 'max' => array( 'required' => false, |
|---|
| 173 | 'format' => 'string', |
|---|
| 174 | 'outputFormats' => array(), |
|---|
| 175 | ), |
|---|
| 176 | 'min' => array( 'required' => false, |
|---|
| 177 | 'format' => 'string', |
|---|
| 178 | 'outputFormats' => array(), |
|---|
| 179 | ), |
|---|
| 180 | 'format' => array( 'required' => false, |
|---|
| 181 | 'format' => 'string', |
|---|
| 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 | { |
|---|
| 259 | return $this->numberformat; |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | $format = explode( $this->attributes['formatseparator'], $this->attributes['numberformat'] ); |
|---|
| 263 | |
|---|
| 264 | if( count( $format ) !== 3 ) |
|---|
| 265 | { |
|---|
| 266 | patErrorManager::raiseWarning( |
|---|
| 267 | PATFORMS_ELEMENT_NUMBER_WARNING_WRONG_FORMAT_STRING, |
|---|
| 268 | 'Incorrect number format string, using default', |
|---|
| 269 | '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'].'"' |
|---|
| 270 | ); |
|---|
| 271 | |
|---|
| 272 | $format = explode( $this->attributes['formatseparator'], $this->attributeDefinition['numberformat']['default'] ); |
|---|
| 273 | } |
|---|
| 274 | |
|---|
| 275 | $this->numberformat = $format; |
|---|
| 276 | |
|---|
| 277 | return $format; |
|---|
| 278 | } |
|---|
| 279 | |
|---|
| 280 | /** |
|---|
| 281 | * Manages the value that will be used |
|---|
| 282 | * |
|---|
| 283 | * @access private |
|---|
| 284 | * @param mixed $value The current raw value |
|---|
| 285 | * @return mixed $value The value that should be used |
|---|
| 286 | */ |
|---|
| 287 | function _manageValue( $value ) |
|---|
| 288 | { |
|---|
| 289 | // not submitted yet - let's see what we want to do with |
|---|
| 290 | // this element |
|---|
| 291 | if( !$this->submitted ) |
|---|
| 292 | { |
|---|
| 293 | // use a default value? |
|---|
| 294 | if( isset( $this->attributes['default'] ) ) |
|---|
| 295 | { |
|---|
| 296 | $value = $this->attributes['default']; |
|---|
| 297 | |
|---|
| 298 | // empty default value: this is a special case |
|---|
| 299 | // to avoid having the number format display, |
|---|
| 300 | // which is the standard behavior. |
|---|
| 301 | if( !strlen( $value ) ) |
|---|
| 302 | { |
|---|
| 303 | echo 'sadsda'; |
|---|
| 304 | $this->attributes['value'] = ''; |
|---|
| 305 | return $value; |
|---|
| 306 | } |
|---|
| 307 | } |
|---|
| 308 | |
|---|
| 309 | // format the number |
|---|
| 310 | $this->attributes['value'] = $this->formatNumber( $value ); |
|---|
| 311 | |
|---|
| 312 | // return the value for this case |
|---|
| 313 | return $value; |
|---|
| 314 | } |
|---|
| 315 | |
|---|
| 316 | // store the value in the value attribute... default |
|---|
| 317 | // behavior regardless of whether the element is valid |
|---|
| 318 | // or not. |
|---|
| 319 | $this->attributes['value'] = $value; |
|---|
| 320 | |
|---|
| 321 | // if the element has been validated we know the |
|---|
| 322 | // value is really a number, we can format it according |
|---|
| 323 | // to the given format. |
|---|
| 324 | if( $this->valid ) |
|---|
| 325 | { |
|---|
| 326 | $this->attributes['value'] = $this->formatNumber( $value ); |
|---|
| 327 | } |
|---|
| 328 | |
|---|
| 329 | // and return to sender... |
|---|
| 330 | return $value; |
|---|
| 331 | } |
|---|
| 332 | |
|---|
| 333 | /** |
|---|
| 334 | * element creation method for the 'HTML' format in the 'default' form mode. |
|---|
| 335 | * |
|---|
| 336 | * @access public |
|---|
| 337 | * @param mixed value of the element |
|---|
| 338 | * @return mixed $element The element, or false if failed. |
|---|
| 339 | */ |
|---|
| 340 | function serializeHtmlDefault( $value ) |
|---|
| 341 | { |
|---|
| 342 | if( $this->attributes['edit'] == 'no' ) |
|---|
| 343 | { |
|---|
| 344 | $this->attributes['disabled'] = 'yes'; |
|---|
| 345 | } |
|---|
| 346 | |
|---|
| 347 | $value = $this->_manageValue( $value ); |
|---|
| 348 | |
|---|
| 349 | if( $this->attributes['display'] == 'no' ) |
|---|
| 350 | { |
|---|
| 351 | return $this->createDisplaylessTag( $value ); |
|---|
| 352 | } |
|---|
| 353 | |
|---|
| 354 | return $this->toHtml(); |
|---|
| 355 | } |
|---|
| 356 | |
|---|
| 357 | /** |
|---|
| 358 | * Formats a number according to the number format set for the element |
|---|
| 359 | * |
|---|
| 360 | * @access private |
|---|
| 361 | * @param int $number The number to format |
|---|
| 362 | * @return string $number The formatted number |
|---|
| 363 | * @see getNumberFormat() |
|---|
| 364 | */ |
|---|
| 365 | function formatNumber( $number ) |
|---|
| 366 | { |
|---|
| 367 | $format = $this->getNumberFormat(); |
|---|
| 368 | |
|---|
| 369 | return number_format( $number, $format[0], $format[1], $format[2] ); |
|---|
| 370 | } |
|---|
| 371 | |
|---|
| 372 | /** |
|---|
| 373 | * element creation method for the 'HTML' format in the 'readonly' form mode. |
|---|
| 374 | * Very simple; just returns the stored element value. |
|---|
| 375 | * |
|---|
| 376 | * @access public |
|---|
| 377 | * @param mixed value of the element |
|---|
| 378 | * @return string $value The element's value |
|---|
| 379 | */ |
|---|
| 380 | function serializeHtmlReadonly( $value ) |
|---|
| 381 | { |
|---|
| 382 | $this->getAttributesFor( $this->getFormat() ); |
|---|
| 383 | |
|---|
| 384 | $value = $this->_manageValue( $value ); |
|---|
| 385 | $tag = $this->createDisplaylessTag( $value ); |
|---|
| 386 | |
|---|
| 387 | if( $this->attributes['display'] == 'no' ) |
|---|
| 388 | { |
|---|
| 389 | return $tag; |
|---|
| 390 | } |
|---|
| 391 | |
|---|
| 392 | return $value.$tag; |
|---|
| 393 | } |
|---|
| 394 | |
|---|
| 395 | /** |
|---|
| 396 | * validates the element. |
|---|
| 397 | * |
|---|
| 398 | * @access public |
|---|
| 399 | * @param mixed value of the element |
|---|
| 400 | * @return bool $isValid True if element could be validated, false otherwise. |
|---|
| 401 | */ |
|---|
| 402 | function validateElement( $value ) |
|---|
| 403 | { |
|---|
| 404 | // required & empty |
|---|
| 405 | if( $this->attributes['required'] == 'yes' && strlen( $value ) == 0 ) |
|---|
| 406 | { |
|---|
| 407 | $this->addValidationError( 1 ); |
|---|
| 408 | return false; |
|---|
| 409 | } |
|---|
| 410 | |
|---|
| 411 | $value = $this->inputValueToFloat( $value ); |
|---|
| 412 | |
|---|
| 413 | // only numeric values are accepted |
|---|
| 414 | if( !is_numeric( $value ) ) |
|---|
| 415 | { |
|---|
| 416 | $this->addValidationError( 2 ); |
|---|
| 417 | return false; |
|---|
| 418 | } |
|---|
| 419 | |
|---|
| 420 | // min |
|---|
| 421 | if( isset( $this->attributes['min'] ) && $value < $this->attributes['min'] ) |
|---|
| 422 | { |
|---|
| 423 | $this->addValidationError( 3, array( 'min' => $this->attributes['min'] ) ); |
|---|
| 424 | return false; |
|---|
| 425 | } |
|---|
| 426 | |
|---|
| 427 | // max |
|---|
| 428 | if( isset( $this->attributes['max'] ) && $value > $this->attributes['max'] ) |
|---|
| 429 | { |
|---|
| 430 | $this->addValidationError( 4, array( 'max' => $this->attributes['max'] ) ); |
|---|
| 431 | return false; |
|---|
| 432 | } |
|---|
| 433 | |
|---|
| 434 | // format |
|---|
| 435 | if( isset( $this->attributes['format'] ) && !$this->validateFormat( $value, $this->attributes['format'] ) ) |
|---|
| 436 | { |
|---|
| 437 | $this->addValidationError( 5 ); |
|---|
| 438 | return false; |
|---|
| 439 | } |
|---|
| 440 | |
|---|
| 441 | $this->value = $value; |
|---|
| 442 | |
|---|
| 443 | return true; |
|---|
| 444 | } |
|---|
| 445 | |
|---|
| 446 | /** |
|---|
| 447 | * transforms input value to floating point number |
|---|
| 448 | * |
|---|
| 449 | * |
|---|
| 450 | * @access private |
|---|
| 451 | * @param string $value the value-string |
|---|
| 452 | * @return float $value transformed value |
|---|
| 453 | */ |
|---|
| 454 | function inputValueToFloat( $value ) |
|---|
| 455 | { |
|---|
| 456 | $format = $this->getNumberFormat(); |
|---|
| 457 | |
|---|
| 458 | // remove thousand-seperator |
|---|
| 459 | $result = str_replace( $format[2], '', $value ); |
|---|
| 460 | |
|---|
| 461 | // replace decimal-point |
|---|
| 462 | $result = str_replace( $format[1], '.', $result ); |
|---|
| 463 | |
|---|
| 464 | // now this should be number! |
|---|
| 465 | if( !is_numeric( $result ) ) |
|---|
| 466 | { |
|---|
| 467 | return $value; |
|---|
| 468 | } |
|---|
| 469 | |
|---|
| 470 | // cast to float |
|---|
| 471 | $result = (float) $result; |
|---|
| 472 | |
|---|
| 473 | return $result; |
|---|
| 474 | } |
|---|
| 475 | } |
|---|
| 476 | ?> |
|---|