Dotclear

source: inc/admin/class.dc.form.php @ 1489:f2398e7f3395

Revision 1489:f2398e7f3395, 30.1 KB checked in by Dsls, 12 years ago (diff)

we'll see behaviors later...

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

Sites map