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 6d6d07d240ab0..52960c068addf 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig @@ -421,8 +421,17 @@
{% endif %} {{ name }} - {% if data.errors is defined and data.errors|length > 0 %} -
{{ data.errors|length }}
+ + {% set errorsCount = 0 %} + {% if data.errors is defined %} + {% set errorsCount = errorsCount + data.errors|length %} + {% endif %} + {% if data.synchronization_failure_cause is defined %} + {% set errorsCount = errorsCount + 1 %} + {% endif %} + + {% if errorsCount > 0 %} +
{{ errorsCount }}
{% endif %} @@ -488,6 +497,26 @@ {% endif %} + {% if data.synchronization_failure_cause is defined %} +
+

+ + Synchronization failure + + +

+ +
+ + + + + +
Cause{{ data.synchronization_failure_cause }}
+
+
+ {% endif %} + {% if data.default_data is defined %}

diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php index cabd801af8ef3..573dc2197cc79 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php @@ -152,6 +152,11 @@ public function collectSubmittedData(FormInterface $form) $this->data['nb_errors'] += count($this->dataByForm[$hash]['errors']); } + // Count synchronization failures + if (isset($this->dataByForm[$hash]['synchronization_failure_cause'])) { + $this->data['nb_errors'] += 1; + } + foreach ($form as $child) { $this->collectSubmittedData($child); } diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php index 80e910177a894..6c7eb6de7bc1e 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Extension\DataCollector; +use Symfony\Component\Form\Form; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter; @@ -134,6 +135,10 @@ public function extractSubmittedData(FormInterface $form) $data['synchronized'] = $this->valueExporter->exportValue($form->isSynchronized()); + if ($form instanceof Form && null !== $form->getSynchronizationFailureCause()) { + $data['synchronization_failure_cause'] = $form->getSynchronizationFailureCause()->getMessage(); + } + return $data; } diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 6c893221aca85..5d1641769c3e3 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -123,10 +123,10 @@ class Form implements \IteratorAggregate, FormInterface /** * Whether the data in model, normalized and view format is * synchronized. Data may not be synchronized if transformation errors - * occur. - * @var bool + * occur. This field stores cause of synchronization failure. + * @var TransformationFailedException */ - private $synchronized = true; + private $synchronizationFailureCause = null; /** * Whether the form's data has been initialized. @@ -634,7 +634,7 @@ public function submit($submittedData, $clearMissing = true) $viewData = $this->normToView($normData); } } catch (TransformationFailedException $e) { - $this->synchronized = false; + $this->synchronizationFailureCause = $e; // If $viewData was not yet set, set it to $submittedData so that // the erroneous data is accessible on the form. @@ -711,7 +711,17 @@ public function isBound() */ public function isSynchronized() { - return $this->synchronized; + return null === $this->synchronizationFailureCause; + } + + /** + * @return TransformationFailedException + * + * @internal Should not be called by user code. + */ + public function getSynchronizationFailureCause() + { + return $this->synchronizationFailureCause; } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php index 885b4b68d1c43..57be01db8ffe4 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php @@ -495,6 +495,7 @@ public function testCollectSubmittedDataCountsErrors() $form1 = $this->createForm('form1'); $childForm1 = $this->createForm('child1'); $form2 = $this->createForm('form2'); + $form3 = $this->createForm('form3'); $form1->add($childForm1); @@ -510,6 +511,10 @@ public function testCollectSubmittedDataCountsErrors() ->method('extractSubmittedData') ->with($form2) ->will($this->returnValue(array('errors' => array('baz')))); + $this->dataExtractor->expects($this->at(3)) + ->method('extractSubmittedData') + ->with($form3) + ->will($this->returnValue(array('errors' => array(), 'synchronization_failure_cause' => 'Failure!'))); $this->dataCollector->collectSubmittedData($form1); @@ -521,6 +526,10 @@ public function testCollectSubmittedDataCountsErrors() $data = $this->dataCollector->getData(); $this->assertSame(4, $data['nb_errors']); + $this->dataCollector->collectSubmittedData($form3); + + $data = $this->dataCollector->getData(); + $this->assertSame(5, $data['nb_errors']); } private function createForm($name) diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php index 06f7f8866d807..51852163af643 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php @@ -379,6 +379,11 @@ function () { $form->submit('Foobar'); + $submittedData = $this->dataExtractor->extractSubmittedData($form); + + $this->assertSynchronizationFailureCause('Fail!', $submittedData); + unset($submittedData['synchronization_failure_cause']); + $this->assertSame(array( 'submitted_data' => array( 'norm' => "'Foobar'", @@ -386,7 +391,7 @@ function () { ), 'errors' => array(), 'synchronized' => 'false', - ), $this->dataExtractor->extractSubmittedData($form)); + ), $submittedData); } public function testExtractViewVariables() @@ -424,4 +429,13 @@ private function createBuilder($name, array $options = array()) { return new FormBuilder($name, null, $this->dispatcher, $this->factory, $options); } + + private function assertSynchronizationFailureCause($expectedCause, $submittedData) + { + $this->assertTrue( + isset($submittedData['synchronization_failure_cause']), + 'cause of synchronization failure was not be extracted' + ); + $this->assertContains($expectedCause, $submittedData['synchronization_failure_cause']); + } } diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 6f2ffdd5cfb0c..38a69b0d4d79e 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -618,6 +618,10 @@ public function testNotSynchronizedIfViewReverseTransformationFailed() $form->submit('foobar'); $this->assertFalse($form->isSynchronized()); + $this->assertInstanceOf( + 'Symfony\\Component\\Form\\Exception\\TransformationFailedException', + $form->getSynchronizationFailureCause() + ); } public function testNotSynchronizedIfModelReverseTransformationFailed()