Dotclear

source: inc/admin/class.dc.form.php @ 1524:913f5a36bbb0

Revision 1524:913f5a36bbb0, 31.2 KB checked in by Dsls, 12 years ago (diff)

columns selection is now functional in admin lists

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2011 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_RC_PATH')) { return; }
13
14/**
15* dcFormNode Twig Node for Form handling
16*
17* @uses     Twig_Node
18*
19*/
20class dcFormNode extends Twig_Node
21{
22     public function __construct($name,Twig_NodeInterface $body,$attr,$lineno,$tag=null)
23     {
24          parent::__construct(array('body' => $body),array('name' => $name, 'attr' => $attr),$lineno,$tag);
25     }
26     
27     /**
28     * Compiles the node to PHP.
29     *
30     * @param Twig_Compiler A Twig_Compiler instance
31     */
32     public function compile(Twig_Compiler $compiler)
33     {
34          $compiler
35               ->addDebugInfo($this);
36          $compiler
37               ->write("\$context['dc_form']->beginForm(")
38               ->subcompile($this->getAttribute('name'));
39          if ($this->getAttribute('attr') !== null) {
40               $compiler
41                    ->write(',')
42                    ->subcompile($this->getAttribute('attr'));
43          }
44          $compiler
45               ->write(");\n");
46          $compiler
47               ->subcompile($this->getNode('body'))
48               ->write("\$context['dc_form']->renderHiddenWidgets();\n")
49               ->write("\$context['dc_form']->endForm();\n")
50          ;
51     }
52}
53
54/**
55 * Template form token parser
56 */
57class dcFormTokenParser extends Twig_TokenParser
58{
59    /**
60     * parse - parses form tag
61     * General syntax is :
62     *  {% form 'formname' %}
63     *  ... {{ form_field (...)}}
64     *  {% endform %}
65     * Specific attributes can be passed to the form, enabling to set
66     * attributes to the form template :
67     * {% form 'formname' with {'id':'myform'} %}
68     * @param mixed \Twig_Token Description.
69     *
70     * @access public
71     *
72     * @return mixed Value.
73     */
74     public function parse(Twig_Token $token)
75     {
76          $lineno = $token->getLine();
77          $stream = $this->parser->getStream();
78          $name = $this->parser->getExpressionParser()->parseExpression();
79          $attr = null;
80          /* parse optional context */
81          if ($stream->test(Twig_Token::NAME_TYPE, 'with')) {
82               $stream->next();
83               $attr = $this->parser->getExpressionParser()->parseExpression();
84          }
85          $stream->expect(Twig_Token::BLOCK_END_TYPE);
86          $body = $this->parser->subparse(array($this,'decideBlockEnd'),true);
87          $stream->expect(Twig_Token::BLOCK_END_TYPE);
88
89          return new dcFormNode($name,$body,$attr,$token->getLine(),$this->getTag());
90     }
91
92     public function decideBlockEnd(Twig_Token $token)
93     {
94          return $token->test('endform');
95     }
96
97     public function getTag()
98     {
99          return 'form';
100     }
101}
102
103/**
104 * Template form extension
105 */
106class dcFormExtension extends Twig_Extension
107{
108     protected $template;
109     protected $tpl;
110     protected $core;
111     protected $twig;
112     protected $forms;
113     protected $currentForm;
114     protected $blocks;
115
116     public function __construct($core)
117     {
118          $this->core = $core;
119          $this->tpl = array('@forms/form_layout.html.twig');
120          $this->forms = array();
121          $this->blocks = array();
122          $this->currentForm = null;
123     }
124
125     public function initRuntime(Twig_Environment $environment)
126     {
127          $this->twig = $environment;
128          $this->twig->getLoader()->addPath(dirname(__FILE__).'/default-templates/forms','forms');
129          foreach ($this->tpl as $tpl) {
130               $this->template = $this->twig->loadTemplate($tpl);
131               $this->blocks = array_merge($this->blocks,$this->template->getBlocks());
132          }
133     }
134
135     public function addTemplate($tpl) {
136          $this->tpl[]=$tpl;
137          if (isset($this->twig)) {
138               $this->template = $this->twig->loadTemplate($tpl);
139               $this->blocks = array_merge($this->blocks,$this->template->getBlocks());
140          }
141     }
142
143     public function getGlobals()
144     {
145          return array('dc_form' => $this);
146     }
147
148     public function getFunctions()
149     {
150          return array(
151               new Twig_SimpleFunction(
152                    'widget',
153                    array($this,'renderWidget'),
154                    array('is_safe' => array('html'))
155               ),
156               new Twig_SimpleFunction(
157                    'haswidget',
158                    array($this,'hasWidget'),
159                    array('is_safe' => array('html'))
160               ),
161               new Twig_SimpleFunction(
162                    'form_field',
163                    array($this,'renderField'),
164                    array('is_safe' => array('html'))
165               ),
166               new Twig_SimpleFunction(
167                    'form_hidden',
168                    array($this,'renderHiddenWidgets'),
169                    array('is_safe' => array('html'))
170               ),
171               new Twig_SimpleFunction(
172                    'form_field_attr',
173                    array($this,'getFieldAttributes'),
174                    array('is_safe' => array('html'))
175               ),
176               new Twig_SimpleFunction(
177                    '_form_is_choice_group',
178                    array($this,'isChoiceGroup'),
179                    array('is_safe' => array('html'))
180               ),
181               new Twig_SimpleFunction(
182                    '_form_is_choice_selected',
183                    array($this,'isChoiceSelected'),
184                    array('is_safe' => array('html'))
185               )
186          );
187     }
188
189    /**
190     * isChoiceGroup - binding for twig function "_form_is_choice_group"
191     *                        returns whether a choice is a group or not
192     * @param mixed $choice the choice.
193     *
194     * @access public
195     *
196     * @return boolean true is choice is a group (optgroup).
197     */
198     public function isChoiceGroup($choice)
199     {
200          return is_array($choice);
201     }
202
203    /**
204     * isChoiceSelected - binding for twig function "_form_is_choice_selected"
205     *                        returns whether current choice matches a value or not
206     * @param mixed $choice the choixe.
207     * @param mixed $value  the value to check matching.
208     *
209     * @access public
210     *
211     * @return boolean if choice is matching the value.
212     */
213     public function isChoiceSelected($choice,$value)
214     {
215          return $choice == $value;
216     }
217
218    /**
219     * getTokenParsers returns token parsers
220     *
221     * @access public
222     *
223     * @return mixed Value.
224     */
225     public function getTokenParsers()
226     {
227          return array(new dcFormTokenParser());
228     }
229
230    /**
231     * hasWidget - binding for twig "haswidget" function
232     *    returns whether a widget is defined or not
233     *
234     * @param mixed $name the widget name.
235     *
236     * @access public
237     *
238     * @return boolean true if the widget exists.
239     */
240     public function hasWidget($name) {
241          return isset($this->blocks[$name]);
242     }
243
244    /**
245     * renderWidget - binding for 'widget' twig function
246     * behaves exactly like "block" function, except that a context
247     * can be passed to the function
248     *
249     * @param mixed $name the widget (block) name to render.
250     * @param mixed $attr Description the context for this block.
251     *
252     *
253     * @return mixed Value.
254     */
255     public function renderWidget($name,$attr) {
256          if (!isset($this->blocks[$name]))
257               return '';
258          echo $this->template->renderBlock(
259               $name,
260               $attr,
261               $this->blocks
262          );
263     }
264
265    /**
266     * getCurrentForm - returns current form if called within a {% form %} tag
267     *
268     * @access public
269     *
270     * @return string the current form.
271     */
272     public function getCurrentForm() {
273          return $this->currentForm;
274     }
275
276    /**
277     * renderField - binding for 'form_field' twig function; renders a field
278     *
279     * @param mixed $name       field name as defined on php side.
280     * @param array $attributes html attributes for field (ex : class, ...).
281     * @param array $extra      extra attributes that may be template specific.
282     *
283     * @access public
284     *
285     * @return mixed Value.
286     */
287     public function renderField($name,$attributes=array(),$extra=array())
288     {
289          $field = $this->currentForm->getField($name);
290          if ($field) {
291               $attr = $field->getAttributes($attributes);
292               if (isset($attr['attr'])) {
293                    $attr['attr'] = array_merge($attr['attr'],$attributes);
294               } else {
295                    $attr['attr'] = $attributes;
296               }
297               $this->renderWidget(
298               $field->getWidgetBlock(),
299                    array_merge(
300                         $attr,
301                         $extra
302                    )
303               );
304          }
305     }
306     
307    /**
308     * getFieldAttributes - binding for 'form_field_attr' twig function; returns all field attributes
309     *
310     * @param mixed $name       field name as defined on php side.
311     * @param mixed $name       the attribute name, null to grab all attributes as an array
312     *
313     * @access public
314     *
315     * @return array the field attributes
316     */   
317     public function getFieldAttributes($name,$attr=null)
318     {
319          $field = $this->currentForm->getField($name);
320          if ($field) {
321               $a = $field->getAttributes();
322               if ($attr !== null) {
323                    if (isset($a[$attr])) {
324                         return $a[$attr];
325                    } else {
326                         return null;
327                    }
328               } else {
329                    return $field->getAttributes();
330               }
331          } else {
332               return array();
333          }
334     }
335
336    /**
337     * renderHiddenWidgets -- renders all form hidden fields
338     *
339     * @access public
340     *
341     * @return mixed Value.
342     */
343     public function renderHiddenWidgets()
344     {   
345          if ($this->currentForm->areHiddenfieldsDisplayed()) {
346               return;
347          }
348          foreach ($this->currentForm->getHiddenFields() as $h) {
349               $this->renderField($h->getName());
350          }
351          $this->currentForm->setHiddenfieldsDisplayed();
352     }
353
354     public function getName()
355     {
356          return 'dc_form';
357     }
358
359    /**
360     * addForm -- registers a new form
361     *
362     * @param mixed \dcForm Description.
363     *
364     * @access public
365     *
366     * @return mixed Value.
367     */
368     public function addForm(dcForm $form)
369     {
370          $this->forms[$form->getName()] = $form;
371     }
372
373    /**
374     * beginForm -- displays form beginning
375     *
376     * @param mixed $name form name.
377     * @param array $attr extra attributes.
378     *
379     * @access public
380     *
381     * @return mixed Value.
382     */
383     public function beginForm($name,$attr=array())
384     {
385          if (isset($this->forms[$name])) {
386               $this->currentForm = $this->forms[$name];
387               $this->currentForm->begin($attr);
388          }
389          else {
390               throw new Twig_Error_Runtime(sprintf(
391                    'Form "%s" does not exist',
392                    $name
393               ));
394          }
395     }
396
397    /**
398     * endForm -- displays form ending
399     *
400     * @access public
401     *
402     * @return mixed Value.
403     */
404     public function endForm()
405     {
406          $this->currentForm->end();
407          $this->currentForm = null;
408     }
409}
410
411/**
412 * Template form exception
413 */
414class InvalidFieldException extends Exception {
415}
416
417/**
418* dcForm - Template form
419*
420*/
421class dcForm
422{
423     /** @var string form id */
424     protected $id;
425     /** @var string form name */
426     protected $name;
427     /** @var dcCore dcCore instance */
428     protected $core;
429     /** @var string form action */
430     protected $action;
431     /** @var array(dcField) list of form fields */
432     protected $fields;
433     /** @var string form method (GET/POST) */
434     protected $method;
435     /** @var array(dcField) list of submit fields */
436     protected $submitfields;
437     /** @var array(dcField) list of hidden fields */
438     protected $hiddenfields;
439     /** @var array(dcField) list of form errors */
440     protected $errors;
441     /** @var array() list of form properties */
442     protected $properties;
443     
444     protected $hiddendisplayed;
445     
446    /**
447     * Class constructor
448     *
449     * @param mixed  $core   dotclear core
450     * @param mixed  $name   form name - can be an array (name,id)
451     * @param mixed  $action form action
452     * @param string $method form method ('GET' or 'POST')
453     *
454     * @access public
455     *
456     * @return mixed Value.
457     */
458     public function __construct($core,$name,$action,$method='POST')
459     {
460          $this->core = $core;
461          $this->setNID($name);
462          $this->method = $method;
463          $this->action = $action;
464          $this->fields = array();
465          $this->core->tpl->getExtension('dc_form')->addForm($this);
466          $this->submitfields = array();
467          $this->hiddenfields = array();
468          $this->errors = array();
469          $this->properties = array();
470          if ($method == 'POST') {
471               $this->addNonce();
472          }
473          $this->hiddendisplayed = false;
474     }
475
476     /**
477     * areHiddenFieldsDisplayed - tells whether hidden fields have been rendered or not
478     *
479     * @return boolean true if hidden fields have already been displayed, false otherwise
480     * @access public
481     */
482     public function areHiddenFieldsDisplayed() {
483          return $this->hiddendisplayed;
484     }
485     
486     /**
487     * setHiddenFieldsDisplayed - sets whether hidden fields have been rendered or not
488     *
489     * @param boolean true (default) if hidden fields are to be set as displayed, false otherwise
490     * @access public
491     */
492     public function setHiddenFieldsDisplayed($value=true) {
493          $this->hiddendisplayed = $value;
494     }
495     
496    /**
497     * setProperty - sets form property
498     *
499     * @param string $name the property name.
500     * @param mixed $value the property value.
501     *
502     * @access public
503     */
504     public function setProperty($prop,$value) {
505          $this->properties[$prop]=$value;
506     }
507     
508    /**
509     * getProperty - gets form property
510     *
511     * @param string $name the property name.
512      *
513     * @return mixed the property value, null if no property found.
514     * @access public
515     */   
516     public function getProperty($prop) {
517          if (isset($this->properties[$prop])) {
518               return $this->properties[$prop];
519          } else {
520               return null;
521          }
522     }
523    /**
524     * addTemplate - Adds a template file to enrich form fields
525     *
526     * @param string $t the template file.
527     *
528     * @access public
529     */
530     public function addTemplate($t) {
531          $this->core->tpl->getExtension('dc_form')->addTemplate($t);
532     }
533
534    /**
535     * addNonce -- adds dc nonce to form fields
536     *
537     * @access protected
538     *
539     * @return nothing
540     */
541     protected function addNonce()
542     {
543          $this->addField(
544               new dcFieldHidden(array('xd_check'),
545               $this->core->getNonce())
546          );
547     }
548
549    /**
550     * Defines Name & ID from field
551     *
552     * @param mixed $nid either an array (name, id) or a string
553     *                   (name only, id will be set to null).
554     *
555     * @access protected
556     *
557     * @return nothing.
558     */
559     protected function setNID($nid)
560     {
561          if (is_array($nid)) {
562               $this->name = $nid[0];
563               $this->id = !empty($nid[1]) ? $nid[1] : null;
564          }
565          else {
566               $this->id = null;
567               $this->name = $nid;
568          }
569     }
570
571    /**
572     * getContext - returns form context (to fill-in twig context for instance),
573     *                   if any
574     *
575     * @access public
576     *
577     * @return array the form context.
578     */
579     public function getContext() {
580          return array();
581     }
582
583
584    /**
585     * Returns form name
586     *
587     * @access public
588     *
589     * @return mixed Value.
590     */
591     public function getName()
592     {
593          return $this->name;
594     }
595
596    /**
597     * getErrors - returns form errors
598     *
599     * @access public
600     *
601     * @return array the list of errors.
602     */
603     public function getErrors()
604     {
605          return $this->errors;
606     }
607
608    /**
609     * addField - adds a new field to form
610     *
611     * @param mixed \dcField the field to add.
612     *
613     * @access public
614     *
615     * @return dcForm the form instance (therefore addField can be chained)
616     */
617     public function addField(dcField $f)
618     {
619          if ($f instanceof dcFieldAction) {
620               $this->submitfields[$f->getName()] = $f;
621          }
622          if ($f instanceof dcFieldHidden) {
623               $this->hiddenfields[$f->getName()] = $f;
624          }
625          $this->fields[$f->getName()] = $f;
626
627          return $this;
628     }
629
630    /**
631     * getField - retrieves a field form form
632     *
633     * @param string the field name
634     *
635     * @access public
636     *
637     * @return dcForm the requested field
638     */   
639      public function getField($name) {
640          if (isset($this->fields[$name])) {
641               return $this->fields[$name];
642          } else {
643               return null;
644          }
645     }
646     
647    /**
648     * removeField - removes a field
649     *
650     * @param mixed \dcField the field to remove.
651     *
652     * @access public
653     *
654     * @return dcForm the form instance (therefore addField can be chained)
655     */
656     public function removeField(dcField $f) {
657          $n = $f->getName();
658          if (isset($this->fields[$n])){
659               unset($this->fields[$n]);
660          }
661          return $this;
662     }
663
664
665    /**
666     * renameField - renames a field
667     *
668     * @param mixed $field   the field to rename.
669     * @param mixed $newname new field name
670     *
671     * @access public
672     *
673     *
674     * @return dcForm the form instance (therefore addField can be chained)
675     */
676     public function renameField($field,$newname) {
677          $oldname = $field->getName();
678          if (isset($this->fields[$oldname])) {
679               unset($this->fields[$oldname]);
680               $field->setName($newname);
681               $this->fields[$newname] = $field;
682          }
683          return $this;
684     }
685
686    /**
687     * begin - begins a form. Should be not be called directly, it is handled
688     *              by the Twig Form extension.
689     *
690     * @param array $attr form extra attributes, if any.
691     *
692     * @access public
693     *
694     * @return mixed Value.
695     */
696     public function begin($attr=array())
697     {
698          $attr['method'] = $this->method;
699          $attr['action'] = $this->action;
700          if (!empty($this->id)) {
701               $attr['id'] = $this->id;
702          }
703          $this->core->tpl->getExtension('dc_form')->renderWidget(
704               'beginform',
705               $attr);
706     }
707
708    /**
709     * end - ends a form. Should be not be called directly, it is handled
710     *              by the Twig Form extension.
711     *
712     * @access public
713     *
714     * @return mixed Value.
715     */
716     public function end($attr=array())
717     {
718          $this->core->tpl->getExtension('dc_form')->renderWidget(
719               'endform',$attr);
720     }
721
722    /**
723     * __isset - magic method isset, checks whether a field exists
724     *                   example : if (isset($form->field1))
725     *
726     * @param mixed $name field name to check.
727     *
728     * @access public
729     *
730     * @return boolean true if the field exists.
731     */
732     public function __isset($name)
733     {
734          return isset($this->fields[$name]);
735     }
736
737    /**
738     * __get -- magic method, retrieves a field from a form
739     *              example : $f = $form->field1
740     *
741     * @param mixed $name Description.
742     *
743     * @access public
744     *
745     * @return mixed Value.
746     */
747     public function __get($name)
748     {
749          if (isset($this->fields[$name])) {
750               $f = $this->fields[$name];
751               if ($f->isMultiple()) {
752                    return $f->getValues();
753               } else {
754                    return $f->getValue();
755               }
756          } else {
757               return $this->getProperty($name);
758          }
759     }
760
761    /**
762     * __set -- magic method, sets a value for a given form field
763     *              example : $form->field1 = 'my value';
764     *
765     * @param mixed $name  the field name.
766     * @param mixed $value the field value.
767     *
768     * @access public
769     */
770     public function __set($name,$value)
771     {
772          if (isset($this->fields[$name])) {
773               $f = $this->fields[$name];
774               if ($f->isMultiple()) {
775                    $this->fields[$name]->setValues($value);
776               } else {
777                    $this->fields[$name]->setValue($value);
778               }
779          } else {
780               $this->setProperty($name,$value);
781          }
782     }
783
784    /**
785     * setupFields - initializes form & fields from $_GET or $_POST
786     *
787     * @access protected
788     */
789     protected function setupFields() {
790          $from = $this->method == 'POST' ? $_POST : $_GET;
791          if (!empty($from)) {
792               foreach ($this->fields as $f) {
793                    $f->setup($from);
794               }
795          }
796     }
797
798    /**
799     * handleActions - handle appropriate actions, according to submitted fields
800     *
801     * @param mixed $submitted the fields that have been submitted.
802     *
803     * @access protected
804     */
805     protected function handleActions($submitted) {
806          $hasActions = false;
807          foreach ($submitted as $f) {
808               $action = $f->getAction();
809               if ($action != NULL && is_callable($action)) {
810                    $hasActions = true;
811                    $ret = call_user_func($action,$this);
812               }
813          }
814     }
815
816    /**
817     * getSubmittedFields - retrieves fields that have been submitted, if any
818     *
819     * @access protected
820     *
821     * @return array the list of submitted fields.
822     */
823     protected function getSubmittedFields() {
824          $s = array();
825          foreach ($this->submitfields as $f) {
826               if ($f->isDefined()) {
827                    $s[$f->getName()] = $f;
828               }
829          }
830          return $s;
831     }
832
833    /**
834     * isSubmitted - returns whether form has been submitted or not
835     *
836     * @access public
837     *
838     * @return boolean true if the form has been submitted.
839     */   
840     public function isSubmitted() {
841          foreach ($this->submitfields as $f) {
842               if ($f->isDefined()) {
843                    return true;
844               }
845          }
846          return false;       
847     }
848     
849    /**
850     * setup - sets up the form, given the parameters given to the page
851     *              should be called after fields have been defined.
852     *
853     * @access public
854     *
855     * @return mixed Value.
856     */
857     public function setup()
858     {
859          $this->setupFields();
860          $submitted = $this->getSubmittedFields();
861          $this->handleActions($submitted);
862     }
863
864    /**
865     * check - checks if the form is valid, errors are filled in, in case of
866     *              incorrect fields
867     *
868     * @access public
869     */
870     public function check(dcAdminContext $ctx)
871     {
872          $valid = true;
873          foreach ($this->fields as $f) {
874               try {
875                    $f->check();
876               }
877               catch (InvalidFieldException $e) {
878                    $valid = false;
879                    $ctx->addError($e->getMessage());
880               }
881          }
882          if (!$valid) {
883               throw new InvalidFieldException ("Some fields are missing");
884          }
885     }
886
887     public function getFieldIDs() {
888          return array_keys($this->fields);
889     }
890     
891    /**
892     * getHiddenFields - returns the list of hidden fields
893     *
894     * @access public
895     *
896     * @return array the list of hidden fields.
897     */
898     public function getHiddenFields()
899     {
900          return $this->hiddenfields;
901     }
902}
903
904/**
905 * Template form field
906 */
907abstract class dcField implements Countable
908{
909     /** @var string field options */
910     protected $options;
911     /** @var string field name */
912     protected $name;
913     /** @var string field values */
914     protected $values;
915     /** @var string field id */
916     protected $id;
917     /** @var boolean true if field can contain multiple values */
918     protected $multiple;
919     /** @var boolean true if the field has been defined */
920     protected $defined;
921
922    /**
923     * __construct - constructor
924     *
925     * @param string $name   Name or array(name,id) for field.
926     * @param array $values  field values.
927     * @param array $options options
928     *
929     * Currently globally available options are :
930     *  * multiple : true/false. Enable multiple values for field
931     * @access public
932     *
933     * @return mixed Value.
934     */
935     public function __construct($name,$values,$options=array())
936     {
937          $this->setNID($name);
938          $this->options = new ArrayObject($options);
939          if ($values === NULL){
940               $values = array();
941          }
942          $this->setValues($values);
943          $this->defined = false;
944          $this->multiple = (isset($options['multiple']) && $options['multiple']);
945
946     }
947
948    /**
949     * defines whether a field is multiple or not
950     *
951     * @param boolean true if the field is multiple
952      *
953     * @access public
954     */
955     public function setMultiple($m=true) {
956          $this->multiple = $m;
957     }
958     
959         /**
960     * Returns whether can have multiple values or not
961     *
962     * @return boolean true if the field has multiple values
963      *
964     * @access public
965     */
966     public function isMultiple($m=true) {
967          return $this->multiple;
968     }
969
970    /**
971     * setNID - defines fiels name & id
972     *
973     * @param mixed $nid field name (string) or an array containing  name (1st)
974     *                   and id (2nd field).
975     *
976     * @access protected
977     */
978     protected function setNID($nid)
979     {
980          if (is_array($nid)) {
981               $this->name = $nid[0];
982               $this->id = !empty($nid[1]) ? $nid[1] : null;
983          }
984          else {
985               $this->id = $this->name = $nid;
986          }
987     }
988
989    /**
990     * setValue - sets field value
991     *
992     * @param mixed $value  field value.
993     * @param int   $offset value offset to define (default 0).
994     *
995     * @access public
996     */
997     public function setValue($value,$offset=0) {
998          $this->values[$offset] = $value;
999     }
1000
1001    /**
1002     * setValues - set field values
1003     *
1004     * @param mixed $values the array of values. If not an array, the parameter
1005     *                      will be converted to an array containing the value
1006     *
1007     * @access public
1008     */
1009     public function setValues($values) {
1010          if (is_array($values)) {
1011               $this->values = $values;
1012          } elseif ($values !== NULL) {
1013               $this->values = array($values);
1014          }
1015
1016     }
1017
1018    /**
1019     * getValues - return field values
1020     *
1021     * @access public
1022     *
1023     * @return mixed the array of values.
1024     */
1025     public function getValues() {
1026          return $this->values;
1027     }
1028
1029    /**
1030     * getValue - retrieves a field value
1031     *
1032     * @param int $offset value offset (by default 1st value is returned).
1033     *
1034     * @access public
1035     *
1036     * @return mixed the field value.
1037     */
1038     public function getValue($offset=0) {
1039          if (isset($this->values[$offset])) {
1040               return $this->values[$offset];
1041          } else {
1042               return NULL;
1043          }
1044     }
1045
1046    /**
1047     * addValue -- Adds a value to the field values.
1048     *
1049     * @param mixed $value Description.
1050     *
1051     * @access public
1052     *
1053     * @return mixed Value.
1054     */
1055     public function addValue($value) {
1056          $this->values[] = $value;
1057     }
1058     public function delValue($offset) {
1059          if (isset($this->values[$offset])) {
1060               array_splice($this->values,$offset,1);
1061          }
1062     }
1063
1064    /**
1065     * count -- returns the number of field values
1066     *
1067     * @access public
1068     *
1069     * @return integer the number of values.
1070     */
1071     public function count() {
1072          return count($this->values);
1073     }
1074
1075     public function __toString()
1076     {
1077          return join(',',$this->values);
1078     }
1079     
1080     abstract public function getWidgetBlock();
1081     
1082     public function isEmpty() {
1083          return (count($this->values) == 0) || empty($this->values[0]);
1084     }
1085
1086    /**
1087     * getAttributes - retrieve field attributes that will be given to the
1088     *                   twig widget
1089     *
1090     * @param array $options extra options given to the widget
1091     *
1092     * @access public
1093     *
1094     * @return array the attributes.
1095     */
1096     public function getAttributes($options=array())
1097     {
1098          $offset = 0;
1099          $attr = $this->options->getArrayCopy();
1100          if (isset($options['offset'])) {
1101               $offset = $options['offset'];
1102               unset($attr['offset']);
1103          }
1104         
1105          $attr['value'] = $this->getValue($offset);
1106          if ($attr['value'] == NULL) {
1107               $attr['value']= $this->getDefaultValue();
1108          }
1109          if ($offset==0 && !empty($this->id)) {
1110               $attr['id']=$this->id;
1111          }
1112          $attr['name'] = $this->name;
1113          if ($this->multiple) {
1114               $attr['name'] = $attr['name'].'[]';
1115          }
1116          return $attr;
1117     }
1118
1119    /**
1120     * getDefaultValue - returns field default value
1121     *
1122     * @access public
1123     *
1124     * @return mixed the field default value.
1125     */
1126     public function getDefaultValue() {
1127          return '';
1128     }
1129
1130    /**
1131     * getName - returns field name
1132     *
1133     * @access public
1134     *
1135     * @return string the field name.
1136     */
1137     public function getName()
1138     {
1139          return $this->name;
1140     }
1141
1142    /**
1143     * setName - defines field name and/or field id
1144     *
1145     * @param mixed $name the field name or an array containing name and id.
1146     *
1147     * @access public
1148     */
1149     public function setName($name) {
1150          $this->setNID($name);
1151     }
1152
1153    /**
1154     * check - checks whether the field is valid or not - raises an exception
1155     *              if not valid
1156     * @access public
1157     */
1158     public function check()
1159     {
1160          if (isset($this->options ['required']) && $this->options['required']) {
1161               if (!$this->defined || $this->isEmpty()) {
1162                    throw new InvalidFieldException(sprintf(
1163                         'Field "%s" is mandatory',
1164                         $this->options['label'])
1165                    );
1166               }
1167          }
1168     }
1169
1170    /**
1171     * parseValues - parses field value from context (GET or POST)
1172     *                   and returns parsed value(s)
1173     *                   NOTE : the field is not updated with this method
1174     *                   use setup() to also update the field.
1175     * @param mixed $from the context (usually $_GET or $_POST).
1176     *
1177     * @access public
1178     *
1179     * @return array the list of values (empty array if no value).
1180     */
1181     public function parseValues($from) {
1182          if (isset($from[$this->name])) {
1183               $n = $from[$this->name];
1184               if (!is_array($n)) {
1185                    $n = array($n);
1186               }
1187               return $n;
1188          }
1189          return array();
1190     }
1191
1192    /**
1193     * setup - sets up the field from conetxt (GET or $POST)
1194     *
1195     * @param mixed $from the context (usually $_GET or $_POST).
1196     *
1197     * @access public
1198     *
1199     * @return mixed Value.
1200     */
1201     public function setup($from)
1202     {
1203          $values = $this->parseValues($from);
1204          if (count($values)) {
1205               $this->setValues($values);
1206               $this->defined = true;
1207          }
1208     }
1209
1210    /**
1211     * isDefined - returns whether the field is defined or not
1212     *                   (a field is defined if some values are set after setup())
1213     * @access public
1214     *
1215     * @return mixed Value.
1216     */
1217     public function isDefined()
1218     {
1219          return $this->defined;
1220     }
1221}
1222
1223
1224/**
1225 * Template form field of type "password"
1226 */
1227class dcFieldPassword extends dcField
1228{
1229     public function getWidgetBlock()
1230     {
1231          return "field_password";
1232     }
1233}
1234
1235/**
1236 * Template form field of type "text"
1237 */
1238class dcFieldText extends dcField
1239{
1240     public function getWidgetBlock()
1241     {
1242     return "field_text";
1243     }
1244}
1245
1246/**
1247 * Template form field of type "textarea"
1248 */
1249class dcFieldTextArea extends dcField
1250{
1251     public function getWidgetBlock()
1252     {
1253          return "field_textarea";
1254     }
1255}
1256
1257/**
1258 * Template form field of type "hidden"
1259 */
1260class dcFieldHidden extends dcField
1261{
1262     public function getWidgetBlock()
1263     {
1264          return "field_hidden";
1265     }
1266}
1267
1268/**
1269 * Template form field of type "checkbox"
1270 */
1271class dcFieldCheckbox extends dcField
1272{
1273     //protected $checked;
1274     
1275     public function __construct($name,$values,$options=array())
1276     {
1277          $val = array();
1278          if (!is_array($values) && $values !== null) {
1279               $values = array("1" => !empty($values));
1280          }         
1281          parent::__construct($name,$values,$options);
1282     }
1283
1284    /**
1285     * setValue - sets field value
1286     *
1287     * @param mixed $value  field value.
1288     * @param int   $offset value offset to define (default 0).
1289     *
1290     * @access public
1291     */
1292     public function setValue($value,$offset=0) {
1293          $keys = array_keys($this->values);
1294          if (isset($keys[$offset])) {
1295               $this->values[$keys[$offset]] = $value;
1296          }
1297     }
1298     
1299     public function addValue ($value,$checked=false) {
1300          $this->values[$value] = $checked;
1301     }
1302
1303     public function getValue($offset=0) {
1304          $keys = array_keys($this->values);
1305          if (isset($keys[$offset])) {
1306               return $this->values[$keys[$offset]];
1307          } else {
1308               return false;
1309          }
1310     }
1311     
1312     public function getAttributes($options=array())
1313     {
1314          $offset = 0;
1315          if (isset($options['offset'])) {
1316               $offset = $options['offset'];
1317          }
1318          $a = parent::getAttributes($options);
1319          $keys = array_keys($this->values);
1320          if (isset( $keys[$offset])) {
1321               $val = $keys[$offset];
1322               $a['value'] = $val;
1323               if (isset($this->values[$val]) && $this->values[$val]) {
1324                    $a['checked']='checked';
1325               }
1326          }
1327         
1328          return $a;
1329     }
1330
1331     public function parseValues($from) {
1332          $val = parent::parseValues($from);
1333          $arr = $this->values;
1334          foreach ($arr as $k=>&$v) {
1335               $v=false;
1336          }
1337          foreach ($val as $v) {
1338               if (isset($arr[$v])) {
1339                    $arr[$v]=true;
1340               }
1341          }
1342          return $arr;
1343     }
1344
1345
1346     public function getWidgetBlock()
1347     {
1348          return "field_checkbox";
1349     }
1350
1351     public function getDefaultValue() {
1352          return false;
1353     }
1354}
1355
1356/**
1357 * Template form action
1358 */
1359abstract class dcFieldAction extends dcField
1360{
1361     protected $action;
1362
1363     public function __construct($name,$values,$options=array())
1364     {
1365          parent::__construct($name,$values,$options);
1366
1367          if (isset($options['action'])) {
1368               $this->action = $options['action'];
1369          } else {
1370               $this->action = NULL;
1371          }
1372     }
1373
1374     public function getAction()
1375     {
1376          return $this->action;
1377     }
1378}
1379
1380/**
1381 * Template form field of type "submit"
1382 */
1383class dcFieldSubmit extends dcFieldAction
1384{
1385     public function getWidgetBlock()
1386     {
1387          return "field_submit";
1388     }
1389}
1390
1391/**
1392 * Template form field of type "combo"
1393 */
1394class dcFieldCombo extends dcField
1395{
1396     protected $combo;
1397     protected $combo_values;
1398
1399     public function __construct($name,$value,$combo,$options=array())
1400     {
1401          $this->combo = $combo;
1402          $this->combo_values = $combo;
1403          foreach ($combo as $k=>$v) {
1404               if (is_array($v)) {
1405                    unset($this->combo_values[$k]);
1406                    $this->combo_values = array_merge($v,$this->combo_values);
1407               }
1408          }
1409          parent::__construct($name,$value,$options);
1410     }
1411
1412     public function getWidgetBlock()
1413     {
1414          return "field_combo";
1415     }
1416
1417     public function getDefaultValue() {
1418          return current(array_keys($this->combo_values));
1419     }
1420
1421     public function parseValues($from) {
1422          $values = parent::parseValues($from);
1423          if (!is_array($values)) {
1424               $values = array($values);
1425          }
1426          foreach ($values as &$v) {
1427               if (!isset($this->combo_values[$v])) {
1428                    $v = $this->getDefaultValue();
1429               }
1430          }
1431          return $values;
1432     }
1433
1434     public function getTextForValue($value) {
1435          if (isset($this->combo_values[$value])) {
1436               return $this->combo_values[$value];
1437          } else {
1438               return false;
1439          }
1440     }
1441     public function getAttributes($options=array()) {
1442          $attr = parent::getAttributes($options);
1443          $attr['options'] = $this->combo;
1444          return $attr;
1445     }
1446}
1447
1448?>
Note: See TracBrowser for help on using the repository browser.

Sites map