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