Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8ea3a43

Browse filesBrowse files
committed
feature #9993 [Form] Errors now reference the field they were added to and the violation/exception that caused them (bschussek)
This PR was merged into the 2.5-dev branch. Discussion ---------- [Form] Errors now reference the field they were added to and the violation/exception that caused them | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #9472, #9582 | License | MIT | Doc PR | - Commits ------- c8a0ee6 [Form] Errors now reference the field they were added to and the violation/exception that caused them
2 parents 147c82b + c8a0ee6 commit 8ea3a43
Copy full SHA for 8ea3a43

File tree

Expand file treeCollapse file tree

10 files changed

+384
-130
lines changed
Filter options
Expand file treeCollapse file tree

10 files changed

+384
-130
lines changed

‎src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig
+24-5Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@
191191
</div>
192192

193193
{% for formName, formData in collector.data.forms %}
194-
{{ form_tree_details(formName, formData) }}
194+
{{ form_tree_details(formName, formData, collector.data.forms_by_hash) }}
195195
{% endfor %}
196196
</div>
197197
{% else %}
@@ -366,7 +366,7 @@
366366
</li>
367367
{% endmacro %}
368368

369-
{% macro form_tree_details(name, data) %}
369+
{% macro form_tree_details(name, data, forms_by_hash) %}
370370
<div class="tree-details" id="{{ data.id }}-details">
371371
<h2>
372372
{{ name }}
@@ -386,13 +386,32 @@
386386

387387
<table id="{{ data.id }}-errors">
388388
<tr>
389-
<th width="50%">Message</th>
389+
<th>Message</th>
390+
<th>Origin</th>
390391
<th>Cause</th>
391392
</tr>
392393
{% for error in data.errors %}
393394
<tr>
394395
<td>{{ error.message }}</td>
395-
<td><em>Unknown.</em></td>
396+
<td>
397+
{% if error.origin is empty %}
398+
<em>This form.</em>
399+
{% elseif forms_by_hash[error.origin] is not defined %}
400+
<em>Unknown.</em>
401+
{% else %}
402+
{{ forms_by_hash[error.origin].name }}
403+
{% endif %}
404+
</td>
405+
<td>
406+
{% if error.cause is empty %}
407+
<em>Unknown.</em>
408+
{% elseif error.cause.root is defined %}
409+
<strong>Constraint Violation</strong><br/>
410+
<pre>{{ error.cause.root }}{% if error.cause.path is not empty %}{% if error.cause.path|first != '[' %}.{% endif %}{{ error.cause.path }}{% endif %} = {{ error.cause.value }}</pre>
411+
{% else %}
412+
<pre>{{ error.cause }}</pre>
413+
{% endif %}
414+
</td>
396415
</tr>
397416
{% endfor %}
398417
</table>
@@ -565,6 +584,6 @@
565584
</div>
566585

567586
{% for childName, childData in data.children %}
568-
{{ _self.form_tree_details(childName, childData) }}
587+
{{ _self.form_tree_details(childName, childData, forms_by_hash) }}
569588
{% endfor %}
570589
{% endmacro %}

‎src/Symfony/Component/Form/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/CHANGELOG.md
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ CHANGELOG
55
------
66

77
* added an option for multiple files upload
8+
* form errors now reference their cause (constraint violation, exception, ...)
9+
* form errors now remember which form they were originally added to
810

911
2.4.0
1012
-----

‎src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
+11-6Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public function __construct(FormDataExtractorInterface $dataExtractor)
6969
$this->dataExtractor = $dataExtractor;
7070
$this->data = array(
7171
'forms' => array(),
72+
'forms_by_hash' => array(),
7273
'nb_errors' => 0,
7374
);
7475
}
@@ -184,7 +185,7 @@ public function buildPreliminaryFormTree(FormInterface $form)
184185
{
185186
$this->data['forms'][$form->getName()] = array();
186187

187-
$this->recursiveBuildPreliminaryFormTree($form, $this->data['forms'][$form->getName()]);
188+
$this->recursiveBuildPreliminaryFormTree($form, $this->data['forms'][$form->getName()], $this->data['forms_by_hash']);
188189
}
189190

190191
/**
@@ -194,7 +195,7 @@ public function buildFinalFormTree(FormInterface $form, FormView $view)
194195
{
195196
$this->data['forms'][$form->getName()] = array();
196197

197-
$this->recursiveBuildFinalFormTree($form, $view, $this->data['forms'][$form->getName()]);
198+
$this->recursiveBuildFinalFormTree($form, $view, $this->data['forms'][$form->getName()], $this->data['forms_by_hash']);
198199
}
199200

200201
/**
@@ -213,24 +214,26 @@ public function getData()
213214
return $this->data;
214215
}
215216

216-
private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output = null)
217+
private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output = null, array &$outputByHash)
217218
{
218219
$hash = spl_object_hash($form);
219220

220221
$output = isset($this->dataByForm[$hash])
221222
? $this->dataByForm[$hash]
222223
: array();
223224

225+
$outputByHash[$hash] = &$output;
226+
224227
$output['children'] = array();
225228

226229
foreach ($form as $name => $child) {
227230
$output['children'][$name] = array();
228231

229-
$this->recursiveBuildPreliminaryFormTree($child, $output['children'][$name]);
232+
$this->recursiveBuildPreliminaryFormTree($child, $output['children'][$name], $outputByHash);
230233
}
231234
}
232235

233-
private function recursiveBuildFinalFormTree(FormInterface $form = null, FormView $view, &$output = null)
236+
private function recursiveBuildFinalFormTree(FormInterface $form = null, FormView $view, &$output = null, array &$outputByHash)
234237
{
235238
$viewHash = spl_object_hash($view);
236239
$formHash = null;
@@ -255,6 +258,8 @@ private function recursiveBuildFinalFormTree(FormInterface $form = null, FormVie
255258
? $this->dataByForm[$formHash]
256259
: array()
257260
);
261+
262+
$outputByHash[$formHash] = &$output;
258263
}
259264

260265
$output['children'] = array();
@@ -268,7 +273,7 @@ private function recursiveBuildFinalFormTree(FormInterface $form = null, FormVie
268273

269274
$output['children'][$name] = array();
270275

271-
$this->recursiveBuildFinalFormTree($childForm, $childView, $output['children'][$name]);
276+
$this->recursiveBuildFinalFormTree($childForm, $childView, $output['children'][$name], $outputByHash);
272277
}
273278
}
274279
}

‎src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php
+26-3Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Form\FormInterface;
1515
use Symfony\Component\Form\FormView;
1616
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
17+
use Symfony\Component\Validator\ConstraintViolationInterface;
1718

1819
/**
1920
* Default implementation of {@link FormDataExtractorInterface}.
@@ -43,6 +44,7 @@ public function extractConfiguration(FormInterface $form)
4344
{
4445
$data = array(
4546
'id' => $this->buildId($form),
47+
'name' => $form->getName(),
4648
'type' => $form->getConfig()->getType()->getName(),
4749
'type_class' => get_class($form->getConfig()->getType()->getInnerType()),
4850
'synchronized' => $this->valueExporter->exportValue($form->isSynchronized()),
@@ -108,9 +110,26 @@ public function extractSubmittedData(FormInterface $form)
108110
}
109111

110112
foreach ($form->getErrors() as $error) {
111-
$data['errors'][] = array(
113+
$errorData = array(
112114
'message' => $error->getMessage(),
115+
'origin' => is_object($error->getOrigin())
116+
? spl_object_hash($error->getOrigin())
117+
: null,
113118
);
119+
120+
$cause = $error->getCause();
121+
122+
if ($cause instanceof ConstraintViolationInterface) {
123+
$errorData['cause'] = array(
124+
'root' => $this->valueExporter->exportValue($cause->getRoot()),
125+
'path' => $this->valueExporter->exportValue($cause->getPropertyPath()),
126+
'value' => $this->valueExporter->exportValue($cause->getInvalidValue()),
127+
);
128+
} else {
129+
$errorData['cause'] = null !== $cause ? $this->valueExporter->exportValue($cause) : null;
130+
}
131+
132+
$data['errors'][] = $errorData;
114133
}
115134

116135
$data['synchronized'] = $this->valueExporter->exportValue($form->isSynchronized());
@@ -127,8 +146,12 @@ public function extractViewVariables(FormView $view)
127146

128147
// Set the ID in case no FormInterface object was collected for this
129148
// view
130-
if (isset($view->vars['id'])) {
131-
$data['id'] = $view->vars['id'];
149+
if (!isset($data['id'])) {
150+
$data['id'] = isset($view->vars['id']) ? $view->vars['id'] : null;
151+
}
152+
153+
if (!isset($data['name'])) {
154+
$data['name'] = isset($view->vars['name']) ? $view->vars['name'] : null;
132155
}
133156

134157
foreach ($view->vars as $varName => $value) {

‎src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ public function mapViolation(ConstraintViolation $violation, FormInterface $form
128128
$violation->getMessage(),
129129
$violation->getMessageTemplate(),
130130
$violation->getMessageParameters(),
131-
$violation->getMessagePluralization()
131+
$violation->getMessagePluralization(),
132+
$violation
132133
));
133134
}
134135
}

‎src/Symfony/Component/Form/Form.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Form.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,10 @@ public function bind($submittedData)
673673
public function addError(FormError $error)
674674
{
675675
if ($this->parent && $this->config->getErrorBubbling()) {
676+
if (null === $error->getOrigin()) {
677+
$error->setOrigin($this);
678+
}
679+
676680
$this->parent->addError($error);
677681
} else {
678682
$this->errors[] = $error;

‎src/Symfony/Component/Form/FormError.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/FormError.php
+83-3Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111

1212
namespace Symfony\Component\Form;
1313

14+
use Symfony\Component\Form\Exception\BadMethodCallException;
15+
1416
/**
1517
* Wraps errors in forms
1618
*
1719
* @author Bernhard Schussek <bschussek@gmail.com>
1820
*/
19-
class FormError
21+
class FormError implements \Serializable
2022
{
2123
/**
2224
* @var string
@@ -41,6 +43,18 @@ class FormError
4143
*/
4244
protected $messagePluralization;
4345

46+
/**
47+
* The cause for this error
48+
* @var mixed
49+
*/
50+
private $cause;
51+
52+
/**
53+
* The form that spawned this error
54+
* @var FormInterface
55+
*/
56+
private $origin;
57+
4458
/**
4559
* Constructor
4660
*
@@ -50,17 +64,19 @@ class FormError
5064
* @param string $message The translated error message
5165
* @param string|null $messageTemplate The template for the error message
5266
* @param array $messageParameters The parameters that should be
53-
* substituted in the message template.
67+
* substituted in the message template
5468
* @param integer|null $messagePluralization The value for error message pluralization
69+
* @param mixed $cause The cause of the error
5570
*
5671
* @see \Symfony\Component\Translation\Translator
5772
*/
58-
public function __construct($message, $messageTemplate = null, array $messageParameters = array(), $messagePluralization = null)
73+
public function __construct($message, $messageTemplate = null, array $messageParameters = array(), $messagePluralization = null, $cause = null)
5974
{
6075
$this->message = $message;
6176
$this->messageTemplate = $messageTemplate ?: $message;
6277
$this->messageParameters = $messageParameters;
6378
$this->messagePluralization = $messagePluralization;
79+
$this->cause = $cause;
6480
}
6581

6682
/**
@@ -102,4 +118,68 @@ public function getMessagePluralization()
102118
{
103119
return $this->messagePluralization;
104120
}
121+
122+
/**
123+
* Returns the cause of this error.
124+
*
125+
* @return mixed The cause of this error
126+
*/
127+
public function getCause()
128+
{
129+
return $this->cause;
130+
}
131+
132+
/**
133+
* Sets the form that caused this error.
134+
*
135+
* This method must only be called once.
136+
*
137+
* @param FormInterface $origin The form that caused this error
138+
*
139+
* @throws BadMethodCallException If the method is called more than once
140+
*/
141+
public function setOrigin(FormInterface $origin)
142+
{
143+
if (null !== $this->origin) {
144+
throw new BadMethodCallException('setOrigin() must only be called once.');
145+
}
146+
147+
$this->origin = $origin;
148+
}
149+
150+
/**
151+
* Returns the form that caused this error.
152+
*
153+
* @return FormInterface The form that caused this error
154+
*/
155+
public function getOrigin()
156+
{
157+
return $this->origin;
158+
}
159+
160+
/**
161+
* Serializes this error.
162+
*
163+
* @return string The serialized error
164+
*/
165+
public function serialize()
166+
{
167+
return serialize(array(
168+
$this->message,
169+
$this->messageTemplate,
170+
$this->messageParameters,
171+
$this->messagePluralization,
172+
$this->cause
173+
));
174+
}
175+
176+
/**
177+
* Unserializes a serialized error.
178+
*
179+
* @param string $serialized The serialized error
180+
*/
181+
public function unserialize($serialized)
182+
{
183+
list($this->message, $this->messageTemplate, $this->messageParameters, $this->messagePluralization, $this->cause) = unserialize($serialized);
184+
}
105185
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.