[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)
{
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');
}
if (!empty($data)) {
$iterator = new VirtualFormAwareIterator($forms);
$iterator = new \RecursiveIteratorIterator($iterator);
$iterator = new VirtualFormAwareIterator($forms);
$iterator = new \RecursiveIteratorIterator($iterator);
foreach ($iterator as $form) {
/* @var FormInterface $form */
$propertyPath = $form->getPropertyPath();
$config = $form->getConfig();
foreach ($iterator as $form) {
/* @var FormInterface $form */
$propertyPath = $form->getPropertyPath();
$config = $form->getConfig();
if (null !== $propertyPath && $config->getMapped()) {
$form->setData($propertyPath->getValue($data));
}
if (null !== $propertyPath && $config->getMapped()) {
$form->setData($propertyPath->getValue($data));
}
}
}
@ -48,6 +50,14 @@ class PropertyPathMapper implements DataMapperInterface
*/
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 \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\UnexpectedTypeException;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Util\FormUtil;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@ -352,7 +353,7 @@ class Form implements \IteratorAggregate, FormInterface
$viewData = $this->normToView($normData);
// Validate if view data matches data class (unless empty)
if ('' !== $viewData && null !== $viewData) {
if (!FormUtil::isEmpty($viewData)) {
$dataClass = $this->config->getDataClass();
$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.
// (think of empty collection forms)
if ($this->config->getCompound()) {
if (null === $submittedData || '' === $submittedData) {
$submittedData = array();
}
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) {
@ -520,7 +521,7 @@ class Form implements \IteratorAggregate, FormInterface
$viewData = $this->getViewData();
}
if (null === $viewData || '' === $viewData) {
if (FormUtil::isEmpty($viewData)) {
$emptyData = $this->config->getEmptyData();
if ($emptyData instanceof \Closure) {
@ -532,7 +533,7 @@ class Form implements \IteratorAggregate, FormInterface
}
// 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);
}
@ -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)
{
if (!$this->config->getViewTransformers()) {
// Scalar values should always be converted to strings to
// facilitate differentiation between empty ("") and zero (0).
// Scalar values should be converted to strings to
// 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;
}

View File

@ -219,4 +219,23 @@ abstract class FormUtil
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;
}
}