Skip to content

Commit

Permalink
[Form] Changed semantics of a "bound" form
Browse files Browse the repository at this point in the history
A form now always has to be bound, independent of whether the request is a POST request or not. The bind() method detects itself whether the request was a post request or not and reads its data accordingly. The "old" bind()/isBound() methods were renamed to submit()/isSubmitted().

	$form = new Form('author');
	$form->bind($request, $author);

	if ($form->isValid()) {
		// isValid() implies isSubmitted(), non-submitted forms can
		// never be valid
		// do something with author now
	}

Alternatively, you can only bind global variables, if you don't have a request object.

	$form->bindGlobals($author);

Note that the $author object is in both cases optional. You can also pass no object at all and read the data using $form->getData(), but then no validation will occur. You can also prefill the form with an object during instantiation.

	$form = new Form('author', array('data' => $author));
	$form->bind($request);

	// etc.
  • Loading branch information
Bernhard Schussek committed Feb 1, 2011
1 parent e5ed98c commit fb1f991
Show file tree
Hide file tree
Showing 34 changed files with 545 additions and 489 deletions.
6 changes: 3 additions & 3 deletions src/Symfony/Component/Form/ChoiceField.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ protected function configure()
}

if ($this->isExpanded()) {
$this->setFieldMode(self::GROUP);
$this->setFieldMode(self::FORM);

$choices = $this->getChoices();

Expand Down Expand Up @@ -218,13 +218,13 @@ protected function newChoiceField($choice, $label)
* Takes care of converting the input from a single radio button
* to an array.
*/
public function bind($value)
public function submit($value)
{
if (!$this->isMultipleChoice() && $this->isExpanded()) {
$value = null === $value ? array() : array($value => true);
}

parent::bind($value);
parent::submit($value);
}

/**
Expand Down
10 changes: 5 additions & 5 deletions src/Symfony/Component/Form/CollectionField.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CollectionField extends Form
protected $prototype;

/**
* Remembers which fields were removed upon binding
* Remembers which fields were removed upon submitting
* @var array
*/
protected $removedFields = array();
Expand Down Expand Up @@ -92,7 +92,7 @@ public function setData($collection)
parent::setData($collection);
}

public function bind($taintedData)
public function submit($taintedData)
{
$this->removedFields = array();

Expand All @@ -113,12 +113,12 @@ public function bind($taintedData)
}
}

parent::bind($taintedData);
parent::submit($taintedData);
}

protected function updateObject(&$objectOrArray)
protected function writeObject(&$objectOrArray)
{
parent::updateObject($objectOrArray);
parent::writeObject($objectOrArray);

foreach ($this->removedFields as $name) {
unset($objectOrArray[$name]);
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/Form/DateField.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ protected function configure()
'output_timezone' => $this->getOption('user_timezone'),
)));

$this->setFieldMode(self::GROUP);
$this->setFieldMode(self::FORM);

$this->addChoiceFields();
}
Expand Down
42 changes: 20 additions & 22 deletions src/Symfony/Component/Form/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Field extends Configurable implements FieldInterface
private $errors = array();
private $key = '';
private $parent = null;
private $bound = false;
private $submitted = false;
private $required = null;
private $data = null;
private $normalizedData = null;
Expand Down Expand Up @@ -112,9 +112,9 @@ public function __clone()
/**
* Returns the data of the field as it is displayed to the user.
*
* @return string|array When the field is not bound, the transformed
* default data is returned. When the field is bound,
* the bound data is returned.
* @return string|array When the field is not submitted, the transformed
* default data is returned. When the field is submitted,
* the submitted data is returned.
*/
public function getDisplayedData()
{
Expand Down Expand Up @@ -296,13 +296,11 @@ public function setData($data)
* Binds POST data to the field, transforms and validates it.
*
* @param string|array $taintedData The POST data
* @return Boolean Whether the form is valid
* @throws AlreadyBoundException when the field is already bound
*/
public function bind($taintedData)
public function submit($data)
{
$this->transformedData = (is_array($taintedData) || is_object($taintedData)) ? $taintedData : (string)$taintedData;
$this->bound = true;
$this->transformedData = (is_array($data) || is_object($data)) ? $data : (string)$data;
$this->submitted = true;
$this->errors = array();

if (is_string($this->transformedData) && $this->getOption('trim')) {
Expand All @@ -320,7 +318,7 @@ public function bind($taintedData)
}

/**
* Processes the bound reverse-transformed data.
* Processes the submitted reverse-transformed data.
*
* This method can be overridden if you want to modify the data entered
* by the user. Note that the data is already in reverse transformed format.
Expand Down Expand Up @@ -348,8 +346,8 @@ public function getData()
/**
* 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
* @return mixed When the field is not submitted, the default data is returned.
* When the field is submitted, the normalized submitted data is
* returned if the field is valid, null otherwise.
*/
protected function getNormalizedData()
Expand All @@ -368,17 +366,17 @@ public function addError(FieldError $error, PropertyPathIterator $pathIterator =
}

/**
* Returns whether the field is bound.
* Returns whether the field is submitted.
*
* @return Boolean true if the form is bound to input values, false otherwise
* @return Boolean true if the form is submitted to input values, false otherwise
*/
public function isBound()
public function isSubmitted()
{
return $this->bound;
return $this->submitted;
}

/**
* Returns whether the bound value could be reverse transformed correctly
* Returns whether the submitted value could be reverse transformed correctly
*
* @return Boolean
*/
Expand All @@ -394,13 +392,13 @@ public function isTransformationSuccessful()
*/
public function isValid()
{
return $this->isBound() ? count($this->errors)==0 : false; // TESTME
return $this->isSubmitted() && !$this->hasErrors(); // TESTME
}

/**
* Returns whether or not there are errors.
*
* @return Boolean true if form is bound and not valid
* @return Boolean true if form is submitted and not valid
*/
public function hasErrors()
{
Expand All @@ -414,7 +412,7 @@ public function hasErrors()
/**
* Returns all errors
*
* @return array An array of FieldError instances that occurred during binding
* @return array An array of FieldError instances that occurred during submitting
*/
public function getErrors()
{
Expand Down Expand Up @@ -520,7 +518,7 @@ protected function reverseTransform($value)
/**
* {@inheritDoc}
*/
public function updateFromProperty(&$objectOrArray)
public function readProperty(&$objectOrArray)
{
// TODO throw exception if not object or array

Expand All @@ -532,7 +530,7 @@ public function updateFromProperty(&$objectOrArray)
/**
* {@inheritDoc}
*/
public function updateProperty(&$objectOrArray)
public function writeProperty(&$objectOrArray)
{
// TODO throw exception if not object or array

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,10 @@ protected function isMappedClass($class)
/**
* @inheritDoc
*/
public function guessClass($object, $property)
public function guessClass($class, $property)
{
$className = get_class($object);

if ($this->isMappedClass($className)) {
$metadata = $this->em->getClassMetadata($className);
if ($this->isMappedClass($class)) {
$metadata = $this->em->getClassMetadata($class);

if ($metadata->hasAssociation($property)) {
$multiple = $metadata->isCollectionValuedAssociation($property);
Expand Down Expand Up @@ -146,10 +144,10 @@ public function guessClass($object, $property)
/**
* @inheritDoc
*/
public function guessRequired($object, $property)
public function guessRequired($class, $property)
{
if ($this->isMappedClass(get_class($object))) {
$metadata = $this->em->getClassMetadata(get_class($object));
if ($this->isMappedClass($class)) {
$metadata = $this->em->getClassMetadata($class);

if ($metadata->hasField($property)) {
if (!$metadata->isNullable($property)) {
Expand All @@ -170,10 +168,10 @@ public function guessRequired($object, $property)
/**
* @inheritDoc
*/
public function guessMaxLength($object, $property)
public function guessMaxLength($class, $property)
{
if ($this->isMappedClass(get_class($object))) {
$metadata = $this->em->getClassMetadata(get_class($object));
if ($this->isMappedClass($class)) {
$metadata = $this->em->getClassMetadata($class);

if (!$metadata->hasAssociation($property)) {
$mapping = $metadata->getFieldMapping($property);
Expand Down
22 changes: 11 additions & 11 deletions src/Symfony/Component/Form/FieldFactory/FieldFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,32 +47,32 @@ public function __construct(array $guessers)
/**
* @inheritDoc
*/
public function getInstance($object, $property, array $options = array())
public function getInstance($class, $property, array $options = array())
{
// guess field class and options
$classGuess = $this->guess(function ($guesser) use ($object, $property) {
return $guesser->guessClass($object, $property);
$classGuess = $this->guess(function ($guesser) use ($class, $property) {
return $guesser->guessClass($class, $property);
});

if (!$classGuess) {
throw new \RuntimeException(sprintf('No field could be guessed for property "%s" of class %s', $property, get_class($object)));
throw new \RuntimeException(sprintf('No field could be guessed for property "%s" of class %s', $property, $class));
}

// guess maximum length
$maxLengthGuess = $this->guess(function ($guesser) use ($object, $property) {
return $guesser->guessMaxLength($object, $property);
$maxLengthGuess = $this->guess(function ($guesser) use ($class, $property) {
return $guesser->guessMaxLength($class, $property);
});

// guess whether field is required
$requiredGuess = $this->guess(function ($guesser) use ($object, $property) {
return $guesser->guessRequired($object, $property);
$requiredGuess = $this->guess(function ($guesser) use ($class, $property) {
return $guesser->guessRequired($class, $property);
});

// construct field
$class = $classGuess->getClass();
$fieldClass = $classGuess->getClass();
$textField = 'Symfony\Component\Form\TextField';

if ($maxLengthGuess && ($class == $textField || is_subclass_of($class, $textField))) {
if ($maxLengthGuess && ($fieldClass == $textField || is_subclass_of($fieldClass, $textField))) {
$options = array_merge(array('max_length' => $maxLengthGuess->getValue()), $options);
}

Expand All @@ -83,7 +83,7 @@ public function getInstance($object, $property, array $options = array())
// user options may override guessed options
$options = array_merge($classGuess->getOptions(), $options);

return new $class($property, $options);
return new $fieldClass($property, $options);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,36 @@
namespace Symfony\Component\Form\FieldFactory;

/**
* Guesses field classes and options for the properties of an object
* Guesses field classes and options for the properties of a class
*
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
interface FieldFactoryGuesserInterface
{
/**
* Returns a field guess for a given property name
* Returns a field guess for a property name of a class
*
* @param object $object The object to guess for
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
* @return FieldFactoryClassGuess A guess for the field's class and options
*/
function guessClass($object, $property);
function guessClass($class, $property);

/**
* Returns a guess whether the given property is required
* Returns a guess whether a property of a class is required
*
* @param object $object The object to guess for
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
* @return FieldFactoryGuess A guess for the field's required setting
*/
function guessRequired($object, $property);
function guessRequired($class, $property);

/**
* Returns a guess about the field's maximum length
*
* @param object $object The object to guess for
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
* @return FieldFactoryGuess A guess for the field's maximum length
*/
function guessMaxLength($object, $property);
function guessMaxLength($class, $property);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@
namespace Symfony\Component\Form\FieldFactory;

/**
* Automatically creates form fields for properties of an object
* Automatically creates form fields for properties of a class
*
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
interface FieldFactoryInterface
{
/**
* Returns a field for a given property name
* Returns a field for a given property name of a class
*
* @param object $object The object to create a field for
* @param string $class The fully qualified class name
* @param string $property The name of the property
* @param array $options Custom options for creating the field
* @return FieldInterface A field instance
*/
function getInstance($object, $property, array $options = array());
function getInstance($class, $property, array $options = array());
}
Loading

0 comments on commit fb1f991

Please sign in to comment.