Skip to content

Commit

Permalink
[Form] Restricted form names to specific characters to (1) fix genera…
Browse files Browse the repository at this point in the history
…tion of HTML IDs and to (2) avoid problems with property paths.

ad (1): HTML4 "id" attributes are limited to strings starting with a letter and containing only letters, digits, underscores, hyphens, periods and colons.

ad (2): Property paths contain three special characters needed for correct parsing: left/right bracket and period.

The rules for form naming are:

* Names may start with a letter, a digit or an underscore. Leading digits or underscores will be stripped from the "id" attributes.
* Names must only contain letters, digits, underscores, hyphens and colons.
* Root forms may have an empty name.

Solves #1919 and #3021 on a wider scope.
  • Loading branch information
webmozart committed Jan 23, 2012
1 parent 87b16e7 commit e1fc5a5
Show file tree
Hide file tree
Showing 10 changed files with 361 additions and 327 deletions.
Expand Up @@ -25,7 +25,7 @@ class CollectionType extends AbstractType
public function buildForm(FormBuilder $builder, array $options)
{
if ($options['allow_add'] && $options['prototype']) {
$prototype = $builder->create('$$' . $options['prototype_name'] . '$$', $options['type'], $options['options']);
$prototype = $builder->create($options['prototype_name'], $options['type'], $options['options']);
$builder->setAttribute('prototype', $prototype->getForm());
}

Expand Down Expand Up @@ -78,7 +78,7 @@ public function getDefaultOptions(array $options)
'allow_add' => false,
'allow_delete' => false,
'prototype' => true,
'prototype_name' => 'name',
'prototype_name' => '__name__',
'type' => 'text',
'options' => array(),
);
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
Expand Up @@ -88,6 +88,11 @@ public function buildView(FormView $view, FormInterface $form)
} else {
$id = $name;
$fullName = $name;

// Strip leading underscores and digits. These are allowed in
// form names, but not in HTML4 ID attributes.
// http://www.w3.org/TR/html401/struct/global.html#adef-id
$id = ltrim($id, '_0123456789');
}

$types = array();
Expand Down
34 changes: 33 additions & 1 deletion src/Symfony/Component/Form/Form.php
Expand Up @@ -193,6 +193,10 @@ public function __construct($name, EventDispatcherInterface $dispatcher,
$required = false, $readOnly = false, $errorBubbling = false,
$emptyData = null, array $attributes = array())
{
$name = (string) $name;

self::validateName($name);

foreach ($clientTransformers as $transformer) {
if (!$transformer instanceof DataTransformerInterface) {
throw new UnexpectedTypeException($transformer, 'Symfony\Component\Form\DataTransformerInterface');
Expand All @@ -211,7 +215,7 @@ public function __construct($name, EventDispatcherInterface $dispatcher,
}
}

$this->name = (string) $name;
$this->name = $name;
$this->dispatcher = $dispatcher;
$this->types = $types;
$this->clientTransformers = $clientTransformers;
Expand Down Expand Up @@ -1055,4 +1059,32 @@ private function clientToNorm($value)

return $value;
}

/**
* Validates whether the given variable is a valid form name.
*
* A name is accepted if it
*
* * is empty
* * starts with a letter, digit or underscore
* * contains only letters, digits, numbers, underscores ("_"),
* hyphens ("-") and colons (":")
*
* @param string $name The tested form name.
* @throws UnexpectedTypeException If the name is not a string.
* @throws \InvalidArgumentException If the name contains invalid characters.
*/
static public function validateName($name)
{
if (!is_string($name)) {
throw new UnexpectedTypeException($name, 'string');
}

if ($name !== '' && !preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name)) {
throw new \InvalidArgumentException(sprintf(
'The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contains letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").',
$name
));
}
}
}
4 changes: 4 additions & 0 deletions src/Symfony/Component/Form/FormBuilder.php
Expand Up @@ -123,6 +123,10 @@ class FormBuilder
*/
public function __construct($name, FormFactoryInterface $factory, EventDispatcherInterface $dispatcher, $dataClass = null)
{
$name = (string) $name;

Form::validateName($name);

$this->name = $name;
$this->factory = $factory;
$this->dispatcher = $dispatcher;
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Form/Util/FormUtil.php
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\Form\Util;

use Symfony\Component\Form\Exception\UnexpectedTypeException;

abstract class FormUtil
{
/**
Expand Down

0 comments on commit e1fc5a5

Please sign in to comment.