1 <?php
2 
3 namespace dokuwiki\Form;
4 
5 /**
6  * Class InputElement
7  *
8  * Base class for all input elements. Uses a wrapping label when label
9  * text is given.
10  *
11  * @todo figure out how to make wrapping or related label configurable
12  * @package dokuwiki\Form
13  */
14 class InputElement extends Element
15 {
16     /**
17      * @var LabelElement
18      */
19     protected $label;
20 
21     /**
22      * @var bool if the element should reflect posted values
23      */
24     protected $useInput = true;
25 
26     /**
27      * @param string $type The type of this element
28      * @param string $name The name of this form element
29      * @param string $label The label text for this element (will be autoescaped)
30      */
31     public function __construct($type, $name, $label = '')
32     {
33         parent::__construct($type, ['name' => $name]);
34         $this->attr('name', $name);
35         $this->attr('type', $type);
36         if ($label) $this->label = new LabelElement($label);
37     }
38 
39     /**
40      * Returns the label element if there's one set
41      *
42      * @return LabelElement|null
43      */
44     public function getLabel()
45     {
46         return $this->label;
47     }
48 
49     /**
50      * Should the user sent input be used to initialize the input field
51      *
52      * The default is true. Any set values will be overwritten by the INPUT
53      * provided values.
54      *
55      * @param bool $useinput
56      * @return $this
57      */
58     public function useInput($useinput)
59     {
60         $this->useInput = (bool) $useinput;
61         return $this;
62     }
63 
64     /**
65      * Get or set the element's ID
66      *
67      * @param null|string $id
68      * @return string|$this
69      */
70     public function id($id = null)
71     {
72         if ($this->label) $this->label->attr('for', $id);
73         return parent::id($id);
74     }
75 
76     /**
77      * Adds a class to the class attribute
78      *
79      * This is the preferred method of setting the element's class
80      *
81      * @param string $class the new class to add
82      * @return $this
83      */
84     public function addClass($class)
85     {
86         if ($this->label) $this->label->addClass($class);
87         return parent::addClass($class);
88     }
89 
90     /**
91      * Figures out how to access the value for this field from INPUT data
92      *
93      * The element's name could have been given as a simple string ('foo')
94      * or in array notation ('foo[bar]').
95      *
96      * Note: this function only handles one level of arrays. If your data
97      * is nested deeper, you should call useInput(false) and set the
98      * correct value yourself
99      *
100      * @return array name and array key (null if not an array)
101      */
102     protected function getInputName()
103     {
104         $name = $this->attr('name');
105         parse_str("$name=1", $parsed);
106 
107         $name = array_keys($parsed);
108         $name = array_shift($name);
109 
110         if (isset($parsed[$name]) && is_array($parsed[$name])) {
111             $key = array_keys($parsed[$name]);
112             $key = array_shift($key);
113         } else {
114             $key = null;
115         }
116 
117         return [$name, $key];
118     }
119 
120     /**
121      * Handles the useInput flag and set the value attribute accordingly
122      */
123     protected function prefillInput()
124     {
125         global $INPUT;
126 
127         [$name, $key] = $this->getInputName();
128         if (!$INPUT->has($name)) return;
129 
130         if ($key === null) {
131             $value = $INPUT->str($name);
132         } else {
133             $value = $INPUT->arr($name);
134             if (isset($value[$key])) {
135                 $value = $value[$key];
136             } else {
137                 $value = '';
138             }
139         }
140         $this->val($value);
141     }
142 
143     /**
144      * The HTML representation of this element
145      *
146      * @return string
147      */
148     protected function mainElementHTML()
149     {
150         if ($this->useInput) $this->prefillInput();
151         return '<input ' . buildAttributes($this->attrs()) . ' />';
152     }
153 
154     /**
155      * The HTML representation of this element wrapped in a label
156      *
157      * @return string
158      */
159     public function toHTML()
160     {
161         if ($this->label) {
162             return '<label ' . buildAttributes($this->label->attrs()) . '>' . DOKU_LF
163                 . '<span>' . hsc($this->label->val()) . '</span>' . DOKU_LF
164                 . $this->mainElementHTML() . DOKU_LF
165                 . '</label>';
166         } else {
167             return $this->mainElementHTML();
168         }
169     }
170 }
171