|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony package. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.com> |
|
7 * |
|
8 * For the full copyright and license information, please view the LICENSE |
|
9 * file that was distributed with this source code. |
|
10 */ |
|
11 |
|
12 namespace Symfony\Component\DomCrawler\Field; |
|
13 |
|
14 /** |
|
15 * ChoiceFormField represents a choice form field. |
|
16 * |
|
17 * It is constructed from a HTML select tag, or a HTML checkbox, or radio inputs. |
|
18 * |
|
19 * @author Fabien Potencier <fabien@symfony.com> |
|
20 * |
|
21 * @api |
|
22 */ |
|
23 class ChoiceFormField extends FormField |
|
24 { |
|
25 private $type; |
|
26 private $multiple; |
|
27 private $options; |
|
28 |
|
29 /** |
|
30 * Returns true if the field should be included in the submitted values. |
|
31 * |
|
32 * @return Boolean true if the field should be included in the submitted values, false otherwise |
|
33 */ |
|
34 public function hasValue() |
|
35 { |
|
36 // don't send a value for unchecked checkboxes |
|
37 if (in_array($this->type, array('checkbox', 'radio')) && null === $this->value) { |
|
38 return false; |
|
39 } |
|
40 |
|
41 return true; |
|
42 } |
|
43 |
|
44 /** |
|
45 * Sets the value of the field. |
|
46 * |
|
47 * @param string $value The value of the field |
|
48 * |
|
49 * @throws \InvalidArgumentException When value type provided is not correct |
|
50 * |
|
51 * @api |
|
52 */ |
|
53 public function select($value) |
|
54 { |
|
55 $this->setValue($value); |
|
56 } |
|
57 |
|
58 /** |
|
59 * Ticks a checkbox. |
|
60 * |
|
61 * @throws \InvalidArgumentException When value type provided is not correct |
|
62 * |
|
63 * @api |
|
64 */ |
|
65 public function tick() |
|
66 { |
|
67 if ('checkbox' !== $this->type) { |
|
68 throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type)); |
|
69 } |
|
70 |
|
71 $this->setValue(true); |
|
72 } |
|
73 |
|
74 /** |
|
75 * Ticks a checkbox. |
|
76 * |
|
77 * @throws \InvalidArgumentException When value type provided is not correct |
|
78 * |
|
79 * @api |
|
80 */ |
|
81 public function untick() |
|
82 { |
|
83 if ('checkbox' !== $this->type) { |
|
84 throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type)); |
|
85 } |
|
86 |
|
87 $this->setValue(false); |
|
88 } |
|
89 |
|
90 /** |
|
91 * Sets the value of the field. |
|
92 * |
|
93 * @param string $value The value of the field |
|
94 * |
|
95 * @throws \InvalidArgumentException When value type provided is not correct |
|
96 */ |
|
97 public function setValue($value) |
|
98 { |
|
99 if ('checkbox' == $this->type && false === $value) { |
|
100 // uncheck |
|
101 $this->value = null; |
|
102 } elseif ('checkbox' == $this->type && true === $value) { |
|
103 // check |
|
104 $this->value = $this->options[0]; |
|
105 } else { |
|
106 if (is_array($value)) { |
|
107 if (!$this->multiple) { |
|
108 throw new \InvalidArgumentException(sprintf('The value for "%s" cannot be an array.', $this->name)); |
|
109 } |
|
110 |
|
111 foreach ($value as $v) { |
|
112 if (!in_array($v, $this->options)) { |
|
113 throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: %s).', $this->name, $v, implode(', ', $this->options))); |
|
114 } |
|
115 } |
|
116 } elseif (!in_array($value, $this->options)) { |
|
117 throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: %s).', $this->name, $value, implode(', ', $this->options))); |
|
118 } |
|
119 |
|
120 if ($this->multiple) { |
|
121 $value = (array) $value; |
|
122 } |
|
123 |
|
124 if (is_array($value)) { |
|
125 $this->value = $value; |
|
126 } else { |
|
127 parent::setValue($value); |
|
128 } |
|
129 } |
|
130 } |
|
131 |
|
132 /** |
|
133 * Adds a choice to the current ones. |
|
134 * |
|
135 * This method should only be used internally. |
|
136 * |
|
137 * @param \DOMNode $node A \DOMNode |
|
138 * |
|
139 * @throws \LogicException When choice provided is not multiple nor radio |
|
140 */ |
|
141 public function addChoice(\DOMNode $node) |
|
142 { |
|
143 if (!$this->multiple && 'radio' != $this->type) { |
|
144 throw new \LogicException(sprintf('Unable to add a choice for "%s" as it is not multiple or is not a radio button.', $this->name)); |
|
145 } |
|
146 |
|
147 $this->options[] = $value = $node->hasAttribute('value') ? $node->getAttribute('value') : '1'; |
|
148 |
|
149 if ($node->getAttribute('checked')) { |
|
150 $this->value = $value; |
|
151 } |
|
152 } |
|
153 |
|
154 /** |
|
155 * Returns the type of the choice field (radio, select, or checkbox). |
|
156 * |
|
157 * @return string The type |
|
158 */ |
|
159 public function getType() |
|
160 { |
|
161 return $this->type; |
|
162 } |
|
163 |
|
164 /** |
|
165 * Returns true if the field accepts multiple values. |
|
166 * |
|
167 * @return Boolean true if the field accepts multiple values, false otherwise |
|
168 */ |
|
169 public function isMultiple() |
|
170 { |
|
171 return $this->multiple; |
|
172 } |
|
173 |
|
174 /** |
|
175 * Initializes the form field. |
|
176 * |
|
177 * @throws \LogicException When node type is incorrect |
|
178 */ |
|
179 protected function initialize() |
|
180 { |
|
181 if ('input' != $this->node->nodeName && 'select' != $this->node->nodeName) { |
|
182 throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input or select tag (%s given).', $this->node->nodeName)); |
|
183 } |
|
184 |
|
185 if ('input' == $this->node->nodeName && 'checkbox' != $this->node->getAttribute('type') && 'radio' != $this->node->getAttribute('type')) { |
|
186 throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input tag with a type of checkbox or radio (given type is %s).', $this->node->getAttribute('type'))); |
|
187 } |
|
188 |
|
189 $this->value = null; |
|
190 $this->options = array(); |
|
191 $this->multiple = false; |
|
192 |
|
193 if ('input' == $this->node->nodeName) { |
|
194 $this->type = $this->node->getAttribute('type'); |
|
195 $this->options[] = $value = $this->node->hasAttribute('value') ? $this->node->getAttribute('value') : '1'; |
|
196 |
|
197 if ($this->node->getAttribute('checked')) { |
|
198 $this->value = $value; |
|
199 } |
|
200 } else { |
|
201 $this->type = 'select'; |
|
202 if ($this->node->hasAttribute('multiple')) { |
|
203 $this->multiple = true; |
|
204 $this->value = array(); |
|
205 $this->name = str_replace('[]', '', $this->name); |
|
206 } |
|
207 |
|
208 $found = false; |
|
209 foreach ($this->xpath->query('descendant::option', $this->node) as $option) { |
|
210 $this->options[] = $option->getAttribute('value'); |
|
211 |
|
212 if ($option->getAttribute('selected')) { |
|
213 $found = true; |
|
214 if ($this->multiple) { |
|
215 $this->value[] = $option->getAttribute('value'); |
|
216 } else { |
|
217 $this->value = $option->getAttribute('value'); |
|
218 } |
|
219 } |
|
220 } |
|
221 |
|
222 // if no option is selected and if it is a simple select box, take the first option as the value |
|
223 $option = $this->xpath->query('descendant::option', $this->node)->item(0); |
|
224 if (!$found && !$this->multiple && $option instanceof \DOMElement) { |
|
225 $this->value = $option->getAttribute('value'); |
|
226 } |
|
227 } |
|
228 } |
|
229 } |