diff --git a/DataMapper/DataMapperInterface.php b/DataMapper/DataMapperInterface.php index 56a7e59d08..530bfe12a9 100644 --- a/DataMapper/DataMapperInterface.php +++ b/DataMapper/DataMapperInterface.php @@ -11,18 +11,17 @@ namespace Symfony\Component\Form\DataMapper; -use Symfony\Component\Form\FieldInterface; use Symfony\Component\Form\FormInterface; interface DataMapperInterface { function createEmptyData(); - function mapDataToForm(&$data, FormInterface $form); + function mapDataToForms($data, array $forms); - function mapDataToField(&$data, FieldInterface $field); + function mapDataToForm($data, FormInterface $form); - function mapFormToData(FormInterface $form, &$data); + function mapFormsToData(array $forms, &$data); - function mapFieldToData(FieldInterface $field, &$data); + function mapFormToData(FormInterface $field, &$data); } \ No newline at end of file diff --git a/DataMapper/PropertyPathMapper.php b/DataMapper/PropertyPathMapper.php index 33356de78a..6bf6cd75d2 100644 --- a/DataMapper/PropertyPathMapper.php +++ b/DataMapper/PropertyPathMapper.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Form\DataMapper; -use Symfony\Component\Form\FieldInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\RecursiveFieldIterator; use Symfony\Component\Form\Exception\FormException; @@ -51,7 +50,7 @@ public function createEmptyData() return array(); } - public function mapDataToForm(&$data, FormInterface $form) + public function mapDataToForms($data, array $forms) { if (!empty($data) && !is_array($data) && !is_object($data)) { throw new \InvalidArgumentException(sprintf('Expected argument of type object or array, %s given', gettype($data))); @@ -62,49 +61,51 @@ public function mapDataToForm(&$data, FormInterface $form) throw new FormException(sprintf('Form data should be instance of %s', $this->dataClass)); } - $iterator = new RecursiveFieldIterator($form); + $iterator = new RecursiveFieldIterator($forms); $iterator = new \RecursiveIteratorIterator($iterator); - foreach ($iterator as $field) { - $this->mapDataToField($data, $field); + foreach ($iterator as $form) { + $this->mapDataToForm($data, $form); } } } - public function mapDataToField(&$data, FieldInterface $field) + public function mapDataToForm($data, FormInterface $form) { - if ($field->getAttribute('property_path') !== null) { - $field->setData($field->getAttribute('property_path')->getValue($data)); + if (!empty($data)) { + if ($form->getAttribute('property_path') !== null) { + $form->setData($form->getAttribute('property_path')->getValue($data)); + } } } - public function mapFormToData(FormInterface $form, &$data) + public function mapFormsToData(array $forms, &$data) { - $iterator = new RecursiveFieldIterator($form); + $iterator = new RecursiveFieldIterator($forms); $iterator = new \RecursiveIteratorIterator($iterator); - foreach ($iterator as $field) { + foreach ($iterator as $form) { $isReference = false; // If the data is identical to the value in $data, we are // dealing with a reference - if ($field->getAttribute('property_path') !== null) { - $isReference = $field->getData() === $field->getAttribute('property_path')->getValue($data); + if ($form->getAttribute('property_path') !== null) { + $isReference = $form->getData() === $form->getAttribute('property_path')->getValue($data); } // Don't write into $data if $data is an object, // $isReference is true (see above) and the option "by_reference" is // true as well - if (!is_object($data) || !$isReference || !$field->getAttribute('by_reference')) { - $this->mapFieldToData($field, $data); + if (!is_object($data) || !$isReference || !$form->getAttribute('by_reference')) { + $this->mapFormToData($form, $data); } } } - public function mapFieldToData(FieldInterface $field, &$data) + public function mapFormToData(FormInterface $form, &$data) { - if ($field->getAttribute('property_path') !== null) { - $field->getAttribute('property_path')->setValue($data, $field->getData()); + if ($form->getAttribute('property_path') !== null) { + $form->getAttribute('property_path')->setValue($data, $form->getData()); } } } \ No newline at end of file diff --git a/Event/DataEvent.php b/Event/DataEvent.php index bd84076458..0780346b61 100644 --- a/Event/DataEvent.php +++ b/Event/DataEvent.php @@ -3,7 +3,7 @@ namespace Symfony\Component\Form\Event; use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; class DataEvent extends Event { @@ -11,7 +11,7 @@ class DataEvent extends Event protected $data; - public function __construct(FieldInterface $field, $data) + public function __construct(FormInterface $field, $data) { $this->field = $field; $this->data = $data; diff --git a/EventListener/FixFileUploadListener.php b/EventListener/FixFileUploadListener.php index ea77b00c59..20755c114d 100644 --- a/EventListener/FixFileUploadListener.php +++ b/EventListener/FixFileUploadListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\EventListener; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Events; use Symfony\Component\Form\Event\FilterDataEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; diff --git a/EventListener/FixRadioInputListener.php b/EventListener/FixRadioInputListener.php index 96fa4477e5..0661696b34 100644 --- a/EventListener/FixRadioInputListener.php +++ b/EventListener/FixRadioInputListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\EventListener; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Events; use Symfony\Component\Form\Event\FilterDataEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; diff --git a/EventListener/FixUrlProtocolListener.php b/EventListener/FixUrlProtocolListener.php index 84606bc2f1..5fc2e7d23d 100644 --- a/EventListener/FixUrlProtocolListener.php +++ b/EventListener/FixUrlProtocolListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\EventListener; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Events; use Symfony\Component\Form\Event\FilterDataEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; diff --git a/EventListener/ResizeFormListener.php b/EventListener/ResizeFormListener.php index d71c8f336a..55316146db 100644 --- a/EventListener/ResizeFormListener.php +++ b/EventListener/ResizeFormListener.php @@ -13,9 +13,8 @@ use Symfony\Component\Form\Events; use Symfony\Component\Form\Event\DataEvent; -use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\EventDispatcher\EventSubscriberInterface; diff --git a/Field.php b/Field.php deleted file mode 100644 index 3adebee1e5..0000000000 --- a/Field.php +++ /dev/null @@ -1,481 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -use Symfony\Component\Form\DataTransformer\DataTransformerInterface; -use Symfony\Component\Form\DataTransformer\TransformationFailedException; -use Symfony\Component\Form\Validator\FieldValidatorInterface; -use Symfony\Component\Form\Renderer\RendererInterface; -use Symfony\Component\Form\Renderer\Plugin\RendererPluginInterface; -use Symfony\Component\Form\Event\DataEvent; -use Symfony\Component\Form\Event\FilterDataEvent; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; - -/** - * Base class for form fields - * - * To implement your own form fields, you need to have a thorough understanding - * of the data flow within a form field. A form field stores its data in three - * different representations: - * - * (1) the format required by the form's object - * (2) a normalized format for internal processing - * (3) the format used for display - * - * A date field, for example, may store a date as "Y-m-d" string (1) in the - * object. To facilitate processing in the field, this value is normalized - * to a DateTime object (2). In the HTML representation of your form, a - * localized string (3) is presented to and modified by the user. - * - * In most cases, format (1) and format (2) will be the same. For example, - * a checkbox field uses a Boolean value both for internal processing as for - * storage in the object. In these cases you simply need to set a value - * transformer to convert between formats (2) and (3). You can do this by - * calling setClientTransformer() in the configure() method. - * - * In some cases though it makes sense to make format (1) configurable. To - * demonstrate this, let's extend our above date field to store the value - * either as "Y-m-d" string or as timestamp. Internally we still want to - * use a DateTime object for processing. To convert the data from string/integer - * to DateTime you can set a normalization transformer by calling - * setNormTransformer() in configure(). The normalized data is then - * converted to the displayed data as described before. - * - * @author Bernhard Schussek - */ -class Field implements FieldInterface -{ - private $errors = array(); - private $name = ''; - private $parent; - private $bound = false; - private $required; - private $data; - private $normData; - private $clientData = ''; - private $normTransformer; - private $clientTransformer; - private $transformationSuccessful = true; - private $validators; - private $renderer; - private $readOnly = false; - private $dispatcher; - private $attributes; - - public function __construct($name, EventDispatcherInterface $dispatcher, - RendererInterface $renderer, DataTransformerInterface $clientTransformer = null, - DataTransformerInterface $normTransformer = null, - array $validators = array(), $required = false, - $readOnly = false, array $attributes = array()) - { - foreach ($validators as $validator) { - if (!$validator instanceof FieldValidatorInterface) { - throw new UnexpectedTypeException($validator, 'Symfony\Component\Form\Validator\FieldValidatorInterface'); - } - } - - $this->name = (string)$name; - $this->dispatcher = $dispatcher; - $this->renderer = $renderer; - $this->clientTransformer = $clientTransformer; - $this->normTransformer = $normTransformer; - $this->validators = $validators; - $this->required = $required; - $this->readOnly = $readOnly; - $this->attributes = $attributes; - - $renderer->setField($this); - - $this->setData(null); - } - - /** - * Cloning is not supported - */ - private function __clone() - { - } - - /** - * {@inheritDoc} - */ - public function getName() - { - return $this->name; - } - - /** - * {@inheritDoc} - */ - public function isRequired() - { - if (null === $this->parent || $this->parent->isRequired()) { - return $this->required; - } - - return false; - } - - /** - * {@inheritDoc} - */ - public function isReadOnly() - { - if (null === $this->parent || !$this->parent->isReadOnly()) { - return $this->readOnly; - } - - return true; - } - - /** - * {@inheritDoc} - */ - public function setParent(FieldInterface $parent = null) - { - $this->parent = $parent; - - return $this; - } - - /** - * Returns the parent field. - * - * @return FieldInterface The parent field - */ - public function getParent() - { - return $this->parent; - } - - /** - * Returns whether the field has a parent. - * - * @return Boolean - */ - public function hasParent() - { - return null !== $this->parent; - } - - /** - * Returns the root of the form tree - * - * @return FieldInterface The root of the tree - */ - public function getRoot() - { - return $this->parent ? $this->parent->getRoot() : $this; - } - - /** - * Returns whether the field is the root of the form tree - * - * @return Boolean - */ - public function isRoot() - { - return !$this->hasParent(); - } - - public function hasAttribute($name) - { - return isset($this->attributes[$name]); - } - - public function getAttribute($name) - { - return $this->attributes[$name]; - } - - /** - * Updates the field with default data - * - * @see FieldInterface - */ - public function setData($appData) - { - $event = new DataEvent($this, $appData); - $this->dispatcher->dispatch(Events::preSetData, $event); - - // Hook to change content of the data - $event = new FilterDataEvent($this, $appData); - $this->dispatcher->dispatch(Events::filterSetData, $event); - $appData = $event->getData(); - - // Treat data as strings unless a value transformer exists - if (null === $this->clientTransformer && is_scalar($appData)) { - $appData = (string)$appData; - } - - // Synchronize representations - must not change the content! - $normData = $this->toNorm($appData); - $clientData = $this->toClient($normData); - - $this->data = $appData; - $this->normData = $normData; - $this->clientData = $clientData; - - $event = new DataEvent($this, $appData); - $this->dispatcher->dispatch(Events::postSetData, $event); - - return $this; - } - - /** - * Binds POST data to the field, transforms and validates it. - * - * @param string|array $data The POST data - */ - public function bind($clientData) - { - if (is_scalar($clientData) || null === $clientData) { - $clientData = (string)$clientData; - } - - $event = new DataEvent($this, $clientData); - $this->dispatcher->dispatch(Events::preBind, $event); - - $appData = null; - $normData = null; - - // Hook to change content of the data bound by the browser - $event = new FilterDataEvent($this, $clientData); - $this->dispatcher->dispatch(Events::filterBoundClientData, $event); - $clientData = $event->getData(); - - try { - // Normalize data to unified representation - $normData = $this->fromClient($clientData); - $this->transformationSuccessful = true; - } catch (TransformationFailedException $e) { - $this->transformationSuccessful = false; - } - - if ($this->transformationSuccessful) { - // Hook to change content of the data in the normalized - // representation - $event = new FilterDataEvent($this, $normData); - $this->dispatcher->dispatch(Events::filterBoundNormData, $event); - $normData = $event->getData(); - - // Synchronize representations - must not change the content! - $appData = $this->fromNorm($normData); - $clientData = $this->toClient($normData); - } - - $this->bound = true; - $this->errors = array(); - $this->data = $appData; - $this->normData = $normData; - $this->clientData = $clientData; - - $event = new DataEvent($this, $clientData); - $this->dispatcher->dispatch(Events::postBind, $event); - - foreach ($this->validators as $validator) { - $validator->validate($this); - } - } - - /** - * Returns the data in the format needed for the underlying object. - * - * @return mixed - */ - public function getData() - { - return $this->data; - } - - /** - * Returns the normalized data of the field. - * - * @return mixed When the field is not bound, the default data is returned. - * When the field is bound, the normalized bound data is - * returned if the field is valid, null otherwise. - */ - public function getNormData() - { - return $this->normData; - } - - /** - * Returns the data transformed by the value transformer - * - * @return string - */ - public function getClientData() - { - return $this->clientData; - } - - /** - * Adds an error to the field. - * - * @see FieldInterface - */ - public function addError(Error $error, PropertyPathIterator $pathIterator = null) - { - $this->errors[] = $error; - } - - /** - * Returns whether the field is bound. - * - * @return Boolean true if the form is bound to input values, false otherwise - */ - public function isBound() - { - return $this->bound; - } - - /** - * Returns whether the bound value could be reverse transformed correctly - * - * @return Boolean - */ - public function isTransformationSuccessful() - { - return $this->transformationSuccessful; - } - - /** - * {@inheritDoc} - */ - public function isEmpty() - { - return null === $this->data || '' === $this->data; - } - - /** - * Returns whether the field is valid. - * - * @return Boolean - */ - public function isValid() - { - return $this->isBound() && !$this->hasErrors(); // TESTME - } - - /** - * Returns whether or not there are errors. - * - * @return Boolean true if form is bound and not valid - */ - public function hasErrors() - { - // Don't call isValid() here, as its semantics are slightly different - // Field groups are not valid if their children are invalid, but - // hasErrors() returns only true if a field/field group itself has - // errors - return count($this->errors) > 0; - } - - /** - * Returns all errors - * - * @return array An array of FieldError instances that occurred during binding - */ - public function getErrors() - { - return $this->errors; - } - - /** - * Returns the DataTransformer. - * - * @return DataTransformerInterface - */ - public function getNormTransformer() - { - return $this->normTransformer; - } - - /** - * Returns the DataTransformer. - * - * @return DataTransformerInterface - */ - public function getClientTransformer() - { - return $this->clientTransformer; - } - - /** - * Returns the renderer - * - * @return RendererInterface - */ - public function getRenderer() - { - return $this->renderer; - } - - /** - * Normalizes the value if a normalization transformer is set - * - * @param mixed $value The value to transform - * @return string - */ - protected function toNorm($value) - { - if (null === $this->normTransformer) { - return $value; - } - return $this->normTransformer->transform($value); - } - - /** - * Reverse transforms a value if a normalization transformer is set. - * - * @param string $value The value to reverse transform - * @return mixed - */ - protected function fromNorm($value) - { - if (null === $this->normTransformer) { - return $value; - } - return $this->normTransformer->reverseTransform($value); - } - - /** - * Transforms the value if a value transformer is set. - * - * @param mixed $value The value to transform - * @return string - */ - protected function toClient($value) - { - if (null === $this->clientTransformer) { - // 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; - } - return $this->clientTransformer->transform($value); - } - - /** - * Reverse transforms a value if a value transformer is set. - * - * @param string $value The value to reverse transform - * @return mixed - */ - protected function fromClient($value) - { - if (null === $this->clientTransformer) { - return '' === $value ? null : $value; - } - return $this->clientTransformer->reverseTransform($value); - } -} diff --git a/FieldBuilder.php b/FieldBuilder.php deleted file mode 100644 index c268d4189e..0000000000 --- a/FieldBuilder.php +++ /dev/null @@ -1,303 +0,0 @@ - - * - * 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\Validator\FieldValidatorInterface; -use Symfony\Component\Form\DataTransformer\DataTransformerInterface; -use Symfony\Component\Form\Renderer\DefaultRenderer; -use Symfony\Component\Form\Renderer\RendererInterface; -use Symfony\Component\Form\Renderer\Plugin\RendererPluginInterface; -use Symfony\Component\Form\Renderer\Theme\ThemeInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -class FieldBuilder -{ - private $name; - - private $data; - - private $dispatcher; - - private $factory; - - private $readOnly; - - private $required; - - private $renderer; - - private $rendererVars = array(); - - private $clientTransformer; - - private $normalizationTransformer; - - private $theme; - - private $validators = array(); - - private $attributes = array(); - - private $parent; - - public function __construct(ThemeInterface $theme, - EventDispatcherInterface $dispatcher) - { - $this->theme = $theme; - $this->dispatcher = $dispatcher; - } - - public function setFormFactory(FormFactoryInterface $factory) - { - $this->factory = $factory; - - return $this; - } - - public function getFormFactory() - { - return $this->factory; - } - - public function setName($name) - { - $this->name = $name; - - return $this; - } - - public function getName() - { - return $this->name; - } - - public function setParent(FieldBuilder $builder) - { - $this->parent = $builder; - - return $this; - } - - public function getParent() - { - return $this->parent; - } - - public function end() - { - return $this->parent; - } - - public function setData($data) - { - $this->data = $data; - - return $this; - } - - public function getData() - { - return $this->data; - } - - public function setReadOnly($readOnly) - { - $this->readOnly = $readOnly; - - return $this; - } - - public function getReadOnly() - { - return $this->readOnly; - } - - /** - * Sets whether this field is required to be filled out when bound. - * - * @param Boolean $required - */ - public function setRequired($required) - { - $this->required = $required; - - return $this; - } - - public function getRequired() - { - return $this->required; - } - - public function addValidator(FieldValidatorInterface $validator) - { - $this->validators[] = $validator; - - return $this; - } - - public function getValidators() - { - return $this->validators; - } - - /** - * Adds an event listener for events on this field - * - * @see Symfony\Component\EventDispatcher\EventDispatcherInterface::addEventListener - */ - public function addEventListener($eventNames, $listener, $priority = 0) - { - $this->dispatcher->addListener($eventNames, $listener, $priority); - - return $this; - } - - /** - * Adds an event subscriber for events on this field - * - * @see Symfony\Component\EventDispatcher\EventDispatcherInterface::addEventSubscriber - */ - public function addEventSubscriber(EventSubscriberInterface $subscriber, $priority = 0) - { - $this->dispatcher->addSubscriber($subscriber, $priority); - - return $this; - } - - protected function buildDispatcher() - { - return $this->dispatcher; - } - - /** - * Sets the DataTransformer. - * - * @param DataTransformerInterface $clientTransformer - */ - public function setNormTransformer(DataTransformerInterface $normalizationTransformer = null) - { - $this->normalizationTransformer = $normalizationTransformer; - - return $this; - } - - public function getNormTransformer() - { - return $this->normalizationTransformer; - } - - /** - * Sets the DataTransformer. - * - * @param DataTransformerInterface $clientTransformer - */ - public function setClientTransformer(DataTransformerInterface $clientTransformer = null) - { - $this->clientTransformer = $clientTransformer; - - return $this; - } - - public function getClientTransformer() - { - return $this->clientTransformer; - } - - /** - * Sets the renderer - * - * @param RendererInterface $renderer - */ - public function setRenderer(RendererInterface $renderer) - { - $this->renderer = $renderer; - - return $this; - } - - public function addRendererPlugin(RendererPluginInterface $plugin) - { - $this->rendererVars[] = $plugin; - - return $this; - } - - public function setRendererVar($name, $value) - { - $this->rendererVars[$name] = $value; - - return $this; - } - - protected function buildRenderer() - { - if (!$this->renderer) { - $this->renderer = new DefaultRenderer($this->theme, 'text'); - } - - foreach ($this->rendererVars as $name => $value) { - if ($value instanceof RendererPluginInterface) { - $this->renderer->addPlugin($value); - continue; - } - - $this->renderer->setVar($name, $value); - } - - return $this->renderer; - } - - public function setAttribute($name, $value) - { - $this->attributes[$name] = $value; - - return $this; - } - - public function getAttribute($name) - { - return $this->attributes[$name]; - } - - public function hasAttribute($name) - { - return isset($this->attributes[$name]); - } - - public function getAttributes() - { - return $this->attributes; - } - - public function getInstance() - { - $instance = new Field( - $this->getName(), - $this->buildDispatcher(), - $this->buildRenderer(), - $this->getClientTransformer(), - $this->getNormTransformer(), - $this->getValidators(), - $this->getRequired(), - $this->getReadOnly(), - $this->getAttributes() - ); - - if ($this->getData()) { - $instance->setData($this->getData()); - } - - return $instance; - } -} \ No newline at end of file diff --git a/FieldInterface.php b/FieldInterface.php deleted file mode 100644 index 656703e71d..0000000000 --- a/FieldInterface.php +++ /dev/null @@ -1,93 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form; - -/** - * A form field that can be embedded in a form. - * - * @author Bernhard Schussek - */ -interface FieldInterface -{ - /** - * Sets the parent field. - * - * @param FieldInterface $parent The parent field - */ - function setParent(FieldInterface $parent = null); - - /** - * Returns the parent field. - * - * @return FieldInterface The parent field - */ - function getParent(); - - /** - * Returns the name by which the field is identified in forms. - * - * @return string The name of the field. - */ - function getName(); - - /** - * Adds an error to this field - * - * @param Error $error - */ - function addError(Error $error); - - /** - * Returns whether the field is valid. - * - * @return Boolean - */ - function isValid(); - - /** - * Returns whether the field is required to be filled out. - * - * If the field 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 - */ - function isRequired(); - - /** - * Returns whether this field can be read only - * - * The content of a read-only field is displayed, but not allowed to be - * modified. The validation of modified read-only fields should fail. - * - * Fields whose parents are read-only are considered read-only regardless of - * their own state. - * - * @return Boolean - */ - function isReadOnly(); - - /** - * Returns whether the field is empty - * - * @return boolean - */ - function isEmpty(); - - /** - * Writes posted data into the field - * - * @param mixed $data The data from the POST request - */ - function bind($data); -} diff --git a/Form.php b/Form.php index 9c70efe2b1..bdd15045bc 100644 --- a/Form.php +++ b/Form.php @@ -24,8 +24,9 @@ use Symfony\Component\Form\Exception\FieldDefinitionException; use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\DataTransformer\DataTransformerInterface; +use Symfony\Component\Form\DataTransformer\TransformationFailedException; use Symfony\Component\Form\DataMapper\DataMapperInterface; -use Symfony\Component\Form\Validator\FieldValidatorInterface; +use Symfony\Component\Form\Validator\FormValidatorInterface; use Symfony\Component\Form\Renderer\RendererInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -42,157 +43,361 @@ * CSRF secret. If the global CSRF secret is also null, then a random one * is generated on the fly. * + * To implement your own form fields, you need to have a thorough understanding + * of the data flow within a form field. A form field stores its data in three + * different representations: + * + * (1) the format required by the form's object + * (2) a normalized format for internal processing + * (3) the format used for display + * + * A date field, for example, may store a date as "Y-m-d" string (1) in the + * object. To facilitate processing in the field, this value is normalized + * to a DateTime object (2). In the HTML representation of your form, a + * localized string (3) is presented to and modified by the user. + * + * In most cases, format (1) and format (2) will be the same. For example, + * a checkbox field uses a Boolean value both for internal processing as for + * storage in the object. In these cases you simply need to set a value + * transformer to convert between formats (2) and (3). You can do this by + * calling setClientTransformer() in the configure() method. + * + * In some cases though it makes sense to make format (1) configurable. To + * demonstrate this, let's extend our above date field to store the value + * either as "Y-m-d" string or as timestamp. Internally we still want to + * use a DateTime object for processing. To convert the data from string/integer + * to DateTime you can set a normalization transformer by calling + * setNormTransformer() in configure(). The normalized data is then + * converted to the displayed data as described before. + * * @author Fabien Potencier * @author Bernhard Schussek */ -class Form extends Field implements \IteratorAggregate, FormInterface +class Form implements \IteratorAggregate, FormInterface { /** - * Contains all the fields of this group + * Contains all the children of this group * @var array */ - private $fields = array(); + private $children = array(); + + private $dataMapper; + private $errors = array(); + private $name = ''; + private $parent; + private $bound = false; + private $required; + private $data; + private $normData; + private $clientData; /** - * Contains the names of bound values who don't belong to any fields + * Contains the names of bound values who don't belong to any children * @var array */ private $extraData = array(); - private $dataMapper; + private $normTransformer; + private $clientTransformer; + private $transformationSuccessful = true; + private $validators; + private $renderer; + private $readOnly = false; + private $dispatcher; + private $attributes; public function __construct($name, EventDispatcherInterface $dispatcher, RendererInterface $renderer, DataTransformerInterface $clientTransformer = null, - DataTransformerInterface $normalizationTransformer = null, - DataMapperInterface $dataMapper, array $validators = null, + DataTransformerInterface $normTransformer = null, + DataMapperInterface $dataMapper = null, array $validators = array(), $required = false, $readOnly = false, array $attributes = array()) { - $dispatcher->addListener(array( - Events::postSetData, - Events::filterSetData, - Events::filterBoundClientData, - ), $this); + foreach ($validators as $validator) { + if (!$validator instanceof FormValidatorInterface) { + throw new UnexpectedTypeException($validator, 'Symfony\Component\Form\Validator\FormValidatorInterface'); + } + } + $this->name = (string)$name; + $this->dispatcher = $dispatcher; + $this->renderer = $renderer; + $this->clientTransformer = $clientTransformer; + $this->normTransformer = $normTransformer; + $this->validators = $validators; $this->dataMapper = $dataMapper; + $this->required = $required; + $this->readOnly = $readOnly; + $this->attributes = $attributes; - parent::__construct($name, $dispatcher, $renderer, $clientTransformer, - $normalizationTransformer, $validators, $required, $readOnly, - $attributes); + $renderer->setField($this); + + $this->setData(null); } /** - * Returns all fields in this group - * - * @return array + * Cloning is not supported */ - public function getFields() + private function __clone() { - return $this->fields; } - public function add(FieldInterface $field) + /** + * {@inheritDoc} + */ + public function getName() { - $this->fields[$field->getName()] = $field; + return $this->name; + } - $field->setParent($this); + /** + * {@inheritDoc} + */ + public function isRequired() + { + if (null === $this->parent || $this->parent->isRequired()) { + return $this->required; + } - $data = $this->getClientData(); + return false; + } - if (!empty($data)) { - $this->dataMapper->mapDataToField($data, $field); + /** + * {@inheritDoc} + */ + public function isReadOnly() + { + if (null === $this->parent || !$this->parent->isReadOnly()) { + return $this->readOnly; } + + return true; } - public function remove($name) + /** + * {@inheritDoc} + */ + public function setParent(FormInterface $parent = null) { - if (isset($this->fields[$name])) { - $this->fields[$name]->setParent(null); + $this->parent = $parent; - unset($this->fields[$name]); - } + return $this; } /** - * Returns whether a field with the given name exists. + * Returns the parent field. * - * @param string $name - * @return Boolean + * @return FormInterface The parent field */ - public function has($name) + public function getParent() { - return isset($this->fields[$name]); + return $this->parent; } /** - * Returns the field with the given name. + * Returns whether the field has a parent. * - * @param string $name - * @return FieldInterface + * @return Boolean */ - public function get($name) + public function hasParent() { - if (isset($this->fields[$name])) { - return $this->fields[$name]; - } + return null !== $this->parent; + } - throw new \InvalidArgumentException(sprintf('Field "%s" does not exist.', $name)); + /** + * Returns the root of the form tree + * + * @return FormInterface The root of the tree + */ + public function getRoot() + { + return $this->parent ? $this->parent->getRoot() : $this; } - public function postSetData(DataEvent $event) + /** + * Returns whether the field is the root of the form tree + * + * @return Boolean + */ + public function isRoot() { - $form = $event->getField(); - $data = $form->getClientData(); + return !$this->hasParent(); + } - $this->dataMapper->mapDataToForm($data, $form); + public function hasAttribute($name) + { + return isset($this->attributes[$name]); } - public function filterSetData(FilterDataEvent $event) + public function getAttribute($name) { - $field = $event->getField(); + return $this->attributes[$name]; + } - if (null === $field->getClientTransformer() && null === $field->getNormTransformer()) { - $data = $event->getData(); + /** + * Updates the field with default data + * + * @see FormInterface + */ + public function setData($appData) + { + $event = new DataEvent($this, $appData); + $this->dispatcher->dispatch(Events::preSetData, $event); + + // Hook to change content of the data + $event = new FilterDataEvent($this, $appData); + $this->dispatcher->dispatch(Events::filterSetData, $event); + $appData = $event->getData(); + + // Fix data if empty + if (!$this->clientTransformer) { + if (empty($appData) && !$this->normTransformer && $this->dataMapper) { + $appData = $this->dataMapper->createEmptyData(); + } - if (empty($data)) { - $event->setData($this->dataMapper->createEmptyData()); + // Treat data as strings unless a value transformer exists + if (is_scalar($appData)) { + $appData = (string)$appData; } } + + // Synchronize representations - must not change the content! + $normData = $this->toNorm($appData); + $clientData = $this->toClient($normData); + + $this->data = $appData; + $this->normData = $normData; + $this->clientData = $clientData; + + if ($this->dataMapper) { + // Update child forms from the data + $this->dataMapper->mapDataToForms($clientData, $this->children); + } + + $event = new DataEvent($this, $appData); + $this->dispatcher->dispatch(Events::postSetData, $event); + + return $this; } - public function filterBoundClientData(FilterDataEvent $event) + /** + * Binds POST data to the field, transforms and validates it. + * + * @param string|array $data The POST data + */ + public function bind($clientData) { - $data = $event->getData(); + if (is_scalar($clientData) || null === $clientData) { + $clientData = (string)$clientData; + } - if (empty($data)) { - $data = array(); + $event = new DataEvent($this, $clientData); + $this->dispatcher->dispatch(Events::preBind, $event); + + $appData = null; + $normData = null; + $extraData = array(); + + // Hook to change content of the data bound by the browser + $event = new FilterDataEvent($this, $clientData); + $this->dispatcher->dispatch(Events::filterBoundClientData, $event); + $clientData = $event->getData(); + + if (count($this->children) > 0) { + if (empty($clientData)) { + $clientData = array(); + } + + if (!is_array($clientData)) { + throw new UnexpectedTypeException($clientData, 'array'); + } + + foreach ($this->children as $name => $child) { + if (!isset($clientData[$name])) { + $clientData[$name] = null; + } + } + + foreach ($clientData as $name => $value) { + if ($this->has($name)) { + $this->children[$name]->bind($value); + } else { + $extraData[$name] = $value; + } + } + + // Merge form data from children into existing client data + if ($this->dataMapper) { + $clientData = $this->getClientData(); + + $this->dataMapper->mapFormsToData($this->children, $clientData); + } } - if (!is_array($data)) { - throw new UnexpectedTypeException($data, 'array'); + try { + // Normalize data to unified representation + $normData = $this->fromClient($clientData); + $this->transformationSuccessful = true; + } catch (TransformationFailedException $e) { + $this->transformationSuccessful = false; } - foreach ($this->fields as $name => $field) { - if (!isset($data[$name])) { - $data[$name] = null; - } + if ($this->transformationSuccessful) { + // Hook to change content of the data in the normalized + // representation + $event = new FilterDataEvent($this, $normData); + $this->dispatcher->dispatch(Events::filterBoundNormData, $event); + $normData = $event->getData(); + + // Synchronize representations - must not change the content! + $appData = $this->fromNorm($normData); + $clientData = $this->toClient($normData); } - $this->extraData = array(); + $this->bound = true; + $this->errors = array(); + $this->data = $appData; + $this->normData = $normData; + $this->clientData = $clientData; + $this->extraData = $extraData; - foreach ($data as $name => $value) { - if ($this->has($name)) { - $this->fields[$name]->bind($value); - } else { - $this->extraData[$name] = $value; - } + $event = new DataEvent($this, $clientData); + $this->dispatcher->dispatch(Events::postBind, $event); + + foreach ($this->validators as $validator) { + $validator->validate($this); } + } - $data = $this->getClientData(); + /** + * Returns the data in the format needed for the underlying object. + * + * @return mixed + */ + public function getData() + { + return $this->data; + } - // Merge form data from fields into existing client data - $this->dataMapper->mapFormToData($this, $data); + /** + * Returns the normalized data of the field. + * + * @return mixed When the field is not bound, the default data is returned. + * When the field is bound, the normalized bound data is + * returned if the field is valid, null otherwise. + */ + public function getNormData() + { + return $this->normData; + } - $event->setData($data); + /** + * Returns the data transformed by the value transformer + * + * @return string + */ + public function getClientData() + { + return $this->clientData; } public function getExtraData() @@ -200,6 +405,50 @@ public function getExtraData() return $this->extraData; } + /** + * Adds an error to the field. + * + * @see FormInterface + */ + public function addError(Error $error, PropertyPathIterator $pathIterator = null) + { + $this->errors[] = $error; + } + + /** + * Returns whether the field is bound. + * + * @return Boolean true if the form is bound to input values, false otherwise + */ + public function isBound() + { + return $this->bound; + } + + /** + * Returns whether the bound value could be reverse transformed correctly + * + * @return Boolean + */ + public function isTransformationSuccessful() + { + return $this->transformationSuccessful; + } + + /** + * {@inheritDoc} + */ + public function isEmpty() + { + foreach ($this->children as $child) { + if (!$child->isEmpty()) { + return false; + } + } + + return array() === $this->data || null === $this->data || '' === $this->data; + } + /** * Returns whether the field is valid. * @@ -207,12 +456,13 @@ public function getExtraData() */ public function isValid() { - if (!parent::isValid()) { + // TESTME + if (!$this->isBound() || $this->hasErrors()) { return false; } - foreach ($this->fields as $field) { - if (!$field->isValid()) { + foreach ($this->children as $child) { + if (!$child->isValid()) { return false; } } @@ -221,9 +471,117 @@ public function isValid() } /** - * Returns true if the field exists (implements the \ArrayAccess interface). + * Returns whether or not there are errors. * - * @param string $name The name of the field + * @return Boolean true if form is bound and not valid + */ + public function hasErrors() + { + // Don't call isValid() here, as its semantics are slightly different + // Field groups are not valid if their children are invalid, but + // hasErrors() returns only true if a field/field group itself has + // errors + return count($this->errors) > 0; + } + + /** + * Returns all errors + * + * @return array An array of FormError instances that occurred during binding + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Returns the DataTransformer. + * + * @return DataTransformerInterface + */ + public function getNormTransformer() + { + return $this->normTransformer; + } + + /** + * Returns the DataTransformer. + * + * @return DataTransformerInterface + */ + public function getClientTransformer() + { + return $this->clientTransformer; + } + + /** + * Returns the renderer + * + * @return RendererInterface + */ + public function getRenderer() + { + return $this->renderer; + } + + /** + * Returns all children in this group + * + * @return array + */ + public function getChildren() + { + return $this->children; + } + + public function add(FormInterface $child) + { + $this->children[$child->getName()] = $child; + + $child->setParent($this); + + $this->dataMapper->mapDataToForm($this->getClientData(), $child); + } + + public function remove($name) + { + if (isset($this->children[$name])) { + $this->children[$name]->setParent(null); + + unset($this->children[$name]); + } + } + + /** + * Returns whether a child with the given name exists. + * + * @param string $name + * @return Boolean + */ + public function has($name) + { + return isset($this->children[$name]); + } + + /** + * Returns the child with the given name. + * + * @param string $name + * @return FormInterface + */ + public function get($name) + { + if (isset($this->children[$name])) { + return $this->children[$name]; + } + + throw new \InvalidArgumentException(sprintf('Field "%s" does not exist.', $name)); + } + + /** + * Returns true if the child exists (implements the \ArrayAccess interface). + * + * @param string $name The name of the child * * @return Boolean true if the widget exists, false otherwise */ @@ -233,11 +591,11 @@ public function offsetExists($name) } /** - * Returns the form field associated with the name (implements the \ArrayAccess interface). + * Returns the form child associated with the name (implements the \ArrayAccess interface). * * @param string $name The offset of the value to get * - * @return Field A form field instance + * @return Field A form child instance */ public function offsetGet($name) { @@ -252,7 +610,7 @@ public function offsetGet($name) * * @throws \LogicException */ - public function offsetSet($name, $field) + public function offsetSet($name, $child) { throw new \BadMethodCallException('offsetSet() is not supported'); } @@ -276,17 +634,79 @@ public function offsetUnset($name) */ public function getIterator() { - return new \ArrayIterator($this->fields); + return new \ArrayIterator($this->children); } /** - * Returns the number of form fields (implements the \Countable interface). + * Returns the number of form children (implements the \Countable interface). * - * @return integer The number of embedded form fields + * @return integer The number of embedded form children */ public function count() { - return count($this->fields); + return count($this->children); + } + + /** + * Normalizes the value if a normalization transformer is set + * + * @param mixed $value The value to transform + * @return string + */ + protected function toNorm($value) + { + if (null === $this->normTransformer) { + return $value; + } + + return $this->normTransformer->transform($value); + } + + /** + * Reverse transforms a value if a normalization transformer is set. + * + * @param string $value The value to reverse transform + * @return mixed + */ + protected function fromNorm($value) + { + if (null === $this->normTransformer) { + return $value; + } + + return $this->normTransformer->reverseTransform($value); + } + + /** + * Transforms the value if a value transformer is set. + * + * @param mixed $value The value to transform + * @return string + */ + protected function toClient($value) + { + if (null === $this->clientTransformer) { + // 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; + } + + return $this->clientTransformer->transform($value); + } + + /** + * Reverse transforms a value if a value transformer is set. + * + * @param string $value The value to reverse transform + * @return mixed + */ + protected function fromClient($value) + { + if (null === $this->clientTransformer) { + return '' === $value ? null : $value; + } + + return $this->clientTransformer->reverseTransform($value); } /** @@ -329,16 +749,17 @@ public function bindRequest(Request $request) * This method is called automatically during the validation process. * * @param ExecutionContext $context The current validation context + * @deprecated */ public function validateData(ExecutionContext $context) { if (is_object($this->getData()) || is_array($this->getData())) { $groups = $this->getAttribute('validation_groups'); - $field = $this; + $child = $this; - while (!$groups && $field->hasParent()) { - $field = $field->getParent(); - $groups = $field->getAttribute('validation_groups'); + while (!$groups && $child->hasParent()) { + $child = $child->getParent(); + $groups = $child->getAttribute('validation_groups'); } if (null === $groups) { @@ -364,18 +785,4 @@ public function validateData(ExecutionContext $context) } } } - - /** - * {@inheritDoc} - */ - public function isEmpty() - { - foreach ($this->fields as $field) { - if (!$field->isEmpty()) { - return false; - } - } - - return true; - } } diff --git a/FormBuilder.php b/FormBuilder.php index da3a6111e6..420bbe0870 100644 --- a/FormBuilder.php +++ b/FormBuilder.php @@ -12,14 +12,48 @@ namespace Symfony\Component\Form; use Symfony\Component\Form\DataMapper\DataMapperInterface; +use Symfony\Component\Form\DataTransformer\DataTransformerInterface; +use Symfony\Component\Form\Renderer\DefaultRenderer; +use Symfony\Component\Form\Renderer\RendererInterface; +use Symfony\Component\Form\Renderer\Plugin\RendererPluginInterface; use Symfony\Component\Form\Renderer\Theme\ThemeInterface; use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface; +use Symfony\Component\Form\Validator\FormValidatorInterface; use Symfony\Component\Form\Exception\FormException; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class FormBuilder extends FieldBuilder +class FormBuilder { + private $name; + + private $data; + + private $dispatcher; + + private $factory; + + private $readOnly; + + private $required; + + private $renderer; + + private $rendererVars = array(); + + private $clientTransformer; + + private $normalizationTransformer; + + private $theme; + + private $validators = array(); + + private $attributes = array(); + + private $parent; + private $dataClass; private $csrfFieldName; @@ -30,6 +64,236 @@ class FormBuilder extends FieldBuilder private $dataMapper; + public function __construct(ThemeInterface $theme, + EventDispatcherInterface $dispatcher) + { + $this->theme = $theme; + $this->dispatcher = $dispatcher; + } + + public function setFormFactory(FormFactoryInterface $factory) + { + $this->factory = $factory; + + return $this; + } + + public function getFormFactory() + { + return $this->factory; + } + + public function setName($name) + { + $this->name = $name; + + return $this; + } + + public function getName() + { + return $this->name; + } + + public function setParent(FormBuilder $builder) + { + $this->parent = $builder; + + return $this; + } + + public function getParent() + { + return $this->parent; + } + + public function end() + { + return $this->parent; + } + + public function setData($data) + { + $this->data = $data; + + return $this; + } + + public function getData() + { + return $this->data; + } + + public function setReadOnly($readOnly) + { + $this->readOnly = $readOnly; + + return $this; + } + + public function getReadOnly() + { + return $this->readOnly; + } + + /** + * Sets whether this field is required to be filled out when bound. + * + * @param Boolean $required + */ + public function setRequired($required) + { + $this->required = $required; + + return $this; + } + + public function getRequired() + { + return $this->required; + } + + public function addValidator(FormValidatorInterface $validator) + { + $this->validators[] = $validator; + + return $this; + } + + public function getValidators() + { + return $this->validators; + } + + /** + * Adds an event listener for events on this field + * + * @see Symfony\Component\EventDispatcher\EventDispatcherInterface::addEventListener + */ + public function addEventListener($eventNames, $listener, $priority = 0) + { + $this->dispatcher->addListener($eventNames, $listener, $priority); + + return $this; + } + + /** + * Adds an event subscriber for events on this field + * + * @see Symfony\Component\EventDispatcher\EventDispatcherInterface::addEventSubscriber + */ + public function addEventSubscriber(EventSubscriberInterface $subscriber, $priority = 0) + { + $this->dispatcher->addSubscriber($subscriber, $priority); + + return $this; + } + + protected function buildDispatcher() + { + return $this->dispatcher; + } + + /** + * Sets the DataTransformer. + * + * @param DataTransformerInterface $clientTransformer + */ + public function setNormTransformer(DataTransformerInterface $normalizationTransformer = null) + { + $this->normalizationTransformer = $normalizationTransformer; + + return $this; + } + + public function getNormTransformer() + { + return $this->normalizationTransformer; + } + + /** + * Sets the DataTransformer. + * + * @param DataTransformerInterface $clientTransformer + */ + public function setClientTransformer(DataTransformerInterface $clientTransformer = null) + { + $this->clientTransformer = $clientTransformer; + + return $this; + } + + public function getClientTransformer() + { + return $this->clientTransformer; + } + + /** + * Sets the renderer + * + * @param RendererInterface $renderer + */ + public function setRenderer(RendererInterface $renderer) + { + $this->renderer = $renderer; + + return $this; + } + + public function addRendererPlugin(RendererPluginInterface $plugin) + { + $this->rendererVars[] = $plugin; + + return $this; + } + + public function setRendererVar($name, $value) + { + $this->rendererVars[$name] = $value; + + return $this; + } + + protected function buildRenderer() + { + if (!$this->renderer) { + $this->renderer = new DefaultRenderer($this->theme, 'text'); + } + + foreach ($this->rendererVars as $name => $value) { + if ($value instanceof RendererPluginInterface) { + $this->renderer->addPlugin($value); + continue; + } + + $this->renderer->setVar($name, $value); + } + + return $this->renderer; + } + + public function setAttribute($name, $value) + { + $this->attributes[$name] = $value; + + return $this; + } + + public function getAttribute($name) + { + return $this->attributes[$name]; + } + + public function hasAttribute($name) + { + return isset($this->attributes[$name]); + } + + public function getAttributes() + { + return $this->attributes; + } + public function setDataMapper(DataMapperInterface $dataMapper) { $this->dataMapper = $dataMapper; @@ -72,8 +336,8 @@ public function getDataMapper() * $form->add($locationGroup); * * - * @param FieldInterface|string $field - * @return FieldInterface + * @param FormInterface|string $field + * @return FormInterface */ public function add($name, $type = null, array $options = array()) { @@ -128,7 +392,7 @@ public function get($name) $field = $this->fields[$name]; - if ($field instanceof FieldBuilder) { + if ($field instanceof FormBuilder) { return $field; } @@ -144,7 +408,7 @@ public function remove($name) { if (isset($this->fields[$name])) { // field might still be lazy - if ($this->fields[$name] instanceof FieldInterface) { + if ($this->fields[$name] instanceof FormInterface) { $this->fields[$name]->setParent(null); } @@ -168,7 +432,7 @@ protected function buildFields() $fields = array(); foreach ($this->fields as $name => $builder) { - if (!$builder instanceof FieldBuilder) { + if (!$builder instanceof FormBuilder) { $builder = $this->build($name, $builder['type'], $builder['options']); } diff --git a/FieldError.php b/FormError.php similarity index 92% rename from FieldError.php rename to FormError.php index aa64d513bd..672ff50070 100644 --- a/FieldError.php +++ b/FormError.php @@ -16,6 +16,6 @@ * * @author Bernhard Schussek */ -class FieldError extends Error +class FormError extends Error { } \ No newline at end of file diff --git a/FormInterface.php b/FormInterface.php index 8cea8d7336..b55cbd2e84 100644 --- a/FormInterface.php +++ b/FormInterface.php @@ -12,10 +12,82 @@ namespace Symfony\Component\Form; /** - * A field group bundling multiple form fields + * A form group bundling multiple form forms * * @author Bernhard Schussek */ -interface FormInterface extends FieldInterface, \ArrayAccess, \Traversable, \Countable +interface FormInterface extends \ArrayAccess, \Traversable, \Countable { + /** + * Sets the parent form. + * + * @param FormInterface $parent The parent form + */ + function setParent(FormInterface $parent = null); + + /** + * Returns the parent form. + * + * @return FormInterface The parent form + */ + function getParent(); + + /** + * Returns the name by which the form is identified in forms. + * + * @return string The name of the form. + */ + function getName(); + + /** + * Adds an error to this form + * + * @param Error $error + */ + function addError(Error $error); + + /** + * Returns whether the form is valid. + * + * @return Boolean + */ + function isValid(); + + /** + * 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 + */ + function isRequired(); + + /** + * Returns whether this form can be read only + * + * The content of a read-only form is displayed, but not allowed to be + * modified. The validation of modified read-only forms should fail. + * + * Fields whose parents are read-only are considered read-only regardless of + * their own state. + * + * @return Boolean + */ + function isReadOnly(); + + /** + * Returns whether the form is empty + * + * @return boolean + */ + function isEmpty(); + + /** + * Writes posted data into the form + * + * @param mixed $data The data from the POST request + */ + function bind($data); } \ No newline at end of file diff --git a/RecursiveFieldIterator.php b/RecursiveFieldIterator.php index e8223bf278..3012373ed8 100644 --- a/RecursiveFieldIterator.php +++ b/RecursiveFieldIterator.php @@ -19,21 +19,16 @@ * * @author Bernhard Schussek */ -class RecursiveFieldIterator extends \IteratorIterator implements \RecursiveIterator +class RecursiveFieldIterator extends \ArrayIterator implements \RecursiveIterator { - public function __construct(FormInterface $group) - { - parent::__construct($group); - } - public function getChildren() { - return new self($this->current()); + return new self($this->current()->getChildren()); } public function hasChildren() { - return $this->current() instanceof FormInterface + return $this->current()->hasAttribute('virtual') && $this->current()->getAttribute('virtual'); } } diff --git a/Renderer/DefaultRenderer.php b/Renderer/DefaultRenderer.php index d7a734f420..f71b9a8af2 100644 --- a/Renderer/DefaultRenderer.php +++ b/Renderer/DefaultRenderer.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Renderer; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\Theme\ThemeInterface; use Symfony\Component\Form\Renderer\Plugin\RendererPluginInterface; @@ -76,7 +76,7 @@ private function initialize() } } - public function setField(FieldInterface $field) + public function setField(FormInterface $field) { $this->field = $field; } @@ -161,7 +161,7 @@ public function getRest(array $vars = array()) /** * Renders the label of the given field * - * @param FieldInterface $field The field to render the label for + * @param FormInterface $field The field to render the label for * @param array $params Additional variables passed to the template */ public function getLabel($label = null, array $vars = array()) diff --git a/Renderer/Plugin/CheckedPlugin.php b/Renderer/Plugin/CheckedPlugin.php index c31fd43cbe..626234555c 100644 --- a/Renderer/Plugin/CheckedPlugin.php +++ b/Renderer/Plugin/CheckedPlugin.php @@ -12,11 +12,11 @@ namespace Symfony\Component\Form\Renderer\Plugin; use Symfony\Component\Form\Renderer\RendererInterface; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; class CheckedPlugin implements RendererPluginInterface { - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { $renderer->setVar('checked', (bool)$field->getData()); } diff --git a/Renderer/Plugin/ChoicePlugin.php b/Renderer/Plugin/ChoicePlugin.php index 0a67ae69a1..0ffbbd0f9b 100644 --- a/Renderer/Plugin/ChoicePlugin.php +++ b/Renderer/Plugin/ChoicePlugin.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; @@ -24,7 +24,7 @@ public function __construct(ChoiceListInterface $choiceList) $this->choiceList = $choiceList; } - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { $choiceList = $this->choiceList; diff --git a/Renderer/Plugin/DatePatternPlugin.php b/Renderer/Plugin/DatePatternPlugin.php index dea81054ff..cdc9467525 100644 --- a/Renderer/Plugin/DatePatternPlugin.php +++ b/Renderer/Plugin/DatePatternPlugin.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; class DatePatternPlugin implements RendererPluginInterface @@ -23,7 +23,7 @@ public function __construct(\IntlDateFormatter $formatter) $this->formatter = $formatter; } - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { $renderer->setVar('date_pattern', $this->getPattern()); } diff --git a/Renderer/Plugin/EnctypePlugin.php b/Renderer/Plugin/EnctypePlugin.php index c978fdfb41..cf0b82d2e7 100644 --- a/Renderer/Plugin/EnctypePlugin.php +++ b/Renderer/Plugin/EnctypePlugin.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; class EnctypePlugin implements RendererPluginInterface { - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { $renderer->setVar('enctype', $field->isMultipart() ? 'enctype="multipart/form-data"' : ''); } diff --git a/Renderer/Plugin/FieldPlugin.php b/Renderer/Plugin/FieldPlugin.php index 5eac848784..0bdf30f644 100644 --- a/Renderer/Plugin/FieldPlugin.php +++ b/Renderer/Plugin/FieldPlugin.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Form\Renderer\Plugin; use Symfony\Component\Form\Renderer\RendererInterface; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; class FieldPlugin implements RendererPluginInterface { @@ -25,7 +25,7 @@ class FieldPlugin implements RendererPluginInterface * * @param Form $field The field for which to render the encoding type */ - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { $fieldKey = $field->getName(); diff --git a/Renderer/Plugin/FormPlugin.php b/Renderer/Plugin/FormPlugin.php index c27091c3cf..f0df5c2c5a 100644 --- a/Renderer/Plugin/FormPlugin.php +++ b/Renderer/Plugin/FormPlugin.php @@ -11,14 +11,13 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; class FormPlugin implements RendererPluginInterface { - public function setUp(FieldInterface $form, RendererInterface $renderer) + public function setUp(FormInterface $form, RendererInterface $renderer) { if (!$form instanceof FormInterface) { throw new UnexpectedTypeException($form, 'Symfony\Component\Form\FormInterface'); diff --git a/Renderer/Plugin/MaxLengthPlugin.php b/Renderer/Plugin/MaxLengthPlugin.php index 9e9da357cf..15341af2a0 100644 --- a/Renderer/Plugin/MaxLengthPlugin.php +++ b/Renderer/Plugin/MaxLengthPlugin.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; class MaxLengthPlugin implements RendererPluginInterface @@ -23,7 +23,7 @@ public function __construct($maxLength) $this->maxLength = $maxLength; } - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { $renderer->setVar('max_length', $this->maxLength); } diff --git a/Renderer/Plugin/MoneyPatternPlugin.php b/Renderer/Plugin/MoneyPatternPlugin.php index d9219f384d..f22ba76266 100644 --- a/Renderer/Plugin/MoneyPatternPlugin.php +++ b/Renderer/Plugin/MoneyPatternPlugin.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; class MoneyPatternPlugin implements RendererPluginInterface @@ -25,7 +25,7 @@ public function __construct($currency) $this->currency = $currency; } - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { $renderer->setVar('money_pattern', self::getPattern($this->currency)); } diff --git a/Renderer/Plugin/ParentNamePlugin.php b/Renderer/Plugin/ParentNamePlugin.php index 8de83e376b..9189e61e23 100644 --- a/Renderer/Plugin/ParentNamePlugin.php +++ b/Renderer/Plugin/ParentNamePlugin.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; class ParentNamePlugin implements RendererPluginInterface { - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { if ($field->hasParent()) { $parentRenderer = $field->getParent()->getRenderer(); diff --git a/Renderer/Plugin/PasswordValuePlugin.php b/Renderer/Plugin/PasswordValuePlugin.php index 0d870ba50d..bb446b1f09 100644 --- a/Renderer/Plugin/PasswordValuePlugin.php +++ b/Renderer/Plugin/PasswordValuePlugin.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; class PasswordValuePlugin implements RendererPluginInterface @@ -23,7 +23,7 @@ public function __construct($alwaysEmpty = true) $this->alwaysEmpty = $alwaysEmpty; } - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { $value = $this->alwaysEmpty || !$field->isBound() ? '' diff --git a/Renderer/Plugin/RendererPluginInterface.php b/Renderer/Plugin/RendererPluginInterface.php index 52e779e296..87dbf5d800 100644 --- a/Renderer/Plugin/RendererPluginInterface.php +++ b/Renderer/Plugin/RendererPluginInterface.php @@ -11,10 +11,10 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; interface RendererPluginInterface { - function setUp(FieldInterface $field, RendererInterface $renderer); + function setUp(FormInterface $field, RendererInterface $renderer); } \ No newline at end of file diff --git a/Renderer/Plugin/SelectMultipleNamePlugin.php b/Renderer/Plugin/SelectMultipleNamePlugin.php index 5df8ef2c3a..12350725c5 100644 --- a/Renderer/Plugin/SelectMultipleNamePlugin.php +++ b/Renderer/Plugin/SelectMultipleNamePlugin.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Renderer\Plugin; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Renderer\RendererInterface; class SelectMultipleNamePlugin implements RendererPluginInterface { - public function setUp(FieldInterface $field, RendererInterface $renderer) + public function setUp(FormInterface $field, RendererInterface $renderer) { // Add "[]" to the name in case a select tag with multiple options is // displayed. Otherwise only one of the selected options is sent in the diff --git a/Renderer/RendererInterface.php b/Renderer/RendererInterface.php index 108caf2119..28dbf127c4 100644 --- a/Renderer/RendererInterface.php +++ b/Renderer/RendererInterface.php @@ -30,7 +30,7 @@ function getRest(array $vars = array()); /** * Renders the label of the given field * - * @param FieldInterface $field The field to render the label for + * @param FormInterface $field The field to render the label for * @param array $params Additional variables passed to the template */ function getLabel($label = null, array $vars = array()); diff --git a/Renderer/Theme/TwigTheme.php b/Renderer/Theme/TwigTheme.php index c86b70a9ae..936bce853f 100644 --- a/Renderer/Theme/TwigTheme.php +++ b/Renderer/Theme/TwigTheme.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Form\Renderer\Theme; use Symfony\Component\Form\Form; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Exception\FormException; class TwigTheme implements ThemeInterface diff --git a/Type/AbstractType.php b/Type/AbstractType.php index a86d789812..36fbbdf855 100644 --- a/Type/AbstractType.php +++ b/Type/AbstractType.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormFactoryInterface; abstract class AbstractType implements FieldTypeInterface { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { } diff --git a/Type/BirthdayType.php b/Type/BirthdayType.php index 540b0e51b3..370996c07a 100644 --- a/Type/BirthdayType.php +++ b/Type/BirthdayType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; class BirthdayType extends AbstractType { diff --git a/Type/CheckboxType.php b/Type/CheckboxType.php index c001ac8f04..03ac059acb 100644 --- a/Type/CheckboxType.php +++ b/Type/CheckboxType.php @@ -11,13 +11,13 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\DataTransformer\BooleanToStringTransformer; use Symfony\Component\Form\Renderer\Plugin\CheckedPlugin; class CheckboxType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setClientTransformer(new BooleanToStringTransformer()) ->addRendererPlugin(new CheckedPlugin()) diff --git a/Type/ChoiceType.php b/Type/ChoiceType.php index 44e793f529..ccda9116e4 100644 --- a/Type/ChoiceType.php +++ b/Type/ChoiceType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\ChoiceList\DefaultChoiceList; use Symfony\Component\Form\EventListener\FixRadioInputListener; use Symfony\Component\Form\Renderer\Plugin\ChoicePlugin; @@ -21,7 +21,7 @@ class ChoiceType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { if ($options['expanded']) { $choices = array_replace( diff --git a/Type/CollectionType.php b/Type/CollectionType.php index acb3ee1be4..8d02b3f6d9 100644 --- a/Type/CollectionType.php +++ b/Type/CollectionType.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\EventListener\ResizeFormListener; class CollectionType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { if ($options['modifiable']) { $builder->add('$$name$$', $options['type'], array( @@ -28,7 +28,7 @@ public function configure(FieldBuilder $builder, array $options) $listener = new ResizeFormListener($builder->getFormFactory(), $options['type'], $options['modifiable']); - $builder->addEventSubscriber($listener, 10); + $builder->addEventSubscriber($listener); } public function getDefaultOptions(array $options) diff --git a/Type/CountryType.php b/Type/CountryType.php index 7f0a0768c3..66da5223d7 100644 --- a/Type/CountryType.php +++ b/Type/CountryType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Locale\Locale; class CountryType extends AbstractType diff --git a/Type/CsrfType.php b/Type/CsrfType.php index 360f418765..b56c595ffb 100644 --- a/Type/CsrfType.php +++ b/Type/CsrfType.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldInterface; -use Symfony\Component\Form\FieldBuilder; -use Symfony\Component\Form\FieldError; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormError; use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\Validator\CallbackValidator; @@ -26,7 +26,7 @@ public function __construct(CsrfProviderInterface $csrfProvider) $this->csrfProvider = $csrfProvider; } - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $csrfProvider = $options['csrf_provider']; $pageId = $options['page_id']; @@ -34,11 +34,11 @@ public function configure(FieldBuilder $builder, array $options) $builder ->setData($csrfProvider->generateCsrfToken($pageId)) ->addValidator(new CallbackValidator( - function (FieldInterface $field) use ($csrfProvider, $pageId) { + function (FormInterface $field) use ($csrfProvider, $pageId) { if (!$csrfProvider->isCsrfTokenValid($pageId, $field->getData())) { // FIXME this error is currently not displayed // it needs to be passed up to the form - $field->addError(new FieldError('The CSRF token is invalid. Please try to resubmit the form')); + $field->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form')); } } )); diff --git a/Type/DateTimeType.php b/Type/DateTimeType.php index 28438bbf7a..2ddb6af758 100644 --- a/Type/DateTimeType.php +++ b/Type/DateTimeType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\DataTransformer\ReversedTransformer; use Symfony\Component\Form\DataTransformer\DataTransformerChain; use Symfony\Component\Form\DataTransformer\DateTimeToArrayTransformer; @@ -21,7 +21,7 @@ class DateTimeType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { // Only pass a subset of the options to children $dateOptions = array_intersect_key($options, array_flip(array( diff --git a/Type/DateType.php b/Type/DateType.php index 0d1c382090..ee6939c3c9 100644 --- a/Type/DateType.php +++ b/Type/DateType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\ChoiceList\PaddedChoiceList; use Symfony\Component\Form\ChoiceList\MonthChoiceList; use Symfony\Component\Form\Renderer\Plugin\DatePatternPlugin; @@ -23,7 +23,7 @@ class DateType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $formatter = new \IntlDateFormatter( \Locale::getDefault(), diff --git a/Type/EntityType.php b/Type/EntityType.php index f74e218398..25af2039d5 100644 --- a/Type/EntityType.php +++ b/Type/EntityType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\ChoiceList\EntityChoiceList; use Symfony\Component\Form\EventListener\MergeCollectionListener; @@ -31,7 +31,7 @@ public function __construct(EntityManager $em) $this->em = $em; } - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $transformers = array(); diff --git a/Type/FieldType.php b/Type/FieldType.php index 3d3ad05f22..b39b7da081 100644 --- a/Type/FieldType.php +++ b/Type/FieldType.php @@ -12,13 +12,14 @@ namespace Symfony\Component\Form\Type; use Symfony\Component\Form\PropertyPath; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\Renderer\DefaultRenderer; use Symfony\Component\Form\Renderer\Theme\ThemeInterface; use Symfony\Component\Form\Renderer\Plugin\FieldPlugin; use Symfony\Component\Form\EventListener\TrimListener; use Symfony\Component\Form\EventListener\ValidationListener; use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface; +use Symfony\Component\Form\Validator\DefaultValidator; use Symfony\Component\Form\Validator\DelegatingValidator; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Validator\ValidatorInterface; @@ -35,7 +36,7 @@ public function __construct(ThemeInterface $theme, ValidatorInterface $validator $this->validator = $validator; } - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { if (false === $options['property_path']) { $options['property_path'] = $builder->getName(); @@ -59,6 +60,7 @@ public function configure(FieldBuilder $builder, array $options) ->setData($options['data']) ->setRenderer(new DefaultRenderer($this->theme, $options['template'])) ->addRendererPlugin(new FieldPlugin()) + ->addValidator(new DefaultValidator()) ->addValidator(new DelegatingValidator($this->validator)); if ($options['trim']) { @@ -83,7 +85,7 @@ public function getDefaultOptions(array $options) public function createBuilder(array $options) { - return new FieldBuilder($this->theme, new EventDispatcher()); + return new FormBuilder($this->theme, new EventDispatcher()); } public function getParent(array $options) diff --git a/Type/FieldTypeInterface.php b/Type/FieldTypeInterface.php index 328c2b24c1..b62ff41c07 100644 --- a/Type/FieldTypeInterface.php +++ b/Type/FieldTypeInterface.php @@ -11,11 +11,11 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; interface FieldTypeInterface { - function configure(FieldBuilder $builder, array $options); + function configure(FormBuilder $builder, array $options); function createBuilder(array $options); diff --git a/Type/FileType.php b/Type/FileType.php index 347a0a2636..e30b9110b0 100644 --- a/Type/FileType.php +++ b/Type/FileType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\EventListener\FixFileUploadListener; use Symfony\Component\Form\DataTransformer\DataTransformerChain; @@ -29,7 +29,7 @@ public function __construct(TemporaryStorage $storage) $this->storage = $storage; } - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { if ($options['type'] === 'string') { $builder->setNormTransformer(new DataTransformerChain(array( diff --git a/Type/FormType.php b/Type/FormType.php index 851b7b11f3..4eb4e3ce2c 100644 --- a/Type/FormType.php +++ b/Type/FormType.php @@ -11,29 +11,19 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\Renderer\Theme\ThemeInterface; use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Renderer\Plugin\FormPlugin; -use Symfony\Component\Form\Validator\FormValidator; use Symfony\Component\EventDispatcher\EventDispatcher; class FormType extends AbstractType { - private $theme; - - public function __construct(ThemeInterface $theme) - { - $this->theme = $theme; - } - - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setAttribute('virtual', $options['virtual']) ->addRendererPlugin(new FormPlugin()) - ->addValidator(new FormValidator()) ->setDataClass($options['data_class']) ->setDataMapper(new PropertyPathMapper( $options['data_class'], @@ -59,11 +49,6 @@ public function getDefaultOptions(array $options) ); } - public function createBuilder(array $options) - { - return new FormBuilder($this->theme, new EventDispatcher()); - } - public function getParent(array $options) { return 'field'; diff --git a/Type/HiddenType.php b/Type/HiddenType.php index 7b4544e134..04e4d05d26 100644 --- a/Type/HiddenType.php +++ b/Type/HiddenType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; class HiddenType extends AbstractType { diff --git a/Type/IntegerType.php b/Type/IntegerType.php index 2c6e8f76a5..3606d582f0 100644 --- a/Type/IntegerType.php +++ b/Type/IntegerType.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\DataTransformer\IntegerToLocalizedStringTransformer; class IntegerType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setClientTransformer(new IntegerToLocalizedStringTransformer(array( 'precision' => $options['precision'], diff --git a/Type/Loader/DefaultTypeLoader.php b/Type/Loader/DefaultTypeLoader.php index cccebbe3d3..7a84033507 100644 --- a/Type/Loader/DefaultTypeLoader.php +++ b/Type/Loader/DefaultTypeLoader.php @@ -30,7 +30,7 @@ public function initialize(FormFactoryInterface $factory, EntityManager $em = null) { $this->addType(new Type\FieldType($theme, $validator)); - $this->addType(new Type\FormType($theme)); + $this->addType(new Type\FormType()); $this->addType(new Type\BirthdayType()); $this->addType(new Type\CheckboxType()); $this->addType(new Type\ChoiceType()); diff --git a/Type/MoneyType.php b/Type/MoneyType.php index d88048141d..ef0310a761 100644 --- a/Type/MoneyType.php +++ b/Type/MoneyType.php @@ -11,13 +11,13 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\DataTransformer\MoneyToLocalizedStringTransformer; use Symfony\Component\Form\Renderer\Plugin\MoneyPatternPlugin; class MoneyType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setClientTransformer(new MoneyToLocalizedStringTransformer(array( 'precision' => $options['precision'], diff --git a/Type/NumberType.php b/Type/NumberType.php index 54424eba87..963f5ca99b 100644 --- a/Type/NumberType.php +++ b/Type/NumberType.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\DataTransformer\NumberToLocalizedStringTransformer; class NumberType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setClientTransformer(new NumberToLocalizedStringTransformer(array( 'precision' => $options['precision'], diff --git a/Type/PasswordType.php b/Type/PasswordType.php index 6defc452f5..e0652b5766 100644 --- a/Type/PasswordType.php +++ b/Type/PasswordType.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\Renderer\Plugin\PasswordValuePlugin; class PasswordType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->addRendererPlugin(new PasswordValuePlugin($options['always_empty'])); } diff --git a/Type/PercentType.php b/Type/PercentType.php index c71872687e..eb908fe9d6 100644 --- a/Type/PercentType.php +++ b/Type/PercentType.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\DataTransformer\PercentToLocalizedStringTransformer; class PercentType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setClientTransformer(new PercentToLocalizedStringTransformer(array( 'precision' => $options['precision'], diff --git a/Type/RadioType.php b/Type/RadioType.php index 9cf57e5ff6..ab18902e3c 100644 --- a/Type/RadioType.php +++ b/Type/RadioType.php @@ -11,14 +11,14 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\DataTransformer\BooleanToStringTransformer; use Symfony\Component\Form\Renderer\Plugin\CheckedPlugin; use Symfony\Component\Form\Renderer\Plugin\ParentNamePlugin; class RadioType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setClientTransformer(new BooleanToStringTransformer()) ->addRendererPlugin(new CheckedPlugin()) diff --git a/Type/RepeatedType.php b/Type/RepeatedType.php index 3ee1b2ef91..ebecf5b830 100644 --- a/Type/RepeatedType.php +++ b/Type/RepeatedType.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\DataTransformer\ValueToDuplicatesTransformer; class RepeatedType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setClientTransformer(new ValueToDuplicatesTransformer(array( $options['first_name'], diff --git a/Type/TextType.php b/Type/TextType.php index cd323a7676..d2a1c65e75 100644 --- a/Type/TextType.php +++ b/Type/TextType.php @@ -11,11 +11,11 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; class TextType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->setRendererVar('max_length', $options['max_length']); } diff --git a/Type/TextareaType.php b/Type/TextareaType.php index 1504a353fb..b675e1ea08 100644 --- a/Type/TextareaType.php +++ b/Type/TextareaType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; class TextareaType extends AbstractType { diff --git a/Type/TimeType.php b/Type/TimeType.php index 9256b622fe..92968b4d19 100644 --- a/Type/TimeType.php +++ b/Type/TimeType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\ChoiceList\PaddedChoiceList; use Symfony\Component\Form\DataTransformer\ReversedTransformer; use Symfony\Component\Form\DataTransformer\DateTimeToStringTransformer; @@ -20,7 +20,7 @@ class TimeType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $hourOptions = $minuteOptions = $secondOptions = array(); $child = $options['widget'] === 'text' ? 'text' : 'choice'; diff --git a/Type/TimezoneType.php b/Type/TimezoneType.php index 1f6ea36da2..2b368a0f87 100644 --- a/Type/TimezoneType.php +++ b/Type/TimezoneType.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\ChoiceList\TimeZoneChoiceList; class TimezoneType extends AbstractType diff --git a/Type/UrlType.php b/Type/UrlType.php index 174fc4cef8..99a9dfc3d0 100644 --- a/Type/UrlType.php +++ b/Type/UrlType.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Type; -use Symfony\Component\Form\FieldBuilder; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\EventListener\FixUrlProtocolListener; class UrlType extends AbstractType { - public function configure(FieldBuilder $builder, array $options) + public function configure(FormBuilder $builder, array $options) { $builder->addEventSubscriber(new FixUrlProtocolListener($options['default_protocol'])); } diff --git a/Validator/CallbackValidator.php b/Validator/CallbackValidator.php index 0f22f53772..4c83319cc4 100644 --- a/Validator/CallbackValidator.php +++ b/Validator/CallbackValidator.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Form\Validator; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; -class CallbackValidator implements FieldValidatorInterface +class CallbackValidator implements FormValidatorInterface { private $callback; @@ -24,7 +24,7 @@ public function __construct($callback) $this->callback = $callback; } - public function validate(FieldInterface $field) + public function validate(FormInterface $field) { return call_user_func($this->callback, $field); } diff --git a/Validator/FormValidator.php b/Validator/DefaultValidator.php similarity index 69% rename from Validator/FormValidator.php rename to Validator/DefaultValidator.php index e7673ba32e..dfc4374b25 100644 --- a/Validator/FormValidator.php +++ b/Validator/DefaultValidator.php @@ -11,15 +11,15 @@ namespace Symfony\Component\Form\Validator; -use Symfony\Component\Form\FieldInterface; -use Symfony\Component\Form\FieldError; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormError; -class FormValidator implements FieldValidatorInterface +class DefaultValidator implements FormValidatorInterface { - public function validate(FieldInterface $form) + public function validate(FormInterface $form) { if (count($form->getExtraData()) > 0) { - $form->addError(new FieldError('This form should not contain extra fields')); + $form->addError(new FormError('This form should not contain extra fields')); } if ($form->isRoot() && isset($_SERVER['CONTENT_LENGTH'])) { @@ -37,7 +37,7 @@ public function validate(FieldInterface $form) } if ($length > $max) { - $form->addError(new FieldError('The uploaded file was too large. Please try to upload a smaller file')); + $form->addError(new FormError('The uploaded file was too large. Please try to upload a smaller file')); } } } diff --git a/Validator/DelegatingValidator.php b/Validator/DelegatingValidator.php index ac997b053f..60ac6db233 100644 --- a/Validator/DelegatingValidator.php +++ b/Validator/DelegatingValidator.php @@ -11,16 +11,15 @@ namespace Symfony\Component\Form\Validator; -use Symfony\Component\Form\FieldInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Error; use Symfony\Component\Form\DataError; -use Symfony\Component\Form\FieldError; +use Symfony\Component\Form\FormError; use Symfony\Component\Form\PropertyPath; use Symfony\Component\Form\PropertyPathIterator; use Symfony\Component\Validator\ValidatorInterface; -class DelegatingValidator implements FieldValidatorInterface +class DelegatingValidator implements FormValidatorInterface { private $validator; @@ -32,7 +31,7 @@ public function __construct(ValidatorInterface $validator) /** * Validates the form and its domain object */ - public function validate(FieldInterface $field) + public function validate(FormInterface $field) { if ($field->isRoot()) { // Validate the field in group "Default" @@ -49,7 +48,7 @@ public function validate(FieldInterface $field) $iterator->next(); // point at the first data element $error = new DataError($template, $parameters); } else { - $error = new FieldError($template, $parameters); + $error = new FormError($template, $parameters); } $this->mapError($error, $field, $iterator); @@ -58,11 +57,11 @@ public function validate(FieldInterface $field) } } - private function mapError(Error $error, FieldInterface $field, + private function mapError(Error $error, FormInterface $field, PropertyPathIterator $pathIterator = null) { if (null !== $pathIterator && $field instanceof FormInterface) { - if ($error instanceof FieldError && $pathIterator->hasNext()) { + if ($error instanceof FormError && $pathIterator->hasNext()) { $pathIterator->next(); if ($pathIterator->isProperty() && $pathIterator->current() === 'fields') { diff --git a/Validator/FieldValidatorInterface.php b/Validator/FormValidatorInterface.php similarity index 71% rename from Validator/FieldValidatorInterface.php rename to Validator/FormValidatorInterface.php index 11f891e9e1..05ffd7522c 100644 --- a/Validator/FieldValidatorInterface.php +++ b/Validator/FormValidatorInterface.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Form\Validator; -use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\FormInterface; -interface FieldValidatorInterface +interface FormValidatorInterface { - function validate(FieldInterface $field); + function validate(FormInterface $field); } \ No newline at end of file