source: trunk/patForms/Element/Combobox.php @ 267

Revision 267, 13.8 KB checked in by schst, 8 years ago (diff)

Pass the element to the datasource, to allow context-sensitive datasources (as requested #151)

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