Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\DomCrawler; Chris@0: Chris@0: use Symfony\Component\DomCrawler\Field\FormField; Chris@0: Chris@0: /** Chris@0: * This is an internal class that must not be used directly. Chris@0: * Chris@0: * @internal Chris@0: */ Chris@0: class FormFieldRegistry Chris@0: { Chris@17: private $fields = []; Chris@0: Chris@0: private $base; Chris@0: Chris@0: /** Chris@0: * Adds a field to the registry. Chris@0: */ Chris@0: public function add(FormField $field) Chris@0: { Chris@0: $segments = $this->getSegments($field->getName()); Chris@0: Chris@0: $target = &$this->fields; Chris@0: while ($segments) { Chris@17: if (!\is_array($target)) { Chris@17: $target = []; Chris@0: } Chris@0: $path = array_shift($segments); Chris@0: if ('' === $path) { Chris@0: $target = &$target[]; Chris@0: } else { Chris@0: $target = &$target[$path]; Chris@0: } Chris@0: } Chris@0: $target = $field; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Removes a field and its children from the registry. Chris@0: * Chris@0: * @param string $name The fully qualified name of the base field Chris@0: */ Chris@0: public function remove($name) Chris@0: { Chris@0: $segments = $this->getSegments($name); Chris@0: $target = &$this->fields; Chris@17: while (\count($segments) > 1) { Chris@0: $path = array_shift($segments); Chris@18: if (!\array_key_exists($path, $target)) { Chris@0: return; Chris@0: } Chris@0: $target = &$target[$path]; Chris@0: } Chris@0: unset($target[array_shift($segments)]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the value of the field and its children. Chris@0: * Chris@0: * @param string $name The fully qualified name of the field Chris@0: * Chris@0: * @return mixed The value of the field Chris@0: * Chris@0: * @throws \InvalidArgumentException if the field does not exist Chris@0: */ Chris@0: public function &get($name) Chris@0: { Chris@0: $segments = $this->getSegments($name); Chris@0: $target = &$this->fields; Chris@0: while ($segments) { Chris@0: $path = array_shift($segments); Chris@18: if (!\array_key_exists($path, $target)) { Chris@0: throw new \InvalidArgumentException(sprintf('Unreachable field "%s"', $path)); Chris@0: } Chris@0: $target = &$target[$path]; Chris@0: } Chris@0: Chris@0: return $target; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests whether the form has the given field. Chris@0: * Chris@0: * @param string $name The fully qualified name of the field Chris@0: * Chris@0: * @return bool Whether the form has the given field Chris@0: */ Chris@0: public function has($name) Chris@0: { Chris@0: try { Chris@0: $this->get($name); Chris@0: Chris@0: return true; Chris@0: } catch (\InvalidArgumentException $e) { Chris@0: return false; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Set the value of a field and its children. Chris@0: * Chris@0: * @param string $name The fully qualified name of the field Chris@0: * @param mixed $value The value Chris@0: * Chris@0: * @throws \InvalidArgumentException if the field does not exist Chris@0: */ Chris@0: public function set($name, $value) Chris@0: { Chris@0: $target = &$this->get($name); Chris@17: if ((!\is_array($value) && $target instanceof Field\FormField) || $target instanceof Field\ChoiceFormField) { Chris@0: $target->setValue($value); Chris@17: } elseif (\is_array($value)) { Chris@0: $fields = self::create($name, $value); Chris@0: foreach ($fields->all() as $k => $v) { Chris@0: $this->set($k, $v); Chris@0: } Chris@0: } else { Chris@0: throw new \InvalidArgumentException(sprintf('Cannot set value on a compound field "%s".', $name)); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the list of field with their value. Chris@0: * Chris@17: * @return FormField[] The list of fields as [string] Fully qualified name => (mixed) value) Chris@0: */ Chris@0: public function all() Chris@0: { Chris@0: return $this->walk($this->fields, $this->base); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates an instance of the class. Chris@0: * Chris@0: * This function is made private because it allows overriding the $base and Chris@0: * the $values properties without any type checking. Chris@0: * Chris@0: * @param string $base The fully qualified name of the base field Chris@0: * @param array $values The values of the fields Chris@0: * Chris@0: * @return static Chris@0: */ Chris@0: private static function create($base, array $values) Chris@0: { Chris@0: $registry = new static(); Chris@0: $registry->base = $base; Chris@0: $registry->fields = $values; Chris@0: Chris@0: return $registry; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Transforms a PHP array in a list of fully qualified name / value. Chris@0: * Chris@0: * @param array $array The PHP array Chris@0: * @param string $base The name of the base field Chris@0: * @param array $output The initial values Chris@0: * Chris@17: * @return array The list of fields as [string] Fully qualified name => (mixed) value) Chris@0: */ Chris@17: private function walk(array $array, $base = '', array &$output = []) Chris@0: { Chris@0: foreach ($array as $k => $v) { Chris@0: $path = empty($base) ? $k : sprintf('%s[%s]', $base, $k); Chris@17: if (\is_array($v)) { Chris@0: $this->walk($v, $path, $output); Chris@0: } else { Chris@0: $output[$path] = $v; Chris@0: } Chris@0: } Chris@0: Chris@0: return $output; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Splits a field name into segments as a web browser would do. Chris@0: * Chris@17: * getSegments('base[foo][3][]') = ['base', 'foo, '3', '']; Chris@0: * Chris@0: * @param string $name The name of the field Chris@0: * Chris@0: * @return string[] The list of segments Chris@0: */ Chris@0: private function getSegments($name) Chris@0: { Chris@0: if (preg_match('/^(?P[^[]+)(?P(\[.*)|$)/', $name, $m)) { Chris@17: $segments = [$m['base']]; Chris@0: while (!empty($m['extra'])) { Chris@0: $extra = $m['extra']; Chris@0: if (preg_match('/^\[(?P.*?)\](?P.*)$/', $extra, $m)) { Chris@0: $segments[] = $m['segment']; Chris@0: } else { Chris@0: $segments[] = $extra; Chris@0: } Chris@0: } Chris@0: Chris@0: return $segments; Chris@0: } Chris@0: Chris@17: return [$name]; Chris@0: } Chris@0: }