source: trunk/patForms/Element/Enum.php @ 258

Revision 258, 14.4 KB checked in by sfuchs, 8 years ago (diff)

changed patForms, patForms_Element and several element subclasses to support "form-namespaces"
closing ticket #129

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