[Form] Made data mappers completely responsible for dealing with empty values. Removed duplication of code.

This commit is contained in:
Bernhard Schussek 2012-07-06 16:46:24 +02:00
parent 9bf6e8ba59
commit 5fe3f39ebc
3 changed files with 56 additions and 23 deletions

View File

@ -23,22 +23,24 @@ class PropertyPathMapper implements DataMapperInterface
*/ */
public function mapDataToForms($data, array $forms) public function mapDataToForms($data, array $forms)
{ {
if (!empty($data) && !is_array($data) && !is_object($data)) { if (null === $data || array() === $data) {
return;
}
if (!is_array($data) && !is_object($data)) {
throw new UnexpectedTypeException($data, 'object, array or empty'); throw new UnexpectedTypeException($data, 'object, array or empty');
} }
if (!empty($data)) { $iterator = new VirtualFormAwareIterator($forms);
$iterator = new VirtualFormAwareIterator($forms); $iterator = new \RecursiveIteratorIterator($iterator);
$iterator = new \RecursiveIteratorIterator($iterator);
foreach ($iterator as $form) { foreach ($iterator as $form) {
/* @var FormInterface $form */ /* @var FormInterface $form */
$propertyPath = $form->getPropertyPath(); $propertyPath = $form->getPropertyPath();
$config = $form->getConfig(); $config = $form->getConfig();
if (null !== $propertyPath && $config->getMapped()) { if (null !== $propertyPath && $config->getMapped()) {
$form->setData($propertyPath->getValue($data)); $form->setData($propertyPath->getValue($data));
}
} }
} }
} }
@ -48,6 +50,14 @@ class PropertyPathMapper implements DataMapperInterface
*/ */
public function mapFormsToData(array $forms, &$data) public function mapFormsToData(array $forms, &$data)
{ {
if (null === $data) {
return;
}
if (!is_array($data) && !is_object($data)) {
throw new UnexpectedTypeException($data, 'object, array or empty');
}
$iterator = new VirtualFormAwareIterator($forms); $iterator = new VirtualFormAwareIterator($forms);
$iterator = new \RecursiveIteratorIterator($iterator); $iterator = new \RecursiveIteratorIterator($iterator);

View File

@ -15,6 +15,7 @@ use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Exception\AlreadyBoundException; use Symfony\Component\Form\Exception\AlreadyBoundException;
use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Util\FormUtil;
use Symfony\Component\Form\Util\PropertyPath; use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@ -352,7 +353,7 @@ class Form implements \IteratorAggregate, FormInterface
$viewData = $this->normToView($normData); $viewData = $this->normToView($normData);
// Validate if view data matches data class (unless empty) // Validate if view data matches data class (unless empty)
if ('' !== $viewData && null !== $viewData) { if (!FormUtil::isEmpty($viewData)) {
$dataClass = $this->config->getDataClass(); $dataClass = $this->config->getDataClass();
$actualType = is_object($viewData) ? 'an instance of class ' . get_class($viewData) : ' a(n) ' . gettype($viewData); $actualType = is_object($viewData) ? 'an instance of class ' . get_class($viewData) : ' a(n) ' . gettype($viewData);
@ -492,12 +493,12 @@ class Form implements \IteratorAggregate, FormInterface
// since forms without children may also be compound. // since forms without children may also be compound.
// (think of empty collection forms) // (think of empty collection forms)
if ($this->config->getCompound()) { if ($this->config->getCompound()) {
if (null === $submittedData || '' === $submittedData) {
$submittedData = array();
}
if (!is_array($submittedData)) { if (!is_array($submittedData)) {
throw new UnexpectedTypeException($submittedData, 'array'); if (!FormUtil::isEmpty($submittedData)) {
throw new UnexpectedTypeException($submittedData, 'array');
}
$submittedData = array();
} }
foreach ($this->children as $name => $child) { foreach ($this->children as $name => $child) {
@ -520,7 +521,7 @@ class Form implements \IteratorAggregate, FormInterface
$viewData = $this->getViewData(); $viewData = $this->getViewData();
} }
if (null === $viewData || '' === $viewData) { if (FormUtil::isEmpty($viewData)) {
$emptyData = $this->config->getEmptyData(); $emptyData = $this->config->getEmptyData();
if ($emptyData instanceof \Closure) { if ($emptyData instanceof \Closure) {
@ -532,7 +533,7 @@ class Form implements \IteratorAggregate, FormInterface
} }
// Merge form data from children into existing view data // Merge form data from children into existing view data
if ($this->config->getCompound() && null !== $viewData) { if ($this->config->getCompound()) {
$this->config->getDataMapper()->mapFormsToData($this->children, $viewData); $this->config->getDataMapper()->mapFormsToData($this->children, $viewData);
} }
@ -701,7 +702,7 @@ class Form implements \IteratorAggregate, FormInterface
} }
} }
return array() === $this->modelData || null === $this->modelData || '' === $this->modelData; return FormUtil::isEmpty($this->modelData) || array() === $this->modelData;
} }
/** /**
@ -1048,9 +1049,12 @@ class Form implements \IteratorAggregate, FormInterface
*/ */
private function normToView($value) private function normToView($value)
{ {
if (!$this->config->getViewTransformers()) { // Scalar values should be converted to strings to
// Scalar values should always be converted to strings to // facilitate differentiation between empty ("") and zero (0).
// facilitate differentiation between empty ("") and zero (0). // Only do this for simple forms, as the resulting value in
// compound forms is passed to the data mapper and thus should
// not be converted to a string before.
if (!$this->config->getViewTransformers() && !$this->config->getCompound()) {
return null === $value || is_scalar($value) ? (string) $value : $value; return null === $value || is_scalar($value) ? (string) $value : $value;
} }

View File

@ -219,4 +219,23 @@ abstract class FormUtil
return $choice === $value; return $choice === $value;
} }
/**
* Returns whether the given data is empty.
*
* This logic is reused multiple times throughout the processing of
* a form and needs to be consistent. PHP's keyword `empty` cannot
* be used as it also considers 0 and "0" to be empty.
*
* @param mixed $data
*
* @return Boolean
*/
static public function isEmpty($data)
{
// Should not do a check for array() === $data!!!
// This method is used in occurrences where arrays are
// not considered to be empty, ever.
return null === $data || '' === $data;
}
} }