root/trunk/patForms/Element/Enum.php

Revision 348, 15.5 kB (checked in by schst, 3 years ago)

Fix validation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 /**
3  * simple dropdown patForms element that builds and validates enumarated fields.
4  *
5  * $Id$
6  *
7  * @access        protected
8  * @package        patForms
9  * @subpackage    Element
10  */
11
12 /**
13  * Error: no default value has been set
14  */
15 define( 'PATFORMS_ELEMENT_ENUM_NOTICE_NO_DEFAULT_VALUE_AVAILABLE', 'patForms:Element:Enum:01');
16
17 /**
18  * simple dropdown patForms element that builds and validates enumarated fields.
19  *
20  * $Id$
21  *
22  * @access        protected
23  * @package        patForms
24  * @subpackage    Element
25  * @author        Sebastian Mordziol <argh@php-tools.net>
26  * @author        Stephan Schmidt <schst@php-tools.net>
27  * @license        LGPL, see license.txt for details
28  */
29 class patForms_Element_Enum extends patForms_Element
30 {
31    /**
32     * Stores the name of the element - this is used mainly by the patForms
33     * error management and should be set in every element class.
34     * @access    public
35     */
36     var $elementName    =    'Enum';
37
38    /**
39     * javascript that will be displayed only once
40     *
41     * @access    private
42     * @var        array
43     */
44     var $globalJavascript    =    array(
45                                         'html' => 'Html/Element/Enum.js'
46                                     );
47
48    /**
49     * javascript that will be displayed once per instance
50     *
51     * @access    private
52     * @var        array
53     */
54     var $instanceJavascript    =    array(
55                                         'html' => "var pfe_[ELEMENT::NAME] = new pFEC_Enum( '[ELEMENT::ID]' );\n"
56                                     );
57
58    /**
59     * the type of the element - set this to the type of element you are creating
60     * if you want to use the {@link patForms_Element::element2html()} method to
61     * create the final HTML tag for your element.
62     *
63     * @access    public
64     * @see        patForms_Element::element2html()
65     */
66     var $elementType    =    array(    "html"    =>    "select",
67                                 );
68
69    /**
70     * set here which attributes you want to include in the element if you want to use
71     * the {@link patForms_Element::convertDefinition2Attributes()} method to automatically
72     * convert the values from your element definition into element attributes.
73     *
74     * @access    protected
75     * @see        patForms_Element::convertDefinition2Attribute()
76     */
77     var    $attributeDefinition    =    array(
78
79             'id'            =>    array(    'required'        =>    false,
80                                         'format'        =>    'string',
81                                         'outputFormats'    =>    array( 'html' ),
82                                     ),
83             'name'            =>    array(    'required'        =>    true,
84                                         'format'        =>    'string',
85                                         'outputFormats'    =>    array( 'html' ),
86                                     ),
87             'title'            =>    array(    'required'        =>    false,
88                                         'format'        =>    'string',
89                                         'outputFormats'    =>    array( 'html' ),
90                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
91                                     ),
92             'description'    =>    array(    'required'        =>    false,
93                                         'format'        =>    'string',
94                                         'outputFormats'    =>    array(),
95                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
96                                     ),
97             'default'        =>    array(    'required'        =>    false,
98                                         'format'        =>    'string',
99                                         'outputFormats'    =>    array(),
100                                     ),
101             'label'            =>    array(    'required'        =>    false,
102                                         'format'        =>    'string',
103                                         'outputFormats'    =>    array(),
104                                     ),
105             'display'        =>    array(    'required'        =>    false,
106                                         'format'        =>    'string',
107                                         'default'        =>    'yes',
108                                         'outputFormats'    =>    array(),
109                                     ),
110             'edit'            =>    array(    'required'        =>    false,
111                                         'format'        =>    'string',
112                                         'default'        =>    'yes',
113                                         'outputFormats'    =>    array(),
114                                     ),
115             'required'        =>    array(    'required'        =>    false,
116                                         'format'        =>    'string',
117                                         'default'        =>    'yes',
118                                         'outputFormats'    =>    array(),
119                                     ),
120             'value'            =>    array(    'required'        =>    false,
121                                         'format'        =>    'string',
122                                         'outputFormats'    =>    array(),
123                                     ),
124             'style'            =>    array(    'required'        =>    false,
125                                         'outputFormats'    =>    array( 'html' ),
126                                         'format'        =>    'string',
127                                     ),
128             'class'            =>    array(    'required'        =>    false,
129                                         'outputFormats'    =>    array( 'html' ),
130                                         'format'        =>    'string',
131                                     ),
132             'onchange'        =>    array(    'required'        =>    false,
133                                         'format'        =>    'string',
134                                         'outputFormats'    =>    array( 'html' ),
135                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
136                                     ),
137             'onclick'        =>    array(    'required'        =>    false,
138                                         'format'        =>    'string',
139                                         'outputFormats'    =>    array( 'html' ),
140                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
141                                     ),
142             'onfocus'        =>    array(    'required'        =>    false,
143                                         'format'        =>    'string',
144                                         'outputFormats'    =>    array( 'html' ),
145                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
146                                     ),
147             'onmouseover'    =>    array(    'required'        =>    false,
148                                         'format'        =>    'string',
149                                         'outputFormats'    =>    array( 'html' ),
150                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
151                                     ),
152             'onmouseout'    =>    array(    'required'        =>    false,
153                                         'format'        =>    'string',
154                                         'outputFormats'    =>    array( 'html' ),
155                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
156                                     ),
157             'onblur'        =>    array(    'required'        =>    false,
158                                         'format'        =>    'string',
159                                         'outputFormats'    =>    array( 'html' ),
160                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
161                                     ),
162             'accesskey'        =>    array(    'required'        =>    false,
163                                         'format'        =>    'string',
164                                         'outputFormats'    =>    array( 'html' ),
165                                     ),
166             'position'        =>    array(    'required'        =>    false,
167                                         'format'        =>    'int',
168                                         'outputFormats'    =>    array(),
169                                     ),
170             'tabindex'        =>    array(    'required'        =>    false,
171                                         'format'        =>    'int',
172                                         'outputFormats'    =>    array( 'html' ),
173                                     ),
174             'values'        =>    array(    'required'        =>    false,
175                                         'format'        =>    'values',
176                                         'outputFormats'    =>    array(),
177                                     ),
178             'disabled'        =>    array(    'required'        =>    false,
179                                         'format'        =>    'string',
180                                         'default'        =>    'no',
181                                         'outputFormats'    =>    array( 'html' ),
182                                     ),
183             'size'        =>    array(        'required'        =>    false,
184                                         'format'        =>    'int',
185                                         'default'        =>    '1',
186                                         'outputFormats'    =>    array( 'html' ),
187                                     ),
188             'datasource'    =>    array(    'required'        =>    false,
189                                         'format'        =>    'datasource',
190                                         'outputFormats'    =>    array(),
191                                     ),
192             'maxsize'        =>    array(    'required'        =>    false,
193                                         'format'        =>    'string',
194                                         'default'        =>    '5',
195                                         'outputFormats'    =>    array(),
196                                     ),
197         );
198
199     /**
200      *    define error codes an messages for each form element
201      *
202      *  @access private
203      *  @var    array    $validatorErrorCodes
204      */
205     var    $validatorErrorCodes  =   array(
206         "C"    =>    array(
207             1    =>    "This field is required, please complete it.",
208             2    =>    "The value given for the element does not match any of the possible values.",
209         ),
210         "de" =>    array(
211             1    =>    "Pflichtfeld. Bitte vervollständigen Sie Ihre Angabe.",
212             2    =>    "Der angegebene Wert stimmt mit keinem der möglichen Werte überein.",
213         ),
214         "fr" =>    array(
215             1    =>    "Ce champ est obligatoire.",
216             2    =>    "La valeur de ce champ ne correspond à aucune des valeurs admises.",
217         )
218     );
219
220    /**
221     * Stores the value that will be displayed in readonly mode
222     * when no entry has been selected, in the available locales.
223     *
224     * @access    private
225     * @var        array
226     */
227     var    $defaultReadonlyValue  =   array(
228         "C"    =>    "No selection",
229         "de" =>    "Keine Angabe",
230         "fr" =>    "Pas de sélection.",
231     );
232
233    /**
234     * sets the data source for this element. If you set a data source object, the element will
235     * ignore the 'values' attribute and request the values from the data source object. The
236     * data source object only needs to implement the getValues() method.
237     *
238     * @access    public
239     * @param    object    &$dataSource    The data source to use.
240     * @see        dataSource
241     */
242     function setDataSource( &$dataSource )
243     {
244         $this->attributes["datasource"]    =&    $dataSource;
245     }
246
247    /**
248     * retrieves the values to fill the list with. If a data source object has been set,
249     * tries to retrieve them from there, otherwise takes them from the 'values' attribute.
250     *
251     * @access    public
252     * @return    mixed    $values    Array with values, or false if failed.
253     * @see        setDataSource()
254     */
255     function getValues()
256     {
257         $values = array();
258
259         if( isset( $this->attributes["datasource"] ) ) {
260             if (is_object( $this->attributes["datasource"])) {
261                 $values    =    $this->attributes["datasource"]->getValues($this);
262             } else {
263                 /**
264                  * if the datasource is no object, it could
265                  * be a callback
266                  *
267                  * The element will be passed to the callback
268                  */
269                 if (is_callable( $this->attributes["datasource"], false)) {
270                     $values    = call_user_func( $this->attributes["datasource"], $this);
271                 }
272             }
273         }
274         if (isset($this->attributes["values"])) {
275             $values = array_merge( $this->attributes["values"], $values );
276         }
277         if (empty($values)) {
278             return patErrorManager::raiseWarning(
279                 PATFORMS_ELEMENT_WARNING_NO_VALUES,
280                 'No values set to create an Enum field',
281                 'The Enum element ['.$this->attributes['name'].'] has no values to create a list from'
282             );
283         }
284         return $values;
285     }
286
287    /**
288     * element creation method for the 'HTML' format in the 'default' form mode.
289     *
290     * @access    public
291     * @param    mixed    value of the element
292     * @return    mixed    $element    The element, or false if failed.
293     * @todo     Fix maxsize=auto when using optgroups
294     */
295     function serializeHtmlDefault( $value )
296     {
297         // handle display attribute
298         if ($this->attributes['display'] == 'no') {
299             return $this->createDisplaylessTag($value);
300         }
301
302         if ($this->attributes['edit'] == 'no') {
303             return $this->serializeHtmlReadonly($value);
304         }
305
306         $values = $this->getValues();
307         if (patErrorManager::isError($values)) {
308             return $values;
309         }
310
311         // automatic size adjustment depending on element value list
312         if ($this->attributes['size'] == 'auto') {
313             $maxsize = count($values);
314             if ($this->attributes['maxsize'] != 'none' && $maxsize > $this->attributes['maxsize']) {
315                 $maxsize    =    $this->attributes['maxsize'];
316             }
317             $this->attributes['size']    =    $maxsize;
318         }
319
320         $attribs = $this->getAttributesFor( $this->getFormat() );
321         $element    =    $this->createTag( "select", "opening", $attribs );
322
323         foreach($values as $line => $optionDef) {
324             // Is it a group?
325             if (isset($optionDef['values'])) {
326                 $attribs = array('label' => $optionDef['label']);
327                 $element .= $this->createTag('optgroup', 'opening', $attribs);
328                 foreach ($optionDef['values'] as $option) {
329                     $element .= $this->_createOptionTag($option, $value);
330                 }
331                 $element .= $this->createTag('optgroup', 'closing');
332                 
333             } else {
334                 $element .= $this->_createOptionTag($optionDef, $value);
335             }
336             
337         }
338
339         $element    .=    $this->createTag( "select", "closing" );
340
341         // and return to sender...
342         return $element;
343     }
344
345    /**
346     * Create an option tag
347     *
348     * @access protected
349     * @param  array
350     * @param  mixed     the current value of the element
351     * @return string
352     */   
353     function _createOptionTag($optionDef, $value)
354     {
355         $attribs = array('value' => $optionDef['value']);
356         if (isset( $optionDef['disabled'] ) && $optionDef['disabled'] == 'yes') {
357             $attribs['disabled'] = 'disabled';
358         }
359
360         if (!empty($optionDef['value'] ) && $optionDef['value'] == $value) {
361             $attribs["selected"] = "selected";
362         }
363         return $this->createTag( "option", "full", $attribs, $optionDef["label"] );
364     }
365     
366    /**
367     * element creation method for the 'HTML' format in the 'readonly' form mode.
368     *
369     * @access    public
370     * @param    mixed    value of the element
371     * @return    string    $value    The element's value
372     */
373     function serializeHtmlReadonly( $value )
374     {
375         $element = null;
376         $values  = $this->getValues();
377
378         if(patErrorManager::isError($values)) {
379             return $values;
380         }
381
382         $tag = $this->createDisplaylessTag($value);
383
384         if($this->attributes['display'] == 'no') {
385             return $tag;
386         }
387
388         // empty value -> no entry selected - display the readonly
389         // default value instead.
390         if ($value === '') {
391             return $this->getReadonlyDefaultValue().$tag;
392         }
393
394         $values = $this->getFlatValues($values);
395         foreach ($values as $line => $optionDef) {
396             if ($optionDef["value"] == $value) {
397                 $element = $optionDef["label"];
398                 break;
399             }
400         }
401
402         if (empty($element)) {
403             $element = $this->getReadonlyDefaultValue();
404         }
405
406         return $element.$tag;
407     }
408
409    /**
410     * get only flat values, without optgroup structure
411     *
412     * @return array
413     */
414     function getFlatValues($options)
415     {
416         $flat = array();
417         foreach ($options as $group) {
418             if (isset($group['value'])) {
419                 array_push($flat, $group);
420                 continue;
421             }
422             $flat = array_merge($flat, $group['values']);
423         }
424         return $flat;
425     }
426     
427    /**
428     * Retrieves the default value to display in the element's readonly mode if the
429     * user has not selected any entry, according to the selected locale
430     *
431     * @access    public
432     * @return    string    $defaultValue    The default readonly value in the needed locale
433     */
434     function getReadonlyDefaultValue()
435     {
436         $lang    =    $this->locale;
437
438         if( !isset( $this->defaultReadonlyValue[$lang] ) )
439         {
440             patErrorManager::raiseNotice(
441                 PATFORMS_ELEMENT_ENUM_NOTICE_NO_DEFAULT_VALUE_AVAILABLE,
442                 'There is no default readonly value available for the locale "'.$lang.'", using default locale "C" instead.'
443             );
444
445             return $this->defaultReadonlyValue['C'];
446         }
447
448         return $this->defaultReadonlyValue[$lang];
449     }
450
451    /**
452     * validates the element.
453     *
454     * @access    public
455     * @param    mixed    value of the element
456     * @return    bool    $isValid    True if element could be validated, false otherwise.
457     */
458     function validateElement( $value )
459     {
460         $values    =    $this->getValues();
461
462         if ($values === false) {
463              $this->valid = false;
464             return false;
465         }
466
467         // required & empty
468         if( isset( $this->attributes["required"] ) && $this->attributes["required"] == "yes" && strlen( $value ) == 0 )
469         {
470             $this->addValidationError( 1 );
471             return false;
472         }
473
474         $values = $this->getFlatValues($values);
475         
476         // is value in values list?
477         $found = false;
478         foreach( $values as $line => $optionDef )
479         {
480             if( $optionDef["value"] == $value )
481             {
482                 $found    =    true;
483             }
484         }
485
486         if( !$found )
487         {
488             $this->