Dotclear

source: inc/admin/class.dc.form.php @ 1153:1e48950b05af

Revision 1153:1e48950b05af, 14.8 KB checked in by Dsls <dsls@…>, 12 years ago (diff)

Merge

RevLine 
[992]1<?php
[1058]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; }
[992]13
[1058]14/**
[1147]15* dcFormNode
16*
17* @uses     Twig_Node
18*
19*/
[1058]20class dcFormNode extends Twig_Node
21{
22     public function __construct($name,Twig_NodeInterface $body,$lineno,$tag=null)
23     {
24          parent::__construct(array('body' => $body),array('name' => $name),$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
[1147]35               ->addDebugInfo($this);
36          $compiler
37               ->write("\$context['dc_form']->beginForm(")
38               ->subcompile($this->getAttribute('name'))
39               ->write(");\n");
40          $compiler
[1058]41               ->subcompile($this->getNode('body'))
42               ->write("\$context['dc_form']->renderHiddenWidgets();\n")
43               ->write("\$context['dc_form']->endForm();\n")
44          ;
45     }
[992]46}
47
[1058]48/**
49 * Template form token parser
50 */
51class dcFormTokenParser extends Twig_TokenParser
52{
53     public function parse(Twig_Token $token)
54     {
55          $lineno = $token->getLine();
56          $stream = $this->parser->getStream();
[1147]57          $name = $this->parser->getExpressionParser()->parseExpression();
[1058]58          $stream->expect(Twig_Token::BLOCK_END_TYPE);
59          $body = $this->parser->subparse(array($this,'decideBlockEnd'),true);
60          $stream->expect(Twig_Token::BLOCK_END_TYPE);
61         
62          return new dcFormNode($name,$body,$token->getLine(),$this->getTag());
[992]63     }
[1058]64     
[992]65     public function decideBlockEnd(Twig_Token $token)
[1058]66     {
67          return $token->test('endform');
68     }
69     
70     public function getTag()
71     {
72          return 'form';
73     }
[992]74}
75
[1058]76/**
77 * Template form extension
78 */
79class dcFormExtension extends Twig_Extension
80{
[992]81     protected $template;
82     protected $tpl;
83     protected $core;
84     protected $twig;
85     protected $forms;
86     protected $currentForm;
[1147]87     protected $blocks;
[1058]88     
89     public function __construct($core)
90     {
[992]91          $this->core = $core;
[1152]92          $this->tpl = array('@forms/form_layout.html.twig');
[992]93          $this->forms = array();
[1152]94          $this->blocks = array();
[992]95          $this->currentForm = null;
96     }
[1058]97     
98     public function initRuntime(Twig_Environment $environment)
99     {
100          $this->twig = $environment;
[1152]101          $this->twig->getLoader()->addPath(dirname(__FILE__).'/default-templates/forms','forms');
102          foreach ($this->tpl as $tpl) {
103               $this->template = $this->twig->loadTemplate($tpl);
104               $this->blocks = array_merge($this->blocks,$this->template->getBlocks());
105          }
[1058]106     }
107     
[1147]108     public function addTemplate($tpl) {
[1152]109          $this->tpl[]=$tpl;
110          if (isset($this->twig)) {
111               $this->template = $this->twig->loadTemplate($tpl);
112               $this->blocks = array_merge($this->blocks,$this->template->getBlocks());
113          }
[1147]114     }
115
[1058]116     public function getGlobals()
117     {
118          return array('dc_form' => $this);
119     }
120     
121     public function getFunctions()
122     {
[992]123          return array(
[1152]124               new Twig_SimpleFunction(
125                    'widget',
126                    array($this,'renderWidget'),
[1058]127                    array('is_safe' => array('html'))
128               ),
[1152]129               new Twig_SimpleFunction(
130                    'haswidget',
131                    array($this,'hasWidget'),
[1058]132                    array('is_safe' => array('html'))
133               ),
[1152]134               new Twig_SimpleFunction(
135                    'form_field',
136                    array($this,'renderField'),
137                    array('is_safe' => array('html'))
138               ),
139               new Twig_SimpleFunction(
140                    '_form_is_choice_group',
141                    array($this,'isChoiceGroup'),
142                    array('is_safe' => array('html'))
143               ),
144               new Twig_SimpleFunction(
145                    '_form_is_choice_selected',
146                    array($this,'isChoiceSelected'),
[1058]147                    array('is_safe' => array('html'))
148               )
[992]149          );
150     }
[1058]151     
152     public function isChoiceGroup($choice)
153     {
[992]154          return is_array($choice);
155     }
[1058]156     
157     public function isChoiceSelected($choice,$value)
158     {
[992]159          return $choice == $value;
160     }
[1058]161     
162     public function getTokenParsers()
163     {
[992]164          return array(new dcFormTokenParser());
165     }
[1058]166     
[1152]167     public function hasWidget($name) {
168          return isset($this->blocks[$name]);
169     }
170     public function renderWidget($name,$attr) {
171          if (!isset($this->blocks[$name]))
172               return '';
[1147]173          echo $this->template->renderBlock(
174               $name,
175               $attr,
176               $this->blocks
177          );
178     }
179
180     public function getCurrentForm() {
181          return $this->currentForm;
182     }
183
[1152]184     public function renderField($name,$attributes=array(),$extra=array())
[1058]185     {
[992]186          $field = $this->currentForm->$name;
[1053]187          if ($field) {
[1152]188               $attr = $field->getAttributes($attributes);
[1147]189               if (isset($attr['attr'])) {
190                    $attr['attr'] = array_merge($attr['attr'],$attributes);
191               } else {
192                    $attr['attr'] = $attributes;
193               }
[1152]194               $this->renderWidget(
[1053]195                    $field->getWidgetBlock(),
[1058]196                    array_merge(
[1147]197                         $attr,
198                         $extra
199                    )
[1058]200               );
[1053]201          }
202     }
[992]203
[1058]204     public function renderHiddenWidgets()
205     {
[1053]206          foreach ($this->currentForm->getHiddenFields() as $h) {
[1152]207               $this->renderField($h->getName());
[1053]208          }
[992]209     }
210
[1058]211     public function getName()
212     {
[992]213          return 'dc_form';
214     }
215
[1058]216     public function addForm(dcForm $form)
217     {
218          $this->forms[$form->getName()] = $form;
[992]219     }
220
[1058]221     public function beginForm($name)
222     {
[992]223          if (isset($this->forms[$name])) {
224               $this->currentForm = $this->forms[$name];
225               $this->currentForm->begin();
[1058]226          }
227          else {
228               throw new Twig_Error_Runtime(sprintf(
229                    'Form "%s" does not exist',
230                    $name
231               ));
[992]232          }
233     }
[1058]234     
235     public function endForm()
236     {
[992]237          $this->currentForm->end();
238          $this->currentForm = null;
239     }
240}
241
[1058]242/**
243 * Template form exception
244 */
[1053]245class InvalidFieldException extends Exception {
246}
247
[1058]248/**
[1147]249* dcForm - Template form
250*
251*/
[1058]252class dcForm
253{
[1090]254     protected $id;
[992]255     protected $name;
256     protected $core;
257     protected $action;
258     protected $fields;
[1053]259     protected $method;
260     protected $submitfields;
261     protected $hiddenfields;
262     protected $errors;
263     
[1152]264     public function addTemplate($t) {
265          $this->core->tpl->getExtension('dc_form')->addTemplate($t);
266     }
[1147]267
268    /**
269     * addNonce -- adds dc nonce to form fields
270     *
271     * @access protected
272     *
273     * @return nothing
274     */
275     protected function addNonce()
[1058]276     {
277          $this->addField(
278               new dcFieldHidden(array('xd_check'),
279               $this->core->getNonce())
280          );
[1053]281     }
282     
[1147]283
284    /**
285     * Defines Name & ID from field
286     *
287     * @param mixed $nid either an array (name, id) or a string (name only, id will be set to null).
288     *
289     * @access protected
290     *
291     * @return nothing.
292     */
293     protected function setNID($nid)
[1090]294     {
295          if (is_array($nid)) {
296               $this->name = $nid[0];
297               $this->id = !empty($nid[1]) ? $nid[1] : null;
298          }
299          else {
300               $this->id = null;
301               $this->name = $nid;
302          }
303     }
304     
[1147]305     public function getContext() {
306          return array();
307     }
308
309    /**
310     * Class constructor
311     *
312     * @param mixed  $core   dotclear core
313     * @param mixed  $name   form name
314     * @param mixed  $action form action
315     * @param string $method form method ('GET' or 'POST')
316     *
317     * @access public
318     *
319     * @return mixed Value.
320     */
[1058]321     public function __construct($core,$name,$action,$method='POST')
322     {
[992]323          $this->core = $core;
[1147]324          $this->setNID($name);
[992]325          $this->method = $method;
326          $this->action = $action;
327          $this->fields = array();
[1056]328          $this->core->tpl->getExtension('dc_form')->addForm($this);
[1053]329          $this->submitfields = array();
330          $this->hiddenfields = array();
331          $this->errors = array();
332          if ($method == 'POST') {
333               $this->addNonce();
334          }
[992]335     }
[1058]336     
[1147]337
338    /**
339     * Returns form name
340     *
341     * @access public
342     *
343     * @return mixed Value.
344     */
[1058]345     public function getName()
346     {
[992]347          return $this->name;
348     }
[1058]349     
350     public function getErrors()
351     {
[1053]352          return $this->errors;
353     }
354     
[1058]355     public function addField(dcField $f)
356     {
[1053]357          if ($f instanceof dcFieldAction) {
[1058]358               $this->submitfields[$f->getName()] = $f;
[1053]359          }
360          if ($f instanceof dcFieldHidden) {
[1058]361               $this->hiddenfields[$f->getName()] = $f;
[1053]362          }
[1058]363          $this->fields[$f->getName()] = $f;
364         
[992]365          return $this;
366     }
[1058]367     
[1147]368     public function removeField(dcField $f) {
369          $n = $f->getName();
370          if (isset($this->fields[$n])){
371               unset($this->fields[$n]);
372          }
373
374     }
375     public function renameField($field,$newname) {
376          $oldname = $field->getName();
377          if (isset($this->fields[$oldname])) {
378               unset($this->fields[$oldname]);
379               $field->setName($newname);
380               $this->fields[$newname] = $field;
381          }
382     }
[1058]383     public function begin()
384     {
385          echo sprintf(
[1090]386               '<form%s method="%s" action="%s">',
387               empty($this->id) ? '' : ' id="'.$this->id.'"',
[1058]388               $this->method,
389               $this->action
390          );
[992]391     }
[1058]392     
393     public function end()
394     {
[992]395          echo '</form>';
396     }
[1058]397     
398     public function __isset($name)
399     {
[992]400          return isset($this->fields[$name]);
[1058]401     }
402     
403     public function __get($name)
404     {
[1147]405          return isset($this->fields[$name]) ?
[1058]406               $this->fields[$name] : null;
407     }
[1147]408
[1058]409     public function __set($name,$value)
410     {
[992]411          if (isset($this->fields[$name])) {
[1152]412               $this->fields[$name]->setValue($value);
[992]413          }
[1058]414     }
[1147]415
[1058]416     public function isSubmitted()
417     {
418          $from = $this->method == 'POST' ? $_POST : $_GET;
[1053]419     }
[1147]420
421     protected function setupFields() {
[1058]422          $from = $this->method == 'POST' ? $_POST : $_GET;
[1053]423          foreach ($this->fields as $f) {
424               $f->setup($from);
425          }
[1147]426     }
427
428     protected function handleActions($submitted) {
429          foreach ($submitted as $f) {
430               $action = $f->getAction();
431               if ($action != NULL) {
432                    $ret = call_user_func($action,$this);
[1053]433               }
434          }
435     }
[1147]436
437     protected function getSubmittedFields() {
438          $s = array();
439          foreach ($this->submitfields as $f) {
440               if ($f->isDefined()) {
441                    $s[$f->getName()] = $f;
442               }
443          }
444          return $s;
445     }
446
447     public function setup()
448     {
449          $this->setupFields();
450          $submitted = $this->getSubmittedFields();
451          $this->handleActions($submitted);
452     }
453
[1058]454     public function check()
455     {
[1053]456          foreach ($this->fields as $f) {
457               try {
458                    $f->check();
[1058]459               }
460               catch (InvalidFieldException $e) {
461                    $this->errors[] = $e->getMessage();
[1053]462               }
463          }
464     }
465     
[1058]466     public function getHiddenFields()
467     {
[1053]468          return $this->hiddenfields;
469     }
[992]470}
471
[1058]472/**
473 * Template form field
474 */
[1152]475abstract class dcField implements Countable
[1058]476{
[1152]477     protected $options;
[992]478     protected $name;
[1152]479     protected $values;
[992]480     protected $id;
[1152]481     protected $multiple;
[1053]482     protected $defined;
[992]483     
[1147]484     protected function setNID($nid)
[1058]485     {
[992]486          if (is_array($nid)) {
487               $this->name = $nid[0];
488               $this->id = !empty($nid[1]) ? $nid[1] : null;
[1058]489          }
490          else {
[992]491               $this->id = $this->name = $nid;
492          }
493     }
[1058]494     
[1152]495     public function __construct($name,$values,$options=array())
[1058]496     {
[1147]497          $this->setNID($name);
[1152]498          $this->options = new ArrayObject($options);
499          if ($values === NULL){
500               $values = array();
501          }
502          $this->setValues($values);
[1053]503          $this->defined = false;
[1152]504          $this->multiple = (isset($options['multiple']) && $options['multiple']);
505
[992]506     }
[1058]507     
[1152]508     public function setValue($value,$offset=0) {
509          $this->values[$offset] = $value;
[1147]510     }
511
[1152]512     public function setValues($values) {
513          if (is_array($values)) {
514               $this->values = $values;
515          } elseif ($values !== NULL) {
516               $this->values = array($values);
517          }
518
519     }
520
521     public function getValues() {
522          return $this->values;
523     }
524
525     public function getValue($offset=0) {
526          if (isset($this->values[$offset])) {
527               return $this->values[$offset];
528          }
529     }
530
531     public function addValue($value) {
532          $this->values[] = $value;
533     }
534     public function delValue($offset) {
535          if (isset($this->values[$offset])) {
536               array_splice($this->values,$offset,1);
537          }
538     }
539
540     public function count() {
541          return count($this->values);
[1147]542     }
543
[1058]544     public function __toString()
545     {
[1152]546          return join(',',$this->values);
[1058]547     }
548     
[992]549     abstract public function getWidgetBlock();
[1058]550     
[1152]551     public function getAttributes($options)
[1058]552     {
[1152]553          $offset = isset($options['offset']) ? $options['offset'] : 0;
554
555          $attr = $this->options->getArrayCopy();
556          if (isset($this->values[$offset])) {
557               $attr['value'] = $this->values[$offset];
558          } else {
559               $attr['value'] = $this->getDefaultValue();
560          }
561          if ($offset==0) {
562               $attr['id']=$this->id;
563          }
564          $attr['name'] = $this->name;
565          if ($this->multiple) {
566               $attr['name'] = $attr['name'].'[]';
567          }
568          return $attr;
[992]569     }
[1058]570     
[1152]571     public function getDefaultValue() {
572          return '';
[992]573     }
[1152]574
[1058]575     public function getName()
576     {
[992]577          return $this->name;
578     }
[1152]579
[1147]580     public function setName($name) {
581          $this->setNID($name);
582     }
583
[1058]584     public function check()
585     {
[1152]586          if (!$this->defined && $this->options['mandatory']) {
[1058]587               throw new InvalidFieldException(sprintf(
588                    'Field "%s" is mandatory',
589                    $this->attributes['label'])
590               );
[1053]591          }
[992]592     }
[1053]593     
[1152]594     public function parseValues($from) {
595          if (isset($from[$this->name])) {
596               $n = $from[$this->name];
597               if (!is_array($n)) {
598                    $n = array($n);
599               }
600               return $n;
[1147]601          }
[1152]602          return array();
[1147]603     }
604
[1058]605     public function setup($from)
606     {
[1152]607          $values = $this->parseValues($from);
608          if (count($values)) {
609               $this->setValues($values);
[1053]610               $this->defined = true;
611          }
612     }
613     
[1058]614     public function isDefined()
615     {
[1053]616          return $this->defined;
617     }
[992]618}
619
[1152]620
[1058]621/**
622 * Template form field of type "password"
623 */
624class dcFieldPassword extends dcField
625{
626     public function getWidgetBlock()
627     {
628          return "field_password";
[992]629     }
630}
631
[1058]632/**
633 * Template form field of type "text"
634 */
635class dcFieldText extends dcField
636{
637     public function getWidgetBlock()
638     {
639     return "field_text";
640     }
641}
[992]642
[1058]643/**
644 * Template form field of type "textarea"
645 */
646class dcFieldTextArea extends dcField
647{
648     public function getWidgetBlock()
649     {
[992]650          return "field_textarea";
651     }
652}
653
[1058]654/**
655 * Template form field of type "hidden"
656 */
657class dcFieldHidden extends dcField
658{
659     public function getWidgetBlock()
660     {
[992]661          return "field_hidden";
662     }
663}
664
[1058]665/**
666 * Template form field of type "checkbox"
667 */
668class dcFieldCheckbox extends dcField
669{
670     public function getWidgetBlock()
671     {
[992]672          return "field_checkbox";
673     }
[1152]674
675     public function getDefaultValue() {
676          return 0;
677     }
[992]678}
679
[1058]680/**
681 * Template form action
682 */
683abstract class dcFieldAction extends dcField
684{
[1053]685     protected $action;
[1152]686
687     public function __construct($name,$values,$options=array())
[1058]688     {
[1152]689          parent::__construct($name,$values,$options);
690
691          if (isset($options['action'])) {
692               $this->action = $options['action'];
[1147]693          } else {
694               $this->action = NULL;
[1053]695          }
696     }
[1152]697
[1058]698     public function getAction()
699     {
[1053]700          return $this->action;
701     }
702}
703
[1058]704/**
705 * Template form field of type "submit"
706 */
707class dcFieldSubmit extends dcFieldAction
708{
709     public function getWidgetBlock()
710     {
[992]711          return "field_submit";
712     }
713}
714
[1058]715/**
716 * Template form field of type "combo"
717 */
718class dcFieldCombo extends dcField
719{
[1152]720     protected $combo;
[1058]721     
[1152]722     public function __construct($name,$value,$combo,$options=array())
[1058]723     {
[1152]724          $this->combo = $combo;
725          parent::__construct($name,$value,$options);
[992]726     }
[1058]727     
728     public function getWidgetBlock()
729     {
[992]730          return "field_combo";
731     }
732
[1152]733     public function getDefaultValue() {
734          return current($this->combo);
735     }
[1147]736
[1152]737     public function parseValues($from) {
738          $values = parent::parseValues($from);
739          if (!is_array($values)) {
740               $values = array($values);
[1147]741          }
[1152]742          foreach ($values as &$v) {
743               if (!isset($this->combo[$v]))
744               $v = $this->getDefaultValue();
745          }
746          return $values;
747     }
748
749     public function getAttributes($options) {
750          $attr = parent::getAttributes($options);
751          $attr['options'] = $this->combo;
752          return $attr;
[1147]753     }
[992]754}
[1152]755
[1014]756?>
Note: See TracBrowser for help on using the repository browser.

Sites map