[Form] Extracted FormConfig class to simplify the Form's constructor
This commit is contained in:
parent
e4e3ce6cc2
commit
29963400e8
@ -11,7 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Core\ChoiceList;
|
||||
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\FormConfig;
|
||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||
use Symfony\Component\Form\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
|
||||
@ -335,7 +335,7 @@ class ChoiceList implements ChoiceListInterface
|
||||
{
|
||||
$index = $this->createIndex($choice);
|
||||
|
||||
if ('' === $index || null === $index || !Form::isValidName((string)$index)) {
|
||||
if ('' === $index || null === $index || !FormConfig::isValidName((string)$index)) {
|
||||
throw new InvalidConfigurationException('The index "' . $index . '" created by the choice list is invalid. It should be a valid, non-empty Form name.');
|
||||
}
|
||||
|
||||
|
@ -58,10 +58,10 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
class Form implements \IteratorAggregate, FormInterface
|
||||
{
|
||||
/**
|
||||
* The name of this form
|
||||
* @var string
|
||||
* The form's configuration
|
||||
* @var FormConfigInterface
|
||||
*/
|
||||
private $name;
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* The parent of this form
|
||||
@ -75,36 +75,18 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
private $children = array();
|
||||
|
||||
/**
|
||||
* The mapper for mapping data to children and back
|
||||
* @var DataMapperInterface
|
||||
*/
|
||||
private $dataMapper;
|
||||
|
||||
/**
|
||||
* The errors of this form
|
||||
* @var array An array of FormError instances
|
||||
*/
|
||||
private $errors = array();
|
||||
|
||||
/**
|
||||
* Whether added errors should bubble up to the parent
|
||||
* @var Boolean
|
||||
*/
|
||||
private $errorBubbling;
|
||||
|
||||
/**
|
||||
* Whether this form is bound
|
||||
* @var Boolean
|
||||
*/
|
||||
private $bound = false;
|
||||
|
||||
/**
|
||||
* Whether this form may or may not be empty
|
||||
* @var Boolean
|
||||
*/
|
||||
private $required;
|
||||
|
||||
/**
|
||||
* The form data in application format
|
||||
* @var mixed
|
||||
@ -123,32 +105,12 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
private $clientData;
|
||||
|
||||
/**
|
||||
* Data used for the client data when no value is bound
|
||||
* @var mixed
|
||||
*/
|
||||
private $emptyData = '';
|
||||
|
||||
/**
|
||||
* The bound values that don't belong to any children
|
||||
* @var array
|
||||
*/
|
||||
private $extraData = array();
|
||||
|
||||
/**
|
||||
* The transformers for transforming from application to normalized format
|
||||
* and back
|
||||
* @var array An array of DataTransformerInterface
|
||||
*/
|
||||
private $normTransformers;
|
||||
|
||||
/**
|
||||
* The transformers for transforming from normalized to client format and
|
||||
* back
|
||||
* @var array An array of DataTransformerInterface
|
||||
*/
|
||||
private $clientTransformers;
|
||||
|
||||
/**
|
||||
* Whether the data in application, normalized and client format is
|
||||
* synchronized. Data may not be synchronized if transformation errors
|
||||
@ -158,78 +120,19 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
private $synchronized = true;
|
||||
|
||||
/**
|
||||
* The validators attached to this form
|
||||
* @var array An array of FormValidatorInterface instances
|
||||
* Creates a new form based on the given configuration.
|
||||
*
|
||||
* @param FormConfigInterface $config The form configuration.
|
||||
*/
|
||||
private $validators;
|
||||
|
||||
/**
|
||||
* Whether this form may only be read, but not bound
|
||||
* @var Boolean
|
||||
*/
|
||||
private $disabled = false;
|
||||
|
||||
/**
|
||||
* The dispatcher for distributing events of this form
|
||||
* @var Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* Key-value store for arbitrary attributes attached to this form
|
||||
* @var array
|
||||
*/
|
||||
private $attributes;
|
||||
|
||||
/**
|
||||
* The FormTypeInterface instances used to create this form
|
||||
* @var array An array of FormTypeInterface
|
||||
*/
|
||||
private $types;
|
||||
|
||||
public function __construct($name, EventDispatcherInterface $dispatcher,
|
||||
array $types = array(), array $clientTransformers = array(),
|
||||
array $normTransformers = array(),
|
||||
DataMapperInterface $dataMapper = null, array $validators = array(),
|
||||
$required = false, $disabled = false, $errorBubbling = null,
|
||||
$emptyData = null, array $attributes = array())
|
||||
public function __construct(FormConfigInterface $config)
|
||||
{
|
||||
$name = (string) $name;
|
||||
|
||||
self::validateName($name);
|
||||
|
||||
foreach ($clientTransformers as $transformer) {
|
||||
if (!$transformer instanceof DataTransformerInterface) {
|
||||
throw new UnexpectedTypeException($transformer, 'Symfony\Component\Form\DataTransformerInterface');
|
||||
}
|
||||
if (!$config instanceof ImmutableFormConfig) {
|
||||
$config = new ImmutableFormConfig($config);
|
||||
}
|
||||
|
||||
foreach ($normTransformers as $transformer) {
|
||||
if (!$transformer instanceof DataTransformerInterface) {
|
||||
throw new UnexpectedTypeException($transformer, 'Symfony\Component\Form\DataTransformerInterface');
|
||||
}
|
||||
}
|
||||
$this->config = $config;
|
||||
|
||||
foreach ($validators as $validator) {
|
||||
if (!$validator instanceof FormValidatorInterface) {
|
||||
throw new UnexpectedTypeException($validator, 'Symfony\Component\Form\FormValidatorInterface');
|
||||
}
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->types = $types;
|
||||
$this->clientTransformers = $clientTransformers;
|
||||
$this->normTransformers = $normTransformers;
|
||||
$this->dataMapper = $dataMapper;
|
||||
$this->validators = $validators;
|
||||
$this->required = (Boolean) $required;
|
||||
$this->disabled = (Boolean) $disabled;
|
||||
$this->errorBubbling = (Boolean) $errorBubbling;
|
||||
$this->emptyData = $emptyData;
|
||||
$this->attributes = $attributes;
|
||||
|
||||
$this->setData(null);
|
||||
$this->setData($config->getData());
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
@ -239,6 +142,16 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration of the form.
|
||||
*
|
||||
* @return ImmutableFormConfig The form's immutable configuration.
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name by which the form is identified in forms.
|
||||
*
|
||||
@ -246,7 +159,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
return $this->config->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -256,22 +169,16 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function getTypes()
|
||||
{
|
||||
return $this->types;
|
||||
return $this->config->getTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the form is required to be filled out.
|
||||
*
|
||||
* If the form has a parent and the parent is not required, this method
|
||||
* will always return false. Otherwise the value set with setRequired()
|
||||
* is returned.
|
||||
*
|
||||
* @return Boolean
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
if (null === $this->parent || $this->parent->isRequired()) {
|
||||
return $this->required;
|
||||
return $this->config->getRequired();
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -283,7 +190,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
public function isDisabled()
|
||||
{
|
||||
if (null === $this->parent || !$this->parent->isDisabled()) {
|
||||
return $this->disabled;
|
||||
return $this->config->getDisabled();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -302,8 +209,8 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
throw new AlreadyBoundException('You cannot set the parent of a bound form');
|
||||
}
|
||||
|
||||
if ('' === $this->getName()) {
|
||||
throw new FormException('Form with empty name can not have parent form.');
|
||||
if ('' === $this->config->getName()) {
|
||||
throw new FormException('A form with an empty name cannot have a parent form.');
|
||||
}
|
||||
|
||||
$this->parent = $parent;
|
||||
@ -360,7 +267,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function hasAttribute($name)
|
||||
{
|
||||
return isset($this->attributes[$name]);
|
||||
return $this->config->hasAttribute($name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -370,7 +277,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function getAttribute($name)
|
||||
{
|
||||
return $this->attributes[$name];
|
||||
return $this->config->getAttribute($name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -387,15 +294,15 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
|
||||
$event = new DataEvent($this, $appData);
|
||||
$this->dispatcher->dispatch(FormEvents::PRE_SET_DATA, $event);
|
||||
$this->config->getEventDispatcher()->dispatch(FormEvents::PRE_SET_DATA, $event);
|
||||
|
||||
// Hook to change content of the data
|
||||
$event = new FilterDataEvent($this, $appData);
|
||||
$this->dispatcher->dispatch(FormEvents::SET_DATA, $event);
|
||||
$this->config->getEventDispatcher()->dispatch(FormEvents::SET_DATA, $event);
|
||||
$appData = $event->getData();
|
||||
|
||||
// Treat data as strings unless a value transformer exists
|
||||
if (!$this->clientTransformers && !$this->normTransformers && is_scalar($appData)) {
|
||||
if (!$this->config->getClientTransformers() && !$this->config->getNormTransformers() && is_scalar($appData)) {
|
||||
$appData = (string) $appData;
|
||||
}
|
||||
|
||||
@ -408,13 +315,13 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
$this->clientData = $clientData;
|
||||
$this->synchronized = true;
|
||||
|
||||
if (count($this->children) > 0 && $this->dataMapper) {
|
||||
if (count($this->children) > 0 && $this->config->getDataMapper()) {
|
||||
// Update child forms from the data
|
||||
$this->dataMapper->mapDataToForms($clientData, $this->children);
|
||||
$this->config->getDataMapper()->mapDataToForms($clientData, $this->children);
|
||||
}
|
||||
|
||||
$event = new DataEvent($this, $appData);
|
||||
$this->dispatcher->dispatch(FormEvents::POST_SET_DATA, $event);
|
||||
$this->config->getEventDispatcher()->dispatch(FormEvents::POST_SET_DATA, $event);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -483,7 +390,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
$this->errors = array();
|
||||
|
||||
$event = new DataEvent($this, $clientData);
|
||||
$this->dispatcher->dispatch(FormEvents::PRE_BIND, $event);
|
||||
$this->config->getEventDispatcher()->dispatch(FormEvents::PRE_BIND, $event);
|
||||
|
||||
$appData = null;
|
||||
$normData = null;
|
||||
@ -492,7 +399,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
|
||||
// Hook to change content of the data bound by the browser
|
||||
$event = new FilterDataEvent($this, $clientData);
|
||||
$this->dispatcher->dispatch(FormEvents::BIND_CLIENT_DATA, $event);
|
||||
$this->config->getEventDispatcher()->dispatch(FormEvents::BIND_CLIENT_DATA, $event);
|
||||
$clientData = $event->getData();
|
||||
|
||||
if (count($this->children) > 0) {
|
||||
@ -520,13 +427,13 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
|
||||
// If we have a data mapper, use old client data and merge
|
||||
// data from the children into it later
|
||||
if ($this->dataMapper) {
|
||||
if ($this->config->getDataMapper()) {
|
||||
$clientData = $this->getClientData();
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $clientData || '' === $clientData) {
|
||||
$emptyData = $this->emptyData;
|
||||
$emptyData = $this->config->getEmptyData();
|
||||
|
||||
if ($emptyData instanceof \Closure) {
|
||||
$emptyData = $emptyData($this, $clientData);
|
||||
@ -536,8 +443,8 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
|
||||
// Merge form data from children into existing client data
|
||||
if (count($this->children) > 0 && $this->dataMapper && null !== $clientData) {
|
||||
$this->dataMapper->mapFormsToData($this->children, $clientData);
|
||||
if (count($this->children) > 0 && $this->config->getDataMapper() && null !== $clientData) {
|
||||
$this->config->getDataMapper()->mapFormsToData($this->children, $clientData);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -551,7 +458,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
// Hook to change content of the data into the normalized
|
||||
// representation
|
||||
$event = new FilterDataEvent($this, $normData);
|
||||
$this->dispatcher->dispatch(FormEvents::BIND_NORM_DATA, $event);
|
||||
$this->config->getEventDispatcher()->dispatch(FormEvents::BIND_NORM_DATA, $event);
|
||||
$normData = $event->getData();
|
||||
|
||||
// Synchronize representations - must not change the content!
|
||||
@ -567,9 +474,9 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
$this->synchronized = $synchronized;
|
||||
|
||||
$event = new DataEvent($this, $clientData);
|
||||
$this->dispatcher->dispatch(FormEvents::POST_BIND, $event);
|
||||
$this->config->getEventDispatcher()->dispatch(FormEvents::POST_BIND, $event);
|
||||
|
||||
foreach ($this->validators as $validator) {
|
||||
foreach ($this->config->getValidators() as $validator) {
|
||||
$validator->validate($this);
|
||||
}
|
||||
|
||||
@ -590,24 +497,26 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function bindRequest(Request $request)
|
||||
{
|
||||
$name = $this->config->getName();
|
||||
|
||||
// Store the bound data in case of a post request
|
||||
switch ($request->getMethod()) {
|
||||
case 'POST':
|
||||
case 'PUT':
|
||||
case 'DELETE':
|
||||
case 'PATCH':
|
||||
if ('' === $this->getName()) {
|
||||
if ('' === $name) {
|
||||
// Form bound without name
|
||||
$params = $request->request->all();
|
||||
$files = $request->files->all();
|
||||
} elseif ($this->hasChildren()) {
|
||||
// Form bound with name and children
|
||||
$params = $request->request->get($this->getName(), array());
|
||||
$files = $request->files->get($this->getName(), array());
|
||||
$params = $request->request->get($name, array());
|
||||
$files = $request->files->get($name, array());
|
||||
} else {
|
||||
// Form bound with name, but without children
|
||||
$params = $request->request->get($this->getName(), null);
|
||||
$files = $request->files->get($this->getName(), null);
|
||||
$params = $request->request->get($name, null);
|
||||
$files = $request->files->get($name, null);
|
||||
}
|
||||
if (is_array($params) && is_array($files)) {
|
||||
$data = array_replace_recursive($params, $files);
|
||||
@ -616,7 +525,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
break;
|
||||
case 'GET':
|
||||
$data = '' === $this->getName() ? $request->query->all() : $request->query->get($this->getName(), array());
|
||||
$data = '' === $name ? $request->query->all() : $request->query->get($name, array());
|
||||
break;
|
||||
default:
|
||||
throw new FormException(sprintf('The request method "%s" is not supported', $request->getMethod()));
|
||||
@ -662,7 +571,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function getErrorBubbling()
|
||||
{
|
||||
return $this->errorBubbling;
|
||||
return $this->config->getErrorBubbling();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -787,7 +696,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function getNormTransformers()
|
||||
{
|
||||
return $this->normTransformers;
|
||||
return $this->config->getNormTransformers();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -797,7 +706,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
public function getClientTransformers()
|
||||
{
|
||||
return $this->clientTransformers;
|
||||
return $this->config->getClientTransformers();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -821,11 +730,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child to the form.
|
||||
*
|
||||
* @param FormInterface $child The FormInterface to add as a child
|
||||
*
|
||||
* @return Form the current form
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add(FormInterface $child)
|
||||
{
|
||||
@ -837,19 +742,15 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
|
||||
$child->setParent($this);
|
||||
|
||||
if ($this->dataMapper) {
|
||||
$this->dataMapper->mapDataToForm($this->getClientData(), $child);
|
||||
if ($this->config->getDataMapper()) {
|
||||
$this->config->getDataMapper()->mapDataToForm($this->getClientData(), $child);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a child from the form.
|
||||
*
|
||||
* @param string $name The name of the child to remove
|
||||
*
|
||||
* @return Form the current form
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
@ -867,11 +768,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a child with the given name exists.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Boolean
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
@ -879,13 +776,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the child with the given name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return FormInterface
|
||||
*
|
||||
* @throws \InvalidArgumentException if the child does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
@ -974,11 +865,11 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
$parent = $this->parent->createView();
|
||||
}
|
||||
|
||||
$view = new FormView($this->name);
|
||||
$view = new FormView($this->config->getName());
|
||||
|
||||
$view->setParent($parent);
|
||||
|
||||
$types = (array) $this->types;
|
||||
$types = (array) $this->config->getTypes();
|
||||
|
||||
foreach ($types as $type) {
|
||||
$type->buildView($view, $this);
|
||||
@ -1012,7 +903,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
private function appToNorm($value)
|
||||
{
|
||||
foreach ($this->normTransformers as $transformer) {
|
||||
foreach ($this->config->getNormTransformers() as $transformer) {
|
||||
$value = $transformer->transform($value);
|
||||
}
|
||||
|
||||
@ -1028,8 +919,10 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
private function normToApp($value)
|
||||
{
|
||||
for ($i = count($this->normTransformers) - 1; $i >= 0; --$i) {
|
||||
$value = $this->normTransformers[$i]->reverseTransform($value);
|
||||
$transformers = $this->config->getNormTransformers();
|
||||
|
||||
for ($i = count($transformers) - 1; $i >= 0; --$i) {
|
||||
$value = $transformers[$i]->reverseTransform($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
@ -1044,13 +937,13 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
private function normToClient($value)
|
||||
{
|
||||
if (!$this->clientTransformers) {
|
||||
if (!$this->config->getClientTransformers()) {
|
||||
// Scalar values should always be converted to strings to
|
||||
// facilitate differentiation between empty ("") and zero (0).
|
||||
return null === $value || is_scalar($value) ? (string) $value : $value;
|
||||
}
|
||||
|
||||
foreach ($this->clientTransformers as $transformer) {
|
||||
foreach ($this->config->getClientTransformers() as $transformer) {
|
||||
$value = $transformer->transform($value);
|
||||
}
|
||||
|
||||
@ -1066,55 +959,16 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*/
|
||||
private function clientToNorm($value)
|
||||
{
|
||||
if (!$this->clientTransformers) {
|
||||
$transformers = $this->config->getClientTransformers();
|
||||
|
||||
if (!$transformers) {
|
||||
return '' === $value ? null : $value;
|
||||
}
|
||||
|
||||
for ($i = count($this->clientTransformers) - 1; $i >= 0; --$i) {
|
||||
$value = $this->clientTransformers[$i]->reverseTransform($value);
|
||||
for ($i = count($transformers) - 1; $i >= 0; --$i) {
|
||||
$value = $transformers[$i]->reverseTransform($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the given variable is a valid form name.
|
||||
*
|
||||
* @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 (!self::isValidName($name)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").',
|
||||
$name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given variable contains 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.
|
||||
*
|
||||
* @return Boolean Whether the name is valid.
|
||||
*/
|
||||
static public function isValidName($name)
|
||||
{
|
||||
return '' === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name);
|
||||
}
|
||||
}
|
||||
|
@ -18,101 +18,37 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* A builder for creating {@link Form} instances.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class FormBuilder
|
||||
class FormBuilder extends FormConfig
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* The form data in application format
|
||||
* @var mixed
|
||||
*/
|
||||
private $appData;
|
||||
|
||||
/**
|
||||
* The event dispatcher
|
||||
* The form factory.
|
||||
*
|
||||
* @var EventDispatcherInterface
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* The form factory
|
||||
* @var FormFactoryInterface
|
||||
*/
|
||||
private $factory;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $disabled;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $required;
|
||||
|
||||
/**
|
||||
* The transformers for transforming from normalized to client format and
|
||||
* back
|
||||
* @var array An array of DataTransformerInterface
|
||||
*/
|
||||
private $clientTransformers = array();
|
||||
|
||||
/**
|
||||
* The transformers for transforming from application to normalized format
|
||||
* and back
|
||||
* @var array An array of DataTransformerInterface
|
||||
*/
|
||||
private $normTransformers = array();
|
||||
|
||||
/**
|
||||
* @var array An array of FormValidatorInterface
|
||||
*/
|
||||
private $validators = array();
|
||||
|
||||
/**
|
||||
* Key-value store for arbitrary attributes attached to the form
|
||||
* @var array
|
||||
*/
|
||||
private $attributes = array();
|
||||
|
||||
/**
|
||||
* @var array An array of FormTypeInterface
|
||||
*/
|
||||
private $types = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $dataClass;
|
||||
|
||||
/**
|
||||
* The children of the form
|
||||
* The children of the form builder.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $children = array();
|
||||
|
||||
/**
|
||||
* @var DataMapperInterface
|
||||
* The data of children who haven't been converted to form builders yet.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $dataMapper;
|
||||
|
||||
/**
|
||||
* Whether added errors should bubble up to the parent
|
||||
* @var Boolean
|
||||
*/
|
||||
private $errorBubbling;
|
||||
|
||||
/**
|
||||
* Data used for the client data when no value is bound
|
||||
* @var mixed
|
||||
*/
|
||||
private $emptyData = '';
|
||||
private $unresolvedChildren = array();
|
||||
|
||||
private $currentLoadingType;
|
||||
|
||||
@ -132,13 +68,9 @@ class FormBuilder
|
||||
*/
|
||||
public function __construct($name, FormFactoryInterface $factory, EventDispatcherInterface $dispatcher, $dataClass = null)
|
||||
{
|
||||
$name = (string) $name;
|
||||
parent::__construct($name, $dispatcher);
|
||||
|
||||
Form::validateName($name);
|
||||
|
||||
$this->name = $name;
|
||||
$this->factory = $factory;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->dataClass = $dataClass;
|
||||
}
|
||||
|
||||
@ -152,383 +84,6 @@ class FormBuilder
|
||||
return $this->factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the form.
|
||||
*
|
||||
* @return string The form name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the field with default data.
|
||||
*
|
||||
* @param array $appData The data formatted as expected for the underlying object
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function setData($appData)
|
||||
{
|
||||
$this->appData = $appData;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data in the format needed for the underlying object.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->appData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the form is disabled.
|
||||
*
|
||||
* @param Boolean $disabled Whether the form is disabled
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function setDisabled($disabled)
|
||||
{
|
||||
$this->disabled = (Boolean) $disabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the form is disabled.
|
||||
*
|
||||
* @return Boolean Whether the form is disabled
|
||||
*/
|
||||
public function getDisabled()
|
||||
{
|
||||
return $this->disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this field is required to be filled out when bound.
|
||||
*
|
||||
* @param Boolean $required
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function setRequired($required)
|
||||
{
|
||||
$this->required = (Boolean) $required;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this field is required to be filled out when bound.
|
||||
*
|
||||
* @return Boolean Whether this field is required
|
||||
*/
|
||||
public function getRequired()
|
||||
{
|
||||
return $this->required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether errors bubble up to the parent.
|
||||
*
|
||||
* @param type $errorBubbling
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function setErrorBubbling($errorBubbling)
|
||||
{
|
||||
$this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether errors bubble up to the parent.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function getErrorBubbling()
|
||||
{
|
||||
return $this->errorBubbling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a validator to the form.
|
||||
*
|
||||
* @param FormValidatorInterface $validator The validator
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*
|
||||
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
|
||||
*/
|
||||
public function addValidator(FormValidatorInterface $validator)
|
||||
{
|
||||
$this->validators[] = $validator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the validators used by the form.
|
||||
*
|
||||
* @return array An array of FormValidatorInterface
|
||||
*
|
||||
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
|
||||
*/
|
||||
public function getValidators()
|
||||
{
|
||||
return $this->validators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event listener for events on this field
|
||||
*
|
||||
* @see Symfony\Component\EventDispatcher\EventDispatcherInterface::addListener
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function addEventListener($eventName, $listener, $priority = 0)
|
||||
{
|
||||
$this->dispatcher->addListener($eventName, $listener, $priority);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event subscriber for events on this field
|
||||
*
|
||||
* @see Symfony\Component\EventDispatcher\EventDispatcherInterface::addSubscriber
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function addEventSubscriber(EventSubscriberInterface $subscriber)
|
||||
{
|
||||
$this->dispatcher->addSubscriber($subscriber);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a transformer to the normalization transformer chain
|
||||
*
|
||||
* @param DataTransformerInterface $normTransformer
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function appendNormTransformer(DataTransformerInterface $normTransformer)
|
||||
{
|
||||
$this->normTransformers[] = $normTransformer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a transformer to the normalization transformer chain
|
||||
*
|
||||
* @param DataTransformerInterface $normTransformer
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function prependNormTransformer(DataTransformerInterface $normTransformer)
|
||||
{
|
||||
array_unshift($this->normTransformers, $normTransformer);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the normalization transformers.
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function resetNormTransformers()
|
||||
{
|
||||
$this->normTransformers = array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the normalization transformers.
|
||||
*
|
||||
* @return array An array of DataTransformerInterface
|
||||
*/
|
||||
public function getNormTransformers()
|
||||
{
|
||||
return $this->normTransformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a transformer to the client transformer chain
|
||||
*
|
||||
* @param DataTransformerInterface $clientTransformer
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function appendClientTransformer(DataTransformerInterface $clientTransformer)
|
||||
{
|
||||
$this->clientTransformers[] = $clientTransformer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a transformer to the client transformer chain
|
||||
*
|
||||
* @param DataTransformerInterface $clientTransformer
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function prependClientTransformer(DataTransformerInterface $clientTransformer)
|
||||
{
|
||||
array_unshift($this->clientTransformers, $clientTransformer);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the client transformers.
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function resetClientTransformers()
|
||||
{
|
||||
$this->clientTransformers = array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the client transformers.
|
||||
*
|
||||
* @return array An array of DataTransformerInterface
|
||||
*/
|
||||
public function getClientTransformers()
|
||||
{
|
||||
return $this->clientTransformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value for an attribute.
|
||||
*
|
||||
* @param string $name The name of the attribute
|
||||
* @param string $value The value of the attribute
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function setAttribute($name, $value)
|
||||
{
|
||||
$this->attributes[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the attributes with the given name.
|
||||
*
|
||||
* @param string $name The name of the attribute
|
||||
*/
|
||||
public function getAttribute($name)
|
||||
{
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the form has an attribute with the given name.
|
||||
*
|
||||
* @param string $name The name of the attribute
|
||||
*/
|
||||
public function hasAttribute($name)
|
||||
{
|
||||
return isset($this->attributes[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the attributes.
|
||||
*
|
||||
* @return array An array of attributes
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data mapper used by the form.
|
||||
*
|
||||
* @param DataMapperInterface $dataMapper
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function setDataMapper(DataMapperInterface $dataMapper = null)
|
||||
{
|
||||
$this->dataMapper = $dataMapper;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data mapper used by the form.
|
||||
*
|
||||
* @return array An array of DataMapperInterface
|
||||
*/
|
||||
public function getDataMapper()
|
||||
{
|
||||
return $this->dataMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the types.
|
||||
*
|
||||
* @param array $types An array FormTypeInterface
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function setTypes(array $types)
|
||||
{
|
||||
$this->types = $types;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the types.
|
||||
*
|
||||
* @return array An array of FormTypeInterface
|
||||
*/
|
||||
public function getTypes()
|
||||
{
|
||||
return $this->types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data used for the client data when no value is bound.
|
||||
*
|
||||
* @param mixed $emptyData
|
||||
*/
|
||||
public function setEmptyData($emptyData)
|
||||
{
|
||||
$this->emptyData = $emptyData;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data used for the client data when no value is bound.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEmptyData()
|
||||
{
|
||||
return $this->emptyData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new field to this group. A field must have a unique name within
|
||||
* the group. Otherwise the existing field is overwritten.
|
||||
@ -540,7 +95,7 @@ class FormBuilder
|
||||
* @param string|FormTypeInterface $type
|
||||
* @param array $options
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
* @return FormBuilder The builder object.
|
||||
*/
|
||||
public function add($child, $type = null, array $options = array())
|
||||
{
|
||||
@ -548,6 +103,9 @@ class FormBuilder
|
||||
$child->setParent($this);
|
||||
$this->children[$child->getName()] = $child;
|
||||
|
||||
// In case an unresolved child with the same name exists
|
||||
unset($this->unresolvedChildren[$child->getName()]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -563,9 +121,9 @@ class FormBuilder
|
||||
throw new CircularReferenceException(is_string($type) ? $this->getFormFactory()->getType($type) : $type);
|
||||
}
|
||||
|
||||
$this->children[$child] = array(
|
||||
'type' => $type,
|
||||
'options' => $options,
|
||||
$this->unresolvedChildren[$child] = array(
|
||||
'type' => $type,
|
||||
'options' => $options,
|
||||
);
|
||||
|
||||
return $this;
|
||||
@ -578,7 +136,7 @@ class FormBuilder
|
||||
* @param string|FormTypeInterface $type The type of the form or null if name is a property
|
||||
* @param array $options The options
|
||||
*
|
||||
* @return FormBuilder The builder
|
||||
* @return FormBuilder The created builder.
|
||||
*/
|
||||
public function create($name, $type = null, array $options = array())
|
||||
{
|
||||
@ -604,19 +162,15 @@ class FormBuilder
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!isset($this->children[$name])) {
|
||||
throw new FormException(sprintf('The field "%s" does not exist', $name));
|
||||
if (isset($this->unresolvedChildren[$name])) {
|
||||
return $this->resolveChild($name);
|
||||
}
|
||||
|
||||
if (!$this->children[$name] instanceof FormBuilder) {
|
||||
$this->children[$name] = $this->create(
|
||||
$name,
|
||||
$this->children[$name]['type'],
|
||||
$this->children[$name]['options']
|
||||
);
|
||||
if (isset($this->children[$name])) {
|
||||
return $this->children[$name];
|
||||
}
|
||||
|
||||
return $this->children[$name];
|
||||
throw new FormException(sprintf('The child with the name "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -624,10 +178,14 @@ class FormBuilder
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
* @return FormBuilder The builder object.
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (isset($this->unresolvedChildren[$name])) {
|
||||
unset($this->unresolvedChildren[$name]);
|
||||
}
|
||||
|
||||
if (isset($this->children[$name])) {
|
||||
if ($this->children[$name] instanceof self) {
|
||||
$this->children[$name]->setParent(null);
|
||||
@ -647,7 +205,15 @@ class FormBuilder
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->children[$name]);
|
||||
if (isset($this->unresolvedChildren[$name])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($this->children[$name])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -657,6 +223,8 @@ class FormBuilder
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
$this->resolveChildren();
|
||||
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
@ -667,30 +235,15 @@ class FormBuilder
|
||||
*/
|
||||
public function getForm()
|
||||
{
|
||||
$instance = new Form(
|
||||
$this->getName(),
|
||||
$this->buildDispatcher(),
|
||||
$this->getTypes(),
|
||||
$this->getClientTransformers(),
|
||||
$this->getNormTransformers(),
|
||||
$this->getDataMapper(),
|
||||
$this->getValidators(),
|
||||
$this->getRequired(),
|
||||
$this->getDisabled(),
|
||||
$this->getErrorBubbling(),
|
||||
$this->getEmptyData(),
|
||||
$this->getAttributes()
|
||||
);
|
||||
$this->resolveChildren();
|
||||
|
||||
foreach ($this->buildChildren() as $child) {
|
||||
$instance->add($child);
|
||||
$form = new Form($this);
|
||||
|
||||
foreach ($this->children as $child) {
|
||||
$form->add($child->getForm());
|
||||
}
|
||||
|
||||
if (null !== $this->getData()) {
|
||||
$instance->setData($this->getData());
|
||||
}
|
||||
|
||||
return $instance;
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function setCurrentLoadingType($type)
|
||||
@ -713,7 +266,7 @@ class FormBuilder
|
||||
*
|
||||
* @param FormBuilder $parent The parent builder
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
* @return FormBuilder The builder object.
|
||||
*/
|
||||
public function setParent(FormBuilder $parent = null)
|
||||
{
|
||||
@ -723,32 +276,31 @@ class FormBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event dispatcher.
|
||||
* Converts an unresolved child into a {@link FormBuilder} instance.
|
||||
*
|
||||
* @return type
|
||||
* @param string $name The name of the unresolved child.
|
||||
*
|
||||
* @return FormBuilder The created instance.
|
||||
*/
|
||||
protected function buildDispatcher()
|
||||
private function resolveChild($name)
|
||||
{
|
||||
return $this->dispatcher;
|
||||
$info = $this->unresolvedChildren[$name];
|
||||
$child = $this->create($name, $info['type'], $info['options']);
|
||||
$this->children[$name] = $child;
|
||||
unset($this->unresolvedChildren[$name]);
|
||||
|
||||
return $child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the children.
|
||||
*
|
||||
* @return array An array of Form
|
||||
* Converts all unresolved children into {@link FormBuilder} instances.
|
||||
*/
|
||||
protected function buildChildren()
|
||||
private function resolveChildren()
|
||||
{
|
||||
$children = array();
|
||||
|
||||
foreach ($this->children as $name => $builder) {
|
||||
if (!$builder instanceof FormBuilder) {
|
||||
$builder = $this->create($name, $builder['type'], $builder['options']);
|
||||
}
|
||||
|
||||
$children[$builder->getName()] = $builder->getForm();
|
||||
foreach ($this->unresolvedChildren as $name => $info) {
|
||||
$this->children[$name] = $this->create($name, $info['type'], $info['options']);
|
||||
}
|
||||
|
||||
return $children;
|
||||
$this->unresolvedChildren = array();
|
||||
}
|
||||
}
|
||||
|
524
src/Symfony/Component/Form/FormConfig.php
Normal file
524
src/Symfony/Component/Form/FormConfig.php
Normal file
@ -0,0 +1,524 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form;
|
||||
|
||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||
use Symfony\Component\Form\Util\PropertyPath;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* A basic form configuration.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class FormConfig implements FormConfigInterface
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $types = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $clientTransformers = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $normTransformers = array();
|
||||
|
||||
/**
|
||||
* @var DataMapperInterface
|
||||
*/
|
||||
private $dataMapper;
|
||||
|
||||
/**
|
||||
* @var FormValidatorInterface
|
||||
*/
|
||||
private $validators = array();
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $required;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $disabled;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $errorBubbling;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $emptyData;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $attributes = array();
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Creates an empty form configuration.
|
||||
*
|
||||
* @param string $name The form name.
|
||||
* @param EventDispatcherInterface $dispatcher The event dispatcher.
|
||||
*/
|
||||
public function __construct($name, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$name = (string) $name;
|
||||
|
||||
self::validateName($name);
|
||||
|
||||
$this->name = $name;
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event listener to an event on this form.
|
||||
*
|
||||
* @param string $eventName The name of the event to listen to.
|
||||
* @param callable $listener The listener to execute.
|
||||
* @param integer $priority The priority of the listener. Listeners
|
||||
* with a higher priority are called before
|
||||
* listeners with a lower priority.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function addEventListener($eventName, $listener, $priority = 0)
|
||||
{
|
||||
$this->dispatcher->addListener($eventName, $listener, $priority);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event subscriber for events on this form.
|
||||
*
|
||||
* @param EventSubscriberInterface $subscriber The subscriber to attach.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function addEventSubscriber(EventSubscriberInterface $subscriber)
|
||||
{
|
||||
$this->dispatcher->addSubscriber($subscriber);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a validator to the form.
|
||||
*
|
||||
* @param FormValidatorInterface $validator The validator.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*
|
||||
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
|
||||
*/
|
||||
public function addValidator(FormValidatorInterface $validator)
|
||||
{
|
||||
$this->validators[] = $validator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a transformer to the client transformer chain
|
||||
*
|
||||
* @param DataTransformerInterface $clientTransformer
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function appendClientTransformer(DataTransformerInterface $clientTransformer)
|
||||
{
|
||||
$this->clientTransformers[] = $clientTransformer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a transformer to the client transformer chain.
|
||||
*
|
||||
* @param DataTransformerInterface $clientTransformer
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function prependClientTransformer(DataTransformerInterface $clientTransformer)
|
||||
{
|
||||
array_unshift($this->clientTransformers, $clientTransformer);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the client transformers.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function resetClientTransformers()
|
||||
{
|
||||
$this->clientTransformers = array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a transformer to the normalization transformer chain
|
||||
*
|
||||
* @param DataTransformerInterface $normTransformer
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function appendNormTransformer(DataTransformerInterface $normTransformer)
|
||||
{
|
||||
$this->normTransformers[] = $normTransformer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a transformer to the normalization transformer chain
|
||||
*
|
||||
* @param DataTransformerInterface $normTransformer
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function prependNormTransformer(DataTransformerInterface $normTransformer)
|
||||
{
|
||||
array_unshift($this->normTransformers, $normTransformer);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the normalization transformers.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function resetNormTransformers()
|
||||
{
|
||||
$this->normTransformers = array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEventDispatcher()
|
||||
{
|
||||
return $this->dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTypes()
|
||||
{
|
||||
return $this->types;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClientTransformers()
|
||||
{
|
||||
return $this->clientTransformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNormTransformers()
|
||||
{
|
||||
return $this->normTransformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data mapper of the form.
|
||||
*
|
||||
* @return DataMapperInterface The data mapper.
|
||||
*/
|
||||
public function getDataMapper()
|
||||
{
|
||||
return $this->dataMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValidators()
|
||||
{
|
||||
return $this->validators;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRequired()
|
||||
{
|
||||
return $this->required;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDisabled()
|
||||
{
|
||||
return $this->disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getErrorBubbling()
|
||||
{
|
||||
return $this->errorBubbling;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEmptyData()
|
||||
{
|
||||
return $this->emptyData;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function hasAttribute($name)
|
||||
{
|
||||
return isset($this->attributes[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function getAttribute($name)
|
||||
{
|
||||
return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value for an attribute.
|
||||
*
|
||||
* @param string $name The name of the attribute
|
||||
* @param string $value The value of the attribute
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setAttribute($name, $value)
|
||||
{
|
||||
$this->attributes[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attributes.
|
||||
*
|
||||
* @param array $attributes The attributes.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setAttributes(array $attributes)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data mapper used by the form.
|
||||
*
|
||||
* @param DataMapperInterface $dataMapper
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setDataMapper(DataMapperInterface $dataMapper = null)
|
||||
{
|
||||
$this->dataMapper = $dataMapper;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the form is disabled.
|
||||
*
|
||||
* @param Boolean $disabled Whether the form is disabled
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setDisabled($disabled)
|
||||
{
|
||||
$this->disabled = (Boolean) $disabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data used for the client data when no value is bound.
|
||||
*
|
||||
* @param mixed $emptyData The empty data.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setEmptyData($emptyData)
|
||||
{
|
||||
$this->emptyData = $emptyData;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether errors bubble up to the parent.
|
||||
*
|
||||
* @param Boolean $errorBubbling
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setErrorBubbling($errorBubbling)
|
||||
{
|
||||
$this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this field is required to be filled out when bound.
|
||||
*
|
||||
* @param Boolean $required
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setRequired($required)
|
||||
{
|
||||
$this->required = (Boolean) $required;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the types.
|
||||
*
|
||||
* @param array $types An array FormTypeInterface
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setTypes(array $types)
|
||||
{
|
||||
$this->types = $types;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial data of the form.
|
||||
*
|
||||
* @param array $data The data of the form in application format.
|
||||
*
|
||||
* @return self The configuration object.
|
||||
*/
|
||||
public function setData($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the given variable is a valid form name.
|
||||
*
|
||||
* @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 (!self::isValidName($name)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").',
|
||||
$name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given variable contains 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.
|
||||
*
|
||||
* @return Boolean Whether the name is valid.
|
||||
*/
|
||||
static public function isValidName($name)
|
||||
{
|
||||
return '' === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name);
|
||||
}
|
||||
}
|
131
src/Symfony/Component/Form/FormConfigInterface.php
Normal file
131
src/Symfony/Component/Form/FormConfigInterface.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form;
|
||||
|
||||
/**
|
||||
* The configuration of a {@link Form} object.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface FormConfigInterface
|
||||
{
|
||||
/**
|
||||
* Returns the event dispatcher used to dispatch form events.
|
||||
*
|
||||
* @return \Symfony\Component\EventDispatcher\EventDispatcherInterface The dispatcher.
|
||||
*/
|
||||
function getEventDispatcher();
|
||||
|
||||
/**
|
||||
* Returns the name of the form used as HTTP parameter.
|
||||
*
|
||||
* @return string The form name.
|
||||
*/
|
||||
function getName();
|
||||
|
||||
/**
|
||||
* Returns the form types used to construct the form.
|
||||
*
|
||||
* @return array An array of {@link FormTypeInterface} instances.
|
||||
*/
|
||||
function getTypes();
|
||||
|
||||
/**
|
||||
* Returns the client transformers of the form.
|
||||
*
|
||||
* @return array An array of {@link DataTransformerInterface} instances.
|
||||
*/
|
||||
function getClientTransformers();
|
||||
|
||||
/**
|
||||
* Returns the view transformers of the form.
|
||||
*
|
||||
* @return array An array of {@link DataTransformerInterface} instances.
|
||||
*/
|
||||
function getNormTransformers();
|
||||
|
||||
/**
|
||||
* Returns the data mapper of the form.
|
||||
*
|
||||
* @return DataMapperInterface The data mapper.
|
||||
*/
|
||||
function getDataMapper();
|
||||
|
||||
/**
|
||||
* Returns the validators of the form.
|
||||
*
|
||||
* @return FormValidatorInterface The form validator.
|
||||
*
|
||||
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
|
||||
*/
|
||||
function getValidators();
|
||||
|
||||
/**
|
||||
* Returns whether the form is required.
|
||||
*
|
||||
* @return Boolean Whether the form is required.
|
||||
*/
|
||||
function getRequired();
|
||||
|
||||
/**
|
||||
* Returns whether the form is disabled.
|
||||
*
|
||||
* @return Boolean Whether the form is disabled.
|
||||
*/
|
||||
function getDisabled();
|
||||
|
||||
/**
|
||||
* Returns whether errors attached to the form will bubble to its parent.
|
||||
*
|
||||
* @return Boolean Whether errors will bubble up.
|
||||
*/
|
||||
function getErrorBubbling();
|
||||
|
||||
/**
|
||||
* Returns the data that should be returned when the form is empty.
|
||||
*
|
||||
* @return mixed|\Closure The data returned if the form is empty.
|
||||
*/
|
||||
function getEmptyData();
|
||||
|
||||
/**
|
||||
* Returns additional attributes of the form.
|
||||
*
|
||||
* @return array An array of key-value combinations.
|
||||
*/
|
||||
function getAttributes();
|
||||
|
||||
/**
|
||||
* Returns whether the attribute with the given name exists.
|
||||
*
|
||||
* @param string $name The attribute name.
|
||||
*
|
||||
* @return Boolean Whether the attribute exists.
|
||||
*/
|
||||
function hasAttribute($name);
|
||||
|
||||
/**
|
||||
* Returns the value of the given attribute.
|
||||
*
|
||||
* @param string $name The attribute name.
|
||||
*
|
||||
* @return mixed The attribute value.
|
||||
*/
|
||||
function getAttribute($name);
|
||||
|
||||
/**
|
||||
* Returns the initial data of the form.
|
||||
*
|
||||
* @return mixed The initial form data.
|
||||
*/
|
||||
function getData();
|
||||
}
|
232
src/Symfony/Component/Form/ImmutableFormConfig.php
Normal file
232
src/Symfony/Component/Form/ImmutableFormConfig.php
Normal file
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form;
|
||||
|
||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||
use Symfony\Component\Form\Util\PropertyPath;
|
||||
|
||||
/**
|
||||
* An immutable form configuration.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class ImmutableFormConfig implements FormConfigInterface
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
private $dispatcher;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $types;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $clientTransformers;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $normTransformers;
|
||||
|
||||
/**
|
||||
* @var DataMapperInterface
|
||||
*/
|
||||
private $dataMapper;
|
||||
|
||||
/**
|
||||
* @var FormValidatorInterface
|
||||
*/
|
||||
private $validators;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $required;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $disabled;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $errorBubbling;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $emptyData;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $attributes;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Creates an immutable copy of a given configuration.
|
||||
*
|
||||
* @param FormConfigInterface $config The configuration to copy.
|
||||
*/
|
||||
public function __construct(FormConfigInterface $config)
|
||||
{
|
||||
$this->dispatcher = $config->getEventDispatcher();
|
||||
$this->name = $config->getName();
|
||||
$this->types = $config->getTypes();
|
||||
$this->clientTransformers = $config->getClientTransformers();
|
||||
$this->normTransformers = $config->getNormTransformers();
|
||||
$this->dataMapper = $config->getDataMapper();
|
||||
$this->validators = $config->getValidators();
|
||||
$this->required = $config->getRequired();
|
||||
$this->disabled = $config->getDisabled();
|
||||
$this->errorBubbling = $config->getErrorBubbling();
|
||||
$this->emptyData = $config->getEmptyData();
|
||||
$this->data = $config->getData();
|
||||
$this->attributes = $config->getAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEventDispatcher()
|
||||
{
|
||||
return $this->dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTypes()
|
||||
{
|
||||
return $this->types;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClientTransformers()
|
||||
{
|
||||
return $this->clientTransformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNormTransformers()
|
||||
{
|
||||
return $this->normTransformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data mapper of the form.
|
||||
*
|
||||
* @return DataMapperInterface The data mapper.
|
||||
*/
|
||||
public function getDataMapper()
|
||||
{
|
||||
return $this->dataMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValidators()
|
||||
{
|
||||
return $this->validators;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRequired()
|
||||
{
|
||||
return $this->required;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDisabled()
|
||||
{
|
||||
return $this->disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getErrorBubbling()
|
||||
{
|
||||
return $this->errorBubbling;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEmptyData()
|
||||
{
|
||||
return $this->emptyData;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function hasAttribute($name)
|
||||
{
|
||||
return isset($this->attributes[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function getAttribute($name)
|
||||
{
|
||||
return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
@ -35,37 +35,6 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->builder = null;
|
||||
}
|
||||
|
||||
public function getHtml4Ids()
|
||||
{
|
||||
// The full list is tested in FormTest, since both Form and FormBuilder
|
||||
// use the same implementation internally
|
||||
return array(
|
||||
array('#', false),
|
||||
array('a ', false),
|
||||
array("a\t", false),
|
||||
array("a\n", false),
|
||||
array('a.', false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getHtml4Ids
|
||||
*/
|
||||
public function testConstructAcceptsOnlyNamesValidAsIdsInHtml4($name, $accepted)
|
||||
{
|
||||
try {
|
||||
new FormBuilder($name, $this->factory, $this->dispatcher);
|
||||
if (!$accepted) {
|
||||
$this->fail(sprintf('The value "%s" should not be accepted', $name));
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// if the value was not accepted, but should be, rethrow exception
|
||||
if ($accepted) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changing the name is not allowed, otherwise the name and property path
|
||||
* are not synchronized anymore
|
||||
@ -111,6 +80,11 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testAll()
|
||||
{
|
||||
$this->factory->expects($this->once())
|
||||
->method('createNamedBuilder')
|
||||
->with('text', 'foo')
|
||||
->will($this->returnValue(new FormBuilder('foo', $this->factory, $this->dispatcher)));
|
||||
|
||||
$this->assertCount(0, $this->builder->all());
|
||||
$this->assertFalse($this->builder->has('foo'));
|
||||
|
||||
@ -120,9 +94,6 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($this->builder->has('foo'));
|
||||
$this->assertCount(1, $children);
|
||||
$this->assertArrayHasKey('foo', $children);
|
||||
|
||||
$foo = $children['foo'];
|
||||
$this->assertEquals('text', $foo['type']);
|
||||
}
|
||||
|
||||
public function testAddFormType()
|
||||
@ -157,7 +128,7 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testGetUnknown()
|
||||
{
|
||||
$this->setExpectedException('Symfony\Component\Form\Exception\FormException', 'The field "foo" does not exist');
|
||||
$this->setExpectedException('Symfony\Component\Form\Exception\FormException', 'The child with the name "foo" does not exist.');
|
||||
$this->builder->get('foo');
|
||||
}
|
||||
|
||||
|
78
src/Symfony/Component/Form/Tests/FormConfigTest.php
Normal file
78
src/Symfony/Component/Form/Tests/FormConfigTest.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Tests;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
use Symfony\Component\Form\FormConfig;
|
||||
|
||||
class FormConfigTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function getHtml4Ids()
|
||||
{
|
||||
return array(
|
||||
array('a0', true),
|
||||
array('a9', true),
|
||||
array('z0', true),
|
||||
array('A0', true),
|
||||
array('A9', true),
|
||||
array('Z0', true),
|
||||
array('#', false),
|
||||
array('a#', false),
|
||||
array('a$', false),
|
||||
array('a%', false),
|
||||
array('a ', false),
|
||||
array("a\t", false),
|
||||
array("a\n", false),
|
||||
array('a-', true),
|
||||
array('a_', true),
|
||||
array('a:', true),
|
||||
// Periods are allowed by the HTML4 spec, but disallowed by us
|
||||
// because they break the generated property paths
|
||||
array('a.', false),
|
||||
// Contrary to the HTML4 spec, we allow names starting with a
|
||||
// number, otherwise naming fields by collection indices is not
|
||||
// possible.
|
||||
// For root forms, leading digits will be stripped from the
|
||||
// "id" attribute to produce valid HTML4.
|
||||
array('0', true),
|
||||
array('9', true),
|
||||
// Contrary to the HTML4 spec, we allow names starting with an
|
||||
// underscore, since this is already a widely used practice in
|
||||
// Symfony2.
|
||||
// For root forms, leading underscores will be stripped from the
|
||||
// "id" attribute to produce valid HTML4.
|
||||
array('_', true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getHtml4Ids
|
||||
*/
|
||||
public function testSetNameAcceptsOnlyNamesValidAsIdsInHtml4($name, $accepted)
|
||||
{
|
||||
$dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
|
||||
try {
|
||||
new FormConfig($name, $dispatcher);
|
||||
if (!$accepted) {
|
||||
$this->fail(sprintf('The value "%s" should not be accepted', $name));
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// if the value was not accepted, but should be, rethrow exception
|
||||
if ($accepted) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Form\Tests;
|
||||
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\FormConfig;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\Form\FormBuilder;
|
||||
use Symfony\Component\Form\FormError;
|
||||
@ -51,72 +52,6 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
$this->form = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
|
||||
*/
|
||||
public function testConstructExpectsValidValidators()
|
||||
{
|
||||
$validators = array(new \stdClass());
|
||||
|
||||
new Form('name', $this->dispatcher, array(), array(), array(), null, $validators);
|
||||
}
|
||||
|
||||
public function getHtml4Ids()
|
||||
{
|
||||
return array(
|
||||
array('a0', true),
|
||||
array('a9', true),
|
||||
array('z0', true),
|
||||
array('A0', true),
|
||||
array('A9', true),
|
||||
array('Z0', true),
|
||||
array('#', false),
|
||||
array('a#', false),
|
||||
array('a$', false),
|
||||
array('a%', false),
|
||||
array('a ', false),
|
||||
array("a\t", false),
|
||||
array("a\n", false),
|
||||
array('a-', true),
|
||||
array('a_', true),
|
||||
array('a:', true),
|
||||
// Periods are allowed by the HTML4 spec, but disallowed by us
|
||||
// because they break the generated property paths
|
||||
array('a.', false),
|
||||
// Contrary to the HTML4 spec, we allow names starting with a
|
||||
// number, otherwise naming fields by collection indices is not
|
||||
// possible.
|
||||
// For root forms, leading digits will be stripped from the
|
||||
// "id" attribute to produce valid HTML4.
|
||||
array('0', true),
|
||||
array('9', true),
|
||||
// Contrary to the HTML4 spec, we allow names starting with an
|
||||
// underscore, since this is already a widely used practice in
|
||||
// Symfony2.
|
||||
// For root forms, leading underscores will be stripped from the
|
||||
// "id" attribute to produce valid HTML4.
|
||||
array('_', true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getHtml4Ids
|
||||
*/
|
||||
public function testConstructAcceptsOnlyNamesValidAsIdsInHtml4($name, $accepted)
|
||||
{
|
||||
try {
|
||||
new Form($name, $this->dispatcher);
|
||||
if (!$accepted) {
|
||||
$this->fail(sprintf('The value "%s" should not be accepted', $name));
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// if the value was not accepted, but should be, rethrow exception
|
||||
if ($accepted) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testDataIsInitializedEmpty()
|
||||
{
|
||||
$norm = new FixedDataTransformer(array(
|
||||
@ -126,7 +61,10 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
'foo' => 'bar',
|
||||
));
|
||||
|
||||
$form = new Form('name', $this->dispatcher, array(), array($client), array($norm));
|
||||
$config = new FormConfig('name', $this->dispatcher);
|
||||
$config->appendClientTransformer($client);
|
||||
$config->appendNormTransformer($norm);
|
||||
$form = new Form($config);
|
||||
|
||||
$this->assertNull($form->getData());
|
||||
$this->assertSame('foo', $form->getNormData());
|
||||
@ -1259,7 +1197,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
/**
|
||||
* @expectedException Symfony\Component\Form\Exception\FormException
|
||||
* @expectedExceptionMessage Form with empty name can not have parent form.
|
||||
* @expectedExceptionMessage A form with an empty name cannot have a parent form.
|
||||
*/
|
||||
public function testFormCannotHaveEmptyNameNotInRootLevel()
|
||||
{
|
||||
|
Reference in New Issue
Block a user