diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig
index 602ae9668ba2..bdeb8d7e948f 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig
@@ -191,7 +191,7 @@
{% for formName, formData in collector.data.forms %}
- {{ form_tree_details(formName, formData) }}
+ {{ form_tree_details(formName, formData, collector.data.forms_by_hash) }}
{% endfor %}
{% else %}
@@ -366,7 +366,7 @@
{% endmacro %}
-{% macro form_tree_details(name, data) %}
+{% macro form_tree_details(name, data, forms_by_hash) %}
{{ name }}
@@ -386,13 +386,32 @@
- Message |
+ Message |
+ Origin |
Cause |
{% for error in data.errors %}
{{ error.message }} |
- Unknown. |
+
+ {% if error.origin is empty %}
+ This form.
+ {% elseif forms_by_hash[error.origin] is not defined %}
+ Unknown.
+ {% else %}
+ {{ forms_by_hash[error.origin].name }}
+ {% endif %}
+ |
+
+ {% if error.cause is empty %}
+ Unknown.
+ {% elseif error.cause.root is defined %}
+ Constraint Violation
+ {{ error.cause.root }}{% if error.cause.path is not empty %}{% if error.cause.path|first != '[' %}.{% endif %}{{ error.cause.path }}{% endif %} = {{ error.cause.value }}
+ {% else %}
+ {{ error.cause }}
+ {% endif %}
+ |
{% endfor %}
@@ -565,6 +584,6 @@
{% for childName, childData in data.children %}
- {{ _self.form_tree_details(childName, childData) }}
+ {{ _self.form_tree_details(childName, childData, forms_by_hash) }}
{% endfor %}
{% endmacro %}
diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md
index b9c8256b5a05..ff4e46284f54 100644
--- a/src/Symfony/Component/Form/CHANGELOG.md
+++ b/src/Symfony/Component/Form/CHANGELOG.md
@@ -5,6 +5,8 @@ CHANGELOG
------
* added an option for multiple files upload
+ * form errors now reference their cause (constraint violation, exception, ...)
+ * form errors now remember which form they were originally added to
2.4.0
-----
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
index 211924813296..bcadfc59773e 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
@@ -69,6 +69,7 @@ public function __construct(FormDataExtractorInterface $dataExtractor)
$this->dataExtractor = $dataExtractor;
$this->data = array(
'forms' => array(),
+ 'forms_by_hash' => array(),
'nb_errors' => 0,
);
}
@@ -184,7 +185,7 @@ public function buildPreliminaryFormTree(FormInterface $form)
{
$this->data['forms'][$form->getName()] = array();
- $this->recursiveBuildPreliminaryFormTree($form, $this->data['forms'][$form->getName()]);
+ $this->recursiveBuildPreliminaryFormTree($form, $this->data['forms'][$form->getName()], $this->data['forms_by_hash']);
}
/**
@@ -194,7 +195,7 @@ public function buildFinalFormTree(FormInterface $form, FormView $view)
{
$this->data['forms'][$form->getName()] = array();
- $this->recursiveBuildFinalFormTree($form, $view, $this->data['forms'][$form->getName()]);
+ $this->recursiveBuildFinalFormTree($form, $view, $this->data['forms'][$form->getName()], $this->data['forms_by_hash']);
}
/**
@@ -213,7 +214,7 @@ public function getData()
return $this->data;
}
- private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output = null)
+ private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output = null, array &$outputByHash)
{
$hash = spl_object_hash($form);
@@ -221,16 +222,18 @@ private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output
? $this->dataByForm[$hash]
: array();
+ $outputByHash[$hash] = &$output;
+
$output['children'] = array();
foreach ($form as $name => $child) {
$output['children'][$name] = array();
- $this->recursiveBuildPreliminaryFormTree($child, $output['children'][$name]);
+ $this->recursiveBuildPreliminaryFormTree($child, $output['children'][$name], $outputByHash);
}
}
- private function recursiveBuildFinalFormTree(FormInterface $form = null, FormView $view, &$output = null)
+ private function recursiveBuildFinalFormTree(FormInterface $form = null, FormView $view, &$output = null, array &$outputByHash)
{
$viewHash = spl_object_hash($view);
$formHash = null;
@@ -255,6 +258,8 @@ private function recursiveBuildFinalFormTree(FormInterface $form = null, FormVie
? $this->dataByForm[$formHash]
: array()
);
+
+ $outputByHash[$formHash] = &$output;
}
$output['children'] = array();
@@ -268,7 +273,7 @@ private function recursiveBuildFinalFormTree(FormInterface $form = null, FormVie
$output['children'][$name] = array();
- $this->recursiveBuildFinalFormTree($childForm, $childView, $output['children'][$name]);
+ $this->recursiveBuildFinalFormTree($childForm, $childView, $output['children'][$name], $outputByHash);
}
}
}
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php
index 8765b13ca4d0..80e910177a89 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php
@@ -14,6 +14,7 @@
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
+use Symfony\Component\Validator\ConstraintViolationInterface;
/**
* Default implementation of {@link FormDataExtractorInterface}.
@@ -43,6 +44,7 @@ public function extractConfiguration(FormInterface $form)
{
$data = array(
'id' => $this->buildId($form),
+ 'name' => $form->getName(),
'type' => $form->getConfig()->getType()->getName(),
'type_class' => get_class($form->getConfig()->getType()->getInnerType()),
'synchronized' => $this->valueExporter->exportValue($form->isSynchronized()),
@@ -108,9 +110,26 @@ public function extractSubmittedData(FormInterface $form)
}
foreach ($form->getErrors() as $error) {
- $data['errors'][] = array(
+ $errorData = array(
'message' => $error->getMessage(),
+ 'origin' => is_object($error->getOrigin())
+ ? spl_object_hash($error->getOrigin())
+ : null,
);
+
+ $cause = $error->getCause();
+
+ if ($cause instanceof ConstraintViolationInterface) {
+ $errorData['cause'] = array(
+ 'root' => $this->valueExporter->exportValue($cause->getRoot()),
+ 'path' => $this->valueExporter->exportValue($cause->getPropertyPath()),
+ 'value' => $this->valueExporter->exportValue($cause->getInvalidValue()),
+ );
+ } else {
+ $errorData['cause'] = null !== $cause ? $this->valueExporter->exportValue($cause) : null;
+ }
+
+ $data['errors'][] = $errorData;
}
$data['synchronized'] = $this->valueExporter->exportValue($form->isSynchronized());
@@ -127,8 +146,12 @@ public function extractViewVariables(FormView $view)
// Set the ID in case no FormInterface object was collected for this
// view
- if (isset($view->vars['id'])) {
- $data['id'] = $view->vars['id'];
+ if (!isset($data['id'])) {
+ $data['id'] = isset($view->vars['id']) ? $view->vars['id'] : null;
+ }
+
+ if (!isset($data['name'])) {
+ $data['name'] = isset($view->vars['name']) ? $view->vars['name'] : null;
}
foreach ($view->vars as $varName => $value) {
diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
index 6ea56eb03b24..15ceb0cf08bd 100644
--- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
+++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
@@ -128,7 +128,8 @@ public function mapViolation(ConstraintViolation $violation, FormInterface $form
$violation->getMessage(),
$violation->getMessageTemplate(),
$violation->getMessageParameters(),
- $violation->getMessagePluralization()
+ $violation->getMessagePluralization(),
+ $violation
));
}
}
diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php
index e677fff62993..f4696c0dfed3 100644
--- a/src/Symfony/Component/Form/Form.php
+++ b/src/Symfony/Component/Form/Form.php
@@ -673,6 +673,10 @@ public function bind($submittedData)
public function addError(FormError $error)
{
if ($this->parent && $this->config->getErrorBubbling()) {
+ if (null === $error->getOrigin()) {
+ $error->setOrigin($this);
+ }
+
$this->parent->addError($error);
} else {
$this->errors[] = $error;
diff --git a/src/Symfony/Component/Form/FormError.php b/src/Symfony/Component/Form/FormError.php
index 343165ca465d..6970244cf7c1 100644
--- a/src/Symfony/Component/Form/FormError.php
+++ b/src/Symfony/Component/Form/FormError.php
@@ -11,12 +11,14 @@
namespace Symfony\Component\Form;
+use Symfony\Component\Form\Exception\BadMethodCallException;
+
/**
* Wraps errors in forms
*
* @author Bernhard Schussek
*/
-class FormError
+class FormError implements \Serializable
{
/**
* @var string
@@ -41,6 +43,18 @@ class FormError
*/
protected $messagePluralization;
+ /**
+ * The cause for this error
+ * @var mixed
+ */
+ private $cause;
+
+ /**
+ * The form that spawned this error
+ * @var FormInterface
+ */
+ private $origin;
+
/**
* Constructor
*
@@ -50,17 +64,19 @@ class FormError
* @param string $message The translated error message
* @param string|null $messageTemplate The template for the error message
* @param array $messageParameters The parameters that should be
- * substituted in the message template.
+ * substituted in the message template
* @param integer|null $messagePluralization The value for error message pluralization
+ * @param mixed $cause The cause of the error
*
* @see \Symfony\Component\Translation\Translator
*/
- public function __construct($message, $messageTemplate = null, array $messageParameters = array(), $messagePluralization = null)
+ public function __construct($message, $messageTemplate = null, array $messageParameters = array(), $messagePluralization = null, $cause = null)
{
$this->message = $message;
$this->messageTemplate = $messageTemplate ?: $message;
$this->messageParameters = $messageParameters;
$this->messagePluralization = $messagePluralization;
+ $this->cause = $cause;
}
/**
@@ -102,4 +118,68 @@ public function getMessagePluralization()
{
return $this->messagePluralization;
}
+
+ /**
+ * Returns the cause of this error.
+ *
+ * @return mixed The cause of this error
+ */
+ public function getCause()
+ {
+ return $this->cause;
+ }
+
+ /**
+ * Sets the form that caused this error.
+ *
+ * This method must only be called once.
+ *
+ * @param FormInterface $origin The form that caused this error
+ *
+ * @throws BadMethodCallException If the method is called more than once
+ */
+ public function setOrigin(FormInterface $origin)
+ {
+ if (null !== $this->origin) {
+ throw new BadMethodCallException('setOrigin() must only be called once.');
+ }
+
+ $this->origin = $origin;
+ }
+
+ /**
+ * Returns the form that caused this error.
+ *
+ * @return FormInterface The form that caused this error
+ */
+ public function getOrigin()
+ {
+ return $this->origin;
+ }
+
+ /**
+ * Serializes this error.
+ *
+ * @return string The serialized error
+ */
+ public function serialize()
+ {
+ return serialize(array(
+ $this->message,
+ $this->messageTemplate,
+ $this->messageParameters,
+ $this->messagePluralization,
+ $this->cause
+ ));
+ }
+
+ /**
+ * Unserializes a serialized error.
+ *
+ * @param string $serialized The serialized error
+ */
+ public function unserialize($serialized)
+ {
+ list($this->message, $this->messageTemplate, $this->messageParameters, $this->messagePluralization, $this->cause) = unserialize($serialized);
+ }
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php
index 99ac76ac2393..885b4b68d1c4 100644
--- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php
@@ -111,23 +111,31 @@ public function testBuildPreliminaryFormTree()
$this->dataCollector->collectSubmittedData($this->form);
$this->dataCollector->buildPreliminaryFormTree($this->form);
- $this->assertSame(array(
- 'forms' => array(
- 'name' => array(
- 'config' => 'foo',
- 'default_data' => 'foo',
- 'submitted_data' => 'foo',
- 'children' => array(
- 'child' => array(
- 'config' => 'bar',
- 'default_data' => 'bar',
- 'submitted_data' => 'bar',
- 'children' => array(),
- ),
- ),
- ),
+ $childFormData = array(
+ 'config' => 'bar',
+ 'default_data' => 'bar',
+ 'submitted_data' => 'bar',
+ 'children' => array(),
+ );
+
+ $formData = array(
+ 'config' => 'foo',
+ 'default_data' => 'foo',
+ 'submitted_data' => 'foo',
+ 'children' => array(
+ 'child' => $childFormData,
),
- 'nb_errors' => 0,
+ );
+
+ $this->assertSame(array(
+ 'forms' => array(
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
+ spl_object_hash($this->childForm) => $childFormData,
+ ),
+ 'nb_errors' => 0,
), $this->dataCollector->getData());
}
@@ -149,28 +157,36 @@ public function testBuildMultiplePreliminaryFormTrees()
$this->dataCollector->collectConfiguration($form2);
$this->dataCollector->buildPreliminaryFormTree($form1);
+ $form1Data = array(
+ 'config' => 'foo',
+ 'children' => array(),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'form1' => array(
- 'config' => 'foo',
- 'children' => array(),
- ),
+ 'form1' => $form1Data,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($form1) => $form1Data,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
$this->dataCollector->buildPreliminaryFormTree($form2);
+ $form2Data = array(
+ 'config' => 'bar',
+ 'children' => array(),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'form1' => array(
- 'config' => 'foo',
- 'children' => array(),
- ),
- 'form2' => array(
- 'config' => 'bar',
- 'children' => array(),
- ),
+ 'form1' => $form1Data,
+ 'form2' => $form2Data,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($form1) => $form1Data,
+ spl_object_hash($form2) => $form2Data,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
@@ -191,12 +207,17 @@ public function testBuildSamePreliminaryFormTreeMultipleTimes()
$this->dataCollector->collectConfiguration($this->form);
$this->dataCollector->buildPreliminaryFormTree($this->form);
+ $formData = array(
+ 'config' => 'foo',
+ 'children' => array(),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'name' => array(
- 'config' => 'foo',
- 'children' => array(),
- ),
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
@@ -204,13 +225,18 @@ public function testBuildSamePreliminaryFormTreeMultipleTimes()
$this->dataCollector->collectDefaultData($this->form);
$this->dataCollector->buildPreliminaryFormTree($this->form);
+ $formData = array(
+ 'config' => 'foo',
+ 'default_data' => 'foo',
+ 'children' => array(),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'name' => array(
- 'config' => 'foo',
- 'default_data' => 'foo',
- 'children' => array(),
- ),
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
@@ -220,11 +246,16 @@ public function testBuildPreliminaryFormTreeWithoutCollectingAnyData()
{
$this->dataCollector->buildPreliminaryFormTree($this->form);
+ $formData = array(
+ 'children' => array(),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'name' => array(
- 'children' => array(),
- ),
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
@@ -278,23 +309,31 @@ public function testBuildFinalFormTree()
$this->dataCollector->collectViewVariables($this->view);
$this->dataCollector->buildFinalFormTree($this->form, $this->view);
+ $childFormData = array(
+ 'view_vars' => 'bar',
+ 'config' => 'bar',
+ 'default_data' => 'bar',
+ 'submitted_data' => 'bar',
+ 'children' => array(),
+ );
+
+ $formData = array(
+ 'view_vars' => 'foo',
+ 'config' => 'foo',
+ 'default_data' => 'foo',
+ 'submitted_data' => 'foo',
+ 'children' => array(
+ 'child' => $childFormData,
+ ),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'name' => array(
- 'view_vars' => 'foo',
- 'config' => 'foo',
- 'default_data' => 'foo',
- 'submitted_data' => 'foo',
- 'children' => array(
- 'child' => array(
- 'view_vars' => 'bar',
- 'config' => 'bar',
- 'default_data' => 'bar',
- 'submitted_data' => 'bar',
- 'children' => array(),
- ),
- ),
- ),
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
+ spl_object_hash($this->childForm) => $childFormData,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
@@ -302,41 +341,57 @@ public function testBuildFinalFormTree()
public function testFinalFormReliesOnFormViewStructure()
{
- $this->form->add($this->createForm('first'));
- $this->form->add($this->createForm('second'));
+ $this->form->add($child1 = $this->createForm('first'));
+ $this->form->add($child2 = $this->createForm('second'));
$this->view->children['second'] = $this->childView;
$this->dataCollector->buildPreliminaryFormTree($this->form);
+ $child1Data = array(
+ 'children' => array(),
+ );
+
+ $child2Data = array(
+ 'children' => array(),
+ );
+
+ $formData = array(
+ 'children' => array(
+ 'first' => $child1Data,
+ 'second' => $child2Data,
+ ),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'name' => array(
- 'children' => array(
- 'first' => array(
- 'children' => array(),
- ),
- 'second' => array(
- 'children' => array(),
- ),
- ),
- ),
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
+ spl_object_hash($child1) => $child1Data,
+ spl_object_hash($child2) => $child2Data,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
$this->dataCollector->buildFinalFormTree($this->form, $this->view);
+ $formData = array(
+ 'children' => array(
+ // "first" not present in FormView
+ 'second' => $child2Data,
+ ),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'name' => array(
- 'children' => array(
- // "first" not present in FormView
- 'second' => array(
- 'children' => array(),
- ),
- ),
- ),
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
+ spl_object_hash($child1) => $child1Data,
+ spl_object_hash($child2) => $child2Data,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
@@ -363,17 +418,25 @@ public function testChildViewsCanBeWithoutCorrespondingChildForms()
$this->dataCollector->collectConfiguration($this->childForm);
$this->dataCollector->buildFinalFormTree($this->form, $this->view);
+ $childFormData = array(
+ // no "config" key
+ 'children' => array(),
+ );
+
+ $formData = array(
+ 'config' => 'foo',
+ 'children' => array(
+ 'child' => $childFormData,
+ ),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'name' => array(
- 'config' => 'foo',
- 'children' => array(
- 'child' => array(
- // no "config" key
- 'children' => array(),
- ),
- ),
- ),
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
+ // no child entry
),
'nb_errors' => 0,
), $this->dataCollector->getData());
@@ -403,17 +466,25 @@ public function testChildViewsWithoutCorrespondingChildFormsMayBeExplicitlyAssoc
$this->dataCollector->collectConfiguration($this->childForm);
$this->dataCollector->buildFinalFormTree($this->form, $this->view);
+ $childFormData = array(
+ 'config' => 'bar',
+ 'children' => array(),
+ );
+
+ $formData = array(
+ 'config' => 'foo',
+ 'children' => array(
+ 'child' => $childFormData,
+ ),
+ );
+
$this->assertSame(array(
'forms' => array(
- 'name' => array(
- 'config' => 'foo',
- 'children' => array(
- 'child' => array(
- 'config' => 'bar',
- 'children' => array(),
- ),
- ),
- ),
+ 'name' => $formData,
+ ),
+ 'forms_by_hash' => array(
+ spl_object_hash($this->form) => $formData,
+ spl_object_hash($this->childForm) => $childFormData,
),
'nb_errors' => 0,
), $this->dataCollector->getData());
diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php
index bf3cd7197566..37b5b7d86cfb 100644
--- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php
@@ -27,7 +27,7 @@ class FormDataExtractorTest_SimpleValueExporter extends ValueExporter
*/
public function exportValue($value)
{
- return var_export($value, true);
+ return is_object($value) ? sprintf('object(%s)', get_class($value)) : var_export($value, true);
}
}
@@ -80,6 +80,7 @@ public function testExtractConfiguration()
$this->assertSame(array(
'id' => 'name',
+ 'name' => 'name',
'type' => 'type_name',
'type_class' => 'stdClass',
'synchronized' => 'true',
@@ -113,6 +114,7 @@ public function testExtractConfigurationSortsPassedOptions()
$this->assertSame(array(
'id' => 'name',
+ 'name' => 'name',
'type' => 'type_name',
'type_class' => 'stdClass',
'synchronized' => 'true',
@@ -147,6 +149,7 @@ public function testExtractConfigurationSortsResolvedOptions()
$this->assertSame(array(
'id' => 'name',
+ 'name' => 'name',
'type' => 'type_name',
'type_class' => 'stdClass',
'synchronized' => 'true',
@@ -186,6 +189,7 @@ public function testExtractConfigurationBuildsIdRecursively()
$this->assertSame(array(
'id' => 'grandParent_parent_name',
+ 'name' => 'name',
'type' => 'type_name',
'type_class' => 'stdClass',
'synchronized' => 'true',
@@ -315,7 +319,48 @@ public function testExtractSubmittedDataStoresErrors()
'norm' => "'Foobar'",
),
'errors' => array(
- array('message' => 'Invalid!'),
+ array('message' => 'Invalid!', 'origin' => null, 'cause' => null),
+ ),
+ 'synchronized' => 'true',
+ ), $this->dataExtractor->extractSubmittedData($form));
+ }
+
+ public function testExtractSubmittedDataStoresErrorOrigin()
+ {
+ $form = $this->createBuilder('name')->getForm();
+
+ $error = new FormError('Invalid!');
+ $error->setOrigin($form);
+
+ $form->submit('Foobar');
+ $form->addError($error);
+
+ $this->assertSame(array(
+ 'submitted_data' => array(
+ 'norm' => "'Foobar'",
+ ),
+ 'errors' => array(
+ array('message' => 'Invalid!', 'origin' => spl_object_hash($form), 'cause' => null),
+ ),
+ 'synchronized' => 'true',
+ ), $this->dataExtractor->extractSubmittedData($form));
+ }
+
+ public function testExtractSubmittedDataStoresErrorCause()
+ {
+ $form = $this->createBuilder('name')->getForm();
+
+ $exception = new \Exception();
+
+ $form->submit('Foobar');
+ $form->addError(new FormError('Invalid!', null, array(), null, $exception));
+
+ $this->assertSame(array(
+ 'submitted_data' => array(
+ 'norm' => "'Foobar'",
+ ),
+ 'errors' => array(
+ array('message' => 'Invalid!', 'origin' => null, 'cause' => 'object(Exception)'),
),
'synchronized' => 'true',
), $this->dataExtractor->extractSubmittedData($form));
@@ -353,15 +398,18 @@ public function testExtractViewVariables()
'a' => 'bar',
'c' => 'baz',
'id' => 'foo_bar',
+ 'name' => 'bar',
);
$this->assertSame(array(
'id' => 'foo_bar',
+ 'name' => 'bar',
'view_vars' => array(
'a' => "'bar'",
'b' => "'foo'",
'c' => "'baz'",
'id' => "'foo_bar'",
+ 'name' => "'bar'",
),
), $this->dataExtractor->extractViewVariables($view));
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php
index a84d5b951ae1..3c9886d7cf23 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php
@@ -19,6 +19,7 @@
use Symfony\Component\Form\FormError;
use Symfony\Component\PropertyAccess\PropertyPath;
use Symfony\Component\Validator\ConstraintViolation;
+use Symfony\Component\Validator\ConstraintViolationInterface;
/**
* @author Bernhard Schussek
@@ -109,9 +110,9 @@ protected function getConstraintViolation($propertyPath)
/**
* @return FormError
*/
- protected function getFormError()
+ protected function getFormError(ConstraintViolationInterface $violation)
{
- return new FormError($this->message, $this->messageTemplate, $this->params);
+ return new FormError($this->message, $this->messageTemplate, $this->params, null, $violation);
}
public function testMapToFormInheritingParentDataIfDataDoesNotMatch()
@@ -127,7 +128,7 @@ public function testMapToFormInheritingParentDataIfDataDoesNotMatch()
$this->mapper->mapViolation($violation, $parent);
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $child->getName().' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $child->getErrors(), $child->getName().' should have an error, but has none');
$this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
}
@@ -154,7 +155,7 @@ public function testFollowDotRules()
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
$this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one');
$this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandGrandChild->getErrors(), $grandGrandChild->getName().' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $grandGrandChild->getErrors(), $grandGrandChild->getName().' should have an error, but has none');
}
public function testAbortMappingIfNotSynchronized()
@@ -745,17 +746,17 @@ public function testDefaultErrorMapping($target, $childName, $childPath, $grandC
$this->mapper->mapViolation($violation, $parent);
if (self::LEVEL_0 === $target) {
- $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $parent->getErrors(), $parent->getName().' should have an error, but has none');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
} elseif (self::LEVEL_1 === $target) {
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $child->getErrors(), $childName.' should have an error, but has none');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
} else {
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
}
}
@@ -1217,17 +1218,17 @@ public function testCustomDataErrorMapping($target, $mapFrom, $mapTo, $childName
}
if (self::LEVEL_0 === $target) {
- $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $parent->getErrors(), $parent->getName().' should have an error, but has none');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
} elseif (self::LEVEL_1 === $target) {
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $child->getErrors(), $childName.' should have an error, but has none');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
} else {
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
}
}
@@ -1399,16 +1400,16 @@ public function testCustomFormErrorMapping($target, $mapFrom, $mapTo, $errorName
if (self::LEVEL_0 === $target) {
$this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $parent->getErrors(), $parent->getName().' should have an error, but has none');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
} elseif (self::LEVEL_1 === $target) {
$this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $child->getErrors(), $childName.' should have an error, but has none');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
} elseif (self::LEVEL_1B === $target) {
- $this->assertEquals(array($this->getFormError()), $errorChild->getErrors(), $errorName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $errorChild->getErrors(), $errorName.' should have an error, but has none');
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
@@ -1416,7 +1417,7 @@ public function testCustomFormErrorMapping($target, $mapFrom, $mapTo, $errorName
$this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one');
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
}
}
@@ -1461,17 +1462,17 @@ public function testErrorMappingForFormInheritingParentData($target, $childName,
$this->mapper->mapViolation($violation, $parent);
if (self::LEVEL_0 === $target) {
- $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName().' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $parent->getErrors(), $parent->getName().' should have an error, but has none');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
} elseif (self::LEVEL_1 === $target) {
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $child->getErrors(), $childName.' should have an error, but has none');
$this->assertCount(0, $grandChild->getErrors(), $grandChildName.' should not have an error, but has one');
} else {
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
$this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one');
- $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
+ $this->assertEquals(array($this->getFormError($violation)), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
}
}
}