root/trunk/patForms/Element/Set.php

Revision 292, 15.6 kB (checked in by argh, 3 years ago)

Fixed bug #179, added error management in serialize*() methods that did not correctly return patError objects on error.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 /**
3  * simple multiple select dropdown patForms element
4  *
5  * $Id$
6  *
7  * @access        protected
8  * @package        patForms
9  * @subpackage    Element
10  */
11
12 /**
13  * no default value has been set
14  */
15 define( 'PATFORMS_ELEMENT_SET_ERROR_NO_DEFAULT_VALUE_AVAILABLE', 'patForms:Element:Set:01' );
16
17 /**
18  * simple multiple select dropdown patForms element
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_Set 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    =    'Set';
37
38    /**
39     * the type of the element - set this to the type of element you are creating
40     * if you want to use the {@link patForms_Element::element2html()} method to
41     * create the final HTML tag for your element.
42     *
43     * @access    public
44     * @see        patForms_Element::element2html()
45     */
46     var $elementType    =    array(
47         'html'    =>    'select',
48     );
49
50    /**
51     * set here which attributes you want to include in the element if you want to use
52     * the {@link patForms_Element::convertDefinition2Attributes()} method to automatically
53     * convert the values from your element definition into element attributes.
54     *
55     * @access    protected
56     * @see        patForms_Element::convertDefinition2Attribute()
57     */
58     var    $attributeDefinition    =    array(
59
60             'id'            =>    array(    'required'        =>    false,
61                                         'format'        =>    'string',
62                                         'outputFormats'    =>    array( 'html' ),
63                                     ),
64             'name'            =>    array(    'required'        =>    true,
65                                         'format'        =>    'string',
66                                         'outputFormats'    =>    array( 'html' ),
67                                     ),
68             'title'            =>    array(    'required'        =>    false,
69                                         'format'        =>    'string',
70                                         'outputFormats'    =>    array( 'html' ),
71                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
72                                     ),
73             'description'    =>    array(    'required'        =>    false,
74                                         'format'        =>    'string',
75                                         'outputFormats'    =>    array(),
76                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
77                                     ),
78             'default'        =>    array(    'required'        =>    false,
79                                         'format'        =>    'string',
80                                         'outputFormats'    =>    array(),
81                                     ),
82             'label'            =>    array(    'required'        =>    false,
83                                         'format'        =>    'string',
84                                         'outputFormats'    =>    array(),
85                                     ),
86             'display'        =>    array(    'required'        =>    false,
87                                         'format'        =>    'string',
88                                         'default'        =>    'yes',
89                                         'outputFormats'    =>    array(),
90                                     ),
91             'edit'            =>    array(    'required'        =>    false,
92                                         'format'        =>    'string',
93                                         'default'        =>    'yes',
94                                         'outputFormats'    =>    array(),
95                                     ),
96             'required'        =>    array(    'required'        =>    false,
97                                         'format'        =>    'string',
98                                         'default'        =>    'yes',
99                                         'outputFormats'    =>    array(),
100                                     ),
101             'value'            =>    array(    'required'        =>    false,
102                                         'format'        =>    'string',
103                                         'outputFormats'    =>    array(),
104                                     ),
105             'style'            =>    array(    'required'        =>    false,
106                                         'outputFormats'    =>    array( 'html' ),
107                                         'format'        =>    'string',
108                                     ),
109             'class'            =>    array(    'required'        =>    false,
110                                         'outputFormats'    =>    array( 'html' ),
111                                         'format'        =>    'string',
112                                     ),
113             'onchange'        =>    array(    'required'        =>    false,
114                                         'format'        =>    'string',
115                                         'outputFormats'    =>    array( 'html' ),
116                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
117                                     ),
118             'onclick'        =>    array(    'required'        =>    false,
119                                         'format'        =>    'string',
120                                         'outputFormats'    =>    array( 'html' ),
121                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
122                                     ),
123             'onfocus'        =>    array(    'required'        =>    false,
124                                         'format'        =>    'string',
125                                         'outputFormats'    =>    array( 'html' ),
126                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
127                                     ),
128             'onmouseover'    =>    array(    'required'        =>    false,
129                                         'format'        =>    'string',
130                                         'outputFormats'    =>    array( 'html' ),
131                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
132                                     ),
133             'onmouseout'    =>    array(    'required'        =>    false,
134                                         'format'        =>    'string',
135                                         'outputFormats'    =>    array( 'html' ),
136                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
137                                     ),
138             'onblur'        =>    array(    'required'        =>    false,
139                                         'format'        =>    'string',
140                                         'outputFormats'    =>    array( 'html' ),
141                                         'modifiers'        =>    array( 'insertSpecials' => array() ),
142                                     ),
143             'accesskey'        =>    array(    'required'        =>    false,
144                                         'format'        =>    'string',
145                                         'outputFormats'    =>    array( 'html' ),
146                                     ),
147             'position'        =>    array(    'required'        =>    false,
148                                         'format'        =>    'int',
149                                         'outputFormats'    =>    array(),
150                                     ),
151             'tabindex'        =>    array(    'required'        =>    false,
152                                         'format'        =>    'int',
153                                         'outputFormats'    =>    array( 'html' ),
154                                     ),
155             'values'        =>    array(    'required'        =>    false,
156                                         'format'        =>    'values',
157                                         'outputFormats'    =>    array(),
158                                     ),
159             'disabled'        =>    array(    'required'        =>    false,
160                                         'format'        =>    'string',
161                                         'outputFormats'    =>    array( 'html' ),
162                                     ),
163             'size'            =>    array(    'required'        =>    false,
164                                         'format'        =>    'string',
165                                         'default'        =>    '3',
166                                         'outputFormats'    =>    array( 'html' ),
167                                     ),
168             'maxsize'        =>    array(    'required'        =>    false,
169                                         'format'        =>    'string',
170                                         'default'        =>    '5',
171                                         'outputFormats'    =>    array(),
172                                     ),
173             'datasource'    =>    array(    'required'        =>    false,
174                                         'format'        =>    'datasource',
175                                         'outputFormats'    =>    array(),
176                                     ),
177             'multiple'        =>    array(    'required'        =>    false,
178                                         'format'        =>    'string',
179                                         'outputFormats'    =>    array( 'html' ),
180                                     ),
181             'min'            =>    array(    'required'        =>    false,
182                                         'format'        =>    'int',
183                                         'outputFormats'    =>    array(),
184                                     ),
185             'max'            =>    array(    'required'        =>    false,
186                                         'format'        =>    'int',
187                                         'outputFormats'    =>    array(),
188                                     ),
189         );
190
191     /**
192      *    define error codes an messages for each form element
193      *
194      *  @access private
195      *  @var    array    $validatorErrorCodes
196      */
197     var    $validatorErrorCodes  =   array(
198         'C'    =>    array(
199             1    =>    'This field is required, please complete it.',
200             2    =>    'The values given for the element does not match any of the possible values.',
201             3    =>    'You have to select at least [MIN] entries.',
202             4    =>    'You may not select more than [MAX] entries.',
203         ),
204         'de' =>    array(
205             1    =>    'Pflichtfeld. Bitte vervollständigen Sie Ihre Angabe.',
206             2    =>    'Die angegebenen Werte stimmen mit keinem der möglichen Werte überein.',
207             3    =>    'Bitte wählen Sie mindestens [MIN] Einträge aus.',
208             4    =>    'Bitte wählen Sie nicht mehr als [MAX] Einträge aus.',
209         ),
210         'fr' =>    array(
211             1    =>    'Ce champ est obligatoire.',
212             2    =>    'Votre sélection ne correspond à aucune des valeurs admises.',
213             3    =>    'Vous devez sélectionner au moins [MIN] éléments dans la liste.',
214             4    =>    'Vous ne pouvez sélectionner qu\'un maximum de [MAX] éléments dans la liste.',
215         )
216     );
217
218     var    $defaultReadonlyValue  =   array(
219         'C'    =>    'No selection',
220         'de' =>    'Keine Angabe',
221         'fr' =>    'Pas de sélection.',
222     );
223
224    /**
225     * sets the data source for this element. If you set a data source object, the element will
226     * ignore the 'values' attribute and request the values from the data source object. The
227     * data source object only needs to implement the getValues() method.
228     *
229     * @access    public
230     * @param    object    &$dataSource    The data source to use.
231     * @see        dataSource
232     */
233     function setDataSource( &$dataSource )
234     {
235         $this->attributes['datasource']    =&    $dataSource;
236     }
237
238    /**
239     * retrieves the values to fill the list with. If a data source object has been set,
240     * tries to retrieve them from there, otherwise takes them from the 'values' attribute.
241     *
242     * @access    public
243     * @return    mixed    $values    Array with values, or false if failed.
244     * @see        setDataSource()
245     */
246     function getValues()
247     {
248         $values = array();
249
250         if( isset( $this->attributes["datasource"] ) ) {
251             if (is_object( $this->attributes["datasource"])) {
252                 $values    =    $this->attributes["datasource"]->getValues($this);
253             } else {
254                 /**
255                  * if the datasource is no object, it could
256                  * be a callback
257                  *
258                  * The element will be passed to the callback
259                  */
260                 if (is_callable( $this->attributes["datasource"], false)) {
261                     $values    = call_user_func( $this->attributes["datasource"], $this);
262                 }
263             }
264         }
265         if (isset($this->attributes["values"])) {
266             $values = array_merge( $this->attributes["values"], $values );
267         }
268         if (empty($values)) {
269             return patErrorManager::raiseWarning(
270                 PATFORMS_ELEMENT_WARNING_NO_VALUES,
271                 'No values set to create a Set field',
272                 'The Set element ['.$this->attributes['name'].'] has no values to create a list from'
273             );
274         }
275
276         return $values;
277     }
278
279    /**
280     * Redefinition of the main patForms_Element method that manages
281     * converting string values to the internal format.
282     *
283     * @access    public
284     * @param    string|array    A single value as string, or a selected values list
285     * @see         patForms_Element::setValue()
286     */
287     function setValue( $value )
288     {
289         if( !is_array( $value ) )
290         {
291             $value = array( $value );
292         }
293     
294         return parent::setValue( $value );
295     }
296     
297    /**
298     * element creation method for the 'HTML' format in the 'default' form mode.
299     *
300     * @access    public
301     * @param    mixed    value of the element
302     * @return    mixed    $element    The element, or false if failed.
303     */
304     function serializeHtmlDefault( $value )
305     {
306         if( !is_array( $value ) )
307         {
308             $value    =    array();
309         }
310
311         if( $this->attributes['display'] == 'no' )
312         {
313             return $this->createDisplaylessTag( $value );
314         }
315
316         $values    = $this->getValues();
317         if( patErrorManager::isError( $values ) ) {
318             return $values;
319         }
320
321         // add multiple flag
322         $this->attributes['multiple']    =    'multiple';
323
324         // add disabled flag if the edit attribute has been set
325         if( isset( $this->attributes['edit'] ) && $this->attributes['edit'] == 'no' )
326         {
327             $this->attributes['disabled'] = 'yes';
328         }
329
330         // automatic size adjustment depending on element value list
331         if( $this->attributes['size'] == 'auto' )
332         {
333             $maxsize    =    count( $values );
334             if( $this->attributes['maxsize'] != 'none' && $maxsize > $this->attributes['maxsize'] )
335             {
336                 $maxsize    =    $this->attributes['maxsize'];
337             }
338
339             $this->attributes['size']    =    $maxsize;
340         }
341
342         $attributeCollection = $this->getAttributesFor( $this->getFormat() );
343
344         // make the name an array
345         $attributeCollection['name'] .= '[]';
346
347         $element    =    $this->createTag( 'select', 'opening', $attributeCollection );
348
349         foreach( $values as $line => $optionDef )
350         {
351             $attribs    =    array(    'value'    =>    $optionDef['value'] );
352
353             if ( isset( $optionDef['disabled'] ) && $optionDef['disabled'] == 'yes' )
354             {
355                 $attribs['disabled'] = 'disabled';
356             }
357
358             if( !empty( $optionDef['value'] ) )
359             {
360                 foreach( $value as $subLine => $val )
361                 {
362                     if( $optionDef['value'] == $val )
363                     {
364                         $attribs['selected']    =    'selected';
365                     }
366                 }
367             }
368
369             $element    .=    $this->createTag( 'option', 'full', $attribs, $optionDef['label'] );
370         }
371
372         $element    .=    $this->createTag( 'select', 'closing' );
373
374         // and return to sender...
375         return $element;
376     }
377
378     function createDisplaylessTag( $value )
379     {
380         if( !is_array( $value ) ) {
381             $value = array();
382         }
383
384         $this->getAttributesFor( $this->getFormat() );
385
386         $tags = null;
387         foreach( $value as $line => $val )
388         {
389             $tags    .=    $this->createHiddenTag( $val );
390         }
391
392         return $tags;
393     }
394
395    /**
396     * element creation method for the 'HTML' format in the 'readonly' form mode.
397     *
398     * @access    public
399     * @return    string    $value    The element's value
400     */
401     function serializeHtmlReadonly( $value )
402     {
403         $tag = $this->createDisplaylessTag( $value );
404
405         if( $this->attributes['display'] == 'no' )
406         {
407             return $tag;
408         }
409
410         if( empty( $value ) )
411         {
412             return $this->getReadonlyDefaultValue().$tag;
413         }
414
415         $element = null;
416
417         $values = $this->getValues();
418         if( patErrorManager::isError( $values ) )
419         {
420             return $values;
421         }
422
423         // build the list of labels for the selected entries
424         $parts    =    array();
425         foreach( $values as $line => $optionDef )
426         {
427             foreach( $value as $subLine => $val )
428             {
429                 if( $optionDef['value'] == $val )
430                 {
431                     array_push( $parts, $optionDef['label'] );
432                 }
433             }
434         }
435
436         // no selected entries
437         if( empty( $parts ) )
438         {
439             return $this->getReadonlyDefaultValue().$tag;
440         }
441
442         return implode( ', ', $parts ).$tag;
443     }
444
445    /**
446     * Redefinition of the method from the patForms Element base class, with added functionality
447     * needed for the set element (store several values in an array via several hidden fields)
448     * @access    public
449     */
450     function createHiddenTag( $value )
451     {
452         $attribs    =    array(    'type'    =>    'hidden',
453                                 'name'    =>    $this->attributes["name"] . '[]',
454                                 'value'    =>    $value,
455                             );
456
457         return $this->createTag( 'input', 'full', $attribs );
458     }
459
460    /**
461     * Retrieves the default value to display in the element's readonly mode if the
462     * user has not selected any entry, according to the selected locale
463     *
464     * @access    public
465     * @return    string    $defaultValue    The default readonly value in the needed locale
466     */
467     function getReadonlyDefaultValue()
468     {
469         $lang    =    $this->locale;
470
471         if( !isset( $this->defaultReadonlyValue[$lang] ) )
472         {
473             patErrorManager::raiseWarning(
474                 PATFORMS_ELEMENT_SET_ERROR_NO_DEFAULT_VALUE_AVAILABLE,
475                 'There is no default readonly value available for the locale "'.$lang.'", using default locale "C" instead.'
476             );
477             return $this->defaultReadonlyValue['C'];
478         }
479
480         return