Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of the Symfony package.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Symfony\Component\DomCrawler;
|
Chris@0
|
13
|
Chris@0
|
14 use Symfony\Component\DomCrawler\Field\FormField;
|
Chris@0
|
15
|
Chris@0
|
16 /**
|
Chris@0
|
17 * This is an internal class that must not be used directly.
|
Chris@0
|
18 *
|
Chris@0
|
19 * @internal
|
Chris@0
|
20 */
|
Chris@0
|
21 class FormFieldRegistry
|
Chris@0
|
22 {
|
Chris@0
|
23 private $fields = array();
|
Chris@0
|
24
|
Chris@0
|
25 private $base;
|
Chris@0
|
26
|
Chris@0
|
27 /**
|
Chris@0
|
28 * Adds a field to the registry.
|
Chris@0
|
29 *
|
Chris@0
|
30 * @param FormField $field The field
|
Chris@0
|
31 */
|
Chris@0
|
32 public function add(FormField $field)
|
Chris@0
|
33 {
|
Chris@0
|
34 $segments = $this->getSegments($field->getName());
|
Chris@0
|
35
|
Chris@0
|
36 $target = &$this->fields;
|
Chris@0
|
37 while ($segments) {
|
Chris@0
|
38 if (!is_array($target)) {
|
Chris@0
|
39 $target = array();
|
Chris@0
|
40 }
|
Chris@0
|
41 $path = array_shift($segments);
|
Chris@0
|
42 if ('' === $path) {
|
Chris@0
|
43 $target = &$target[];
|
Chris@0
|
44 } else {
|
Chris@0
|
45 $target = &$target[$path];
|
Chris@0
|
46 }
|
Chris@0
|
47 }
|
Chris@0
|
48 $target = $field;
|
Chris@0
|
49 }
|
Chris@0
|
50
|
Chris@0
|
51 /**
|
Chris@0
|
52 * Removes a field and its children from the registry.
|
Chris@0
|
53 *
|
Chris@0
|
54 * @param string $name The fully qualified name of the base field
|
Chris@0
|
55 */
|
Chris@0
|
56 public function remove($name)
|
Chris@0
|
57 {
|
Chris@0
|
58 $segments = $this->getSegments($name);
|
Chris@0
|
59 $target = &$this->fields;
|
Chris@0
|
60 while (count($segments) > 1) {
|
Chris@0
|
61 $path = array_shift($segments);
|
Chris@0
|
62 if (!array_key_exists($path, $target)) {
|
Chris@0
|
63 return;
|
Chris@0
|
64 }
|
Chris@0
|
65 $target = &$target[$path];
|
Chris@0
|
66 }
|
Chris@0
|
67 unset($target[array_shift($segments)]);
|
Chris@0
|
68 }
|
Chris@0
|
69
|
Chris@0
|
70 /**
|
Chris@0
|
71 * Returns the value of the field and its children.
|
Chris@0
|
72 *
|
Chris@0
|
73 * @param string $name The fully qualified name of the field
|
Chris@0
|
74 *
|
Chris@0
|
75 * @return mixed The value of the field
|
Chris@0
|
76 *
|
Chris@0
|
77 * @throws \InvalidArgumentException if the field does not exist
|
Chris@0
|
78 */
|
Chris@0
|
79 public function &get($name)
|
Chris@0
|
80 {
|
Chris@0
|
81 $segments = $this->getSegments($name);
|
Chris@0
|
82 $target = &$this->fields;
|
Chris@0
|
83 while ($segments) {
|
Chris@0
|
84 $path = array_shift($segments);
|
Chris@0
|
85 if (!array_key_exists($path, $target)) {
|
Chris@0
|
86 throw new \InvalidArgumentException(sprintf('Unreachable field "%s"', $path));
|
Chris@0
|
87 }
|
Chris@0
|
88 $target = &$target[$path];
|
Chris@0
|
89 }
|
Chris@0
|
90
|
Chris@0
|
91 return $target;
|
Chris@0
|
92 }
|
Chris@0
|
93
|
Chris@0
|
94 /**
|
Chris@0
|
95 * Tests whether the form has the given field.
|
Chris@0
|
96 *
|
Chris@0
|
97 * @param string $name The fully qualified name of the field
|
Chris@0
|
98 *
|
Chris@0
|
99 * @return bool Whether the form has the given field
|
Chris@0
|
100 */
|
Chris@0
|
101 public function has($name)
|
Chris@0
|
102 {
|
Chris@0
|
103 try {
|
Chris@0
|
104 $this->get($name);
|
Chris@0
|
105
|
Chris@0
|
106 return true;
|
Chris@0
|
107 } catch (\InvalidArgumentException $e) {
|
Chris@0
|
108 return false;
|
Chris@0
|
109 }
|
Chris@0
|
110 }
|
Chris@0
|
111
|
Chris@0
|
112 /**
|
Chris@0
|
113 * Set the value of a field and its children.
|
Chris@0
|
114 *
|
Chris@0
|
115 * @param string $name The fully qualified name of the field
|
Chris@0
|
116 * @param mixed $value The value
|
Chris@0
|
117 *
|
Chris@0
|
118 * @throws \InvalidArgumentException if the field does not exist
|
Chris@0
|
119 */
|
Chris@0
|
120 public function set($name, $value)
|
Chris@0
|
121 {
|
Chris@0
|
122 $target = &$this->get($name);
|
Chris@0
|
123 if ((!is_array($value) && $target instanceof Field\FormField) || $target instanceof Field\ChoiceFormField) {
|
Chris@0
|
124 $target->setValue($value);
|
Chris@0
|
125 } elseif (is_array($value)) {
|
Chris@0
|
126 $fields = self::create($name, $value);
|
Chris@0
|
127 foreach ($fields->all() as $k => $v) {
|
Chris@0
|
128 $this->set($k, $v);
|
Chris@0
|
129 }
|
Chris@0
|
130 } else {
|
Chris@0
|
131 throw new \InvalidArgumentException(sprintf('Cannot set value on a compound field "%s".', $name));
|
Chris@0
|
132 }
|
Chris@0
|
133 }
|
Chris@0
|
134
|
Chris@0
|
135 /**
|
Chris@0
|
136 * Returns the list of field with their value.
|
Chris@0
|
137 *
|
Chris@0
|
138 * @return FormField[] The list of fields as array((string) Fully qualified name => (mixed) value)
|
Chris@0
|
139 */
|
Chris@0
|
140 public function all()
|
Chris@0
|
141 {
|
Chris@0
|
142 return $this->walk($this->fields, $this->base);
|
Chris@0
|
143 }
|
Chris@0
|
144
|
Chris@0
|
145 /**
|
Chris@0
|
146 * Creates an instance of the class.
|
Chris@0
|
147 *
|
Chris@0
|
148 * This function is made private because it allows overriding the $base and
|
Chris@0
|
149 * the $values properties without any type checking.
|
Chris@0
|
150 *
|
Chris@0
|
151 * @param string $base The fully qualified name of the base field
|
Chris@0
|
152 * @param array $values The values of the fields
|
Chris@0
|
153 *
|
Chris@0
|
154 * @return static
|
Chris@0
|
155 */
|
Chris@0
|
156 private static function create($base, array $values)
|
Chris@0
|
157 {
|
Chris@0
|
158 $registry = new static();
|
Chris@0
|
159 $registry->base = $base;
|
Chris@0
|
160 $registry->fields = $values;
|
Chris@0
|
161
|
Chris@0
|
162 return $registry;
|
Chris@0
|
163 }
|
Chris@0
|
164
|
Chris@0
|
165 /**
|
Chris@0
|
166 * Transforms a PHP array in a list of fully qualified name / value.
|
Chris@0
|
167 *
|
Chris@0
|
168 * @param array $array The PHP array
|
Chris@0
|
169 * @param string $base The name of the base field
|
Chris@0
|
170 * @param array $output The initial values
|
Chris@0
|
171 *
|
Chris@0
|
172 * @return array The list of fields as array((string) Fully qualified name => (mixed) value)
|
Chris@0
|
173 */
|
Chris@0
|
174 private function walk(array $array, $base = '', array &$output = array())
|
Chris@0
|
175 {
|
Chris@0
|
176 foreach ($array as $k => $v) {
|
Chris@0
|
177 $path = empty($base) ? $k : sprintf('%s[%s]', $base, $k);
|
Chris@0
|
178 if (is_array($v)) {
|
Chris@0
|
179 $this->walk($v, $path, $output);
|
Chris@0
|
180 } else {
|
Chris@0
|
181 $output[$path] = $v;
|
Chris@0
|
182 }
|
Chris@0
|
183 }
|
Chris@0
|
184
|
Chris@0
|
185 return $output;
|
Chris@0
|
186 }
|
Chris@0
|
187
|
Chris@0
|
188 /**
|
Chris@0
|
189 * Splits a field name into segments as a web browser would do.
|
Chris@0
|
190 *
|
Chris@0
|
191 * <code>
|
Chris@0
|
192 * getSegments('base[foo][3][]') = array('base', 'foo, '3', '');
|
Chris@0
|
193 * </code>
|
Chris@0
|
194 *
|
Chris@0
|
195 * @param string $name The name of the field
|
Chris@0
|
196 *
|
Chris@0
|
197 * @return string[] The list of segments
|
Chris@0
|
198 */
|
Chris@0
|
199 private function getSegments($name)
|
Chris@0
|
200 {
|
Chris@0
|
201 if (preg_match('/^(?P<base>[^[]+)(?P<extra>(\[.*)|$)/', $name, $m)) {
|
Chris@0
|
202 $segments = array($m['base']);
|
Chris@0
|
203 while (!empty($m['extra'])) {
|
Chris@0
|
204 $extra = $m['extra'];
|
Chris@0
|
205 if (preg_match('/^\[(?P<segment>.*?)\](?P<extra>.*)$/', $extra, $m)) {
|
Chris@0
|
206 $segments[] = $m['segment'];
|
Chris@0
|
207 } else {
|
Chris@0
|
208 $segments[] = $extra;
|
Chris@0
|
209 }
|
Chris@0
|
210 }
|
Chris@0
|
211
|
Chris@0
|
212 return $segments;
|
Chris@0
|
213 }
|
Chris@0
|
214
|
Chris@0
|
215 return array($name);
|
Chris@0
|
216 }
|
Chris@0
|
217 }
|