friendship ended with social-app. php is my new best friend
at main 5.0 kB view raw
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 12namespace Symfony\Component\DomCrawler; 13 14use Symfony\Component\DomCrawler\Field\FormField; 15 16/** 17 * This is an internal class that must not be used directly. 18 * 19 * @internal 20 */ 21class FormFieldRegistry 22{ 23 private array $fields = []; 24 private string $base = ''; 25 26 /** 27 * Adds a field to the registry. 28 */ 29 public function add(FormField $field): void 30 { 31 $segments = $this->getSegments($field->getName()); 32 33 $target = &$this->fields; 34 while ($segments) { 35 if (!\is_array($target)) { 36 $target = []; 37 } 38 $path = array_shift($segments); 39 if ('' === $path) { 40 $target = &$target[]; 41 } else { 42 $target = &$target[$path]; 43 } 44 } 45 $target = $field; 46 } 47 48 /** 49 * Removes a field based on the fully qualified name and its children from the registry. 50 */ 51 public function remove(string $name): void 52 { 53 $segments = $this->getSegments($name); 54 $target = &$this->fields; 55 while (\count($segments) > 1) { 56 $path = array_shift($segments); 57 if (!\is_array($target) || !\array_key_exists($path, $target)) { 58 return; 59 } 60 $target = &$target[$path]; 61 } 62 unset($target[array_shift($segments)]); 63 } 64 65 /** 66 * Returns the value of the field based on the fully qualified name and its children. 67 * 68 * @return FormField|FormField[]|FormField[][] 69 * 70 * @throws \InvalidArgumentException if the field does not exist 71 */ 72 public function &get(string $name): FormField|array 73 { 74 $segments = $this->getSegments($name); 75 $target = &$this->fields; 76 while ($segments) { 77 $path = array_shift($segments); 78 if (!\is_array($target) || !\array_key_exists($path, $target)) { 79 throw new \InvalidArgumentException(\sprintf('Unreachable field "%s".', $path)); 80 } 81 $target = &$target[$path]; 82 } 83 84 return $target; 85 } 86 87 /** 88 * Tests whether the form has the given field based on the fully qualified name. 89 */ 90 public function has(string $name): bool 91 { 92 try { 93 $this->get($name); 94 95 return true; 96 } catch (\InvalidArgumentException) { 97 return false; 98 } 99 } 100 101 /** 102 * Set the value of a field based on the fully qualified name and its children. 103 * 104 * @throws \InvalidArgumentException if the field does not exist 105 */ 106 public function set(string $name, mixed $value): void 107 { 108 $target = &$this->get($name); 109 if ((!\is_array($value) && $target instanceof FormField) || $target instanceof Field\ChoiceFormField) { 110 $target->setValue($value); 111 } elseif (\is_array($value)) { 112 $registry = new static(); 113 $registry->base = $name; 114 $registry->fields = $value; 115 foreach ($registry->all() as $k => $v) { 116 $this->set($k, $v); 117 } 118 } else { 119 throw new \InvalidArgumentException(\sprintf('Cannot set value on a compound field "%s".', $name)); 120 } 121 } 122 123 /** 124 * Returns the list of field with their value. 125 * 126 * @return FormField[] The list of fields as [string] Fully qualified name => (mixed) value) 127 */ 128 public function all(): array 129 { 130 return $this->walk($this->fields, $this->base); 131 } 132 133 /** 134 * Transforms a PHP array in a list of fully qualified name / value. 135 */ 136 private function walk(array $array, ?string $base = '', array &$output = []): array 137 { 138 foreach ($array as $k => $v) { 139 $path = $base ? \sprintf('%s[%s]', $base, $k) : $k; 140 if (\is_array($v)) { 141 $this->walk($v, $path, $output); 142 } else { 143 $output[$path] = $v; 144 } 145 } 146 147 return $output; 148 } 149 150 /** 151 * Splits a field name into segments as a web browser would do. 152 * 153 * getSegments('base[foo][3][]') = ['base', 'foo, '3', '']; 154 * 155 * @return string[] 156 */ 157 private function getSegments(string $name): array 158 { 159 if (preg_match('/^(?P<base>[^[]+)(?P<extra>(\[.*)|$)/', $name, $m)) { 160 $segments = [$m['base']]; 161 while (!empty($m['extra'])) { 162 $extra = $m['extra']; 163 if (preg_match('/^\[(?P<segment>.*?)\](?P<extra>.*)$/', $extra, $m)) { 164 $segments[] = $m['segment']; 165 } else { 166 $segments[] = $extra; 167 } 168 } 169 170 return $segments; 171 } 172 173 return [$name]; 174 } 175}