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: }