Dotclear

source: inc/admin/class.dc.form.php @ 1498:6d67bea812f3

Revision 1498:6d67bea812f3, 31.4 KB checked in by Dsls, 12 years ago (diff)

formfilters improvement, added applied filters features

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

Sites map